Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at c9a28fa7b9ac19b676deefa0a171ce7df8755c08 926 lines 25 kB view raw
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 &reg); 237 if (res != CS_SUCCESS) { 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 &reg); 249 if (res != CS_SUCCESS) { 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(hw_priv->link, &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 &reg); 325 if (res != CS_SUCCESS) { 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 &reg); 342 if (res != CS_SUCCESS) { 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 &reg); 377 if (res != CS_SUCCESS) { 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 &reg); 389 if (res != CS_SUCCESS) { 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 &reg); 402 if (res != CS_SUCCESS) { 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 &reg); 436 if (res != CS_SUCCESS) { 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 &reg); 449 if (res != CS_SUCCESS) { 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 &reg); 463 if (res != CS_SUCCESS) { 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 &reg); 475 if (res != CS_SUCCESS) { 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#define CFG_CHECK2(fn, retf) \ 536do { int ret = (retf); \ 537if (ret != 0) { \ 538 PDEBUG(DEBUG_EXTRA, "CardServices(" #fn ") returned %d\n", ret); \ 539 cs_error(link, fn, ret); \ 540 goto next_entry; \ 541} \ 542} while (0) 543 544 545/* run after a CARD_INSERTION event is received to configure the PCMCIA 546 * socket and make the device available to the system */ 547static int prism2_config(struct pcmcia_device *link) 548{ 549 struct net_device *dev; 550 struct hostap_interface *iface; 551 local_info_t *local; 552 int ret = 1; 553 tuple_t tuple; 554 cisparse_t *parse; 555 int last_fn, last_ret; 556 u_char buf[64]; 557 config_info_t conf; 558 cistpl_cftable_entry_t dflt = { 0 }; 559 struct hostap_cs_priv *hw_priv; 560 561 PDEBUG(DEBUG_FLOW, "prism2_config()\n"); 562 563 parse = kmalloc(sizeof(cisparse_t), GFP_KERNEL); 564 hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL); 565 if (parse == NULL || hw_priv == NULL) { 566 ret = -ENOMEM; 567 goto failed; 568 } 569 570 tuple.Attributes = 0; 571 tuple.TupleData = buf; 572 tuple.TupleDataMax = sizeof(buf); 573 tuple.TupleOffset = 0; 574 575 CS_CHECK(GetConfigurationInfo, 576 pcmcia_get_configuration_info(link, &conf)); 577 578 /* Look for an appropriate configuration table entry in the CIS */ 579 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; 580 CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); 581 for (;;) { 582 cistpl_cftable_entry_t *cfg = &(parse->cftable_entry); 583 CFG_CHECK2(GetTupleData, 584 pcmcia_get_tuple_data(link, &tuple)); 585 CFG_CHECK2(ParseTuple, 586 pcmcia_parse_tuple(link, &tuple, parse)); 587 588 if (cfg->flags & CISTPL_CFTABLE_DEFAULT) 589 dflt = *cfg; 590 if (cfg->index == 0) 591 goto next_entry; 592 link->conf.ConfigIndex = cfg->index; 593 PDEBUG(DEBUG_EXTRA, "Checking CFTABLE_ENTRY 0x%02X " 594 "(default 0x%02X)\n", cfg->index, dflt.index); 595 596 /* Does this card need audio output? */ 597 if (cfg->flags & CISTPL_CFTABLE_AUDIO) { 598 link->conf.Attributes |= CONF_ENABLE_SPKR; 599 link->conf.Status = CCSR_AUDIO_ENA; 600 } 601 602 /* Use power settings for Vcc and Vpp if present */ 603 /* Note that the CIS values need to be rescaled */ 604 if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { 605 if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 606 10000 && !ignore_cis_vcc) { 607 PDEBUG(DEBUG_EXTRA, " Vcc mismatch - skipping" 608 " this entry\n"); 609 goto next_entry; 610 } 611 } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { 612 if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / 613 10000 && !ignore_cis_vcc) { 614 PDEBUG(DEBUG_EXTRA, " Vcc (default) mismatch " 615 "- skipping this entry\n"); 616 goto next_entry; 617 } 618 } 619 620 if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) 621 link->conf.Vpp = 622 cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; 623 else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) 624 link->conf.Vpp = 625 dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; 626 627 /* Do we need to allocate an interrupt? */ 628 if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) 629 link->conf.Attributes |= CONF_ENABLE_IRQ; 630 else if (!(link->conf.Attributes & CONF_ENABLE_IRQ)) { 631 /* At least Compaq WL200 does not have IRQInfo1 set, 632 * but it does not work without interrupts.. */ 633 printk("Config has no IRQ info, but trying to enable " 634 "IRQ anyway..\n"); 635 link->conf.Attributes |= CONF_ENABLE_IRQ; 636 } 637 638 /* IO window settings */ 639 PDEBUG(DEBUG_EXTRA, "IO window settings: cfg->io.nwin=%d " 640 "dflt.io.nwin=%d\n", 641 cfg->io.nwin, dflt.io.nwin); 642 link->io.NumPorts1 = link->io.NumPorts2 = 0; 643 if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { 644 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; 645 link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; 646 PDEBUG(DEBUG_EXTRA, "io->flags = 0x%04X, " 647 "io.base=0x%04x, len=%d\n", io->flags, 648 io->win[0].base, io->win[0].len); 649 if (!(io->flags & CISTPL_IO_8BIT)) 650 link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; 651 if (!(io->flags & CISTPL_IO_16BIT)) 652 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; 653 link->io.IOAddrLines = io->flags & 654 CISTPL_IO_LINES_MASK; 655 link->io.BasePort1 = io->win[0].base; 656 link->io.NumPorts1 = io->win[0].len; 657 if (io->nwin > 1) { 658 link->io.Attributes2 = link->io.Attributes1; 659 link->io.BasePort2 = io->win[1].base; 660 link->io.NumPorts2 = io->win[1].len; 661 } 662 } 663 664 /* This reserves IO space but doesn't actually enable it */ 665 CFG_CHECK2(RequestIO, 666 pcmcia_request_io(link, &link->io)); 667 668 /* This configuration table entry is OK */ 669 break; 670 671 next_entry: 672 CS_CHECK(GetNextTuple, 673 pcmcia_get_next_tuple(link, &tuple)); 674 } 675 676 /* Need to allocate net_device before requesting IRQ handler */ 677 dev = prism2_init_local_data(&prism2_pccard_funcs, 0, 678 &handle_to_dev(link)); 679 if (dev == NULL) 680 goto failed; 681 link->priv = dev; 682 683 iface = netdev_priv(dev); 684 local = iface->local; 685 local->hw_priv = hw_priv; 686 hw_priv->link = link; 687 strcpy(hw_priv->node.dev_name, dev->name); 688 link->dev_node = &hw_priv->node; 689 690 /* 691 * Allocate an interrupt line. Note that this does not assign a 692 * handler to the interrupt, unless the 'Handler' member of the 693 * irq structure is initialized. 694 */ 695 if (link->conf.Attributes & CONF_ENABLE_IRQ) { 696 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; 697 link->irq.IRQInfo1 = IRQ_LEVEL_ID; 698 link->irq.Handler = prism2_interrupt; 699 link->irq.Instance = dev; 700 CS_CHECK(RequestIRQ, 701 pcmcia_request_irq(link, &link->irq)); 702 } 703 704 /* 705 * This actually configures the PCMCIA socket -- setting up 706 * the I/O windows and the interrupt mapping, and putting the 707 * card and host interface into "Memory and IO" mode. 708 */ 709 CS_CHECK(RequestConfiguration, 710 pcmcia_request_configuration(link, &link->conf)); 711 712 dev->irq = link->irq.AssignedIRQ; 713 dev->base_addr = link->io.BasePort1; 714 715 /* Finally, report what we've done */ 716 printk(KERN_INFO "%s: index 0x%02x: ", 717 dev_info, link->conf.ConfigIndex); 718 if (link->conf.Vpp) 719 printk(", Vpp %d.%d", link->conf.Vpp / 10, 720 link->conf.Vpp % 10); 721 if (link->conf.Attributes & CONF_ENABLE_IRQ) 722 printk(", irq %d", link->irq.AssignedIRQ); 723 if (link->io.NumPorts1) 724 printk(", io 0x%04x-0x%04x", link->io.BasePort1, 725 link->io.BasePort1+link->io.NumPorts1-1); 726 if (link->io.NumPorts2) 727 printk(" & 0x%04x-0x%04x", link->io.BasePort2, 728 link->io.BasePort2+link->io.NumPorts2-1); 729 printk("\n"); 730 731 local->shutdown = 0; 732 733 sandisk_enable_wireless(dev); 734 735 ret = prism2_hw_config(dev, 1); 736 if (!ret) { 737 ret = hostap_hw_ready(dev); 738 if (ret == 0 && local->ddev) 739 strcpy(hw_priv->node.dev_name, local->ddev->name); 740 } 741 kfree(parse); 742 return ret; 743 744 cs_failed: 745 cs_error(link, last_fn, last_ret); 746 747 failed: 748 kfree(parse); 749 kfree(hw_priv); 750 prism2_release((u_long)link); 751 return ret; 752} 753 754 755static void prism2_release(u_long arg) 756{ 757 struct pcmcia_device *link = (struct pcmcia_device *)arg; 758 759 PDEBUG(DEBUG_FLOW, "prism2_release\n"); 760 761 if (link->priv) { 762 struct net_device *dev = link->priv; 763 struct hostap_interface *iface; 764 765 iface = netdev_priv(dev); 766 prism2_hw_shutdown(dev, 0); 767 iface->local->shutdown = 1; 768 } 769 770 pcmcia_disable_device(link); 771 PDEBUG(DEBUG_FLOW, "release - done\n"); 772} 773 774static int hostap_cs_suspend(struct pcmcia_device *link) 775{ 776 struct net_device *dev = (struct net_device *) link->priv; 777 int dev_open = 0; 778 struct hostap_interface *iface = NULL; 779 780 if (dev) 781 iface = netdev_priv(dev); 782 783 PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_SUSPEND\n", dev_info); 784 if (iface && iface->local) 785 dev_open = iface->local->num_dev_open > 0; 786 if (dev_open) { 787 netif_stop_queue(dev); 788 netif_device_detach(dev); 789 } 790 prism2_suspend(dev); 791 792 return 0; 793} 794 795static int hostap_cs_resume(struct pcmcia_device *link) 796{ 797 struct net_device *dev = (struct net_device *) link->priv; 798 int dev_open = 0; 799 struct hostap_interface *iface = NULL; 800 801 if (dev) 802 iface = netdev_priv(dev); 803 804 PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_RESUME\n", dev_info); 805 806 if (iface && iface->local) 807 dev_open = iface->local->num_dev_open > 0; 808 809 prism2_hw_shutdown(dev, 1); 810 prism2_hw_config(dev, dev_open ? 0 : 1); 811 if (dev_open) { 812 netif_device_attach(dev); 813 netif_start_queue(dev); 814 } 815 816 return 0; 817} 818 819static struct pcmcia_device_id hostap_cs_ids[] = { 820 PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), 821 PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), 822 PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), 823 PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), 824 PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), 825 PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x3301), 826 PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), 827 PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030b), 828 PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), 829 PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), 830 PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), 831 PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), 832 PCMCIA_DEVICE_MANF_CARD(0x02d2, 0x0001), 833 PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x0001), 834 PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), 835/* PCMCIA_DEVICE_MANF_CARD(0xc00f, 0x0000), conflict with pcnet_cs */ 836 PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), 837 PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), 838 PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010), 839 PCMCIA_DEVICE_MANF_CARD(0x0126, 0x0002), 840 PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0xd601, 0x0005, "ADLINK 345 CF", 841 0x2d858104), 842 PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "INTERSIL", 843 0x74c5e40d), 844 PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "Intersil", 845 0x4b801a17), 846 PCMCIA_MFC_DEVICE_PROD_ID12(0, "SanDisk", "ConnectPlus", 847 0x7a954bd9, 0x74be00c6), 848 PCMCIA_DEVICE_PROD_ID123( 849 "Intersil", "PRISM 2_5 PCMCIA ADAPTER", "ISL37300P", 850 0x4b801a17, 0x6345a0bf, 0xc9049a39), 851 /* D-Link DWL-650 Rev. P1; manfid 0x000b, 0x7110 */ 852 PCMCIA_DEVICE_PROD_ID123( 853 "D-Link", "DWL-650 Wireless PC Card RevP", "ISL37101P-10", 854 0x1a424a1c, 0x6ea57632, 0xdd97a26b), 855 PCMCIA_DEVICE_PROD_ID123( 856 "Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02", 857 0xe6ec52ce, 0x08649af2, 0x4b74baa0), 858 PCMCIA_DEVICE_PROD_ID123( 859 "D", "Link DWL-650 11Mbps WLAN Card", "Version 01.02", 860 0x71b18589, 0xb6f1b0ab, 0x4b74baa0), 861 PCMCIA_DEVICE_PROD_ID123( 862 "Instant Wireless ", " Network PC CARD", "Version 01.02", 863 0x11d901af, 0x6e9bd926, 0x4b74baa0), 864 PCMCIA_DEVICE_PROD_ID123( 865 "SMC", "SMC2632W", "Version 01.02", 866 0xc4f8b18b, 0x474a1f2a, 0x4b74baa0), 867 PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", 868 0x2decece3, 0x82067c18), 869 PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", 870 0x54f7c49c, 0x15a75e5b), 871 PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", 872 0x74c5e40d, 0xdb472a18), 873 PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", 874 0x0733cc81, 0x0c52f395), 875 PCMCIA_DEVICE_PROD_ID12( 876 "ZoomAir 11Mbps High", "Rate wireless Networking", 877 0x273fe3db, 0x32a1eaee), 878 PCMCIA_DEVICE_PROD_ID123( 879 "Pretec", "CompactWLAN Card 802.11b", "2.5", 880 0x1cadd3e5, 0xe697636c, 0x7a5bfcf1), 881 PCMCIA_DEVICE_PROD_ID123( 882 "U.S. Robotics", "IEEE 802.11b PC-CARD", "Version 01.02", 883 0xc7b8df9d, 0x1700d087, 0x4b74baa0), 884 PCMCIA_DEVICE_PROD_ID123( 885 "Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", 886 "Ver. 1.00", 887 0x5cd01705, 0x4271660f, 0x9d08ee12), 888 PCMCIA_DEVICE_PROD_ID123( 889 "corega", "WL PCCL-11", "ISL37300P", 890 0xa21501a, 0x59868926, 0xc9049a39), 891 PCMCIA_DEVICE_PROD_ID123( 892 "The Linksys Group, Inc.", "Wireless Network CF Card", "ISL37300P", 893 0xa5f472c2, 0x9c05598d, 0xc9049a39), 894 PCMCIA_DEVICE_PROD_ID123( 895 "Wireless LAN" , "11Mbps PC Card", "Version 01.02", 896 0x4b8870ff, 0x70e946d1, 0x4b74baa0), 897 PCMCIA_DEVICE_NULL 898}; 899MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids); 900 901 902static struct pcmcia_driver hostap_driver = { 903 .drv = { 904 .name = "hostap_cs", 905 }, 906 .probe = hostap_cs_probe, 907 .remove = prism2_detach, 908 .owner = THIS_MODULE, 909 .id_table = hostap_cs_ids, 910 .suspend = hostap_cs_suspend, 911 .resume = hostap_cs_resume, 912}; 913 914static int __init init_prism2_pccard(void) 915{ 916 return pcmcia_register_driver(&hostap_driver); 917} 918 919static void __exit exit_prism2_pccard(void) 920{ 921 pcmcia_unregister_driver(&hostap_driver); 922} 923 924 925module_init(init_prism2_pccard); 926module_exit(exit_prism2_pccard);