Main Page | Data Structures | Directories | File List | Data Fields | Globals

hostap_pci.c

Go to the documentation of this file.
00001 #define PRISM2_PCI
00002 
00003 /* Host AP driver's support for Intersil Prism2.5 PCI cards is based on
00004  * driver patches from Reyk Floeter <reyk@vantronix.net> and
00005  * Andy Warner <andyw@pobox.com> */
00006 
00007 #include <linux/config.h>
00008 #include <linux/version.h>
00009 #include <linux/module.h>
00010 #include <linux/init.h>
00011 #include <linux/if.h>
00012 #include <linux/skbuff.h>
00013 #include <linux/netdevice.h>
00014 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,44))
00015 #include <linux/tqueue.h>
00016 #else
00017 #include <linux/workqueue.h>
00018 #endif
00019 #include "hostap_wext.h"
00020 
00021 #include <linux/ioport.h>
00022 #include <linux/pci.h>
00023 
00024 #include "hostap_wlan.h"
00025 
00026 
00027 static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
00028 static char *dev_info = "hostap_pci";
00029 
00030 
00031 MODULE_AUTHOR("SSH Communications Security Corp, Jouni Malinen");
00032 MODULE_DESCRIPTION("Support for Intersil Prism2.5-based 802.11 wireless LAN "
00033                    "PCI cards.");
00034 MODULE_SUPPORTED_DEVICE("Intersil Prism2.5-based WLAN PCI cards");
00035 MODULE_LICENSE("GPL");
00036 
00037 
00038 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
00039 /* PCI initialization uses Linux 2.4.x version and older kernels do not support
00040  * this */
00041 #error Prism2.5 PCI version requires at least Linux kernel version 2.4.0
00042 #endif /* kernel < 2.4.0 */
00043 
00044 
00045 /* FIX: do we need mb/wmb/rmb with memory operations? */
00046 
00047 
00048 static struct pci_device_id prism2_pci_id_table[] __devinitdata = {
00049         /* Intersil Prism3 ISL3872 11Mb/s WLAN Controller */
00050         { 0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID },
00051         /* Intersil Prism2.5 ISL3874 11Mb/s WLAN Controller */
00052         { 0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID },
00053         /* Samsung MagicLAN SWL-2210P */
00054         { 0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID },
00055         { 0 }
00056 };
00057 
00058 
00059 #ifdef PRISM2_IO_DEBUG
00060 
00061 static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
00062 {
00063         struct hostap_interface *iface = dev->priv;
00064         local_info_t *local = iface->local;
00065         unsigned long flags;
00066 
00067         spin_lock_irqsave(&local->lock, flags);
00068         prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
00069         writeb(v, dev->mem_start + a);
00070         spin_unlock_irqrestore(&local->lock, flags);
00071 }
00072 
00073 static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
00074 {
00075         struct hostap_interface *iface = dev->priv;
00076         local_info_t *local = iface->local;
00077         unsigned long flags;
00078         u8 v;
00079 
00080         spin_lock_irqsave(&local->lock, flags);
00081         v = readb(dev->mem_start + a);
00082         prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v);
00083         spin_unlock_irqrestore(&local->lock, flags);
00084         return v;
00085 }
00086 
00087 static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
00088 {
00089         struct hostap_interface *iface = dev->priv;
00090         local_info_t *local = iface->local;
00091         unsigned long flags;
00092 
00093         spin_lock_irqsave(&local->lock, flags);
00094         prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
00095         writew(v, dev->mem_start + a);
00096         spin_unlock_irqrestore(&local->lock, flags);
00097 }
00098 
00099 static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
00100 {
00101         struct hostap_interface *iface = dev->priv;
00102         local_info_t *local = iface->local;
00103         unsigned long flags;
00104         u16 v;
00105 
00106         spin_lock_irqsave(&local->lock, flags);
00107         v = readw(dev->mem_start + a);
00108         prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v);
00109         spin_unlock_irqrestore(&local->lock, flags);
00110         return v;
00111 }
00112 
00113 #define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
00114 #define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
00115 #define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
00116 #define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
00117 #define HFA384X_OUTW_DATA(v,a) hfa384x_outw_debug(dev, (a), cpu_to_le16((v)))
00118 #define HFA384X_INW_DATA(a) (u16) le16_to_cpu(hfa384x_inw_debug(dev, (a)))
00119 
00120 #else /* PRISM2_IO_DEBUG */
00121 
00122 #define HFA384X_OUTB(v,a) writeb((v), dev->mem_start + (a))
00123 #define HFA384X_INB(a) (u8) readb(dev->mem_start + (a))
00124 #define HFA384X_OUTW(v,a) writew((v), dev->mem_start + (a))
00125 #define HFA384X_INW(a) (u16) readw(dev->mem_start + (a))
00126 #define HFA384X_OUTW_DATA(v,a) writew(cpu_to_le16(v), dev->mem_start + (a))
00127 #define HFA384X_INW_DATA(a) (u16) le16_to_cpu(readw(dev->mem_start + (a)))
00128 
00129 #endif /* PRISM2_IO_DEBUG */
00130 
00131 
00132 static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
00133                             int len)
00134 {
00135         u16 d_off;
00136         u16 *pos;
00137 
00138         d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
00139         pos = (u16 *) buf;
00140 
00141         for ( ; len > 1; len -= 2)
00142                 *pos++ = HFA384X_INW_DATA(d_off);
00143 
00144         if (len & 1)
00145                 *((char *) pos) = HFA384X_INB(d_off);
00146 
00147         return 0;
00148 }
00149 
00150 
00151 static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
00152 {
00153         u16 d_off;
00154         u16 *pos;
00155 
00156         d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
00157         pos = (u16 *) buf;
00158 
00159         for ( ; len > 1; len -= 2)
00160                 HFA384X_OUTW_DATA(*pos++, d_off);
00161 
00162         if (len & 1)
00163                 HFA384X_OUTB(*((char *) pos), d_off);
00164 
00165         return 0;
00166 }
00167 
00168 
00169 /* FIX: This might change at some point.. */
00170 #include "hostap_hw.c"
00171 
00172 static void prism2_pci_cor_sreset(local_info_t *local)
00173 {
00174         struct net_device *dev = local->dev;
00175 
00176         /* linux-wlan-ng uses extremely long hold and settle times for
00177          * COR sreset. A comment in the driver code mentions that the long
00178          * delays appear to be necessary. However, at least IBM 22P6901 seems
00179          * to work fine with shorter delays.
00180          *
00181          * Longer delays can be configured by uncommenting following line: */
00182 /* #define PRISM2_PCI_USE_LONG_DELAYS */
00183 
00184 #ifdef PRISM2_PCI_USE_LONG_DELAYS
00185         int i;
00186 
00187         HFA384X_OUTW(0x0080, HFA384X_PCICOR_OFF);
00188         mdelay(250);
00189 
00190         HFA384X_OUTW(0x0, HFA384X_PCICOR_OFF);
00191         mdelay(500);
00192 
00193         /* Wait for f/w to complete initialization (CMD:BUSY == 0) */
00194         i = 2000000 / 10;
00195         while ((HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) && --i)
00196                 udelay(10);
00197 
00198 #else /* PRISM2_PCI_USE_LONG_DELAYS */
00199 
00200         HFA384X_OUTW(0x0080, HFA384X_PCICOR_OFF);
00201         mdelay(1);
00202         HFA384X_OUTW(0x0, HFA384X_PCICOR_OFF);
00203         mdelay(1);
00204 
00205 #endif /* PRISM2_PCI_USE_LONG_DELAYS */
00206 
00207         if (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) {
00208                 printk(KERN_DEBUG "%s: COR sreset timeout\n", dev->name);
00209         }
00210 }
00211 
00212 
00213 static void prism2_pci_genesis_reset(local_info_t *local, int hcr)
00214 {
00215         struct net_device *dev = local->dev;
00216 
00217         HFA384X_OUTW(0x00C5, HFA384X_PCICOR_OFF);
00218         mdelay(10);
00219         HFA384X_OUTW(hcr, HFA384X_PCIHCR_OFF);
00220         mdelay(10);
00221         HFA384X_OUTW(0x0045, HFA384X_PCICOR_OFF);
00222         mdelay(10);
00223 }
00224 
00225 
00226 static struct prism2_helper_functions prism2_pci_funcs =
00227 {
00228         .card_present   = NULL,
00229         .cor_sreset     = prism2_pci_cor_sreset,
00230         .dev_open       = NULL,
00231         .dev_close      = NULL,
00232         .genesis_reset  = prism2_pci_genesis_reset,
00233 };
00234 
00235 
00236 static int prism2_pci_probe(struct pci_dev *pdev,
00237                             const struct pci_device_id *id)
00238 {
00239         unsigned long phymem;
00240         unsigned long mem = 0;
00241         local_info_t *local = NULL;
00242         struct net_device *dev = NULL;
00243         static int cards_found /* = 0 */;
00244         int irq_registered = 0;
00245         struct hostap_interface *iface;
00246 
00247         if (pci_enable_device(pdev))
00248                 return -EIO;
00249 
00250         phymem = pci_resource_start(pdev, 0);
00251 
00252         if (!request_mem_region(phymem, pci_resource_len(pdev, 0), "Prism2")) {
00253                 printk(KERN_ERR "prism2: Cannot reserve PCI memory region\n");
00254                 goto err_out_disable;
00255         }
00256 
00257         mem = (unsigned long) ioremap(phymem, pci_resource_len(pdev, 0));
00258         if (!mem) {
00259                 printk(KERN_ERR "prism2: Cannot remap PCI memory region\n") ;
00260                 goto fail;
00261         }
00262 
00263 #ifdef PRISM2_BUS_MASTER
00264         pci_set_master(pdev);
00265 #endif /* PRISM2_BUS_MASTER */
00266 
00267         dev = prism2_init_local_data(&prism2_pci_funcs, cards_found);
00268         if (dev == NULL)
00269                 goto fail;
00270         iface = dev->priv;
00271         local = iface->local;
00272         cards_found++;
00273 
00274         dev->irq = pdev->irq;
00275         dev->mem_start = mem;
00276         dev->mem_end = mem + pci_resource_len(pdev, 0);
00277 
00278         if (prism2_init_dev(local))
00279                 goto fail;
00280 
00281         prism2_pci_cor_sreset(local);
00282 
00283         pci_set_drvdata(pdev, dev);
00284 
00285         if (request_irq(dev->irq, prism2_interrupt, SA_SHIRQ, dev->name,
00286                         dev)) {
00287                 printk(KERN_WARNING "%s: request_irq failed\n", dev->name);
00288                 goto fail;
00289         } else
00290                 irq_registered = 1;
00291 
00292         if (!local->pri_only && prism2_hw_config(dev, 1)) {
00293                 printk(KERN_DEBUG "%s: hardware initialization failed\n",
00294                        dev_info);
00295                 goto fail;
00296         }
00297 
00298         printk(KERN_INFO "%s: Intersil Prism2.5 PCI: "
00299                "mem=0x%lx, irq=%d\n", dev->name, phymem, dev->irq);
00300 
00301         return 0;
00302 
00303  fail:
00304         if (irq_registered && dev)
00305                 free_irq(dev->irq, dev);
00306 
00307         if (mem)
00308                 iounmap((void *) mem);
00309 
00310         release_mem_region(phymem, pci_resource_len(pdev, 0));
00311 
00312  err_out_disable:
00313 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4))
00314         pci_disable_device(pdev);
00315 #endif
00316 
00317         prism2_free_local_data(dev);
00318 
00319         return -ENODEV;
00320 }
00321 
00322 
00323 static void prism2_pci_remove(struct pci_dev *pdev)
00324 {
00325         struct net_device *dev = pci_get_drvdata(pdev);
00326         struct hostap_interface *iface = dev->priv;
00327         unsigned long mem_start;
00328 
00329         /* Reset the hardware, and ensure interrupts are disabled. */
00330         prism2_pci_cor_sreset(iface->local);
00331         hfa384x_disable_interrupts(dev);
00332 
00333         if (dev->irq)
00334                 free_irq(dev->irq, dev);
00335 
00336         mem_start = dev->mem_start;
00337         prism2_free_local_data(dev);
00338 
00339         iounmap((void *) mem_start);
00340 
00341         release_mem_region(pci_resource_start(pdev, 0),
00342                            pci_resource_len(pdev, 0));
00343 
00344 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4))
00345         pci_disable_device(pdev);
00346 #endif
00347 }
00348 
00349 
00350 #ifdef CONFIG_PM
00351 static int prism2_pci_suspend(struct pci_dev *pdev, u32 state)
00352 {
00353         struct net_device *dev = pci_get_drvdata(pdev);
00354         struct hostap_interface *iface = dev->priv;
00355         local_info_t *local = iface->local;
00356 
00357         if (netif_running(dev)) {
00358                 hostap_netif_stop_queues(dev);
00359                 netif_device_detach(dev);
00360         }
00361         prism2_hw_shutdown(dev, 0);
00362 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,6))
00363         pci_save_state(pdev, local->pci_save_state);
00364 #endif
00365 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4))
00366         pci_disable_device(pdev);
00367 #endif
00368         pci_set_power_state(pdev, 3);
00369 
00370         return 0;
00371 }
00372 
00373 static int prism2_pci_resume(struct pci_dev *pdev)
00374 {
00375         struct net_device *dev = pci_get_drvdata(pdev);
00376         struct hostap_interface *iface = dev->priv;
00377         local_info_t *local = iface->local;
00378 
00379         pci_enable_device(pdev);
00380 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,6))
00381         pci_restore_state(pdev, local->pci_save_state);
00382 #endif
00383         prism2_hw_config(dev, 0);
00384         if (netif_running(dev)) {
00385                 netif_device_attach(dev);
00386                 netif_start_queue(dev);
00387         }
00388 
00389         return 0;
00390 }
00391 #endif /* CONFIG_PM */
00392 
00393 
00394 MODULE_DEVICE_TABLE(pci, prism2_pci_id_table);
00395 
00396 static struct pci_driver prism2_pci_drv_id = {
00397         .name           = "prism2_pci",
00398         .id_table       = prism2_pci_id_table,
00399         .probe          = prism2_pci_probe,
00400         .remove         = prism2_pci_remove,
00401 #ifdef CONFIG_PM
00402         .suspend        = prism2_pci_suspend,
00403         .resume         = prism2_pci_resume,
00404 #endif /* CONFIG_PM */
00405         /* Linux 2.4.6 added save_state and enable_wake that are not used here
00406          */
00407 };
00408 
00409 
00410 static int __init init_prism2_pci(void)
00411 {
00412         printk(KERN_INFO "%s: %s\n", dev_info, version);
00413 
00414         if (pci_register_driver(&prism2_pci_drv_id) <= 0) {
00415                 printk("hostap_pci: No devices found, driver not "
00416                        "installed.\n");
00417                 pci_unregister_driver(&prism2_pci_drv_id);
00418                 return -ENODEV;
00419         }
00420 
00421         return 0;
00422 }
00423 
00424 
00425 static void __exit exit_prism2_pci(void)
00426 {
00427         pci_unregister_driver(&prism2_pci_drv_id);
00428         printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
00429 }
00430 
00431 
00432 module_init(init_prism2_pci);
00433 module_exit(exit_prism2_pci);

Generated on Mon Nov 21 15:58:09 2005 for openwifi by  doxygen 1.4.1