diff options
Diffstat (limited to 'drivers/net/wireless/orinoco_cs.c')
-rw-r--r-- | drivers/net/wireless/orinoco_cs.c | 208 |
1 files changed, 73 insertions, 135 deletions
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index dc1128a00971..b664708481cc 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c | |||
@@ -43,17 +43,6 @@ module_param(ignore_cis_vcc, int, 0); | |||
43 | MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket"); | 43 | MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket"); |
44 | 44 | ||
45 | /********************************************************************/ | 45 | /********************************************************************/ |
46 | /* Magic constants */ | ||
47 | /********************************************************************/ | ||
48 | |||
49 | /* | ||
50 | * The dev_info variable is the "key" that is used to match up this | ||
51 | * device driver with appropriate cards, through the card | ||
52 | * configuration database. | ||
53 | */ | ||
54 | static dev_info_t dev_info = DRIVER_NAME; | ||
55 | |||
56 | /********************************************************************/ | ||
57 | /* Data structures */ | 46 | /* Data structures */ |
58 | /********************************************************************/ | 47 | /********************************************************************/ |
59 | 48 | ||
@@ -69,19 +58,14 @@ struct orinoco_pccard { | |||
69 | unsigned long hard_reset_in_progress; | 58 | unsigned long hard_reset_in_progress; |
70 | }; | 59 | }; |
71 | 60 | ||
72 | /* | ||
73 | * A linked list of "instances" of the device. Each actual PCMCIA | ||
74 | * card corresponds to one device instance, and is described by one | ||
75 | * dev_link_t structure (defined in ds.h). | ||
76 | */ | ||
77 | static dev_link_t *dev_list; /* = NULL */ | ||
78 | 61 | ||
79 | /********************************************************************/ | 62 | /********************************************************************/ |
80 | /* Function prototypes */ | 63 | /* Function prototypes */ |
81 | /********************************************************************/ | 64 | /********************************************************************/ |
82 | 65 | ||
66 | static void orinoco_cs_config(dev_link_t *link); | ||
83 | static void orinoco_cs_release(dev_link_t *link); | 67 | static void orinoco_cs_release(dev_link_t *link); |
84 | static void orinoco_cs_detach(dev_link_t *link); | 68 | static void orinoco_cs_detach(struct pcmcia_device *p_dev); |
85 | 69 | ||
86 | /********************************************************************/ | 70 | /********************************************************************/ |
87 | /* Device methods */ | 71 | /* Device methods */ |
@@ -119,19 +103,17 @@ orinoco_cs_hard_reset(struct orinoco_private *priv) | |||
119 | * The dev_link structure is initialized, but we don't actually | 103 | * The dev_link structure is initialized, but we don't actually |
120 | * configure the card at this point -- we wait until we receive a card | 104 | * configure the card at this point -- we wait until we receive a card |
121 | * insertion event. */ | 105 | * insertion event. */ |
122 | static dev_link_t * | 106 | static int |
123 | orinoco_cs_attach(void) | 107 | orinoco_cs_attach(struct pcmcia_device *p_dev) |
124 | { | 108 | { |
125 | struct net_device *dev; | 109 | struct net_device *dev; |
126 | struct orinoco_private *priv; | 110 | struct orinoco_private *priv; |
127 | struct orinoco_pccard *card; | 111 | struct orinoco_pccard *card; |
128 | dev_link_t *link; | 112 | dev_link_t *link; |
129 | client_reg_t client_reg; | ||
130 | int ret; | ||
131 | 113 | ||
132 | dev = alloc_orinocodev(sizeof(*card), orinoco_cs_hard_reset); | 114 | dev = alloc_orinocodev(sizeof(*card), orinoco_cs_hard_reset); |
133 | if (! dev) | 115 | if (! dev) |
134 | return NULL; | 116 | return -ENOMEM; |
135 | priv = netdev_priv(dev); | 117 | priv = netdev_priv(dev); |
136 | card = priv->card; | 118 | card = priv->card; |
137 | 119 | ||
@@ -154,22 +136,15 @@ orinoco_cs_attach(void) | |||
154 | link->conf.IntType = INT_MEMORY_AND_IO; | 136 | link->conf.IntType = INT_MEMORY_AND_IO; |
155 | 137 | ||
156 | /* Register with Card Services */ | 138 | /* Register with Card Services */ |
157 | /* FIXME: need a lock? */ | 139 | link->next = NULL; |
158 | link->next = dev_list; | 140 | |
159 | dev_list = link; | 141 | link->handle = p_dev; |
160 | 142 | p_dev->instance = link; | |
161 | client_reg.dev_info = &dev_info; | 143 | |
162 | client_reg.Version = 0x0210; /* FIXME: what does this mean? */ | 144 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
163 | client_reg.event_callback_args.client_data = link; | 145 | orinoco_cs_config(link); |
164 | |||
165 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
166 | if (ret != CS_SUCCESS) { | ||
167 | cs_error(link->handle, RegisterClient, ret); | ||
168 | orinoco_cs_detach(link); | ||
169 | return NULL; | ||
170 | } | ||
171 | 146 | ||
172 | return link; | 147 | return 0; |
173 | } /* orinoco_cs_attach */ | 148 | } /* orinoco_cs_attach */ |
174 | 149 | ||
175 | /* | 150 | /* |
@@ -178,27 +153,14 @@ orinoco_cs_attach(void) | |||
178 | * are freed. Otherwise, the structures will be freed when the device | 153 | * are freed. Otherwise, the structures will be freed when the device |
179 | * is released. | 154 | * is released. |
180 | */ | 155 | */ |
181 | static void orinoco_cs_detach(dev_link_t *link) | 156 | static void orinoco_cs_detach(struct pcmcia_device *p_dev) |
182 | { | 157 | { |
183 | dev_link_t **linkp; | 158 | dev_link_t *link = dev_to_instance(p_dev); |
184 | struct net_device *dev = link->priv; | 159 | struct net_device *dev = link->priv; |
185 | 160 | ||
186 | /* Locate device structure */ | ||
187 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
188 | if (*linkp == link) | ||
189 | break; | ||
190 | |||
191 | BUG_ON(*linkp == NULL); | ||
192 | |||
193 | if (link->state & DEV_CONFIG) | 161 | if (link->state & DEV_CONFIG) |
194 | orinoco_cs_release(link); | 162 | orinoco_cs_release(link); |
195 | 163 | ||
196 | /* Break the link with Card Services */ | ||
197 | if (link->handle) | ||
198 | pcmcia_deregister_client(link->handle); | ||
199 | |||
200 | /* Unlink device structure, and free it */ | ||
201 | *linkp = link->next; | ||
202 | DEBUG(0, PFX "detach: link=%p link->dev=%p\n", link, link->dev); | 164 | DEBUG(0, PFX "detach: link=%p link->dev=%p\n", link, link->dev); |
203 | if (link->dev) { | 165 | if (link->dev) { |
204 | DEBUG(0, PFX "About to unregister net device %p\n", | 166 | DEBUG(0, PFX "About to unregister net device %p\n", |
@@ -465,106 +427,82 @@ orinoco_cs_release(dev_link_t *link) | |||
465 | ioport_unmap(priv->hw.iobase); | 427 | ioport_unmap(priv->hw.iobase); |
466 | } /* orinoco_cs_release */ | 428 | } /* orinoco_cs_release */ |
467 | 429 | ||
468 | /* | 430 | static int orinoco_cs_suspend(struct pcmcia_device *p_dev) |
469 | * The card status event handler. Mostly, this schedules other stuff | ||
470 | * to run after an event is received. | ||
471 | */ | ||
472 | static int | ||
473 | orinoco_cs_event(event_t event, int priority, | ||
474 | event_callback_args_t * args) | ||
475 | { | 431 | { |
476 | dev_link_t *link = args->client_data; | 432 | dev_link_t *link = dev_to_instance(p_dev); |
477 | struct net_device *dev = link->priv; | 433 | struct net_device *dev = link->priv; |
478 | struct orinoco_private *priv = netdev_priv(dev); | 434 | struct orinoco_private *priv = netdev_priv(dev); |
479 | struct orinoco_pccard *card = priv->card; | 435 | struct orinoco_pccard *card = priv->card; |
480 | int err = 0; | 436 | int err = 0; |
481 | unsigned long flags; | 437 | unsigned long flags; |
482 | 438 | ||
483 | switch (event) { | 439 | link->state |= DEV_SUSPEND; |
484 | case CS_EVENT_CARD_REMOVAL: | 440 | if (link->state & DEV_CONFIG) { |
485 | link->state &= ~DEV_PRESENT; | 441 | /* This is probably racy, but I can't think of |
486 | if (link->state & DEV_CONFIG) { | 442 | a better way, short of rewriting the PCMCIA |
487 | unsigned long flags; | 443 | layer to not suck :-( */ |
488 | 444 | if (! test_bit(0, &card->hard_reset_in_progress)) { | |
489 | spin_lock_irqsave(&priv->lock, flags); | 445 | spin_lock_irqsave(&priv->lock, flags); |
446 | |||
447 | err = __orinoco_down(dev); | ||
448 | if (err) | ||
449 | printk(KERN_WARNING "%s: Error %d downing interface\n", | ||
450 | dev->name, err); | ||
451 | |||
490 | netif_device_detach(dev); | 452 | netif_device_detach(dev); |
491 | priv->hw_unavailable++; | 453 | priv->hw_unavailable++; |
454 | |||
492 | spin_unlock_irqrestore(&priv->lock, flags); | 455 | spin_unlock_irqrestore(&priv->lock, flags); |
493 | } | 456 | } |
494 | break; | ||
495 | 457 | ||
496 | case CS_EVENT_CARD_INSERTION: | 458 | pcmcia_release_configuration(link->handle); |
497 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | 459 | } |
498 | orinoco_cs_config(link); | ||
499 | break; | ||
500 | 460 | ||
501 | case CS_EVENT_PM_SUSPEND: | 461 | return 0; |
502 | link->state |= DEV_SUSPEND; | 462 | } |
503 | /* Fall through... */ | 463 | |
504 | case CS_EVENT_RESET_PHYSICAL: | 464 | static int orinoco_cs_resume(struct pcmcia_device *p_dev) |
505 | /* Mark the device as stopped, to block IO until later */ | 465 | { |
506 | if (link->state & DEV_CONFIG) { | 466 | dev_link_t *link = dev_to_instance(p_dev); |
507 | /* This is probably racy, but I can't think of | 467 | struct net_device *dev = link->priv; |
508 | a better way, short of rewriting the PCMCIA | 468 | struct orinoco_private *priv = netdev_priv(dev); |
509 | layer to not suck :-( */ | 469 | struct orinoco_pccard *card = priv->card; |
510 | if (! test_bit(0, &card->hard_reset_in_progress)) { | 470 | int err = 0; |
511 | spin_lock_irqsave(&priv->lock, flags); | 471 | unsigned long flags; |
512 | 472 | ||
513 | err = __orinoco_down(dev); | 473 | link->state &= ~DEV_SUSPEND; |
514 | if (err) | 474 | if (link->state & DEV_CONFIG) { |
515 | printk(KERN_WARNING "%s: %s: Error %d downing interface\n", | 475 | /* FIXME: should we double check that this is |
516 | dev->name, | 476 | * the same card as we had before */ |
517 | event == CS_EVENT_PM_SUSPEND ? "SUSPEND" : "RESET_PHYSICAL", | 477 | pcmcia_request_configuration(link->handle, &link->conf); |
518 | err); | 478 | |
519 | 479 | if (! test_bit(0, &card->hard_reset_in_progress)) { | |
520 | netif_device_detach(dev); | 480 | err = orinoco_reinit_firmware(dev); |
521 | priv->hw_unavailable++; | 481 | if (err) { |
522 | 482 | printk(KERN_ERR "%s: Error %d re-initializing firmware\n", | |
523 | spin_unlock_irqrestore(&priv->lock, flags); | 483 | dev->name, err); |
484 | return -EIO; | ||
524 | } | 485 | } |
525 | 486 | ||
526 | pcmcia_release_configuration(link->handle); | 487 | spin_lock_irqsave(&priv->lock, flags); |
527 | } | 488 | |
528 | break; | 489 | netif_device_attach(dev); |
490 | priv->hw_unavailable--; | ||
529 | 491 | ||
530 | case CS_EVENT_PM_RESUME: | 492 | if (priv->open && ! priv->hw_unavailable) { |
531 | link->state &= ~DEV_SUSPEND; | 493 | err = __orinoco_up(dev); |
532 | /* Fall through... */ | 494 | if (err) |
533 | case CS_EVENT_CARD_RESET: | 495 | printk(KERN_ERR "%s: Error %d restarting card\n", |
534 | if (link->state & DEV_CONFIG) { | ||
535 | /* FIXME: should we double check that this is | ||
536 | * the same card as we had before */ | ||
537 | pcmcia_request_configuration(link->handle, &link->conf); | ||
538 | |||
539 | if (! test_bit(0, &card->hard_reset_in_progress)) { | ||
540 | err = orinoco_reinit_firmware(dev); | ||
541 | if (err) { | ||
542 | printk(KERN_ERR "%s: Error %d re-initializing firmware\n", | ||
543 | dev->name, err); | 496 | dev->name, err); |
544 | break; | ||
545 | } | ||
546 | |||
547 | spin_lock_irqsave(&priv->lock, flags); | ||
548 | |||
549 | netif_device_attach(dev); | ||
550 | priv->hw_unavailable--; | ||
551 | |||
552 | if (priv->open && ! priv->hw_unavailable) { | ||
553 | err = __orinoco_up(dev); | ||
554 | if (err) | ||
555 | printk(KERN_ERR "%s: Error %d restarting card\n", | ||
556 | dev->name, err); | ||
557 | |||
558 | } | ||
559 | |||
560 | spin_unlock_irqrestore(&priv->lock, flags); | ||
561 | } | 497 | } |
498 | |||
499 | spin_unlock_irqrestore(&priv->lock, flags); | ||
562 | } | 500 | } |
563 | break; | ||
564 | } | 501 | } |
565 | 502 | ||
566 | return err; | 503 | return 0; |
567 | } /* orinoco_cs_event */ | 504 | } |
505 | |||
568 | 506 | ||
569 | /********************************************************************/ | 507 | /********************************************************************/ |
570 | /* Module initialization */ | 508 | /* Module initialization */ |
@@ -665,10 +603,11 @@ static struct pcmcia_driver orinoco_driver = { | |||
665 | .drv = { | 603 | .drv = { |
666 | .name = DRIVER_NAME, | 604 | .name = DRIVER_NAME, |
667 | }, | 605 | }, |
668 | .attach = orinoco_cs_attach, | 606 | .probe = orinoco_cs_attach, |
669 | .detach = orinoco_cs_detach, | 607 | .remove = orinoco_cs_detach, |
670 | .event = orinoco_cs_event, | ||
671 | .id_table = orinoco_cs_ids, | 608 | .id_table = orinoco_cs_ids, |
609 | .suspend = orinoco_cs_suspend, | ||
610 | .resume = orinoco_cs_resume, | ||
672 | }; | 611 | }; |
673 | 612 | ||
674 | static int __init | 613 | static int __init |
@@ -683,7 +622,6 @@ static void __exit | |||
683 | exit_orinoco_cs(void) | 622 | exit_orinoco_cs(void) |
684 | { | 623 | { |
685 | pcmcia_unregister_driver(&orinoco_driver); | 624 | pcmcia_unregister_driver(&orinoco_driver); |
686 | BUG_ON(dev_list != NULL); | ||
687 | } | 625 | } |
688 | 626 | ||
689 | module_init(init_orinoco_cs); | 627 | module_init(init_orinoco_cs); |