3c509 as a module is different from other modules

Jacques Gelinas (jack@solucorp.qc.ca)
Thu, 14 Nov 1996 14:42:18 -0500 (EST)


I have tried to put 3 3c509's in a machine and load the driver as a
module. It has failed. I was doing something like

modprobe 3c509 io=0x300,0x320,0x340 irq=10,11,15

Only one device was detected. I have looked at the code and found out that
the 3c509 is different. It support only a single device when loaded as a
module. Further, loading the module 3 time is not an option. The 3c509 has
some magic to probe and a special static variable in 3c509.c is there to
differentiate the different adaptor at probe time.

Anyway, I have fixed this driver so it behave like other adaptor. The
change affect only the #ifdef MODULE ... #endif section. Here it is. This
is against 2.0.25.

*** linux-2.0.25/drivers/net/3c509.c Tue Oct 29 23:57:38 1996
--- linux/drivers/net/3c509.c Thu Nov 14 12:47:04 1996
***************
*** 758,794 ****
}

#ifdef MODULE
! static char devicename[9] = { 0, };
! static struct device dev_3c509 = {
! devicename, /* device name is inserted by linux/drivers/net/net_init.c */
! 0, 0, 0, 0,
! 0, 0,
! 0, 0, 0, NULL, el3_probe };

! static int io = 0;
! static int irq = 0;

int
init_module(void)
{
! dev_3c509.base_addr = io;
! dev_3c509.irq = irq;
! if (!EISA_bus && !io) {
! printk("3c509: WARNING! Module load-time probing works reliably only for EISA bus!!\n");
}
- if (register_netdev(&dev_3c509) != 0)
- return -EIO;
return 0;
}

void
cleanup_module(void)
{
! unregister_netdev(&dev_3c509);
! kfree_s(dev_3c509.priv,sizeof(struct el3_private));
! dev_3c509.priv=NULL;
! /* If we don't do this, we can't re-insmod it later. */
! release_region(dev_3c509.base_addr, EL3_IO_EXTENT);
}
#endif /* MODULE */

--- 758,819 ----
}

#ifdef MODULE
! #define MAX_3C_CARDS 4 /* Max number of NE cards per module */
! #define NAMELEN 8 /* # of chars for storing dev->name */
! static char namelist[NAMELEN * MAX_3C_CARDS] = { 0, };
! static struct device dev_3c509[MAX_3C_CARDS] = {
! {
! NULL, /* assign a chunk of namelist[] below */
! 0, 0, 0, 0,
! 0, 0,
! 0, 0, 0, NULL, NULL
! },
! };

! static int io[MAX_3C_CARDS] = { 0, };
! static int irq[MAX_3C_CARDS] = { 0, };

int
init_module(void)
{
! int this_dev, found = 0;
!
! for (this_dev = 0; this_dev < MAX_3C_CARDS; this_dev++) {
! struct device *dev = &dev_3c509[this_dev];
! dev->name = namelist+(NAMELEN*this_dev);
! dev->irq = irq[this_dev];
! dev->base_addr = io[this_dev];
! dev->init = el3_probe;
! if (io[this_dev] == 0) {
! if (this_dev != 0) break; /* only complain once */
! printk("3c509: WARNING! Module load-time probing works reliably only for EISA bus!!\n");
! }
! if (register_netdev(dev) != 0) {
! printk(KERN_WARNING "3c509.c: No 3c509 card found (i/o = 0x%x).\n", io[this_dev]);
! if (found != 0) return 0; /* Got at least one. */
! return -ENXIO;
! }
! found++;
}
return 0;
}

void
cleanup_module(void)
{
! int this_dev;
!
! for (this_dev = 0; this_dev < MAX_3C_CARDS; this_dev++) {
! struct device *dev = &dev_3c509[this_dev];
! if (dev->priv != NULL) {
! kfree_s(dev->priv,sizeof(struct el3_private));
! dev->priv = NULL;
! free_irq(dev->irq, NULL);
! irq2dev_map[dev->irq] = NULL;
! release_region(dev->base_addr, EL3_IO_EXTENT);
! unregister_netdev(dev);
! }
! }
}
#endif /* MODULE */

--------------------------------------------------------
Jacques Gelinas (jacques@solucorp.qc.ca)
Linuxconf: The ultimate administration system for Linux.
see http://www.solucorp.qc.ca/linuxconf