diff options
Diffstat (limited to 'drivers/net/sk_g16.c')
-rw-r--r-- | drivers/net/sk_g16.c | 91 |
1 files changed, 80 insertions, 11 deletions
diff --git a/drivers/net/sk_g16.c b/drivers/net/sk_g16.c index 0699fc879..0f0d15518 100644 --- a/drivers/net/sk_g16.c +++ b/drivers/net/sk_g16.c @@ -19,6 +19,8 @@ * Paul Gortmaker, 03/97: Fix for v2.1.x to use read{b,w} * write{b,w} and memcpy -> memcpy_{to,from}io * + * Jeff Garzik, 06/2000, Modularize + * -*/ static const char *rcsid = "$Id: sk_g16.c,v 1.1 1994/06/30 16:25:15 root Exp $"; @@ -53,8 +55,10 @@ static const char *rcsid = "$Id: sk_g16.c,v 1.1 1994/06/30 16:25:15 root Exp $"; * - Try to find out if the board is in 8 Bit or 16 Bit slot. * If in 8 Bit mode don't use IRQ 11. * - (Try to make it slightly faster.) + * - Power management support */ +#include <linux/module.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/ptrace.h> @@ -455,7 +459,8 @@ struct priv /* static variables */ static SK_RAM *board; /* pointer to our memory mapped board components */ - +static struct net_device *SK_dev; +unsigned long SK_ioaddr; static spinlock_t SK_lock = SPIN_LOCK_UNLOCKED; /* Macros */ @@ -537,7 +542,7 @@ void SK_print_ram(struct net_device *dev); int __init SK_init(struct net_device *dev) { - int ioaddr = 0; /* I/O port address used for POS regs */ + int ioaddr; /* I/O port address used for POS regs */ int *port, ports[] = SK_IO_PORTS; /* SK_G16 supported ports */ /* get preconfigured base_addr from dev which is done in Space.c */ @@ -548,15 +553,23 @@ int __init SK_init(struct net_device *dev) if (base_addr > 0x0ff) /* Check a single specified address */ { + int rc = -ENODEV; + + ioaddr = base_addr; + /* Check if on specified address is a SK_G16 */ + if (!request_region(ioaddr, ETHERCARD_TOTAL_SIZE, "sk_g16")) + return -EBUSY; if ( (inb(SK_POS0) == SK_IDLOW) || (inb(SK_POS1) == SK_IDHIGH) ) { - return SK_probe(dev, base_addr); + rc = SK_probe(dev, ioaddr); } - return -ENODEV; /* Sorry, but on specified address NO SK_G16 */ + if (rc) + release_region(ioaddr, ETHERCARD_TOTAL_SIZE); + return rc; } else if (base_addr > 0) /* Don't probe at all */ { @@ -571,7 +584,7 @@ int __init SK_init(struct net_device *dev) /* Check if I/O Port region is used by another board */ - if (check_region(ioaddr, ETHERCARD_TOTAL_SIZE)) + if (!request_region(ioaddr, ETHERCARD_TOTAL_SIZE, "sk_g16")) { continue; /* Try next Port address */ } @@ -581,6 +594,7 @@ int __init SK_init(struct net_device *dev) if ( !(inb(SK_POS0) == SK_IDLOW) || !(inb(SK_POS1) == SK_IDHIGH) ) { + release_region(ioaddr, ETHERCARD_TOTAL_SIZE); continue; /* Try next Port address */ } @@ -590,6 +604,8 @@ int __init SK_init(struct net_device *dev) { return 0; /* Card found and initialized */ } + + release_region(ioaddr, ETHERCARD_TOTAL_SIZE); } dev->base_addr = base_addr; /* Write back original base_addr */ @@ -598,6 +614,60 @@ int __init SK_init(struct net_device *dev) } /* End of SK_init */ + +static int io = 0; /* 0 == probe */ +MODULE_AUTHOR("Patrick J.D. Weichmann"); +MODULE_DESCRIPTION("Schneider & Koch G16 Ethernet Device Driver"); +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "0 to probe common ports (unsafe), or the I/O base of the board"); + + +#ifdef MODULE +static int __init SK_init_module (void) +{ + int rc; + + SK_dev = init_etherdev (NULL, 0); + if (!SK_dev) + return -ENOMEM; + + rc = SK_init (SK_dev); + if (rc) { + unregister_netdev (SK_dev); + kfree (SK_dev); + SK_dev = NULL; + } + + return rc; +} +#endif /* MODULE */ + + +static void __exit SK_cleanup_module (void) +{ + if (SK_dev) { + if (SK_dev->priv) { + kfree(SK_dev->priv); + SK_dev->priv = NULL; + } + unregister_netdev(SK_dev); + kfree(SK_dev); + SK_dev = NULL; + } + if (SK_ioaddr) { + release_region(SK_ioaddr, ETHERCARD_TOTAL_SIZE); + SK_ioaddr = 0; + } + +} + + +#ifdef MODULE +module_init(SK_init_module); +#endif +module_exit(SK_cleanup_module); + + /*- * Function : SK_probe @@ -774,9 +844,6 @@ int __init SK_probe(struct net_device *dev, short ioaddr) } memset((char *) dev->priv, 0, sizeof(struct priv)); /* clear memory */ - /* Grab the I/O Port region */ - request_region(ioaddr, ETHERCARD_TOTAL_SIZE,"sk_g16"); - /* Assign our Device Driver functions */ dev->open = SK_open; @@ -817,6 +884,9 @@ int __init SK_probe(struct net_device *dev, short ioaddr) SK_print_ram(dev); #endif + SK_dev = dev; + SK_ioaddr = ioaddr; + return 0; /* Initialization done */ } /* End of SK_probe() */ @@ -1078,8 +1148,7 @@ static int SK_lance_init(struct net_device *dev, unsigned short mode) /* Prepare LANCE Control and Status Registers */ - save_flags(flags); - cli(); + spin_lock_irqsave(&SK_lock, flags); SK_write_reg(CSR3, CSR3_ACON); /* Ale Control !!!THIS MUST BE SET!!!! */ @@ -1114,7 +1183,7 @@ static int SK_lance_init(struct net_device *dev, unsigned short mode) SK_write_reg(CSR0, CSR0_INIT); - restore_flags(flags); + spin_unlock_irqrestore(&SK_lock, flags); /* Wait until LANCE finished initialization */ |