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