1#define PRISM2_PCI 2 3/* Host AP driver's support for Intersil Prism2.5 PCI cards is based on 4 * driver patches from Reyk Floeter <reyk@vantronix.net> and 5 * Andy Warner <andyw@pobox.com> */ 6 7#include <linux/module.h> 8#include <linux/init.h> 9#include <linux/if.h> 10#include <linux/skbuff.h> 11#include <linux/netdevice.h> 12#include <linux/slab.h> 13#include <linux/workqueue.h> 14#include <linux/wireless.h> 15#include <net/iw_handler.h> 16 17#include <linux/ioport.h> 18#include <linux/pci.h> 19#include <asm/io.h> 20 21#include "hostap_wlan.h" 22 23 24static char *dev_info = "hostap_pci"; 25 26 27MODULE_AUTHOR("Jouni Malinen"); 28MODULE_DESCRIPTION("Support for Intersil Prism2.5-based 802.11 wireless LAN " 29 "PCI cards."); 30MODULE_SUPPORTED_DEVICE("Intersil Prism2.5-based WLAN PCI cards"); 31MODULE_LICENSE("GPL"); 32 33 34/* struct local_info::hw_priv */ 35struct hostap_pci_priv { 36 void __iomem *mem_start; 37}; 38 39 40/* FIX: do we need mb/wmb/rmb with memory operations? */ 41 42 43static DEFINE_PCI_DEVICE_TABLE(prism2_pci_id_table) = { 44 /* Intersil Prism3 ISL3872 11Mb/s WLAN Controller */ 45 { 0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID }, 46 /* Intersil Prism2.5 ISL3874 11Mb/s WLAN Controller */ 47 { 0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID }, 48 /* Samsung MagicLAN SWL-2210P */ 49 { 0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID }, 50 { 0 } 51}; 52 53 54#ifdef PRISM2_IO_DEBUG 55 56static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) 57{ 58 struct hostap_interface *iface; 59 struct hostap_pci_priv *hw_priv; 60 local_info_t *local; 61 unsigned long flags; 62 63 iface = netdev_priv(dev); 64 local = iface->local; 65 hw_priv = local->hw_priv; 66 67 spin_lock_irqsave(&local->lock, flags); 68 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v); 69 writeb(v, hw_priv->mem_start + a); 70 spin_unlock_irqrestore(&local->lock, flags); 71} 72 73static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) 74{ 75 struct hostap_interface *iface; 76 struct hostap_pci_priv *hw_priv; 77 local_info_t *local; 78 unsigned long flags; 79 u8 v; 80 81 iface = netdev_priv(dev); 82 local = iface->local; 83 hw_priv = local->hw_priv; 84 85 spin_lock_irqsave(&local->lock, flags); 86 v = readb(hw_priv->mem_start + a); 87 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v); 88 spin_unlock_irqrestore(&local->lock, flags); 89 return v; 90} 91 92static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) 93{ 94 struct hostap_interface *iface; 95 struct hostap_pci_priv *hw_priv; 96 local_info_t *local; 97 unsigned long flags; 98 99 iface = netdev_priv(dev); 100 local = iface->local; 101 hw_priv = local->hw_priv; 102 103 spin_lock_irqsave(&local->lock, flags); 104 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v); 105 writew(v, hw_priv->mem_start + a); 106 spin_unlock_irqrestore(&local->lock, flags); 107} 108 109static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) 110{ 111 struct hostap_interface *iface; 112 struct hostap_pci_priv *hw_priv; 113 local_info_t *local; 114 unsigned long flags; 115 u16 v; 116 117 iface = netdev_priv(dev); 118 local = iface->local; 119 hw_priv = local->hw_priv; 120 121 spin_lock_irqsave(&local->lock, flags); 122 v = readw(hw_priv->mem_start + a); 123 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v); 124 spin_unlock_irqrestore(&local->lock, flags); 125 return v; 126} 127 128#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v)) 129#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a)) 130#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v)) 131#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a)) 132#define HFA384X_OUTW_DATA(v,a) hfa384x_outw_debug(dev, (a), le16_to_cpu((v))) 133#define HFA384X_INW_DATA(a) cpu_to_le16(hfa384x_inw_debug(dev, (a))) 134 135#else /* PRISM2_IO_DEBUG */ 136 137static inline void hfa384x_outb(struct net_device *dev, int a, u8 v) 138{ 139 struct hostap_interface *iface; 140 struct hostap_pci_priv *hw_priv; 141 iface = netdev_priv(dev); 142 hw_priv = iface->local->hw_priv; 143 writeb(v, hw_priv->mem_start + a); 144} 145 146static inline u8 hfa384x_inb(struct net_device *dev, int a) 147{ 148 struct hostap_interface *iface; 149 struct hostap_pci_priv *hw_priv; 150 iface = netdev_priv(dev); 151 hw_priv = iface->local->hw_priv; 152 return readb(hw_priv->mem_start + a); 153} 154 155static inline void hfa384x_outw(struct net_device *dev, int a, u16 v) 156{ 157 struct hostap_interface *iface; 158 struct hostap_pci_priv *hw_priv; 159 iface = netdev_priv(dev); 160 hw_priv = iface->local->hw_priv; 161 writew(v, hw_priv->mem_start + a); 162} 163 164static inline u16 hfa384x_inw(struct net_device *dev, int a) 165{ 166 struct hostap_interface *iface; 167 struct hostap_pci_priv *hw_priv; 168 iface = netdev_priv(dev); 169 hw_priv = iface->local->hw_priv; 170 return readw(hw_priv->mem_start + a); 171} 172 173#define HFA384X_OUTB(v,a) hfa384x_outb(dev, (a), (v)) 174#define HFA384X_INB(a) hfa384x_inb(dev, (a)) 175#define HFA384X_OUTW(v,a) hfa384x_outw(dev, (a), (v)) 176#define HFA384X_INW(a) hfa384x_inw(dev, (a)) 177#define HFA384X_OUTW_DATA(v,a) hfa384x_outw(dev, (a), le16_to_cpu((v))) 178#define HFA384X_INW_DATA(a) cpu_to_le16(hfa384x_inw(dev, (a))) 179 180#endif /* PRISM2_IO_DEBUG */ 181 182 183static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf, 184 int len) 185{ 186 u16 d_off; 187 __le16 *pos; 188 189 d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; 190 pos = (__le16 *) buf; 191 192 for ( ; len > 1; len -= 2) 193 *pos++ = HFA384X_INW_DATA(d_off); 194 195 if (len & 1) 196 *((char *) pos) = HFA384X_INB(d_off); 197 198 return 0; 199} 200 201 202static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len) 203{ 204 u16 d_off; 205 __le16 *pos; 206 207 d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; 208 pos = (__le16 *) buf; 209 210 for ( ; len > 1; len -= 2) 211 HFA384X_OUTW_DATA(*pos++, d_off); 212 213 if (len & 1) 214 HFA384X_OUTB(*((char *) pos), d_off); 215 216 return 0; 217} 218 219 220/* FIX: This might change at some point.. */ 221#include "hostap_hw.c" 222 223static void prism2_pci_cor_sreset(local_info_t *local) 224{ 225 struct net_device *dev = local->dev; 226 u16 reg; 227 228 reg = HFA384X_INB(HFA384X_PCICOR_OFF); 229 printk(KERN_DEBUG "%s: Original COR value: 0x%0x\n", dev->name, reg); 230 231 /* linux-wlan-ng uses extremely long hold and settle times for 232 * COR sreset. A comment in the driver code mentions that the long 233 * delays appear to be necessary. However, at least IBM 22P6901 seems 234 * to work fine with shorter delays. 235 * 236 * Longer delays can be configured by uncommenting following line: */ 237/* #define PRISM2_PCI_USE_LONG_DELAYS */ 238 239#ifdef PRISM2_PCI_USE_LONG_DELAYS 240 int i; 241 242 HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF); 243 mdelay(250); 244 245 HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF); 246 mdelay(500); 247 248 /* Wait for f/w to complete initialization (CMD:BUSY == 0) */ 249 i = 2000000 / 10; 250 while ((HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) && --i) 251 udelay(10); 252 253#else /* PRISM2_PCI_USE_LONG_DELAYS */ 254 255 HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF); 256 mdelay(2); 257 HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF); 258 mdelay(2); 259 260#endif /* PRISM2_PCI_USE_LONG_DELAYS */ 261 262 if (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) { 263 printk(KERN_DEBUG "%s: COR sreset timeout\n", dev->name); 264 } 265} 266 267 268static void prism2_pci_genesis_reset(local_info_t *local, int hcr) 269{ 270 struct net_device *dev = local->dev; 271 272 HFA384X_OUTW(0x00C5, HFA384X_PCICOR_OFF); 273 mdelay(10); 274 HFA384X_OUTW(hcr, HFA384X_PCIHCR_OFF); 275 mdelay(10); 276 HFA384X_OUTW(0x0045, HFA384X_PCICOR_OFF); 277 mdelay(10); 278} 279 280 281static struct prism2_helper_functions prism2_pci_funcs = 282{ 283 .card_present = NULL, 284 .cor_sreset = prism2_pci_cor_sreset, 285 .genesis_reset = prism2_pci_genesis_reset, 286 .hw_type = HOSTAP_HW_PCI, 287}; 288 289 290static int prism2_pci_probe(struct pci_dev *pdev, 291 const struct pci_device_id *id) 292{ 293 unsigned long phymem; 294 void __iomem *mem = NULL; 295 local_info_t *local = NULL; 296 struct net_device *dev = NULL; 297 static int cards_found /* = 0 */; 298 int irq_registered = 0; 299 struct hostap_interface *iface; 300 struct hostap_pci_priv *hw_priv; 301 302 hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL); 303 if (hw_priv == NULL) 304 return -ENOMEM; 305 306 if (pci_enable_device(pdev)) 307 goto err_out_free; 308 309 phymem = pci_resource_start(pdev, 0); 310 311 if (!request_mem_region(phymem, pci_resource_len(pdev, 0), "Prism2")) { 312 printk(KERN_ERR "prism2: Cannot reserve PCI memory region\n"); 313 goto err_out_disable; 314 } 315 316 mem = pci_ioremap_bar(pdev, 0); 317 if (mem == NULL) { 318 printk(KERN_ERR "prism2: Cannot remap PCI memory region\n") ; 319 goto fail; 320 } 321 322 dev = prism2_init_local_data(&prism2_pci_funcs, cards_found, 323 &pdev->dev); 324 if (dev == NULL) 325 goto fail; 326 iface = netdev_priv(dev); 327 local = iface->local; 328 local->hw_priv = hw_priv; 329 cards_found++; 330 331 dev->irq = pdev->irq; 332 hw_priv->mem_start = mem; 333 dev->base_addr = (unsigned long) mem; 334 335 prism2_pci_cor_sreset(local); 336 337 pci_set_drvdata(pdev, dev); 338 339 if (request_irq(dev->irq, prism2_interrupt, IRQF_SHARED, dev->name, 340 dev)) { 341 printk(KERN_WARNING "%s: request_irq failed\n", dev->name); 342 goto fail; 343 } else 344 irq_registered = 1; 345 346 if (!local->pri_only && prism2_hw_config(dev, 1)) { 347 printk(KERN_DEBUG "%s: hardware initialization failed\n", 348 dev_info); 349 goto fail; 350 } 351 352 printk(KERN_INFO "%s: Intersil Prism2.5 PCI: " 353 "mem=0x%lx, irq=%d\n", dev->name, phymem, dev->irq); 354 355 return hostap_hw_ready(dev); 356 357 fail: 358 if (irq_registered && dev) 359 free_irq(dev->irq, dev); 360 361 if (mem) 362 iounmap(mem); 363 364 release_mem_region(phymem, pci_resource_len(pdev, 0)); 365 366 err_out_disable: 367 pci_disable_device(pdev); 368 prism2_free_local_data(dev); 369 370 err_out_free: 371 kfree(hw_priv); 372 373 return -ENODEV; 374} 375 376 377static void prism2_pci_remove(struct pci_dev *pdev) 378{ 379 struct net_device *dev; 380 struct hostap_interface *iface; 381 void __iomem *mem_start; 382 struct hostap_pci_priv *hw_priv; 383 384 dev = pci_get_drvdata(pdev); 385 iface = netdev_priv(dev); 386 hw_priv = iface->local->hw_priv; 387 388 /* Reset the hardware, and ensure interrupts are disabled. */ 389 prism2_pci_cor_sreset(iface->local); 390 hfa384x_disable_interrupts(dev); 391 392 if (dev->irq) 393 free_irq(dev->irq, dev); 394 395 mem_start = hw_priv->mem_start; 396 prism2_free_local_data(dev); 397 kfree(hw_priv); 398 399 iounmap(mem_start); 400 401 release_mem_region(pci_resource_start(pdev, 0), 402 pci_resource_len(pdev, 0)); 403 pci_disable_device(pdev); 404} 405 406 407#ifdef CONFIG_PM 408static int prism2_pci_suspend(struct pci_dev *pdev, pm_message_t state) 409{ 410 struct net_device *dev = pci_get_drvdata(pdev); 411 412 if (netif_running(dev)) { 413 netif_stop_queue(dev); 414 netif_device_detach(dev); 415 } 416 prism2_suspend(dev); 417 pci_save_state(pdev); 418 pci_disable_device(pdev); 419 pci_set_power_state(pdev, PCI_D3hot); 420 421 return 0; 422} 423 424static int prism2_pci_resume(struct pci_dev *pdev) 425{ 426 struct net_device *dev = pci_get_drvdata(pdev); 427 int err; 428 429 err = pci_enable_device(pdev); 430 if (err) { 431 printk(KERN_ERR "%s: pci_enable_device failed on resume\n", 432 dev->name); 433 return err; 434 } 435 pci_restore_state(pdev); 436 prism2_hw_config(dev, 0); 437 if (netif_running(dev)) { 438 netif_device_attach(dev); 439 netif_start_queue(dev); 440 } 441 442 return 0; 443} 444#endif /* CONFIG_PM */ 445 446 447MODULE_DEVICE_TABLE(pci, prism2_pci_id_table); 448 449static struct pci_driver prism2_pci_driver = { 450 .name = "hostap_pci", 451 .id_table = prism2_pci_id_table, 452 .probe = prism2_pci_probe, 453 .remove = prism2_pci_remove, 454#ifdef CONFIG_PM 455 .suspend = prism2_pci_suspend, 456 .resume = prism2_pci_resume, 457#endif /* CONFIG_PM */ 458}; 459 460 461static int __init init_prism2_pci(void) 462{ 463 return pci_register_driver(&prism2_pci_driver); 464} 465 466 467static void __exit exit_prism2_pci(void) 468{ 469 pci_unregister_driver(&prism2_pci_driver); 470} 471 472 473module_init(init_prism2_pci); 474module_exit(exit_prism2_pci); 475