|
|
1.1 ! root 1: /* orinoco_cs.c 0.13e - (formerly known as dldwd_cs.c) ! 2: * ! 3: * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such ! 4: * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ ! 5: * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others). ! 6: * It should also be usable on various Prism II based cards such as the ! 7: * Linksys, D-Link and Farallon Skyline. It should also work on Symbol ! 8: * cards such as the 3Com AirConnect and Ericsson WLAN. ! 9: * ! 10: * Copyright notice & release notes in file orinoco.c ! 11: */ ! 12: ! 13: #include <linux/config.h> ! 14: #include <linux/module.h> ! 15: #include <linux/kernel.h> ! 16: #include <linux/init.h> ! 17: #include <linux/sched.h> ! 18: #include <linux/ptrace.h> ! 19: #include <linux/slab.h> ! 20: #include <linux/string.h> ! 21: #include <linux/ioport.h> ! 22: #include <linux/netdevice.h> ! 23: #include <linux/if_arp.h> ! 24: #include <linux/etherdevice.h> ! 25: #include <linux/wireless.h> ! 26: ! 27: #include <pcmcia/version.h> ! 28: #include <pcmcia/cs_types.h> ! 29: #include <pcmcia/cs.h> ! 30: #include <pcmcia/cistpl.h> ! 31: #include <pcmcia/cisreg.h> ! 32: #include <pcmcia/ds.h> ! 33: ! 34: #include <asm/uaccess.h> ! 35: #include <asm/io.h> ! 36: #include <asm/system.h> ! 37: ! 38: #include "orinoco.h" ! 39: ! 40: /********************************************************************/ ! 41: /* Module stuff */ ! 42: /********************************************************************/ ! 43: ! 44: MODULE_AUTHOR("David Gibson <[email protected]>"); ! 45: MODULE_DESCRIPTION("Driver for PCMCIA Lucent Orinoco, Prism II based and similar wireless cards"); ! 46: #ifdef MODULE_LICENSE ! 47: MODULE_LICENSE("Dual MPL/GPL"); ! 48: #endif ! 49: ! 50: /* Module parameters */ ! 51: ! 52: /* The old way: bit map of interrupts to choose from */ ! 53: /* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */ ! 54: static uint irq_mask = 0xdeb8; ! 55: /* Newer, simpler way of listing specific interrupts */ ! 56: static int irq_list[4] = { -1 }; ! 57: ! 58: /* Some D-Link cards have buggy CIS. They do work at 5v properly, but ! 59: * don't have any CIS entry for it. This workaround it... */ ! 60: static int ignore_cis_vcc; /* = 0 */ ! 61: ! 62: MODULE_PARM(irq_mask, "i"); ! 63: MODULE_PARM(irq_list, "1-4i"); ! 64: MODULE_PARM(ignore_cis_vcc, "i"); ! 65: ! 66: /********************************************************************/ ! 67: /* Magic constants */ ! 68: /********************************************************************/ ! 69: ! 70: /* ! 71: * The dev_info variable is the "key" that is used to match up this ! 72: * device driver with appropriate cards, through the card ! 73: * configuration database. ! 74: */ ! 75: static dev_info_t dev_info = "orinoco_cs"; ! 76: ! 77: /********************************************************************/ ! 78: /* Data structures */ ! 79: /********************************************************************/ ! 80: ! 81: /* PCMCIA specific device information (goes in the card field of ! 82: * struct orinoco_private */ ! 83: struct orinoco_pccard { ! 84: dev_link_t link; ! 85: dev_node_t node; ! 86: ! 87: /* Used to handle hard reset */ ! 88: /* yuck, we need this hack to work around the insanity of the ! 89: * PCMCIA layer */ ! 90: unsigned long hard_reset_in_progress; ! 91: }; ! 92: ! 93: /* ! 94: * A linked list of "instances" of the device. Each actual PCMCIA ! 95: * card corresponds to one device instance, and is described by one ! 96: * dev_link_t structure (defined in ds.h). ! 97: */ ! 98: static dev_link_t *dev_list; /* = NULL */ ! 99: ! 100: /********************************************************************/ ! 101: /* Function prototypes */ ! 102: /********************************************************************/ ! 103: ! 104: /* device methods */ ! 105: static int orinoco_cs_hard_reset(struct orinoco_private *priv); ! 106: ! 107: /* PCMCIA gumpf */ ! 108: static void orinoco_cs_config(dev_link_t * link); ! 109: static void orinoco_cs_release(u_long arg); ! 110: static int orinoco_cs_event(event_t event, int priority, ! 111: event_callback_args_t * args); ! 112: ! 113: static dev_link_t *orinoco_cs_attach(void); ! 114: static void orinoco_cs_detach(dev_link_t *); ! 115: ! 116: /********************************************************************/ ! 117: /* Device methods */ ! 118: /********************************************************************/ ! 119: ! 120: static int ! 121: orinoco_cs_hard_reset(struct orinoco_private *priv) ! 122: { ! 123: struct orinoco_pccard *card = priv->card; ! 124: dev_link_t *link = &card->link; ! 125: int err; ! 126: ! 127: /* We need atomic ops here, because we're not holding the lock */ ! 128: set_bit(0, &card->hard_reset_in_progress); ! 129: ! 130: err = CardServices(ResetCard, link->handle, NULL); ! 131: if (err) ! 132: return err; ! 133: ! 134: clear_bit(0, &card->hard_reset_in_progress); ! 135: ! 136: return 0; ! 137: } ! 138: ! 139: /********************************************************************/ ! 140: /* PCMCIA stuff */ ! 141: /********************************************************************/ ! 142: ! 143: /* In 2.5 (as of 2.5.69 at least) there is a cs_error exported which ! 144: * does this, but it's not in 2.4 so we do our own for now. */ ! 145: static void ! 146: orinoco_cs_error(client_handle_t handle, int func, int ret) ! 147: { ! 148: error_info_t err = { func, ret }; ! 149: CardServices(ReportError, handle, &err); ! 150: } ! 151: ! 152: ! 153: /* Remove zombie instances (card removed, detach pending) */ ! 154: static void ! 155: flush_stale_links(void) ! 156: { ! 157: dev_link_t *link, *next; ! 158: ! 159: TRACE_ENTER(""); ! 160: ! 161: for (link = dev_list; link; link = next) { ! 162: next = link->next; ! 163: if (link->state & DEV_STALE_LINK) { ! 164: orinoco_cs_detach(link); ! 165: } ! 166: } ! 167: TRACE_EXIT(""); ! 168: } ! 169: ! 170: /* ! 171: * This creates an "instance" of the driver, allocating local data ! 172: * structures for one device. The device is registered with Card ! 173: * Services. ! 174: * ! 175: * The dev_link structure is initialized, but we don't actually ! 176: * configure the card at this point -- we wait until we receive a card ! 177: * insertion event. */ ! 178: static dev_link_t * ! 179: orinoco_cs_attach(void) ! 180: { ! 181: struct net_device *dev; ! 182: struct orinoco_private *priv; ! 183: struct orinoco_pccard *card; ! 184: dev_link_t *link; ! 185: client_reg_t client_reg; ! 186: int ret, i; ! 187: ! 188: /* A bit of cleanup */ ! 189: flush_stale_links(); ! 190: ! 191: dev = alloc_orinocodev(sizeof(*card), orinoco_cs_hard_reset); ! 192: if (! dev) ! 193: return NULL; ! 194: priv = dev->priv; ! 195: card = priv->card; ! 196: ! 197: /* Link both structures together */ ! 198: link = &card->link; ! 199: link->priv = dev; ! 200: ! 201: /* Initialize the dev_link_t structure */ ! 202: init_timer(&link->release); ! 203: link->release.function = &orinoco_cs_release; ! 204: link->release.data = (u_long) link; ! 205: ! 206: /* Interrupt setup */ ! 207: link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; ! 208: link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; ! 209: if (irq_list[0] == -1) ! 210: link->irq.IRQInfo2 = irq_mask; ! 211: else ! 212: for (i = 0; i < 4; i++) ! 213: link->irq.IRQInfo2 |= 1 << irq_list[i]; ! 214: link->irq.Handler = NULL; ! 215: ! 216: /* General socket configuration defaults can go here. In this ! 217: * client, we assume very little, and rely on the CIS for ! 218: * almost everything. In most clients, many details (i.e., ! 219: * number, sizes, and attributes of IO windows) are fixed by ! 220: * the nature of the device, and can be hard-wired here. */ ! 221: link->conf.Attributes = 0; ! 222: link->conf.IntType = INT_MEMORY_AND_IO; ! 223: ! 224: /* Register with Card Services */ ! 225: /* FIXME: need a lock? */ ! 226: link->next = dev_list; ! 227: dev_list = link; ! 228: ! 229: client_reg.dev_info = &dev_info; ! 230: client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; ! 231: client_reg.EventMask = ! 232: CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | ! 233: CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | ! 234: CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; ! 235: client_reg.event_handler = &orinoco_cs_event; ! 236: client_reg.Version = 0x0210; /* FIXME: what does this mean? */ ! 237: client_reg.event_callback_args.client_data = link; ! 238: ! 239: ret = CardServices(RegisterClient, &link->handle, &client_reg); ! 240: if (ret != CS_SUCCESS) { ! 241: orinoco_cs_error(link->handle, RegisterClient, ret); ! 242: orinoco_cs_detach(link); ! 243: return NULL; ! 244: } ! 245: ! 246: return link; ! 247: } /* orinoco_cs_attach */ ! 248: ! 249: /* ! 250: * This deletes a driver "instance". The device is de-registered with ! 251: * Card Services. If it has been released, all local data structures ! 252: * are freed. Otherwise, the structures will be freed when the device ! 253: * is released. ! 254: */ ! 255: static void ! 256: orinoco_cs_detach(dev_link_t * link) ! 257: { ! 258: dev_link_t **linkp; ! 259: struct net_device *dev = link->priv; ! 260: ! 261: /* Locate device structure */ ! 262: for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) ! 263: if (*linkp == link) ! 264: break; ! 265: if (*linkp == NULL) { ! 266: BUG(); ! 267: return; ! 268: } ! 269: ! 270: if (link->state & DEV_CONFIG) { ! 271: orinoco_cs_release((u_long)link); ! 272: if (link->state & DEV_CONFIG) { ! 273: link->state |= DEV_STALE_LINK; ! 274: return; ! 275: } ! 276: } ! 277: ! 278: /* Break the link with Card Services */ ! 279: if (link->handle) ! 280: CardServices(DeregisterClient, link->handle); ! 281: ! 282: /* Unlink device structure, and free it */ ! 283: *linkp = link->next; ! 284: DEBUG(0, "orinoco_cs: detach: link=%p link->dev=%p\n", link, link->dev); ! 285: if (link->dev) { ! 286: DEBUG(0, "orinoco_cs: About to unregister net device %p\n", ! 287: dev); ! 288: unregister_netdev(dev); ! 289: } ! 290: kfree(dev); ! 291: } /* orinoco_cs_detach */ ! 292: ! 293: /* ! 294: * orinoco_cs_config() is scheduled to run after a CARD_INSERTION ! 295: * event is received, to configure the PCMCIA socket, and to make the ! 296: * device available to the system. ! 297: */ ! 298: ! 299: #define CS_CHECK(fn, args...) \ ! 300: while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed ! 301: ! 302: #define CFG_CHECK(fn, args...) \ ! 303: if (CardServices(fn, args) != 0) goto next_entry ! 304: ! 305: static void ! 306: orinoco_cs_config(dev_link_t *link) ! 307: { ! 308: struct net_device *dev = link->priv; ! 309: client_handle_t handle = link->handle; ! 310: struct orinoco_private *priv = dev->priv; ! 311: struct orinoco_pccard *card = priv->card; ! 312: hermes_t *hw = &priv->hw; ! 313: int last_fn, last_ret; ! 314: u_char buf[64]; ! 315: config_info_t conf; ! 316: cisinfo_t info; ! 317: tuple_t tuple; ! 318: cisparse_t parse; ! 319: ! 320: CS_CHECK(ValidateCIS, handle, &info); ! 321: ! 322: /* ! 323: * This reads the card's CONFIG tuple to find its ! 324: * configuration registers. ! 325: */ ! 326: tuple.DesiredTuple = CISTPL_CONFIG; ! 327: tuple.Attributes = 0; ! 328: tuple.TupleData = buf; ! 329: tuple.TupleDataMax = sizeof(buf); ! 330: tuple.TupleOffset = 0; ! 331: CS_CHECK(GetFirstTuple, handle, &tuple); ! 332: CS_CHECK(GetTupleData, handle, &tuple); ! 333: CS_CHECK(ParseTuple, handle, &tuple, &parse); ! 334: link->conf.ConfigBase = parse.config.base; ! 335: link->conf.Present = parse.config.rmask[0]; ! 336: ! 337: /* Configure card */ ! 338: link->state |= DEV_CONFIG; ! 339: ! 340: /* Look up the current Vcc */ ! 341: CS_CHECK(GetConfigurationInfo, handle, &conf); ! 342: link->conf.Vcc = conf.Vcc; ! 343: ! 344: /* ! 345: * In this loop, we scan the CIS for configuration table ! 346: * entries, each of which describes a valid card ! 347: * configuration, including voltage, IO window, memory window, ! 348: * and interrupt settings. ! 349: * ! 350: * We make no assumptions about the card to be configured: we ! 351: * use just the information available in the CIS. In an ideal ! 352: * world, this would work for any PCMCIA card, but it requires ! 353: * a complete and accurate CIS. In practice, a driver usually ! 354: * "knows" most of these things without consulting the CIS, ! 355: * and most client drivers will only use the CIS to fill in ! 356: * implementation-defined details. ! 357: */ ! 358: tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; ! 359: CS_CHECK(GetFirstTuple, handle, &tuple); ! 360: while (1) { ! 361: cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); ! 362: cistpl_cftable_entry_t dflt = { .index = 0 }; ! 363: ! 364: CFG_CHECK(GetTupleData, handle, &tuple); ! 365: CFG_CHECK(ParseTuple, handle, &tuple, &parse); ! 366: ! 367: if (cfg->flags & CISTPL_CFTABLE_DEFAULT) ! 368: dflt = *cfg; ! 369: if (cfg->index == 0) ! 370: goto next_entry; ! 371: link->conf.ConfigIndex = cfg->index; ! 372: ! 373: /* Does this card need audio output? */ ! 374: if (cfg->flags & CISTPL_CFTABLE_AUDIO) { ! 375: link->conf.Attributes |= CONF_ENABLE_SPKR; ! 376: link->conf.Status = CCSR_AUDIO_ENA; ! 377: } ! 378: ! 379: /* Use power settings for Vcc and Vpp if present */ ! 380: /* Note that the CIS values need to be rescaled */ ! 381: if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { ! 382: if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { ! 383: DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); ! 384: if (!ignore_cis_vcc) ! 385: goto next_entry; ! 386: } ! 387: } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { ! 388: if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) { ! 389: DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000); ! 390: if(!ignore_cis_vcc) ! 391: goto next_entry; ! 392: } ! 393: } ! 394: ! 395: if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) ! 396: link->conf.Vpp1 = link->conf.Vpp2 = ! 397: cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; ! 398: else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) ! 399: link->conf.Vpp1 = link->conf.Vpp2 = ! 400: dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; ! 401: ! 402: /* Do we need to allocate an interrupt? */ ! 403: if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) ! 404: link->conf.Attributes |= CONF_ENABLE_IRQ; ! 405: ! 406: /* IO window settings */ ! 407: link->io.NumPorts1 = link->io.NumPorts2 = 0; ! 408: if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { ! 409: cistpl_io_t *io = ! 410: (cfg->io.nwin) ? &cfg->io : &dflt.io; ! 411: link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; ! 412: if (!(io->flags & CISTPL_IO_8BIT)) ! 413: link->io.Attributes1 = ! 414: IO_DATA_PATH_WIDTH_16; ! 415: if (!(io->flags & CISTPL_IO_16BIT)) ! 416: link->io.Attributes1 = ! 417: IO_DATA_PATH_WIDTH_8; ! 418: link->io.IOAddrLines = ! 419: io->flags & CISTPL_IO_LINES_MASK; ! 420: link->io.BasePort1 = io->win[0].base; ! 421: link->io.NumPorts1 = io->win[0].len; ! 422: if (io->nwin > 1) { ! 423: link->io.Attributes2 = ! 424: link->io.Attributes1; ! 425: link->io.BasePort2 = io->win[1].base; ! 426: link->io.NumPorts2 = io->win[1].len; ! 427: } ! 428: ! 429: /* This reserves IO space but doesn't actually enable it */ ! 430: CFG_CHECK(RequestIO, link->handle, &link->io); ! 431: } ! 432: ! 433: ! 434: /* If we got this far, we're cool! */ ! 435: ! 436: break; ! 437: ! 438: next_entry: ! 439: if (link->io.NumPorts1) ! 440: CardServices(ReleaseIO, link->handle, &link->io); ! 441: last_ret = CardServices(GetNextTuple, handle, &tuple); ! 442: if (last_ret == CS_NO_MORE_ITEMS) { ! 443: printk(KERN_ERR "GetNextTuple(). No matching CIS configuration, " ! 444: "maybe you need the ignore_cis_vcc=1 parameter.\n"); ! 445: goto cs_failed; ! 446: } ! 447: } ! 448: ! 449: /* ! 450: * Allocate an interrupt line. Note that this does not assign ! 451: * a handler to the interrupt, unless the 'Handler' member of ! 452: * the irq structure is initialized. ! 453: */ ! 454: if (link->conf.Attributes & CONF_ENABLE_IRQ) { ! 455: int i; ! 456: ! 457: link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; ! 458: link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; ! 459: if (irq_list[0] == -1) ! 460: link->irq.IRQInfo2 = irq_mask; ! 461: else ! 462: for (i=0; i<4; i++) ! 463: link->irq.IRQInfo2 |= 1 << irq_list[i]; ! 464: ! 465: link->irq.Handler = orinoco_interrupt; ! 466: link->irq.Instance = dev; ! 467: ! 468: CS_CHECK(RequestIRQ, link->handle, &link->irq); ! 469: } ! 470: ! 471: /* We initialize the hermes structure before completing PCMCIA ! 472: * configuration just in case the interrupt handler gets ! 473: * called. */ ! 474: hermes_struct_init(hw, link->io.BasePort1, ! 475: HERMES_IO, HERMES_16BIT_REGSPACING); ! 476: ! 477: /* ! 478: * This actually configures the PCMCIA socket -- setting up ! 479: * the I/O windows and the interrupt mapping, and putting the ! 480: * card and host interface into "Memory and IO" mode. ! 481: */ ! 482: CS_CHECK(RequestConfiguration, link->handle, &link->conf); ! 483: ! 484: /* Ok, we have the configuration, prepare to register the netdev */ ! 485: dev->base_addr = link->io.BasePort1; ! 486: dev->irq = link->irq.AssignedIRQ; ! 487: SET_MODULE_OWNER(dev); ! 488: card->node.major = card->node.minor = 0; ! 489: ! 490: /* register_netdev will give us an ethX name */ ! 491: dev->name[0] = '\0'; ! 492: /* Tell the stack we exist */ ! 493: if (register_netdev(dev) != 0) { ! 494: printk(KERN_ERR "orinoco_cs: register_netdev() failed\n"); ! 495: goto failed; ! 496: } ! 497: ! 498: /* At this point, the dev_node_t structure(s) needs to be ! 499: * initialized and arranged in a linked list at link->dev. */ ! 500: strcpy(card->node.dev_name, dev->name); ! 501: link->dev = &card->node; /* link->dev being non-NULL is also ! 502: used to indicate that the ! 503: net_device has been registered */ ! 504: link->state &= ~DEV_CONFIG_PENDING; ! 505: ! 506: /* Finally, report what we've done */ ! 507: printk(KERN_DEBUG "%s: index 0x%02x: Vcc %d.%d", ! 508: dev->name, link->conf.ConfigIndex, ! 509: link->conf.Vcc / 10, link->conf.Vcc % 10); ! 510: if (link->conf.Vpp1) ! 511: printk(", Vpp %d.%d", link->conf.Vpp1 / 10, ! 512: link->conf.Vpp1 % 10); ! 513: if (link->conf.Attributes & CONF_ENABLE_IRQ) ! 514: printk(", irq %d", link->irq.AssignedIRQ); ! 515: if (link->io.NumPorts1) ! 516: printk(", io 0x%04x-0x%04x", link->io.BasePort1, ! 517: link->io.BasePort1 + link->io.NumPorts1 - 1); ! 518: if (link->io.NumPorts2) ! 519: printk(" & 0x%04x-0x%04x", link->io.BasePort2, ! 520: link->io.BasePort2 + link->io.NumPorts2 - 1); ! 521: printk("\n"); ! 522: ! 523: return; ! 524: ! 525: cs_failed: ! 526: orinoco_cs_error(link->handle, last_fn, last_ret); ! 527: ! 528: failed: ! 529: orinoco_cs_release((u_long) link); ! 530: } /* orinoco_cs_config */ ! 531: ! 532: /* ! 533: * After a card is removed, orinoco_cs_release() will unregister the ! 534: * device, and release the PCMCIA configuration. If the device is ! 535: * still open, this will be postponed until it is closed. ! 536: */ ! 537: static void ! 538: orinoco_cs_release(u_long arg) ! 539: { ! 540: dev_link_t *link = (dev_link_t *) arg; ! 541: struct net_device *dev = link->priv; ! 542: struct orinoco_private *priv = dev->priv; ! 543: unsigned long flags; ! 544: ! 545: /* We're committed to taking the device away now, so mark the ! 546: * hardware as unavailable */ ! 547: spin_lock_irqsave(&priv->lock, flags); ! 548: priv->hw_unavailable++; ! 549: spin_unlock_irqrestore(&priv->lock, flags); ! 550: ! 551: /* Don't bother checking to see if these succeed or not */ ! 552: CardServices(ReleaseConfiguration, link->handle); ! 553: if (link->io.NumPorts1) ! 554: CardServices(ReleaseIO, link->handle, &link->io); ! 555: if (link->irq.AssignedIRQ) ! 556: CardServices(ReleaseIRQ, link->handle, &link->irq); ! 557: link->state &= ~DEV_CONFIG; ! 558: } /* orinoco_cs_release */ ! 559: ! 560: /* ! 561: * The card status event handler. Mostly, this schedules other stuff ! 562: * to run after an event is received. ! 563: */ ! 564: static int ! 565: orinoco_cs_event(event_t event, int priority, ! 566: event_callback_args_t * args) ! 567: { ! 568: dev_link_t *link = args->client_data; ! 569: struct net_device *dev = link->priv; ! 570: struct orinoco_private *priv = dev->priv; ! 571: struct orinoco_pccard *card = priv->card; ! 572: int err = 0; ! 573: unsigned long flags; ! 574: ! 575: switch (event) { ! 576: case CS_EVENT_CARD_REMOVAL: ! 577: link->state &= ~DEV_PRESENT; ! 578: if (link->state & DEV_CONFIG) { ! 579: orinoco_lock(priv, &flags); ! 580: ! 581: netif_device_detach(dev); ! 582: priv->hw_unavailable++; ! 583: ! 584: orinoco_unlock(priv, &flags); ! 585: } ! 586: break; ! 587: ! 588: case CS_EVENT_CARD_INSERTION: ! 589: link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; ! 590: orinoco_cs_config(link); ! 591: break; ! 592: ! 593: case CS_EVENT_PM_SUSPEND: ! 594: link->state |= DEV_SUSPEND; ! 595: /* Fall through... */ ! 596: case CS_EVENT_RESET_PHYSICAL: ! 597: /* Mark the device as stopped, to block IO until later */ ! 598: if (link->state & DEV_CONFIG) { ! 599: /* This is probably racy, but I can't think of ! 600: a better way, short of rewriting the PCMCIA ! 601: layer to not suck :-( */ ! 602: if (! test_bit(0, &card->hard_reset_in_progress)) { ! 603: spin_lock_irqsave(&priv->lock, flags); ! 604: ! 605: err = __orinoco_down(dev); ! 606: if (err) ! 607: printk(KERN_WARNING "%s: %s: Error %d downing interface\n", ! 608: dev->name, ! 609: event == CS_EVENT_PM_SUSPEND ? "SUSPEND" : "RESET_PHYSICAL", ! 610: err); ! 611: ! 612: netif_device_detach(dev); ! 613: priv->hw_unavailable++; ! 614: ! 615: spin_unlock_irqrestore(&priv->lock, flags); ! 616: } ! 617: ! 618: CardServices(ReleaseConfiguration, link->handle); ! 619: } ! 620: break; ! 621: ! 622: case CS_EVENT_PM_RESUME: ! 623: link->state &= ~DEV_SUSPEND; ! 624: /* Fall through... */ ! 625: case CS_EVENT_CARD_RESET: ! 626: if (link->state & DEV_CONFIG) { ! 627: /* FIXME: should we double check that this is ! 628: * the same card as we had before */ ! 629: CardServices(RequestConfiguration, link->handle, ! 630: &link->conf); ! 631: ! 632: if (! test_bit(0, &card->hard_reset_in_progress)) { ! 633: err = orinoco_reinit_firmware(dev); ! 634: if (err) { ! 635: printk(KERN_ERR "%s: Error %d re-initializing firmware\n", ! 636: dev->name, err); ! 637: break; ! 638: } ! 639: ! 640: spin_lock_irqsave(&priv->lock, flags); ! 641: ! 642: netif_device_attach(dev); ! 643: priv->hw_unavailable--; ! 644: ! 645: if (priv->open && ! priv->hw_unavailable) { ! 646: err = __orinoco_up(dev); ! 647: if (err) ! 648: printk(KERN_ERR "%s: Error %d restarting card\n", ! 649: dev->name, err); ! 650: ! 651: } ! 652: ! 653: spin_unlock_irqrestore(&priv->lock, flags); ! 654: } ! 655: } ! 656: break; ! 657: } ! 658: ! 659: return err; ! 660: } /* orinoco_cs_event */ ! 661: ! 662: /********************************************************************/ ! 663: /* Module initialization */ ! 664: /********************************************************************/ ! 665: ! 666: /* Can't be declared "const" or the whole __initdata section will ! 667: * become const */ ! 668: static char version[] __initdata = "orinoco_cs.c 0.13e (David Gibson <[email protected]> and others)"; ! 669: ! 670: static int __init ! 671: init_orinoco_cs(void) ! 672: { ! 673: servinfo_t serv; ! 674: ! 675: printk(KERN_DEBUG "%s\n", version); ! 676: ! 677: CardServices(GetCardServicesInfo, &serv); ! 678: if (serv.Revision != CS_RELEASE_CODE) { ! 679: printk(KERN_NOTICE "orinoco_cs: Card Services release " ! 680: "does not match!\n"); ! 681: return -EINVAL; ! 682: } ! 683: ! 684: register_pccard_driver(&dev_info, &orinoco_cs_attach, &orinoco_cs_detach); ! 685: ! 686: return 0; ! 687: } ! 688: ! 689: static void __exit ! 690: exit_orinoco_cs(void) ! 691: { ! 692: unregister_pccard_driver(&dev_info); ! 693: ! 694: if (dev_list) ! 695: DEBUG(0, "orinoco_cs: Removing leftover devices.\n"); ! 696: while (dev_list != NULL) { ! 697: if (dev_list->state & DEV_CONFIG) ! 698: orinoco_cs_release((u_long) dev_list); ! 699: orinoco_cs_detach(dev_list); ! 700: } ! 701: } ! 702: ! 703: module_init(init_orinoco_cs); ! 704: module_exit(exit_orinoco_cs); ! 705:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.