Commit 92133ef4 authored by Stephen Hemminger's avatar Stephen Hemminger Committed by David S. Miller

[NET]: Convert SLIP driver to alloc_netdev.

parent 760bddfb
...@@ -83,12 +83,7 @@ ...@@ -83,12 +83,7 @@
#define SLIP_VERSION "0.8.4-NET3.019-NEWTTY" #define SLIP_VERSION "0.8.4-NET3.019-NEWTTY"
static struct net_device **slip_devs;
typedef struct slip_ctrl {
struct slip ctrl; /* SLIP things */
struct net_device dev; /* the device */
} slip_ctrl_t;
static slip_ctrl_t **slip_ctrls;
int slip_maxdev = SL_NRUNIT; /* Can be overridden with insmod! */ int slip_maxdev = SL_NRUNIT; /* Can be overridden with insmod! */
MODULE_PARM(slip_maxdev, "i"); MODULE_PARM(slip_maxdev, "i");
...@@ -624,32 +619,45 @@ static int sl_init(struct net_device *dev) ...@@ -624,32 +619,45 @@ static int sl_init(struct net_device *dev)
*/ */
dev->mtu = sl->mtu; dev->mtu = sl->mtu;
dev->hard_start_xmit = sl_xmit; dev->type = ARPHRD_SLIP + sl->mode;
#ifdef SL_CHECK_TRANSMIT #ifdef SL_CHECK_TRANSMIT
dev->tx_timeout = sl_tx_timeout; dev->tx_timeout = sl_tx_timeout;
dev->watchdog_timeo = 20*HZ; dev->watchdog_timeo = 20*HZ;
#endif #endif
return 0;
}
static void sl_uninit(struct net_device *dev)
{
struct slip *sl = (struct slip*)(dev->priv);
sl_free_bufs(sl);
}
static void sl_setup(struct net_device *dev)
{
dev->init = sl_init;
dev->uninit = sl_uninit;
dev->open = sl_open; dev->open = sl_open;
dev->destructor = (void (*)(struct net_device *))kfree;
dev->stop = sl_close; dev->stop = sl_close;
dev->get_stats = sl_get_stats; dev->get_stats = sl_get_stats;
dev->change_mtu = sl_change_mtu; dev->change_mtu = sl_change_mtu;
dev->hard_start_xmit = sl_xmit;
#ifdef CONFIG_SLIP_SMART #ifdef CONFIG_SLIP_SMART
dev->do_ioctl = sl_ioctl; dev->do_ioctl = sl_ioctl;
#endif #endif
dev->hard_header_len = 0; dev->hard_header_len = 0;
dev->addr_len = 0; dev->addr_len = 0;
dev->type = ARPHRD_SLIP + sl->mode;
dev->tx_queue_len = 10; dev->tx_queue_len = 10;
SET_MODULE_OWNER(dev); SET_MODULE_OWNER(dev);
/* New-style flags. */ /* New-style flags. */
dev->flags = IFF_NOARP|IFF_POINTOPOINT|IFF_MULTICAST; dev->flags = IFF_NOARP|IFF_POINTOPOINT|IFF_MULTICAST;
return 0;
} }
/****************************************** /******************************************
Routines looking at TTY side. Routines looking at TTY side.
******************************************/ ******************************************/
...@@ -702,52 +710,57 @@ static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, ch ...@@ -702,52 +710,57 @@ static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, ch
static void sl_sync(void) static void sl_sync(void)
{ {
int i; int i;
struct net_device *dev;
struct slip *sl;
for (i = 0; i < slip_maxdev; i++) { for (i = 0; i < slip_maxdev; i++) {
slip_ctrl_t *slp = slip_ctrls[i]; if ((dev = slip_devs[i]) == NULL)
if (slp == NULL)
break; break;
if (slp->ctrl.tty || slp->ctrl.leased)
sl = dev->priv;
if (sl->tty || sl->leased)
continue; continue;
if (slp->dev.flags&IFF_UP) if (dev->flags&IFF_UP)
dev_close(&slp->dev); dev_close(dev);
} }
} }
/* Find a free SLIP channel, and link in this `tty' line. */ /* Find a free SLIP channel, and link in this `tty' line. */
static struct slip * static struct slip *
sl_alloc(dev_t line) sl_alloc(dev_t line)
{ {
struct slip *sl;
slip_ctrl_t *slp = NULL;
int i; int i;
int sel = -1; int sel = -1;
int score = -1; int score = -1;
struct net_device *dev = NULL;
struct slip *sl;
if (slip_ctrls == NULL) if (slip_devs == NULL)
return NULL; /* Master array missing ! */ return NULL; /* Master array missing ! */
for (i = 0; i < slip_maxdev; i++) { for (i = 0; i < slip_maxdev; i++) {
slp = slip_ctrls[i]; dev = slip_devs[i];
if (slp == NULL) if (dev == NULL)
break; break;
if (slp->ctrl.leased) { sl = dev->priv;
if (slp->ctrl.line != line) if (sl->leased) {
if (sl->line != line)
continue; continue;
if (slp->ctrl.tty) if (sl->tty)
return NULL; return NULL;
/* Clear ESCAPE & ERROR flags */ /* Clear ESCAPE & ERROR flags */
slp->ctrl.flags &= (1 << SLF_INUSE); sl->flags &= (1 << SLF_INUSE);
return &slp->ctrl; return sl;
} }
if (slp->ctrl.tty) if (sl->tty)
continue; continue;
if (current->pid == slp->ctrl.pid) { if (current->pid == sl->pid) {
if (slp->ctrl.line == line && score < 3) { if (sl->line == line && score < 3) {
sel = i; sel = i;
score = 3; score = 3;
continue; continue;
...@@ -758,7 +771,7 @@ sl_alloc(dev_t line) ...@@ -758,7 +771,7 @@ sl_alloc(dev_t line)
} }
continue; continue;
} }
if (slp->ctrl.line == line && score < 1) { if (sl->line == line && score < 1) {
sel = i; sel = i;
score = 1; score = 1;
continue; continue;
...@@ -771,10 +784,11 @@ sl_alloc(dev_t line) ...@@ -771,10 +784,11 @@ sl_alloc(dev_t line)
if (sel >= 0) { if (sel >= 0) {
i = sel; i = sel;
slp = slip_ctrls[i]; dev = slip_devs[i];
if (score > 1) { if (score > 1) {
slp->ctrl.flags &= (1 << SLF_INUSE); sl = dev->priv;
return &slp->ctrl; sl->flags &= (1 << SLF_INUSE);
return sl;
} }
} }
...@@ -782,26 +796,32 @@ sl_alloc(dev_t line) ...@@ -782,26 +796,32 @@ sl_alloc(dev_t line)
if (i >= slip_maxdev) if (i >= slip_maxdev)
return NULL; return NULL;
if (slp) { if (dev) {
if (test_bit(SLF_INUSE, &slp->ctrl.flags)) { sl = dev->priv;
unregister_netdevice(&slp->dev); if (test_bit(SLF_INUSE, &sl->flags)) {
sl_free_bufs(&slp->ctrl); unregister_netdevice(dev);
dev = NULL;
slip_devs[i] = NULL;
} }
} else if ((slp = (slip_ctrl_t *)kmalloc(sizeof(slip_ctrl_t),GFP_KERNEL)) == NULL) }
return NULL;
if (!dev) {
char name[IFNAMSIZ];
sprintf(name, "sl%d", i);
dev = alloc_netdev(sizeof(*sl), name, sl_setup);
if (!dev)
return NULL;
dev->base_addr = i;
}
memset(slp, 0, sizeof(slip_ctrl_t)); sl = dev->priv;
sl = &slp->ctrl;
/* Initialize channel control data */ /* Initialize channel control data */
sl->magic = SLIP_MAGIC; sl->magic = SLIP_MAGIC;
sl->dev = &slp->dev; sl->dev = dev;
spin_lock_init(&sl->lock); spin_lock_init(&sl->lock);
sl->mode = SL_MODE_DEFAULT; sl->mode = SL_MODE_DEFAULT;
sprintf(slp->dev.name, "sl%d", i);
slp->dev.base_addr = i;
slp->dev.priv = (void*)sl;
slp->dev.init = sl_init;
#ifdef CONFIG_SLIP_SMART #ifdef CONFIG_SLIP_SMART
init_timer(&sl->keepalive_timer); /* initialize timer_list struct */ init_timer(&sl->keepalive_timer); /* initialize timer_list struct */
sl->keepalive_timer.data=(unsigned long)sl; sl->keepalive_timer.data=(unsigned long)sl;
...@@ -810,8 +830,9 @@ sl_alloc(dev_t line) ...@@ -810,8 +830,9 @@ sl_alloc(dev_t line)
sl->outfill_timer.data=(unsigned long)sl; sl->outfill_timer.data=(unsigned long)sl;
sl->outfill_timer.function=sl_outfill; sl->outfill_timer.function=sl_outfill;
#endif #endif
slip_ctrls[i] = slp; slip_devs[i] = dev;
return &slp->ctrl;
return sl;
} }
/* /*
...@@ -865,12 +886,10 @@ slip_open(struct tty_struct *tty) ...@@ -865,12 +886,10 @@ slip_open(struct tty_struct *tty)
if ((err = sl_alloc_bufs(sl, SL_MTU)) != 0) if ((err = sl_alloc_bufs(sl, SL_MTU)) != 0)
goto err_free_chan; goto err_free_chan;
if (register_netdevice(sl->dev)) {
sl_free_bufs(sl);
goto err_free_chan;
}
set_bit(SLF_INUSE, &sl->flags); set_bit(SLF_INUSE, &sl->flags);
if ((err = register_netdevice(sl->dev)))
goto err_free_bufs;
} }
#ifdef CONFIG_SLIP_SMART #ifdef CONFIG_SLIP_SMART
...@@ -888,6 +907,9 @@ slip_open(struct tty_struct *tty) ...@@ -888,6 +907,9 @@ slip_open(struct tty_struct *tty)
rtnl_unlock(); rtnl_unlock();
return sl->dev->base_addr; return sl->dev->base_addr;
err_free_bufs:
sl_free_bufs(sl);
err_free_chan: err_free_chan:
sl->tty = NULL; sl->tty = NULL;
tty->disc_data = NULL; tty->disc_data = NULL;
...@@ -1335,14 +1357,14 @@ static int __init slip_init(void) ...@@ -1335,14 +1357,14 @@ static int __init slip_init(void)
printk(KERN_INFO "SLIP linefill/keepalive option.\n"); printk(KERN_INFO "SLIP linefill/keepalive option.\n");
#endif #endif
slip_ctrls = kmalloc(sizeof(void*)*slip_maxdev, GFP_KERNEL); slip_devs = kmalloc(sizeof(struct net_device *)*slip_maxdev, GFP_KERNEL);
if (!slip_ctrls) { if (!slip_devs) {
printk(KERN_ERR "SLIP: Can't allocate slip_ctrls[] array! Uaargh! (-> No SLIP available)\n"); printk(KERN_ERR "SLIP: Can't allocate slip devices array! Uaargh! (-> No SLIP available)\n");
return -ENOMEM; return -ENOMEM;
} }
/* Clear the pointer array, we allocate devices when we need them */ /* Clear the pointer array, we allocate devices when we need them */
memset(slip_ctrls, 0, sizeof(void*)*slip_maxdev); /* Pointers */ memset(slip_devs, 0, sizeof(struct net_device *)*slip_maxdev);
/* Fill in our line protocol discipline, and register it */ /* Fill in our line protocol discipline, and register it */
if ((status = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0) { if ((status = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0) {
...@@ -1354,51 +1376,59 @@ static int __init slip_init(void) ...@@ -1354,51 +1376,59 @@ static int __init slip_init(void)
static void __exit slip_exit(void) static void __exit slip_exit(void)
{ {
int i; int i;
struct net_device *dev;
struct slip *sl;
unsigned long timeout = jiffies + HZ;
int busy = 0;
if (slip_ctrls != NULL) { if (slip_devs == NULL)
unsigned long timeout = jiffies + HZ; return;
int busy = 0;
/* First of all: check for active disciplines and hangup them. /* First of all: check for active disciplines and hangup them.
*/ */
do { do {
if (busy) if (busy) {
yield(); current->state = TASK_INTERRUPTIBLE;
schedule_timeout(HZ / 10);
busy = 0; current->state = TASK_RUNNING;
local_bh_disable(); }
for (i = 0; i < slip_maxdev; i++) {
struct slip_ctrl *slc = slip_ctrls[i];
if (!slc)
continue;
spin_lock(&slc->ctrl.lock);
if (slc->ctrl.tty) {
busy++;
tty_hangup(slc->ctrl.tty);
}
spin_unlock(&slc->ctrl.lock);
}
local_bh_enable();
} while (busy && time_before(jiffies, timeout));
busy = 0;
for (i = 0; i < slip_maxdev; i++) { for (i = 0; i < slip_maxdev; i++) {
struct slip_ctrl *slc = slip_ctrls[i]; dev = slip_devs[i];
if (slc) { if (!dev)
unregister_netdev(&slc->dev); continue;
if (slc->ctrl.tty) { sl = dev->priv;
printk(KERN_ERR "%s: tty discipline is still running\n", slc->dev.name); spin_lock_bh(&sl->lock);
/* Intentionally leak the control block. */ if (sl->tty) {
} else { busy++;
sl_free_bufs(&slc->ctrl); tty_hangup(sl->tty);
kfree(slc);
}
slip_ctrls[i] = NULL;
} }
spin_unlock_bh(&sl->lock);
} }
} while (busy && time_before(jiffies, timeout));
for (i = 0; i < slip_maxdev; i++) {
dev = slip_devs[i];
if (!dev)
continue;
slip_devs[i] = NULL;
sl = dev->priv;
if (sl->tty) {
printk(KERN_ERR "%s: tty discipline still running\n",
dev->name);
/* Intentionally leak the control block. */
dev->destructor = NULL;
}
kfree(slip_ctrls); unregister_netdev(dev);
slip_ctrls = NULL;
} }
kfree(slip_devs);
slip_devs = NULL;
if ((i = tty_register_ldisc(N_SLIP, NULL))) if ((i = tty_register_ldisc(N_SLIP, NULL)))
{ {
printk(KERN_ERR "SLIP: can't unregister line discipline (err = %d)\n", i); printk(KERN_ERR "SLIP: can't unregister line discipline (err = %d)\n", i);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment