summaryrefslogtreecommitdiff
path: root/linux/src/drivers/net/cb_shim.c
diff options
context:
space:
mode:
authorThomas Schwinge <tschwinge@gnu.org>2006-01-22 15:54:41 +0000
committerThomas Schwinge <tschwinge@gnu.org>2009-06-18 00:26:29 +0200
commit4ad86505c480b2964548328a959c662e8aef5422 (patch)
tree9cc9b8f80d561ae7d7451d95a26ff8c252e86504 /linux/src/drivers/net/cb_shim.c
parent656d6634de02862e837f3a7d80a49e9ca072398d (diff)
2006-01-22 Thomas Schwinge <tschwinge@gnu.org>
* configure, i386/configure, i386/linux/configure, linux/configure, i386/linux/device-drivers.h.in: Regenerated. * linux/src/drivers/net/ne2k-pci.c: Resolve conflicts. 2006-01-22 Guillem Jover <guillem@hadrons.org> * i386/linux/configure.ac: Renamed winbond-840 driver to winbond_840. Enable the starfire, intel_gige and natsemi network drivers. Remove "CONFIG_" from cb_chim, starfire, sundance, winbond840, hamachi, natsemi, myson803 and ns820 driver declarations. Replace INTER_GIGE with INTEL_GIGE. * linux/dev/drivers/net/Space.c: Add conditional probes for natsemi, ns820, winbond840, hamachi, sundance, starfire, myson803 and intel-gige drivers. * linux/src/include/asm-i386/cache.h: New file from linux 2.2.26. * linux/dev/include/linux/malloc.h: Include <asm/cache.h>. * linux/src/drivers/net/ns820.c (netsami_drv_id): Renamed to ... (ns820_drv_id): ... this. Fix all callers. * linux/src/drivers/net/intel-gige.c (skel_netdev_probe): Renamed to ... (igige_probe): ... this. * linux/dev/drivers/net/eepro100.c: Remove obsoleted file. * linux/src/drivers/net/eepro100.c (pci_id_tbl): Add PCI ID's from linux-2.6.14-rc4. 2006-01-22 Alfred M. Szmidt <ams@gnu.org> * i386/linux/configure.ac: Added `pci-scan.o' to the network driver class. (ns820, myson803, sundance, winbond-840, hamachi): New drivers. * i386/linux/Makefile.in (linux-net-files): Added `cb_shim.c', `hamachi.c', `intel-gige.c', `myson803.c', `natsemi.c', `ns820.c', `starfire.c', `sundance.c', `winbond-840.c' and `pci-scan.c'. * linux/dev/include/linux/modversions.h: New file. * linux/src/drivers/net/cb_shim.c, linux/src/drivers/net/hamachi.c, linux/src/drivers/net/intel-gige.c, linux/src/drivers/net/myson803.c, linux/src/drivers/net/natsemi.c, linux/src/drivers/net/ns820.c, linux/src/drivers/net/starfire.c, linux/src/drivers/net/sundance.c, linux/src/drivers/net/winbond-840.c, linux/src/drivers/net/kern_compat.h, linux/src/drivers/net/pci-scan.c, linux/src/drivers/net/pci-scan.h: New files from netdrivers 3.5 package (http://www.scyld.com/network). * linux/src/drivers/net/3c59x.c, linux/src/drivers/net/eepro100.c, linux/src/drivers/net/epic100.c, linux/src/drivers/net/ne2k-pci.c, linux/src/drivers/net/rtl8139.c, linux/src/drivers/net/tulip.c, linux/src/drivers/net/via-rhine.c, linux/src/drivers/net/yellowfin.c: Updated files from netdrivers 3.5 (http://www.scyld.com/network).
Diffstat (limited to 'linux/src/drivers/net/cb_shim.c')
-rw-r--r--linux/src/drivers/net/cb_shim.c296
1 files changed, 296 insertions, 0 deletions
diff --git a/linux/src/drivers/net/cb_shim.c b/linux/src/drivers/net/cb_shim.c
new file mode 100644
index 0000000..599b5bb
--- /dev/null
+++ b/linux/src/drivers/net/cb_shim.c
@@ -0,0 +1,296 @@
+/* cb_shim.c: Linux CardBus device support code. */
+/*
+ Written 1999-2002 by Donald Becker.
+
+ This software may be used and distributed according to the terms of
+ the GNU General Public License (GPL), incorporated herein by
+ reference. This is not a documented interface. Drivers incorporating
+ or interacting with these functions are derivative works and thus
+ are covered the GPL. They must include an explicit GPL notice.
+
+ This code provides a shim to allow newer drivers to interact with the
+ older Cardbus driver activation code. The functions supported are
+ attach, suspend, power-off, resume and eject.
+
+ The author may be reached as becker@scyld.com, or
+ Donald Becker
+ Scyld Computing Corporation
+ 410 Severn Ave., Suite 210
+ Annapolis MD 21403
+
+ Support and updates available at
+ http://www.scyld.com/network/drivers.html
+
+ Other contributers: (none yet)
+*/
+
+static const char version1[] =
+"cb_shim.c:v1.03 7/12/2002 Donald Becker <becker@scyld.com>\n";
+static const char version2[] =
+" http://www.scyld.com/linux/drivers.html\n";
+
+/* Module options. */
+static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
+
+#ifndef __KERNEL__
+#define __KERNEL__
+#endif
+#include <linux/config.h>
+#if defined(CONFIG_SMP) && ! defined(__SMP__)
+#define __SMP__
+#endif
+#if defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)
+#define MODVERSIONS
+#endif
+
+#include <linux/version.h>
+#if defined(MODVERSIONS)
+#include <linux/modversions.h>
+#endif
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#if LINUX_VERSION_CODE >= 0x20400
+#include <linux/slab.h>
+#else
+#include <linux/malloc.h>
+#endif
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+/* These might be awkward to locate. */
+#include <pcmcia/driver_ops.h>
+#include "pci-scan.h"
+#include "kern_compat.h"
+
+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
+MODULE_DESCRIPTION("Hot-swap-PCI and Cardbus event dispatch");
+MODULE_LICENSE("GPL");
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Enable additional status messages (0-7)");
+
+/* Note: this is used in a slightly sleazy manner: it is passed to routines
+ that expect and return just dev_node_t. However using the too-simple
+ dev_node_t complicates devices management -- older drivers had to
+ look up dev_node_t.name in their private list. */
+
+struct registered_pci_device {
+ struct dev_node_t node;
+ int magic;
+ struct registered_pci_device *next;
+ struct drv_id_info *drv_info;
+ struct pci_dev *pci_loc;
+ void *dev_instance;
+} static *root_pci_devs = 0;
+
+struct drv_shim {
+ struct drv_id_info *did;
+ struct driver_operations drv_ops;
+ int magic;
+ struct drv_shim *next;
+} static *root_drv_id = 0;
+
+static void drv_power_op(struct dev_node_t *node, enum drv_pwr_action action)
+{
+ struct registered_pci_device **devp, **next, *rpin = (void *)node, *rp;
+ if (debug > 1)
+ printk(KERN_DEBUG "power operation(%s, %d).\n",
+ rpin->drv_info->name, action);
+ /* With our wrapper structure we can almost do
+ rpin->drv_info->pwr_event(rpin->dev_instance, action);
+ But the detach operation requires us to remove the object from the
+ list, so we check for uncontrolled "ghost" devices. */
+ for (devp = &root_pci_devs; *devp; devp = next) {
+ rp = *devp;
+ next = &rp->next;
+ if (rp == rpin) {
+ if (rp->drv_info->pwr_event)
+ rp->drv_info->pwr_event((*devp)->dev_instance, action);
+ else
+ printk(KERN_ERR "No power event hander for driver %s.\n",
+ rpin->drv_info->name);
+ if (action == DRV_DETACH) {
+ kfree(rp);
+ *devp = *next;
+ MOD_DEC_USE_COUNT;
+ }
+ return;
+ }
+ }
+ if (debug)
+ printk(KERN_WARNING "power operation(%s, %d) for a ghost device.\n",
+ node->dev_name, action);
+}
+/* Wrappers / static lambdas. */
+static void drv_suspend(struct dev_node_t *node)
+{
+ drv_power_op(node, DRV_SUSPEND);
+}
+static void drv_resume(struct dev_node_t *node)
+{
+ drv_power_op(node, DRV_RESUME);
+}
+static void drv_detach(struct dev_node_t *node)
+{
+ drv_power_op(node, DRV_DETACH);
+}
+
+/* The CardBus interaction does not identify the driver the attach() is
+ for, thus we must search for the ID in all PCI device tables.
+ While ugly, we likely only have one driver loaded anyway.
+*/
+static dev_node_t *drv_attach(struct dev_locator_t *loc)
+{
+ struct drv_shim *dp;
+ struct drv_id_info *drv_id = NULL;
+ struct pci_id_info *pci_tbl = NULL;
+ u32 pci_id, subsys_id, pci_rev, pciaddr;
+ u8 irq;
+ int chip_idx = 0, pci_flags, bus, devfn;
+ long ioaddr;
+ void *newdev;
+
+ if (debug > 1)
+ printk(KERN_INFO "drv_attach()\n");
+ if (loc->bus != LOC_PCI) return NULL;
+ bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
+ if (debug > 1)
+ printk(KERN_DEBUG "drv_attach(bus %d, function %d)\n", bus, devfn);
+
+ pcibios_read_config_dword(bus, devfn, PCI_VENDOR_ID, &pci_id);
+ pcibios_read_config_dword(bus, devfn, PCI_SUBSYSTEM_ID, &subsys_id);
+ pcibios_read_config_dword(bus, devfn, PCI_REVISION_ID, &pci_rev);
+ pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
+ for (dp = root_drv_id; dp; dp = dp->next) {
+ drv_id = dp->did;
+ pci_tbl = drv_id->pci_dev_tbl;
+ for (chip_idx = 0; pci_tbl[chip_idx].name; chip_idx++) {
+ struct pci_id_info *chip = &pci_tbl[chip_idx];
+ if ((pci_id & chip->id.pci_mask) == chip->id.pci
+ && (subsys_id & chip->id.subsystem_mask) == chip->id.subsystem
+ && (pci_rev & chip->id.revision_mask) == chip->id.revision)
+ break;
+ }
+ if (pci_tbl[chip_idx].name) /* Compiled out! */
+ break;
+ }
+ if (dp == 0) {
+ printk(KERN_WARNING "No driver match for device %8.8x at %d/%d.\n",
+ pci_id, bus, devfn);
+ return 0;
+ }
+ pci_flags = pci_tbl[chip_idx].pci_flags;
+ pcibios_read_config_dword(bus, devfn, ((pci_flags >> 2) & 0x1C) + 0x10,
+ &pciaddr);
+ if ((pciaddr & PCI_BASE_ADDRESS_SPACE_IO)) {
+ ioaddr = pciaddr & PCI_BASE_ADDRESS_IO_MASK;
+ } else
+ ioaddr = (long)ioremap(pciaddr & PCI_BASE_ADDRESS_MEM_MASK,
+ pci_tbl[chip_idx].io_size);
+ if (ioaddr == 0 || irq == 0) {
+ printk(KERN_ERR "The %s at %d/%d was not assigned an %s.\n"
+ KERN_ERR " It will not be activated.\n",
+ pci_tbl[chip_idx].name, bus, devfn,
+ ioaddr == 0 ? "address" : "IRQ");
+ return NULL;
+ }
+ printk(KERN_INFO "Found a %s at %d/%d address 0x%x->0x%lx IRQ %d.\n",
+ pci_tbl[chip_idx].name, bus, devfn, pciaddr, ioaddr, irq);
+ {
+ u16 pci_command;
+ pcibios_read_config_word(bus, devfn, PCI_COMMAND, &pci_command);
+ printk(KERN_INFO "%s at %d/%d command 0x%x.\n",
+ pci_tbl[chip_idx].name, bus, devfn, pci_command);
+ }
+
+ newdev = drv_id->probe1(pci_find_slot(bus, devfn), 0,
+ ioaddr, irq, chip_idx, 0);
+ if (newdev) {
+ struct registered_pci_device *hsdev =
+ kmalloc(sizeof(struct registered_pci_device), GFP_KERNEL);
+ if (drv_id->pci_class == PCI_CLASS_NETWORK_ETHERNET<<8)
+ strcpy(hsdev->node.dev_name, ((struct net_device *)newdev)->name);
+ hsdev->node.major = hsdev->node.minor = 0;
+ hsdev->node.next = NULL;
+ hsdev->drv_info = drv_id;
+ hsdev->dev_instance = newdev;
+ hsdev->next = root_pci_devs;
+ root_pci_devs = hsdev;
+ drv_id->pwr_event(newdev, DRV_ATTACH);
+ MOD_INC_USE_COUNT;
+ return &hsdev->node;
+ }
+ return NULL;
+}
+
+/* Add/remove a driver ID structure to our private list of known drivers. */
+int do_cb_register(struct drv_id_info *did)
+{
+ struct driver_operations *dop;
+ struct drv_shim *dshim = kmalloc(sizeof(*dshim), GFP_KERNEL);
+ if (dshim == 0)
+ return 0;
+ if (debug > 1)
+ printk(KERN_INFO "Registering driver support for '%s'.\n",
+ did->name);
+ MOD_INC_USE_COUNT;
+ dshim->did = did;
+ dop = &dshim->drv_ops;
+ dop->name = (char *)did->name;
+ dop->attach = drv_attach;
+ dop->suspend = drv_suspend;
+ dop->resume = drv_resume;
+ dop->detach = drv_detach;
+ dshim->next = root_drv_id;
+ root_drv_id = dshim;
+ return register_driver(dop);
+}
+
+void do_cb_unregister(struct drv_id_info *did)
+{
+ struct drv_shim **dp;
+ for (dp = &root_drv_id; *dp; dp = &(*dp)->next)
+ if ((*dp)->did == did) {
+ struct drv_shim *dshim = *dp;
+ unregister_driver(&dshim->drv_ops);
+ *dp = dshim->next;
+ kfree(dshim);
+ MOD_DEC_USE_COUNT;
+ return;
+ }
+}
+
+extern int (*register_hotswap_hook)(struct drv_id_info *did);
+extern void (*unregister_hotswap_hook)(struct drv_id_info *did);
+
+int (*old_cb_hook)(struct drv_id_info *did);
+void (*old_un_cb_hook)(struct drv_id_info *did);
+
+int init_module(void)
+{
+ if (debug)
+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
+ old_cb_hook = register_hotswap_hook;
+ old_un_cb_hook = unregister_hotswap_hook;
+ register_hotswap_hook = do_cb_register;
+ unregister_hotswap_hook = do_cb_unregister;
+ return 0;
+}
+void cleanup_module(void)
+{
+ register_hotswap_hook = old_cb_hook;
+ unregister_hotswap_hook = old_un_cb_hook;
+ return;
+}
+
+
+/*
+ * Local variables:
+ * compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c cb_shim.c -I/usr/include/ -I/usr/src/pcmcia/include/"
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
+