--- linux-2.5.45/include/linux/device.h 2002-10-30 16:43:40.000000000 -0800 +++ linux/include/linux/device.h 2002-11-02 05:20:36.000000000 -0800 @@ -114,6 +114,7 @@ char * name; struct bus_type * bus; struct device_class * devclass; + int drvdata_size; rwlock_t lock; atomic_t refcount; --- linux-2.5.45/drivers/base/bus.c 2002-10-30 16:42:20.000000000 -0800 +++ linux/drivers/base/bus.c 2002-11-02 21:24:12.000000000 -0800 @@ -12,6 +12,7 @@ #include #include #include +#include #include "base.h" static LIST_HEAD(bus_driver_list); @@ -94,16 +95,35 @@ list_add_tail(&dev->driver_list,&dev->driver->devices); } +static void free_driver_data(struct device *dev) +{ + if (dev->driver->drvdata_size && dev->driver_data) + kfree(dev->driver_data); + dev->driver = NULL; +} + static int bus_match(struct device * dev, struct device_driver * drv) { int error = -ENODEV; if (dev->bus->match(dev,drv)) { + + if (drv->drvdata_size > 0) { + dev->driver_data = kmalloc(drv->drvdata_size, + GFP_KERNEL); + if (dev->driver_data) + memset(dev->driver_data, 0, drv->drvdata_size); + else + return -ENOMEM; + } + else + dev->driver_data = NULL; + dev->driver = drv; if (drv->probe) { if (!(error = drv->probe(dev))) attach(dev); else - dev->driver = NULL; + free_driver_data(dev); } else attach(dev); } @@ -166,7 +186,7 @@ devclass_remove_device(dev); if (drv->remove) drv->remove(dev); - dev->driver = NULL; + free_driver_data(dev); } } --- linux-2.5.45/include/linux/netdevice.h 2002-10-30 16:43:43.000000000 -0800 +++ linux/include/linux/netdevice.h 2002-11-02 20:08:04.000000000 -0800 @@ -615,6 +623,8 @@ /* WILL BE REMOVED IN 2.5.0 */ } +extern void netdev_kfree_priv(struct net_device *dev); + extern int netdev_finish_unregister(struct net_device *dev); static inline void dev_put(struct net_device *dev) --- linux-2.5.45/net/core/dev.c 2002-10-30 16:42:56.000000000 -0800 +++ linux/net/core/dev.c 2002-11-02 20:08:16.000000000 -0800 @@ -2488,6 +2679,19 @@ } /** + * netdev_kfree_priv - Simple dev.destructor to free private data + * @dev: device + * + * Simply calls kfree(dev->priv). + */ +void +netdev_kfree_priv(struct net_device *dev) +{ + kfree(dev->priv); +} +EXPORT_SYMBOL(netdev_kfree_priv); + +/** * netdev_finish_unregister - complete unregistration * @dev: device * --- linux-2.5.45/drivers/net/via-rhine.c 2002-10-30 16:43:44.000000000 -0800 +++ linux/drivers/net/via-rhine.c 2002-11-02 21:47:02.000000000 -0800 @@ -501,6 +501,7 @@ unsigned int mii_cnt; /* number of MIIs found, but only the first one is used */ u16 mii_status; /* last read MII status */ struct mii_if_info mii_if; + struct net_device netdev; }; static int mdio_read(struct net_device *dev, int phy_id, int location); @@ -571,8 +572,8 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { - struct net_device *dev; - struct netdev_private *np; + struct netdev_private *np = pci_get_drvdata(pdev); + struct net_device *dev = &np->netdev; int i, option; int chip_id = (int) ent->driver_data; static int card_idx = -1; @@ -618,15 +619,13 @@ if (pci_flags & PCI_USES_MASTER) pci_set_master (pdev); - dev = alloc_etherdev(sizeof(*np)); - if (dev == NULL) { - printk (KERN_ERR "init_ethernet failed for card #%d\n", card_idx); + if (pci_request_regions(pdev, shortname)) goto err_out; - } + + init_etherdev(dev, 0); SET_MODULE_OWNER(dev); - - if (pci_request_regions(pdev, shortname)) - goto err_out_free_netdev; + dev->priv = np; + dev->destructor = netdev_kfree_priv; #ifdef USE_MEM ioaddr0 = ioaddr; @@ -707,7 +706,6 @@ dev->irq = pdev->irq; - np = dev->priv; spin_lock_init (&np->lock); np->chip_id = chip_id; np->drv_flags = via_rhine_chip_info[chip_id].drv_flags; @@ -760,8 +758,6 @@ printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], pdev->irq); - pci_set_drvdata(pdev, dev); - if (np->drv_flags & CanHaveMII) { int phy, phy_idx = 0; np->phys[0] = 1; /* Standard for this chip. */ @@ -812,8 +808,6 @@ err_out_free_res: #endif pci_release_regions(pdev); -err_out_free_netdev: - kfree (dev); err_out: return -ENODEV; } @@ -1730,7 +1724,8 @@ static void __devexit via_rhine_remove_one (struct pci_dev *pdev) { - struct net_device *dev = pci_get_drvdata(pdev); + struct netdev_private *np = pci_get_drvdata(pdev); + struct net_device *dev = &np->netdev; unregister_netdev(dev); @@ -1740,7 +1735,6 @@ iounmap((char *)(dev->base_addr)); #endif - kfree(dev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); } @@ -1751,6 +1745,9 @@ .id_table = via_rhine_pci_tbl, .probe = via_rhine_init_one, .remove = __devexit_p(via_rhine_remove_one), + .driver = { + .drvdata_size = sizeof(struct netdev_private) + }, };