00001 #define PRISM2_PCI
00002
00003
00004
00005
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
00040
00041 #error Prism2.5 PCI version requires at least Linux kernel version 2.4.0
00042 #endif
00043
00044
00045
00046
00047
00048 static struct pci_device_id prism2_pci_id_table[] __devinitdata = {
00049
00050 { 0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID },
00051
00052 { 0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID },
00053
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
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
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
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
00177
00178
00179
00180
00181
00182
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
00194 i = 2000000 / 10;
00195 while ((HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) && --i)
00196 udelay(10);
00197
00198 #else
00199
00200 HFA384X_OUTW(0x0080, HFA384X_PCICOR_OFF);
00201 mdelay(1);
00202 HFA384X_OUTW(0x0, HFA384X_PCICOR_OFF);
00203 mdelay(1);
00204
00205 #endif
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 ;
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
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
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
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
00405
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);