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