Commit c9f8652f authored by Stephen Hemminger's avatar Stephen Hemminger

[NET]: Convert ltpc to new initialization.

Originally from Al Viro
NE11-ltpc
* switched ltpc to dynamic allocation
* ltpc: embedded ->priv
* ltpc: fixed bugs in DMA allocation
* ltpc: fixed resource leaks on failure exits
* ltpc: fixed part of timer bugs (still a-f**ing-plenty of those)
* ltpc: fixed order of freeing bugs
Added
* switch to free_netdev
parent 4e39f29b
...@@ -103,6 +103,9 @@ extern struct net_device *sdla_init(void); ...@@ -103,6 +103,9 @@ extern struct net_device *sdla_init(void);
#ifdef CONFIG_COPS #ifdef CONFIG_COPS
extern struct net_device *cops_probe(int unit); extern struct net_device *cops_probe(int unit);
#endif #endif
#ifdef CONFIG_LTPC
extern struct net_device *ltpc_probe(void);
#endif
/* Detachable devices ("pocket adaptors") */ /* Detachable devices ("pocket adaptors") */
extern int de620_probe(struct net_device *); extern int de620_probe(struct net_device *);
...@@ -470,23 +473,15 @@ void __init probe_old_netdevs(void) ...@@ -470,23 +473,15 @@ void __init probe_old_netdevs(void)
cops_probe(1); cops_probe(1);
cops_probe(2); cops_probe(2);
#endif #endif
#ifdef CONFIG_LTPC
ltpc_probe();
#endif
#ifdef CONFIG_SDLA #ifdef CONFIG_SDLA
sdla_init(); sdla_init();
#endif #endif
} }
#if defined(CONFIG_LTPC)
extern int ltpc_probe(struct net_device *);
static struct net_device dev_ltpc = {
.name = "lt0",
.next = NEXT_DEV,
.init = ltpc_probe
};
#undef NEXT_DEV
#define NEXT_DEV (&dev_ltpc)
#endif /* LTPC */
/* /*
* The @dev_base list is protected by @dev_base_lock and the rtln * The @dev_base list is protected by @dev_base_lock and the rtln
* semaphore. * semaphore.
......
...@@ -879,34 +879,6 @@ static int ltpc_hard_header (struct sk_buff *skb, struct net_device *dev, ...@@ -879,34 +879,6 @@ static int ltpc_hard_header (struct sk_buff *skb, struct net_device *dev,
return 0; return 0;
} }
static int ltpc_init(struct net_device *dev)
{
/* Initialize the device structure. */
/* Fill in the fields of the device structure with ethernet-generic values. */
ltalk_setup(dev);
dev->hard_start_xmit = ltpc_xmit;
dev->hard_header = ltpc_hard_header;
dev->priv = kmalloc(sizeof(struct ltpc_private), GFP_KERNEL);
if(!dev->priv)
{
printk(KERN_INFO "%s: could not allocate statistics buffer\n", dev->name);
return -ENOMEM;
}
memset(dev->priv, 0, sizeof(struct ltpc_private));
dev->get_stats = ltpc_get_stats;
/* add the ltpc-specific things */
dev->do_ioctl = &ltpc_ioctl;
dev->set_multicast_list = &set_multicast_list;
dev->mc_list = NULL;
return 0;
}
static int ltpc_poll_counter; static int ltpc_poll_counter;
static void ltpc_poll(unsigned long l) static void ltpc_poll(unsigned long l)
...@@ -983,35 +955,40 @@ static struct net_device_stats *ltpc_get_stats(struct net_device *dev) ...@@ -983,35 +955,40 @@ static struct net_device_stats *ltpc_get_stats(struct net_device *dev)
/* initialization stuff */ /* initialization stuff */
static int __init ltpc_probe_dma(int base) static int __init ltpc_probe_dma(int base, int dma)
{ {
int dma = 0; int want = (dma == 3) ? 2 : (dma == 1) ? 1 : 3;
unsigned long timeout; unsigned long timeout;
unsigned long f; unsigned long f;
if (!request_dma(1,"ltpc")) { if (want & 1) {
f=claim_dma_lock(); if (request_dma(1,"ltpc")) {
disable_dma(1); want &= ~1;
clear_dma_ff(1); } else {
set_dma_mode(1,DMA_MODE_WRITE); f=claim_dma_lock();
set_dma_addr(1,virt_to_bus(ltdmabuf)); disable_dma(1);
set_dma_count(1,sizeof(struct lt_mem)); clear_dma_ff(1);
enable_dma(1); set_dma_mode(1,DMA_MODE_WRITE);
release_dma_lock(f); set_dma_addr(1,virt_to_bus(ltdmabuf));
dma|=1; set_dma_count(1,sizeof(struct lt_mem));
enable_dma(1);
release_dma_lock(f);
}
} }
if (!request_dma(3,"ltpc")) { if (want & 2) {
f=claim_dma_lock(); if (request_dma(3,"ltpc")) {
disable_dma(3); want &= ~2;
clear_dma_ff(3); } else {
set_dma_mode(3,DMA_MODE_WRITE); f=claim_dma_lock();
set_dma_addr(3,virt_to_bus(ltdmabuf)); disable_dma(3);
set_dma_count(3,sizeof(struct lt_mem)); clear_dma_ff(3);
enable_dma(3); set_dma_mode(3,DMA_MODE_WRITE);
release_dma_lock(f); set_dma_addr(3,virt_to_bus(ltdmabuf));
dma|=2; set_dma_count(3,sizeof(struct lt_mem));
enable_dma(3);
release_dma_lock(f);
}
} }
/* set up request */ /* set up request */
/* FIXME -- do timings better! */ /* FIXME -- do timings better! */
...@@ -1037,65 +1014,62 @@ static int __init ltpc_probe_dma(int base) ...@@ -1037,65 +1014,62 @@ static int __init ltpc_probe_dma(int base)
/* release the other dma channel (if we opened both of them) */ /* release the other dma channel (if we opened both of them) */
if ( (dma&0x2) && (get_dma_residue(3)==sizeof(struct lt_mem)) ){ if ((want & 2) && (get_dma_residue(3)==sizeof(struct lt_mem))) {
dma&=1; want &= ~2;
free_dma(3); free_dma(3);
} }
if ( (dma&0x1) && (get_dma_residue(1)==sizeof(struct lt_mem)) ){ if ((want & 1) && (get_dma_residue(1)==sizeof(struct lt_mem))) {
dma&=0x2; want &= ~1;
free_dma(1); free_dma(1);
} }
/* fix up dma number */ if (!want)
dma|=1; return 0;
return dma; return (want & 2) ? 3 : 1;
} }
int __init ltpc_probe(struct net_device *dev) struct net_device * __init ltpc_probe(void)
{ {
int err; struct net_device *dev;
int err = -ENOMEM;
int x=0,y=0; int x=0,y=0;
int autoirq; int autoirq;
unsigned long f; unsigned long f;
int portfound=0;
unsigned long timeout; unsigned long timeout;
dev = alloc_netdev(sizeof(struct ltpc_private), "lt%d", ltalk_setup);
if (!dev)
goto out;
SET_MODULE_OWNER(dev); SET_MODULE_OWNER(dev);
/* probe for the I/O port address */ /* probe for the I/O port address */
if (io != 0x240 && request_region(0x220,8,"ltpc")) { if (io != 0x240 && request_region(0x220,8,"ltpc")) {
x = inb_p(0x220+6); x = inb_p(0x220+6);
if ( (x!=0xff) && (x>=0xf0) ) { if ( (x!=0xff) && (x>=0xf0) ) {
io = 0x220; io = 0x220;
portfound=1; goto got_port;
}
else {
release_region(0x220,8);
} }
release_region(0x220,8);
} }
if (io != 0x220 && request_region(0x240,8,"ltpc")) { if (io != 0x220 && request_region(0x240,8,"ltpc")) {
y = inb_p(0x240+6); y = inb_p(0x240+6);
if ( (y!=0xff) && (y>=0xf0) ){ if ( (y!=0xff) && (y>=0xf0) ){
io = 0x240; io = 0x240;
portfound=1; goto got_port;
}
else {
release_region(0x240,8);
} }
release_region(0x240,8);
} }
if(io && !portfound && request_region(io,8,"ltpc")){ /* give up in despair */
portfound = 1; printk(KERN_ERR "LocalTalk card not found; 220 = %02x, 240 = %02x.\n", x,y);
} err = -ENODEV;
if(!portfound) { goto out1;
/* give up in despair */
printk(KERN_ERR "LocalTalk card not found; 220 = %02x, 240 = %02x.\n", x,y);
return -1;
}
got_port:
/* probe for the IRQ line */ /* probe for the IRQ line */
if (irq < 2) { if (irq < 2) {
unsigned long irq_mask; unsigned long irq_mask;
...@@ -1111,22 +1085,21 @@ int __init ltpc_probe(struct net_device *dev) ...@@ -1111,22 +1085,21 @@ int __init ltpc_probe(struct net_device *dev)
if (autoirq == 0) { if (autoirq == 0) {
printk(KERN_ERR "ltpc: probe at %#x failed to detect IRQ line.\n", io); printk(KERN_ERR "ltpc: probe at %#x failed to detect IRQ line.\n", io);
} } else {
else {
irq = autoirq; irq = autoirq;
} }
} }
/* allocate a DMA buffer */ /* allocate a DMA buffer */
ltdmabuf = (unsigned char *) dma_mem_alloc(1000); ltdmabuf = (unsigned char *) dma_mem_alloc(1000);
if (ltdmabuf) ltdmacbuf = &ltdmabuf[800];
if (!ltdmabuf) { if (!ltdmabuf) {
printk(KERN_ERR "ltpc: mem alloc failed\n"); printk(KERN_ERR "ltpc: mem alloc failed\n");
return -1; err = -ENOMEM;
goto out2;
} }
ltdmacbuf = &ltdmabuf[800];
if(debug & DEBUG_VERBOSE) { if(debug & DEBUG_VERBOSE) {
printk("ltdmabuf pointer %08lx\n",(unsigned long) ltdmabuf); printk("ltdmabuf pointer %08lx\n",(unsigned long) ltdmabuf);
} }
...@@ -1154,25 +1127,29 @@ int __init ltpc_probe(struct net_device *dev) ...@@ -1154,25 +1127,29 @@ int __init ltpc_probe(struct net_device *dev)
already been specified */ already been specified */
/* well, 0 is a legal DMA channel, but the LTPC card doesn't /* well, 0 is a legal DMA channel, but the LTPC card doesn't
use it... */ use it... */
if (dma == 0) { dma = ltpc_probe_dma(io, dma);
dma = ltpc_probe_dma(io); if (!dma) { /* no dma channel */
if (!dma) { /* no dma channel */ printk(KERN_ERR "No DMA channel found on ltpc card.\n");
printk(KERN_ERR "No DMA channel found on ltpc card.\n"); err = -ENODEV;
return -1; goto out3;
}
} }
/* print out friendly message */ /* print out friendly message */
if(irq) if(irq)
printk(KERN_INFO "Apple/Farallon LocalTalk-PC card at %03x, IR%d, DMA%d.\n",io,irq,dma); printk(KERN_INFO "Apple/Farallon LocalTalk-PC card at %03x, IR%d, DMA%d.\n",io,irq,dma);
else else
printk(KERN_INFO "Apple/Farallon LocalTalk-PC card at %03x, DMA%d. Using polled mode.\n",io,dma); printk(KERN_INFO "Apple/Farallon LocalTalk-PC card at %03x, DMA%d. Using polled mode.\n",io,dma);
/* seems more logical to do this *after* probing the card... */ /* Fill in the fields of the device structure with ethernet-generic values. */
err = ltpc_init(dev); dev->hard_start_xmit = ltpc_xmit;
if (err) return err; dev->hard_header = ltpc_hard_header;
dev->get_stats = ltpc_get_stats;
/* add the ltpc-specific things */
dev->do_ioctl = &ltpc_ioctl;
dev->set_multicast_list = &set_multicast_list;
dev->mc_list = NULL;
dev->base_addr = io; dev->base_addr = io;
dev->irq = irq; dev->irq = irq;
dev->dma = dma; dev->dma = dma;
...@@ -1212,6 +1189,7 @@ int __init ltpc_probe(struct net_device *dev) ...@@ -1212,6 +1189,7 @@ int __init ltpc_probe(struct net_device *dev)
} else { } else {
if( irq ) if( irq )
printk(KERN_ERR "ltpc: IRQ already in use, using polled mode.\n"); printk(KERN_ERR "ltpc: IRQ already in use, using polled mode.\n");
dev->irq = 0;
/* polled mode -- 20 times per second */ /* polled mode -- 20 times per second */
/* this is really, really slow... should it poll more often? */ /* this is really, really slow... should it poll more often? */
init_timer(&ltpc_timer); init_timer(&ltpc_timer);
...@@ -1221,8 +1199,23 @@ int __init ltpc_probe(struct net_device *dev) ...@@ -1221,8 +1199,23 @@ int __init ltpc_probe(struct net_device *dev)
ltpc_timer.expires = jiffies + HZ/20; ltpc_timer.expires = jiffies + HZ/20;
add_timer(&ltpc_timer); add_timer(&ltpc_timer);
} }
err = register_netdev(dev);
if (err)
goto out4;
return 0; return 0;
out4:
del_timer_sync(&ltpc_timer);
if (dev->irq)
free_irq(dev->irq, dev);
out3:
free_pages((unsigned long)ltdmabuf, get_order(1000));
out2:
release_region(io, 8);
out1:
kfree(dev);
out:
return ERR_PTR(err);
} }
#ifndef MODULE #ifndef MODULE
...@@ -1259,7 +1252,7 @@ static int __init ltpc_setup(char *str) ...@@ -1259,7 +1252,7 @@ static int __init ltpc_setup(char *str)
__setup("ltpc=", ltpc_setup); __setup("ltpc=", ltpc_setup);
#endif /* MODULE */ #endif /* MODULE */
static struct net_device dev_ltpc; static struct net_device *dev_ltpc;
#ifdef MODULE #ifdef MODULE
...@@ -1272,79 +1265,47 @@ MODULE_PARM(dma, "i"); ...@@ -1272,79 +1265,47 @@ MODULE_PARM(dma, "i");
int __init init_module(void) int __init init_module(void)
{ {
int err, result;
if(io == 0) if(io == 0)
printk(KERN_NOTICE printk(KERN_NOTICE
"ltpc: Autoprobing is not recommended for modules\n"); "ltpc: Autoprobing is not recommended for modules\n");
/* Find a name for this unit */ dev_ltpc = ltpc_probe();
dev_ltpc.init = ltpc_probe; if (IS_ERR(dev_ltpc))
err=dev_alloc_name(&dev_ltpc,"lt%d"); return PTR_ERR(dev_ltpc);
return 0;
if(err<0)
return err;
if ((result = register_netdev(&dev_ltpc)) != 0) {
printk(KERN_DEBUG "could not register Localtalk-PC device\n");
return result;
} else {
if(debug & DEBUG_VERBOSE) printk("0 from register_netdev\n");
return 0;
}
} }
#endif #endif
static void __exit ltpc_cleanup(void) static void __exit ltpc_cleanup(void)
{ {
unsigned long timeout;
if(debug & DEBUG_VERBOSE) printk("unregister_netdev\n");
unregister_netdev(dev_ltpc);
ltpc_timer.data = 0; /* signal the poll routine that we're done */ ltpc_timer.data = 0; /* signal the poll routine that we're done */
del_timer_sync(&ltpc_timer);
if(debug & DEBUG_VERBOSE) printk("freeing irq\n"); if(debug & DEBUG_VERBOSE) printk("freeing irq\n");
if(dev_ltpc.irq) { if (dev_ltpc->irq)
free_irq(dev_ltpc.irq,&dev_ltpc); free_irq(dev_ltpc->irq, dev_ltpc);
dev_ltpc.irq = 0;
}
if(del_timer(&ltpc_timer))
{
/* either the poll was never started, or a poll is in process */
if(debug & DEBUG_VERBOSE) printk("waiting\n");
/* if it's in process, wait a bit for it to finish */
timeout = jiffies+HZ;
add_timer(&ltpc_timer);
while(del_timer(&ltpc_timer) && time_after(timeout, jiffies))
{
add_timer(&ltpc_timer);
schedule();
}
}
if(debug & DEBUG_VERBOSE) printk("freeing dma\n"); if(debug & DEBUG_VERBOSE) printk("freeing dma\n");
if(dev_ltpc.dma) { if (dev_ltpc->dma)
free_dma(dev_ltpc.dma); free_dma(dev_ltpc->dma);
dev_ltpc.dma = 0;
}
if(debug & DEBUG_VERBOSE) printk("freeing ioaddr\n"); if(debug & DEBUG_VERBOSE) printk("freeing ioaddr\n");
if(dev_ltpc.base_addr) { if (dev_ltpc->base_addr)
release_region(dev_ltpc.base_addr,8); release_region(dev_ltpc->base_addr,8);
dev_ltpc.base_addr = 0;
} free_netdev(dev_ltpc);
if(debug & DEBUG_VERBOSE) printk("free_pages\n"); if(debug & DEBUG_VERBOSE) printk("free_pages\n");
free_pages( (unsigned long) ltdmabuf, get_order(1000)); free_pages( (unsigned long) ltdmabuf, get_order(1000));
ltdmabuf=NULL;
ltdmacbuf=NULL;
if(debug & DEBUG_VERBOSE) printk("unregister_netdev\n");
unregister_netdev(&dev_ltpc);
if(debug & DEBUG_VERBOSE) printk("returning from cleanup_module\n"); if(debug & DEBUG_VERBOSE) printk("returning from cleanup_module\n");
} }
......
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