aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/wlan-ng/prism2_plx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/wlan-ng/prism2_plx.c')
-rw-r--r--drivers/staging/wlan-ng/prism2_plx.c472
1 files changed, 472 insertions, 0 deletions
diff --git a/drivers/staging/wlan-ng/prism2_plx.c b/drivers/staging/wlan-ng/prism2_plx.c
new file mode 100644
index 000000000000..320443f37a8f
--- /dev/null
+++ b/drivers/staging/wlan-ng/prism2_plx.c
@@ -0,0 +1,472 @@
+#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 __devinit
+prism2sta_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;
+ void __iomem *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,
+ (unsigned 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 (
+ readb(attr_mem + 0) != 0x01 || readb(attr_mem + 2) != 0x03 ||
+ readb(attr_mem + 4) != 0x00 || readb(attr_mem + 6) != 0x00 ||
+ readb(attr_mem + 8) != 0xFF || readb(attr_mem + 10) != 0x17 ||
+ readb(attr_mem + 12) != 0x04 || readb(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 */
+ writeb(COR_VALUE, attr_mem + COR_OFFSET);
+ reg = readb(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(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 __iomem *)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);
+
+static 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 MODULE
+
+static 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 // MODULE
+
+
+int 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 = readb(hw->membase + COR_OFFSET);
+ /* Write reset bit (BIT7) */
+ writeb(corsave | BIT7, hw->membase + COR_OFFSET);
+ /* Hold for holdtime */
+ mdelay(holdtime);
+
+ if (genesis) {
+ writeb(genesis, hw->membase + HCR_OFFSET);
+ /* Hold for holdtime */
+ mdelay(holdtime);
+ }
+
+ /* Clear reset bit */
+ writeb(corsave & ~BIT7, hw->membase + COR_OFFSET);
+ /* Wait for settletime */
+ mdelay(settletime);
+ /* Set non-reset bits back what they were */
+ writeb(corsave, hw->membase + COR_OFFSET);
+ DBFEXIT;
+ return result;
+}