📄 prism2_plx.c
字号:
#define WLAN_HOSTIF WLAN_PLX#include "hfa384x.c"#include "prism2mgmt.c"#include "prism2mib.c"#include "prism2sta.c"#define PLX_ATTR_SIZE 0x1000 /* Attribute memory size - 4K bytes */#define COR_OFFSET 0x3e0 /* COR attribute offset of Prism2 PC card */#define COR_VALUE 0x41 /* Enable PC card with irq in level trigger */#define PLX_INTCSR 0x4c /* Interrupt Control and Status Register */#define PLX_INTCSR_INTEN (1<<6) /* Interrupt Enable bit */#define PLX_MIN_ATTR_LEN 512 /* at least 2 x 256 is needed for CIS *//* 3Com 3CRW777A (PLX) board ID */#define PCIVENDOR_3COM 0x10B7#define PCIDEVICE_AIRCONNECT 0x7770/* Eumitcom PCI WL11000 PCI Adapter (PLX) board device+vendor ID */#define PCIVENDOR_EUMITCOM 0x1638UL#define PCIDEVICE_WL11000 0x1100UL/* Global Sun Tech GL24110P PCI Adapter (PLX) board device+vendor ID */#define PCIVENDOR_GLOBALSUN 0x16abUL#define PCIDEVICE_GL24110P 0x1101UL#define PCIDEVICE_GL24110P_ALT 0x1102UL/* Netgear MA301 PCI Adapter (PLX) board device+vendor ID */#define PCIVENDOR_NETGEAR 0x1385UL#define PCIDEVICE_MA301 0x4100UL/* US Robotics USR2410 PCI Adapter (PLX) board device+vendor ID */#define PCIVENDOR_USROBOTICS 0x16ecUL#define PCIDEVICE_USR2410 0x3685UL/* Linksys WPC11 card with the WDT11 adapter (PLX) board device+vendor ID */#define PCIVENDOR_Linksys 0x16abUL#define PCIDEVICE_Wpc11Wdt11 0x1102UL/* National Datacomm Corp SOHOware Netblaster II PCI */#define PCIVENDOR_NDC 0x15e8UL#define PCIDEVICE_NCP130_PLX 0x0130UL#define PCIDEVICE_NCP130_ASIC 0x0131UL/* NDC NCP130_PLX is also sold by Corega. Their name is CGWLPCIA11 */#define PCIVENDOR_COREGA PCIVENDOR_NDC#define PCIDEVICE_CGWLPCIA11 PCIDEVICE_NCP130_PLX/* PCI Class & Sub-Class code, Network-'Other controller' */#define PCI_CLASS_NETWORK_OTHERS 0x280/*----------------------------------------------------------------* prism2sta_probe_plx** Probe routine called when a PCI device w/ matching ID is found. * This PLX implementation uses the following map:* BAR0: Unused* BAR1: ????* BAR2: PCMCIA attribute memory* BAR3: PCMCIA i/o space * Here's the sequence:* - Allocate the PCI resources. * - Read the PCMCIA attribute memory to make sure we have a WLAN card* - Reset the MAC using the PCMCIA COR* - Initialize the netdev and wlan data* - Initialize the MAC** Arguments:* pdev ptr to pci device structure containing info about * pci configuration.* id ptr to the device id entry that matched this device.** Returns: * zero - success* negative - failed** Side effects:* ** Call context:* process thread* ----------------------------------------------------------------*/static int __devinitprism2sta_probe_plx( struct pci_dev *pdev, const struct pci_device_id *id){ int result; phys_t pccard_ioaddr; phys_t pccard_attr_mem; unsigned int pccard_attr_len; UINT8 *attr_mem = NULL; UINT32 plx_addr; wlandevice_t *wlandev = NULL; hfa384x_t *hw = NULL; int reg; u32 regic; if (pci_enable_device(pdev)) return -EIO; /* TMC7160 boards are special */ if ((pdev->vendor == PCIVENDOR_NDC) && (pdev->device == PCIDEVICE_NCP130_ASIC)) { unsigned long delay; pccard_attr_mem = 0; pccard_ioaddr = pci_resource_start(pdev, 1); outb(0x45, pccard_ioaddr); delay = jiffies + 1*HZ; while (time_before(jiffies, delay)); if (inb(pccard_ioaddr) != 0x45) { WLAN_LOG_ERROR("Initialize the TMC7160 failed. (0x%x)\n", inb(pccard_ioaddr)); return -EIO; } pccard_ioaddr = pci_resource_start(pdev, 2); prism2_doreset = 0; WLAN_LOG_INFO("NDC NCP130 with TMC716(ASIC) PCI interface device found at io:0x%x, irq:%d\n", pccard_ioaddr, pdev->irq); goto init; } /* Collect the resource requirements */ pccard_attr_mem = pci_resource_start(pdev, 2); pccard_attr_len = pci_resource_len(pdev, 2); if (pccard_attr_len < PLX_MIN_ATTR_LEN) return -EIO; pccard_ioaddr = pci_resource_start(pdev, 3); /* bjoern: We need to tell the card to enable interrupts, in * case the serial eprom didn't do this already. See the * PLX9052 data book, p8-1 and 8-24 for reference. * [MSM]: This bit of code came from the orinoco_cs driver. */ plx_addr = pci_resource_start(pdev, 1); regic = 0; regic = inl(plx_addr+PLX_INTCSR); if(regic & PLX_INTCSR_INTEN) { WLAN_LOG_DEBUG(1, "%s: Local Interrupt already enabled\n", dev_info); } else { regic |= PLX_INTCSR_INTEN; outl(regic, plx_addr+PLX_INTCSR); regic = inl(plx_addr+PLX_INTCSR); if(!(regic & PLX_INTCSR_INTEN)) { WLAN_LOG_ERROR( "%s: Couldn't enable Local Interrupts\n", dev_info); return -EIO; } } /* These assignments are here in case of future mappings for * io space and irq that might be similar to ioremap */ if (!request_mem_region(pccard_attr_mem, pci_resource_len(pdev, 2), "Prism2")) { WLAN_LOG_ERROR("%s: Couldn't reserve PCI memory region\n", dev_info); return -EIO; } attr_mem = ioremap(pccard_attr_mem, pccard_attr_len); WLAN_LOG_INFO("A PLX PCI/PCMCIA interface device found, " "phymem:0x%llx, phyio=0x%x, irq:%d, " "mem: 0x%lx\n", (unsigned long long)pccard_attr_mem, pccard_ioaddr, pdev->irq, (long)attr_mem); /* Verify whether PC card is present. * [MSM] This needs improvement, the right thing to do is * probably to walk the CIS looking for the vendor and product * IDs. It would be nice if this could be tied in with the * etc/pcmcia/wlan-ng.conf file. Any volunteers? ;-) */ if ( attr_mem[0] != 0x01 || attr_mem[2] != 0x03 || attr_mem[4] != 0x00 || attr_mem[6] != 0x00 || attr_mem[8] != 0xFF || attr_mem[10] != 0x17 || attr_mem[12] != 0x04 || attr_mem[14] != 0x67) { WLAN_LOG_ERROR("Prism2 PC card CIS is invalid.\n"); return -EIO; } WLAN_LOG_INFO("A PCMCIA WLAN adapter was found.\n"); /* Write COR to enable PC card */ attr_mem[COR_OFFSET] = COR_VALUE; reg = attr_mem[COR_OFFSET]; init: /* * Now do everything the same as a PCI device * [MSM] TODO: We could probably factor this out of pcmcia/pci/plx * and perhaps usb. Perhaps a task for another day....... */ if ((wlandev = create_wlan()) == NULL) { WLAN_LOG_ERROR("%s: Memory allocation failure.\n", dev_info); result = -EIO; goto failed; } hw = wlandev->priv; if ( wlan_setup(wlandev) != 0 ) { WLAN_LOG_ERROR("%s: wlan_setup() failed.\n", dev_info); result = -EIO; goto failed; } /* Setup netdevice's ability to report resources * Note: the netdevice was allocated by wlan_setup() */ wlandev->netdev->irq = pdev->irq; wlandev->netdev->base_addr = pccard_ioaddr; wlandev->netdev->mem_start = (unsigned long)attr_mem; wlandev->netdev->mem_end = (unsigned long)attr_mem + pci_resource_len(pdev, 0); /* Initialize the hw data */ hfa384x_create(hw, wlandev->netdev->irq, pccard_ioaddr, attr_mem); hw->wlandev = wlandev; /* Register the wlandev, this gets us a name and registers the * linux netdevice. */ SET_MODULE_OWNER(wlandev->netdev);#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) SET_NETDEV_DEV(wlandev->netdev, &(pdev->dev));#endif if ( register_wlandev(wlandev) != 0 ) { WLAN_LOG_ERROR("%s: register_wlandev() failed.\n", dev_info); result = -EIO; goto failed; }#if 0 /* TODO: Move this and an irq test into an hfa384x_testif() routine. */ outw(PRISM2STA_MAGIC, HFA384x_SWSUPPORT(wlandev->netdev->base_addr)); reg=inw( HFA384x_SWSUPPORT(wlandev->netdev->base_addr)); if ( reg != PRISM2STA_MAGIC ) { WLAN_LOG_ERROR("MAC register access test failed!\n"); result = -EIO; goto failed; } #endif /* Do a chip-level reset on the MAC */ if (prism2_doreset) { result = hfa384x_corereset(hw, prism2_reset_holdtime, prism2_reset_settletime, 0); if (result != 0) { unregister_wlandev(wlandev); hfa384x_destroy(hw); WLAN_LOG_ERROR( "%s: hfa384x_corereset() failed.\n", dev_info); result = -EIO; goto failed; } } pci_set_drvdata(pdev, wlandev); /* Shouldn't actually hook up the IRQ until we * _know_ things are alright. A test routine would help. */ request_irq(wlandev->netdev->irq, hfa384x_interrupt, SA_SHIRQ, wlandev->name, wlandev); wlandev->msdstate = WLAN_MSD_HWPRESENT; result = 0; goto done; failed: pci_set_drvdata(pdev, NULL); if (wlandev) kfree(wlandev); if (hw) kfree(hw); if (attr_mem) iounmap((void *) attr_mem); pci_release_regions(pdev); pci_disable_device(pdev); done: DBFEXIT; return result;}static void __devexit prism2sta_remove_plx(struct pci_dev *pdev){ wlandevice_t *wlandev; hfa384x_t *hw; wlandev = (wlandevice_t *) pci_get_drvdata(pdev); hw = wlandev->priv; p80211netdev_hwremoved(wlandev); /* reset hardware */ prism2sta_ifstate(wlandev, P80211ENUM_ifstate_disable); if (pdev->irq) free_irq(pdev->irq, wlandev); unregister_wlandev(wlandev); /* free local stuff */ if (hw) { hfa384x_destroy(hw); kfree(hw); } iounmap((void*)wlandev->netdev->mem_start); wlan_unsetup(wlandev); pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); kfree(wlandev);}static struct pci_device_id plx_id_tbl[] = { { PCIVENDOR_EUMITCOM, PCIDEVICE_WL11000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* Driver data, we just put the name here */ (unsigned long)"Eumitcom WL11000 PCI(PLX) card" }, { PCIVENDOR_GLOBALSUN, PCIDEVICE_GL24110P, PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* Driver data, we just put the name here */ (unsigned long)"Global Sun Tech GL24110P PCI(PLX) card" }, { PCIVENDOR_GLOBALSUN, PCIDEVICE_GL24110P_ALT, PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* Driver data, we just put the name here */ (unsigned long)"Global Sun Tech GL24110P PCI(PLX) card" }, { PCIVENDOR_NETGEAR, PCIDEVICE_MA301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* Driver data, we just put the name here */ (unsigned long)"Global Sun Tech GL24110P PCI(PLX) card" }, { PCIVENDOR_USROBOTICS, PCIDEVICE_USR2410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* Driver data, we just put the name here */ (unsigned long)"US Robotics USR2410 PCI(PLX) card" }, { PCIVENDOR_Linksys, PCIDEVICE_Wpc11Wdt11, PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* Driver data, we just put the name here */ (unsigned long)"Linksys WPC11 with WDT11 PCI(PLX) adapter" }, { PCIVENDOR_NDC, PCIDEVICE_NCP130_PLX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* Driver data, we just put the name here */ (unsigned long)"NDC Netblaster II PCI(PLX)" }, { PCIVENDOR_NDC, PCIDEVICE_NCP130_ASIC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* Driver data, we just put the name here */ (unsigned long)"NDC Netblaster II PCI(TMC7160)" }, { PCIVENDOR_3COM, PCIDEVICE_AIRCONNECT, PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* Driver data, we just put the name here */ (unsigned long)"3Com AirConnect PCI 802.11b 11Mb/s WLAN Controller" }, { 0, 0, 0, 0, 0, 0, 0 }};MODULE_DEVICE_TABLE(pci, plx_id_tbl);/* Function declared here because of ptr reference below */static int __devinit prism2sta_probe_plx(struct pci_dev *pdev, const struct pci_device_id *);static void __devexit prism2sta_remove_plx(struct pci_dev *pdev);struct pci_driver prism2_plx_drv_id = { .name = "prism2_plx", .id_table = plx_id_tbl, .probe = prism2sta_probe_plx, .remove = prism2sta_remove_plx,#ifdef CONFIG_PM .suspend = prism2sta_suspend_pci, .resume = prism2sta_resume_pci,#endif};#ifdef MODULEstatic int __init prism2plx_init(void){ WLAN_LOG_NOTICE("%s Loaded\n", version); return pci_module_init(&prism2_plx_drv_id);};static void __exit prism2plx_cleanup(void){ pci_unregister_driver(&prism2_plx_drv_id);};module_init(prism2plx_init);module_exit(prism2plx_cleanup);#endif // MODULEint hfa384x_corereset(hfa384x_t *hw, int holdtime, int settletime, int genesis){ int result = 0;#define COR_OFFSET 0x3e0 /* COR attribute offset of Prism2 PC card */#define COR_VALUE 0x41 /* Enable PC card with irq in level trigger */#define HCR_OFFSET 0x3e2 /* HCR attribute offset of Prism2 PC card */ UINT8 corsave; DBFENTER; WLAN_LOG_DEBUG(3, "Doing reset via direct COR access.\n"); /* Collect COR */ corsave = ((UINT8*)hw->membase)[COR_OFFSET]; /* Write reset bit (BIT7) */ ((UINT8*)hw->membase)[COR_OFFSET] = corsave | BIT7; /* Hold for holdtime */ mdelay(holdtime); if (genesis) { ((UINT8*)hw->membase)[HCR_OFFSET] = genesis; /* Hold for holdtime */ mdelay(holdtime); } /* Clear reset bit */ ((UINT8*)hw->membase)[COR_OFFSET] = corsave & ~BIT7; /* Wait for settletime */ mdelay(settletime); /* Set non-reset bits back what they were */ ((UINT8*)hw->membase)[COR_OFFSET] = corsave; DBFEXIT; return result;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -