hostap_cs.c revision ea9edaf6bc0e3f3a7bd167d9ba369276a30c9953
1#define PRISM2_PCCARD 2 3#include <linux/module.h> 4#include <linux/init.h> 5#include <linux/if.h> 6#include <linux/wait.h> 7#include <linux/timer.h> 8#include <linux/skbuff.h> 9#include <linux/netdevice.h> 10#include <linux/workqueue.h> 11#include <linux/wireless.h> 12#include <net/iw_handler.h> 13 14#include <pcmcia/cs_types.h> 15#include <pcmcia/cs.h> 16#include <pcmcia/cistpl.h> 17#include <pcmcia/cisreg.h> 18#include <pcmcia/ds.h> 19 20#include <asm/io.h> 21 22#include "hostap_wlan.h" 23 24 25static dev_info_t dev_info = "hostap_cs"; 26 27MODULE_AUTHOR("Jouni Malinen"); 28MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN " 29 "cards (PC Card)."); 30MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PC Card)"); 31MODULE_LICENSE("GPL"); 32 33 34static int ignore_cis_vcc; 35module_param(ignore_cis_vcc, int, 0444); 36MODULE_PARM_DESC(ignore_cis_vcc, "Ignore broken CIS VCC entry"); 37 38 39/* struct local_info::hw_priv */ 40struct hostap_cs_priv { 41 dev_node_t node; 42 struct pcmcia_device *link; 43 int sandisk_connectplus; 44}; 45 46 47#ifdef PRISM2_IO_DEBUG 48 49static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) 50{ 51 struct hostap_interface *iface; 52 local_info_t *local; 53 unsigned long flags; 54 55 iface = netdev_priv(dev); 56 local = iface->local; 57 spin_lock_irqsave(&local->lock, flags); 58 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v); 59 outb(v, dev->base_addr + a); 60 spin_unlock_irqrestore(&local->lock, flags); 61} 62 63static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) 64{ 65 struct hostap_interface *iface; 66 local_info_t *local; 67 unsigned long flags; 68 u8 v; 69 70 iface = netdev_priv(dev); 71 local = iface->local; 72 spin_lock_irqsave(&local->lock, flags); 73 v = inb(dev->base_addr + a); 74 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v); 75 spin_unlock_irqrestore(&local->lock, flags); 76 return v; 77} 78 79static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) 80{ 81 struct hostap_interface *iface; 82 local_info_t *local; 83 unsigned long flags; 84 85 iface = netdev_priv(dev); 86 local = iface->local; 87 spin_lock_irqsave(&local->lock, flags); 88 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v); 89 outw(v, dev->base_addr + a); 90 spin_unlock_irqrestore(&local->lock, flags); 91} 92 93static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) 94{ 95 struct hostap_interface *iface; 96 local_info_t *local; 97 unsigned long flags; 98 u16 v; 99 100 iface = netdev_priv(dev); 101 local = iface->local; 102 spin_lock_irqsave(&local->lock, flags); 103 v = inw(dev->base_addr + a); 104 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v); 105 spin_unlock_irqrestore(&local->lock, flags); 106 return v; 107} 108 109static inline void hfa384x_outsw_debug(struct net_device *dev, int a, 110 u8 *buf, int wc) 111{ 112 struct hostap_interface *iface; 113 local_info_t *local; 114 unsigned long flags; 115 116 iface = netdev_priv(dev); 117 local = iface->local; 118 spin_lock_irqsave(&local->lock, flags); 119 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc); 120 outsw(dev->base_addr + a, buf, wc); 121 spin_unlock_irqrestore(&local->lock, flags); 122} 123 124static inline void hfa384x_insw_debug(struct net_device *dev, int a, 125 u8 *buf, int wc) 126{ 127 struct hostap_interface *iface; 128 local_info_t *local; 129 unsigned long flags; 130 131 iface = netdev_priv(dev); 132 local = iface->local; 133 spin_lock_irqsave(&local->lock, flags); 134 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc); 135 insw(dev->base_addr + a, buf, wc); 136 spin_unlock_irqrestore(&local->lock, flags); 137} 138 139#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v)) 140#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a)) 141#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v)) 142#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a)) 143#define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc)) 144#define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc)) 145 146#else /* PRISM2_IO_DEBUG */ 147 148#define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a)) 149#define HFA384X_INB(a) inb(dev->base_addr + (a)) 150#define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a)) 151#define HFA384X_INW(a) inw(dev->base_addr + (a)) 152#define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc) 153#define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc) 154 155#endif /* PRISM2_IO_DEBUG */ 156 157 158static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf, 159 int len) 160{ 161 u16 d_off; 162 u16 *pos; 163 164 d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; 165 pos = (u16 *) buf; 166 167 if (len / 2) 168 HFA384X_INSW(d_off, buf, len / 2); 169 pos += len / 2; 170 171 if (len & 1) 172 *((char *) pos) = HFA384X_INB(d_off); 173 174 return 0; 175} 176 177 178static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len) 179{ 180 u16 d_off; 181 u16 *pos; 182 183 d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; 184 pos = (u16 *) buf; 185 186 if (len / 2) 187 HFA384X_OUTSW(d_off, buf, len / 2); 188 pos += len / 2; 189 190 if (len & 1) 191 HFA384X_OUTB(*((char *) pos), d_off); 192 193 return 0; 194} 195 196 197/* FIX: This might change at some point.. */ 198#include "hostap_hw.c" 199 200 201 202static void prism2_detach(struct pcmcia_device *p_dev); 203static void prism2_release(u_long arg); 204static int prism2_config(struct pcmcia_device *link); 205 206 207static int prism2_pccard_card_present(local_info_t *local) 208{ 209 struct hostap_cs_priv *hw_priv = local->hw_priv; 210 if (hw_priv != NULL && hw_priv->link != NULL && pcmcia_dev_present(hw_priv->link)) 211 return 1; 212 return 0; 213} 214 215 216/* 217 * SanDisk CompactFlash WLAN Flashcard - Product Manual v1.0 218 * Document No. 20-10-00058, January 2004 219 * http://www.sandisk.com/pdf/industrial/ProdManualCFWLANv1.0.pdf 220 */ 221#define SANDISK_WLAN_ACTIVATION_OFF 0x40 222#define SANDISK_HCR_OFF 0x42 223 224 225static void sandisk_set_iobase(local_info_t *local) 226{ 227 int res; 228 conf_reg_t reg; 229 struct hostap_cs_priv *hw_priv = local->hw_priv; 230 231 reg.Function = 0; 232 reg.Action = CS_WRITE; 233 reg.Offset = 0x10; /* 0x3f0 IO base 1 */ 234 reg.Value = hw_priv->link->io.BasePort1 & 0x00ff; 235 res = pcmcia_access_configuration_register(hw_priv->link, 236 ®); 237 if (res != 0) { 238 printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 0 -" 239 " res=%d\n", res); 240 } 241 udelay(10); 242 243 reg.Function = 0; 244 reg.Action = CS_WRITE; 245 reg.Offset = 0x12; /* 0x3f2 IO base 2 */ 246 reg.Value = (hw_priv->link->io.BasePort1 & 0xff00) >> 8; 247 res = pcmcia_access_configuration_register(hw_priv->link, 248 ®); 249 if (res != 0) { 250 printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 1 -" 251 " res=%d\n", res); 252 } 253} 254 255 256static void sandisk_write_hcr(local_info_t *local, int hcr) 257{ 258 struct net_device *dev = local->dev; 259 int i; 260 261 HFA384X_OUTB(0x80, SANDISK_WLAN_ACTIVATION_OFF); 262 udelay(50); 263 for (i = 0; i < 10; i++) { 264 HFA384X_OUTB(hcr, SANDISK_HCR_OFF); 265 } 266 udelay(55); 267 HFA384X_OUTB(0x45, SANDISK_WLAN_ACTIVATION_OFF); 268} 269 270 271static int sandisk_enable_wireless(struct net_device *dev) 272{ 273 int res, ret = 0; 274 conf_reg_t reg; 275 struct hostap_interface *iface = netdev_priv(dev); 276 local_info_t *local = iface->local; 277 tuple_t tuple; 278 cisparse_t *parse = NULL; 279 u_char buf[64]; 280 struct hostap_cs_priv *hw_priv = local->hw_priv; 281 282 if (hw_priv->link->io.NumPorts1 < 0x42) { 283 /* Not enough ports to be SanDisk multi-function card */ 284 ret = -ENODEV; 285 goto done; 286 } 287 288 parse = kmalloc(sizeof(cisparse_t), GFP_KERNEL); 289 if (parse == NULL) { 290 ret = -ENOMEM; 291 goto done; 292 } 293 294 tuple.Attributes = TUPLE_RETURN_COMMON; 295 tuple.TupleData = buf; 296 tuple.TupleDataMax = sizeof(buf); 297 tuple.TupleOffset = 0; 298 299 if (hw_priv->link->manf_id != 0xd601 || hw_priv->link->card_id != 0x0101) { 300 /* No SanDisk manfid found */ 301 ret = -ENODEV; 302 goto done; 303 } 304 305 tuple.DesiredTuple = CISTPL_LONGLINK_MFC; 306 if (pcmcia_get_first_tuple(hw_priv->link, &tuple) || 307 pcmcia_get_tuple_data(hw_priv->link, &tuple) || 308 pcmcia_parse_tuple(&tuple, parse) || 309 parse->longlink_mfc.nfn < 2) { 310 /* No multi-function links found */ 311 ret = -ENODEV; 312 goto done; 313 } 314 315 printk(KERN_DEBUG "%s: Multi-function SanDisk ConnectPlus detected" 316 " - using vendor-specific initialization\n", dev->name); 317 hw_priv->sandisk_connectplus = 1; 318 319 reg.Function = 0; 320 reg.Action = CS_WRITE; 321 reg.Offset = CISREG_COR; 322 reg.Value = COR_SOFT_RESET; 323 res = pcmcia_access_configuration_register(hw_priv->link, 324 ®); 325 if (res != 0) { 326 printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n", 327 dev->name, res); 328 goto done; 329 } 330 mdelay(5); 331 332 reg.Function = 0; 333 reg.Action = CS_WRITE; 334 reg.Offset = CISREG_COR; 335 /* 336 * Do not enable interrupts here to avoid some bogus events. Interrupts 337 * will be enabled during the first cor_sreset call. 338 */ 339 reg.Value = COR_LEVEL_REQ | 0x8 | COR_ADDR_DECODE | COR_FUNC_ENA; 340 res = pcmcia_access_configuration_register(hw_priv->link, 341 ®); 342 if (res != 0) { 343 printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n", 344 dev->name, res); 345 goto done; 346 } 347 mdelay(5); 348 349 sandisk_set_iobase(local); 350 351 HFA384X_OUTB(0xc5, SANDISK_WLAN_ACTIVATION_OFF); 352 udelay(10); 353 HFA384X_OUTB(0x4b, SANDISK_WLAN_ACTIVATION_OFF); 354 udelay(10); 355 356done: 357 kfree(parse); 358 return ret; 359} 360 361 362static void prism2_pccard_cor_sreset(local_info_t *local) 363{ 364 int res; 365 conf_reg_t reg; 366 struct hostap_cs_priv *hw_priv = local->hw_priv; 367 368 if (!prism2_pccard_card_present(local)) 369 return; 370 371 reg.Function = 0; 372 reg.Action = CS_READ; 373 reg.Offset = CISREG_COR; 374 reg.Value = 0; 375 res = pcmcia_access_configuration_register(hw_priv->link, 376 ®); 377 if (res != 0) { 378 printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 1 (%d)\n", 379 res); 380 return; 381 } 382 printk(KERN_DEBUG "prism2_pccard_cor_sreset: original COR %02x\n", 383 reg.Value); 384 385 reg.Action = CS_WRITE; 386 reg.Value |= COR_SOFT_RESET; 387 res = pcmcia_access_configuration_register(hw_priv->link, 388 ®); 389 if (res != 0) { 390 printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 2 (%d)\n", 391 res); 392 return; 393 } 394 395 mdelay(hw_priv->sandisk_connectplus ? 5 : 2); 396 397 reg.Value &= ~COR_SOFT_RESET; 398 if (hw_priv->sandisk_connectplus) 399 reg.Value |= COR_IREQ_ENA; 400 res = pcmcia_access_configuration_register(hw_priv->link, 401 ®); 402 if (res != 0) { 403 printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 3 (%d)\n", 404 res); 405 return; 406 } 407 408 mdelay(hw_priv->sandisk_connectplus ? 5 : 2); 409 410 if (hw_priv->sandisk_connectplus) 411 sandisk_set_iobase(local); 412} 413 414 415static void prism2_pccard_genesis_reset(local_info_t *local, int hcr) 416{ 417 int res; 418 conf_reg_t reg; 419 int old_cor; 420 struct hostap_cs_priv *hw_priv = local->hw_priv; 421 422 if (!prism2_pccard_card_present(local)) 423 return; 424 425 if (hw_priv->sandisk_connectplus) { 426 sandisk_write_hcr(local, hcr); 427 return; 428 } 429 430 reg.Function = 0; 431 reg.Action = CS_READ; 432 reg.Offset = CISREG_COR; 433 reg.Value = 0; 434 res = pcmcia_access_configuration_register(hw_priv->link, 435 ®); 436 if (res != 0) { 437 printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 1 " 438 "(%d)\n", res); 439 return; 440 } 441 printk(KERN_DEBUG "prism2_pccard_genesis_sreset: original COR %02x\n", 442 reg.Value); 443 old_cor = reg.Value; 444 445 reg.Action = CS_WRITE; 446 reg.Value |= COR_SOFT_RESET; 447 res = pcmcia_access_configuration_register(hw_priv->link, 448 ®); 449 if (res != 0) { 450 printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 2 " 451 "(%d)\n", res); 452 return; 453 } 454 455 mdelay(10); 456 457 /* Setup Genesis mode */ 458 reg.Action = CS_WRITE; 459 reg.Value = hcr; 460 reg.Offset = CISREG_CCSR; 461 res = pcmcia_access_configuration_register(hw_priv->link, 462 ®); 463 if (res != 0) { 464 printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 3 " 465 "(%d)\n", res); 466 return; 467 } 468 mdelay(10); 469 470 reg.Action = CS_WRITE; 471 reg.Offset = CISREG_COR; 472 reg.Value = old_cor & ~COR_SOFT_RESET; 473 res = pcmcia_access_configuration_register(hw_priv->link, 474 ®); 475 if (res != 0) { 476 printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 4 " 477 "(%d)\n", res); 478 return; 479 } 480 481 mdelay(10); 482} 483 484 485static struct prism2_helper_functions prism2_pccard_funcs = 486{ 487 .card_present = prism2_pccard_card_present, 488 .cor_sreset = prism2_pccard_cor_sreset, 489 .genesis_reset = prism2_pccard_genesis_reset, 490 .hw_type = HOSTAP_HW_PCCARD, 491}; 492 493 494/* allocate local data and register with CardServices 495 * initialize dev_link structure, but do not configure the card yet */ 496static int hostap_cs_probe(struct pcmcia_device *p_dev) 497{ 498 int ret; 499 500 PDEBUG(DEBUG_HW, "%s: setting Vcc=33 (constant)\n", dev_info); 501 p_dev->conf.IntType = INT_MEMORY_AND_IO; 502 503 ret = prism2_config(p_dev); 504 if (ret) { 505 PDEBUG(DEBUG_EXTRA, "prism2_config() failed\n"); 506 } 507 508 return ret; 509} 510 511 512static void prism2_detach(struct pcmcia_device *link) 513{ 514 PDEBUG(DEBUG_FLOW, "prism2_detach\n"); 515 516 prism2_release((u_long)link); 517 518 /* release net devices */ 519 if (link->priv) { 520 struct hostap_cs_priv *hw_priv; 521 struct net_device *dev; 522 struct hostap_interface *iface; 523 dev = link->priv; 524 iface = netdev_priv(dev); 525 hw_priv = iface->local->hw_priv; 526 prism2_free_local_data(dev); 527 kfree(hw_priv); 528 } 529} 530 531 532#define CS_CHECK(fn, ret) \ 533do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) 534 535 536/* run after a CARD_INSERTION event is received to configure the PCMCIA 537 * socket and make the device available to the system */ 538 539static int prism2_config_check(struct pcmcia_device *p_dev, 540 cistpl_cftable_entry_t *cfg, 541 cistpl_cftable_entry_t *dflt, 542 unsigned int vcc, 543 void *priv_data) 544{ 545 if (cfg->index == 0) 546 return -ENODEV; 547 548 PDEBUG(DEBUG_EXTRA, "Checking CFTABLE_ENTRY 0x%02X " 549 "(default 0x%02X)\n", cfg->index, dflt->index); 550 551 /* Does this card need audio output? */ 552 if (cfg->flags & CISTPL_CFTABLE_AUDIO) { 553 p_dev->conf.Attributes |= CONF_ENABLE_SPKR; 554 p_dev->conf.Status = CCSR_AUDIO_ENA; 555 } 556 557 /* Use power settings for Vcc and Vpp if present */ 558 /* Note that the CIS values need to be rescaled */ 559 if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { 560 if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 561 10000 && !ignore_cis_vcc) { 562 PDEBUG(DEBUG_EXTRA, " Vcc mismatch - skipping" 563 " this entry\n"); 564 return -ENODEV; 565 } 566 } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) { 567 if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 568 10000 && !ignore_cis_vcc) { 569 PDEBUG(DEBUG_EXTRA, " Vcc (default) mismatch " 570 "- skipping this entry\n"); 571 return -ENODEV; 572 } 573 } 574 575 if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) 576 p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; 577 else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM)) 578 p_dev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000; 579 580 /* Do we need to allocate an interrupt? */ 581 if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1) 582 p_dev->conf.Attributes |= CONF_ENABLE_IRQ; 583 else if (!(p_dev->conf.Attributes & CONF_ENABLE_IRQ)) { 584 /* At least Compaq WL200 does not have IRQInfo1 set, 585 * but it does not work without interrupts.. */ 586 printk(KERN_WARNING "Config has no IRQ info, but trying to " 587 "enable IRQ anyway..\n"); 588 p_dev->conf.Attributes |= CONF_ENABLE_IRQ; 589 } 590 591 /* IO window settings */ 592 PDEBUG(DEBUG_EXTRA, "IO window settings: cfg->io.nwin=%d " 593 "dflt->io.nwin=%d\n", 594 cfg->io.nwin, dflt->io.nwin); 595 p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; 596 if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { 597 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; 598 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; 599 PDEBUG(DEBUG_EXTRA, "io->flags = 0x%04X, " 600 "io.base=0x%04x, len=%d\n", io->flags, 601 io->win[0].base, io->win[0].len); 602 if (!(io->flags & CISTPL_IO_8BIT)) 603 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; 604 if (!(io->flags & CISTPL_IO_16BIT)) 605 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; 606 p_dev->io.IOAddrLines = io->flags & 607 CISTPL_IO_LINES_MASK; 608 p_dev->io.BasePort1 = io->win[0].base; 609 p_dev->io.NumPorts1 = io->win[0].len; 610 if (io->nwin > 1) { 611 p_dev->io.Attributes2 = p_dev->io.Attributes1; 612 p_dev->io.BasePort2 = io->win[1].base; 613 p_dev->io.NumPorts2 = io->win[1].len; 614 } 615 } 616 617 /* This reserves IO space but doesn't actually enable it */ 618 return pcmcia_request_io(p_dev, &p_dev->io); 619} 620 621static int prism2_config(struct pcmcia_device *link) 622{ 623 struct net_device *dev; 624 struct hostap_interface *iface; 625 local_info_t *local; 626 int ret = 1; 627 int last_fn, last_ret; 628 struct hostap_cs_priv *hw_priv; 629 630 PDEBUG(DEBUG_FLOW, "prism2_config()\n"); 631 632 hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL); 633 if (hw_priv == NULL) { 634 ret = -ENOMEM; 635 goto failed; 636 } 637 638 /* Look for an appropriate configuration table entry in the CIS */ 639 last_ret = pcmcia_loop_config(link, prism2_config_check, NULL); 640 if (last_ret) { 641 if (!ignore_cis_vcc) 642 printk(KERN_ERR "GetNextTuple(): No matching " 643 "CIS configuration. Maybe you need the " 644 "ignore_cis_vcc=1 parameter.\n"); 645 cs_error(link, RequestIO, last_ret); 646 goto failed; 647 } 648 649 /* Need to allocate net_device before requesting IRQ handler */ 650 dev = prism2_init_local_data(&prism2_pccard_funcs, 0, 651 &handle_to_dev(link)); 652 if (dev == NULL) 653 goto failed; 654 link->priv = dev; 655 656 iface = netdev_priv(dev); 657 local = iface->local; 658 local->hw_priv = hw_priv; 659 hw_priv->link = link; 660 strcpy(hw_priv->node.dev_name, dev->name); 661 link->dev_node = &hw_priv->node; 662 663 /* 664 * Allocate an interrupt line. Note that this does not assign a 665 * handler to the interrupt, unless the 'Handler' member of the 666 * irq structure is initialized. 667 */ 668 if (link->conf.Attributes & CONF_ENABLE_IRQ) { 669 link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | 670 IRQ_HANDLE_PRESENT; 671 link->irq.IRQInfo1 = IRQ_LEVEL_ID; 672 link->irq.Handler = prism2_interrupt; 673 link->irq.Instance = dev; 674 CS_CHECK(RequestIRQ, 675 pcmcia_request_irq(link, &link->irq)); 676 } 677 678 /* 679 * This actually configures the PCMCIA socket -- setting up 680 * the I/O windows and the interrupt mapping, and putting the 681 * card and host interface into "Memory and IO" mode. 682 */ 683 CS_CHECK(RequestConfiguration, 684 pcmcia_request_configuration(link, &link->conf)); 685 686 dev->irq = link->irq.AssignedIRQ; 687 dev->base_addr = link->io.BasePort1; 688 689 /* Finally, report what we've done */ 690 printk(KERN_INFO "%s: index 0x%02x: ", 691 dev_info, link->conf.ConfigIndex); 692 if (link->conf.Vpp) 693 printk(", Vpp %d.%d", link->conf.Vpp / 10, 694 link->conf.Vpp % 10); 695 if (link->conf.Attributes & CONF_ENABLE_IRQ) 696 printk(", irq %d", link->irq.AssignedIRQ); 697 if (link->io.NumPorts1) 698 printk(", io 0x%04x-0x%04x", link->io.BasePort1, 699 link->io.BasePort1+link->io.NumPorts1-1); 700 if (link->io.NumPorts2) 701 printk(" & 0x%04x-0x%04x", link->io.BasePort2, 702 link->io.BasePort2+link->io.NumPorts2-1); 703 printk("\n"); 704 705 local->shutdown = 0; 706 707 sandisk_enable_wireless(dev); 708 709 ret = prism2_hw_config(dev, 1); 710 if (!ret) { 711 ret = hostap_hw_ready(dev); 712 if (ret == 0 && local->ddev) 713 strcpy(hw_priv->node.dev_name, local->ddev->name); 714 } 715 return ret; 716 717 cs_failed: 718 cs_error(link, last_fn, last_ret); 719 720 failed: 721 kfree(hw_priv); 722 prism2_release((u_long)link); 723 return ret; 724} 725 726 727static void prism2_release(u_long arg) 728{ 729 struct pcmcia_device *link = (struct pcmcia_device *)arg; 730 731 PDEBUG(DEBUG_FLOW, "prism2_release\n"); 732 733 if (link->priv) { 734 struct net_device *dev = link->priv; 735 struct hostap_interface *iface; 736 737 iface = netdev_priv(dev); 738 prism2_hw_shutdown(dev, 0); 739 iface->local->shutdown = 1; 740 } 741 742 pcmcia_disable_device(link); 743 PDEBUG(DEBUG_FLOW, "release - done\n"); 744} 745 746static int hostap_cs_suspend(struct pcmcia_device *link) 747{ 748 struct net_device *dev = (struct net_device *) link->priv; 749 int dev_open = 0; 750 struct hostap_interface *iface = NULL; 751 752 if (!dev) 753 return -ENODEV; 754 755 iface = netdev_priv(dev); 756 757 PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_SUSPEND\n", dev_info); 758 if (iface && iface->local) 759 dev_open = iface->local->num_dev_open > 0; 760 if (dev_open) { 761 netif_stop_queue(dev); 762 netif_device_detach(dev); 763 } 764 prism2_suspend(dev); 765 766 return 0; 767} 768 769static int hostap_cs_resume(struct pcmcia_device *link) 770{ 771 struct net_device *dev = (struct net_device *) link->priv; 772 int dev_open = 0; 773 struct hostap_interface *iface = NULL; 774 775 if (!dev) 776 return -ENODEV; 777 778 iface = netdev_priv(dev); 779 780 PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_RESUME\n", dev_info); 781 782 if (iface && iface->local) 783 dev_open = iface->local->num_dev_open > 0; 784 785 prism2_hw_shutdown(dev, 1); 786 prism2_hw_config(dev, dev_open ? 0 : 1); 787 if (dev_open) { 788 netif_device_attach(dev); 789 netif_start_queue(dev); 790 } 791 792 return 0; 793} 794 795static struct pcmcia_device_id hostap_cs_ids[] = { 796 PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), 797 PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), 798 PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), 799 PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), 800 PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), 801 PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x3301), 802 PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), 803 PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030b), 804 PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), 805 PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), 806 PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), 807 PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), 808 PCMCIA_DEVICE_MANF_CARD(0x02d2, 0x0001), 809 PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x0001), 810 PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), 811/* PCMCIA_DEVICE_MANF_CARD(0xc00f, 0x0000), conflict with pcnet_cs */ 812 PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002), 813 PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), 814 PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), 815 PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010), 816 PCMCIA_DEVICE_MANF_CARD(0x0126, 0x0002), 817 PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0xd601, 0x0005, "ADLINK 345 CF", 818 0x2d858104), 819 PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "INTERSIL", 820 0x74c5e40d), 821 PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "Intersil", 822 0x4b801a17), 823 PCMCIA_MFC_DEVICE_PROD_ID12(0, "SanDisk", "ConnectPlus", 824 0x7a954bd9, 0x74be00c6), 825 PCMCIA_DEVICE_PROD_ID123( 826 "Intersil", "PRISM 2_5 PCMCIA ADAPTER", "ISL37300P", 827 0x4b801a17, 0x6345a0bf, 0xc9049a39), 828 /* D-Link DWL-650 Rev. P1; manfid 0x000b, 0x7110 */ 829 PCMCIA_DEVICE_PROD_ID123( 830 "D-Link", "DWL-650 Wireless PC Card RevP", "ISL37101P-10", 831 0x1a424a1c, 0x6ea57632, 0xdd97a26b), 832 PCMCIA_DEVICE_PROD_ID123( 833 "Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02", 834 0xe6ec52ce, 0x08649af2, 0x4b74baa0), 835 PCMCIA_DEVICE_PROD_ID123( 836 "D", "Link DWL-650 11Mbps WLAN Card", "Version 01.02", 837 0x71b18589, 0xb6f1b0ab, 0x4b74baa0), 838 PCMCIA_DEVICE_PROD_ID123( 839 "Instant Wireless ", " Network PC CARD", "Version 01.02", 840 0x11d901af, 0x6e9bd926, 0x4b74baa0), 841 PCMCIA_DEVICE_PROD_ID123( 842 "SMC", "SMC2632W", "Version 01.02", 843 0xc4f8b18b, 0x474a1f2a, 0x4b74baa0), 844 PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", 845 0x2decece3, 0x82067c18), 846 PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", 847 0x54f7c49c, 0x15a75e5b), 848 PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", 849 0x74c5e40d, 0xdb472a18), 850 PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", 851 0x0733cc81, 0x0c52f395), 852 PCMCIA_DEVICE_PROD_ID12( 853 "ZoomAir 11Mbps High", "Rate wireless Networking", 854 0x273fe3db, 0x32a1eaee), 855 PCMCIA_DEVICE_PROD_ID123( 856 "Pretec", "CompactWLAN Card 802.11b", "2.5", 857 0x1cadd3e5, 0xe697636c, 0x7a5bfcf1), 858 PCMCIA_DEVICE_PROD_ID123( 859 "U.S. Robotics", "IEEE 802.11b PC-CARD", "Version 01.02", 860 0xc7b8df9d, 0x1700d087, 0x4b74baa0), 861 PCMCIA_DEVICE_PROD_ID123( 862 "Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", 863 "Ver. 1.00", 864 0x5cd01705, 0x4271660f, 0x9d08ee12), 865 PCMCIA_DEVICE_PROD_ID123( 866 "corega", "WL PCCL-11", "ISL37300P", 867 0xa21501a, 0x59868926, 0xc9049a39), 868 PCMCIA_DEVICE_PROD_ID123( 869 "The Linksys Group, Inc.", "Wireless Network CF Card", "ISL37300P", 870 0xa5f472c2, 0x9c05598d, 0xc9049a39), 871 PCMCIA_DEVICE_PROD_ID123( 872 "Wireless LAN" , "11Mbps PC Card", "Version 01.02", 873 0x4b8870ff, 0x70e946d1, 0x4b74baa0), 874 PCMCIA_DEVICE_NULL 875}; 876MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids); 877 878 879static struct pcmcia_driver hostap_driver = { 880 .drv = { 881 .name = "hostap_cs", 882 }, 883 .probe = hostap_cs_probe, 884 .remove = prism2_detach, 885 .owner = THIS_MODULE, 886 .id_table = hostap_cs_ids, 887 .suspend = hostap_cs_suspend, 888 .resume = hostap_cs_resume, 889}; 890 891static int __init init_prism2_pccard(void) 892{ 893 return pcmcia_register_driver(&hostap_driver); 894} 895 896static void __exit exit_prism2_pccard(void) 897{ 898 pcmcia_unregister_driver(&hostap_driver); 899} 900 901 902module_init(init_prism2_pccard); 903module_exit(exit_prism2_pccard); 904