aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn/hisax/sedlbauer_cs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/isdn/hisax/sedlbauer_cs.c')
-rw-r--r--drivers/isdn/hisax/sedlbauer_cs.c169
1 files changed, 36 insertions, 133 deletions
diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c
index dc334aab433e..6f5213a18a8d 100644
--- a/drivers/isdn/hisax/sedlbauer_cs.c
+++ b/drivers/isdn/hisax/sedlbauer_cs.c
@@ -97,8 +97,6 @@ module_param(protocol, int, 0);
97 97
98static void sedlbauer_config(dev_link_t *link); 98static void sedlbauer_config(dev_link_t *link);
99static void sedlbauer_release(dev_link_t *link); 99static void sedlbauer_release(dev_link_t *link);
100static int sedlbauer_event(event_t event, int priority,
101 event_callback_args_t *args);
102 100
103/* 101/*
104 The attach() and detach() entry points are used to create and destroy 102 The attach() and detach() entry points are used to create and destroy
@@ -106,8 +104,7 @@ static int sedlbauer_event(event_t event, int priority,
106 needed to manage one actual PCMCIA card. 104 needed to manage one actual PCMCIA card.
107*/ 105*/
108 106
109static dev_link_t *sedlbauer_attach(void); 107static void sedlbauer_detach(struct pcmcia_device *p_dev);
110static void sedlbauer_detach(dev_link_t *);
111 108
112/* 109/*
113 You'll also need to prototype all the functions that will actually 110 You'll also need to prototype all the functions that will actually
@@ -117,35 +114,6 @@ static void sedlbauer_detach(dev_link_t *);
117*/ 114*/
118 115
119/* 116/*
120 The dev_info variable is the "key" that is used to match up this
121 device driver with appropriate cards, through the card configuration
122 database.
123*/
124
125static dev_info_t dev_info = "sedlbauer_cs";
126
127/*
128 A linked list of "instances" of the sedlbauer device. Each actual
129 PCMCIA card corresponds to one device instance, and is described
130 by one dev_link_t structure (defined in ds.h).
131
132 You may not want to use a linked list for this -- for example, the
133 memory card driver uses an array of dev_link_t pointers, where minor
134 device numbers are used to derive the corresponding array index.
135*/
136
137static dev_link_t *dev_list = NULL;
138
139/*
140 A dev_link_t structure has fields for most things that are needed
141 to keep track of a socket, but there will usually be some device
142 specific information that also needs to be kept track of. The
143 'priv' pointer in a dev_link_t structure can be used to point to
144 a device-specific private data structure, like this.
145
146 To simplify the data structure handling, we actually include the
147 dev_link_t structure in the device's private data structure.
148
149 A driver needs to provide a dev_node_t structure for each device 117 A driver needs to provide a dev_node_t structure for each device
150 on a card. In some cases, there is only one device per card (for 118 on a card. In some cases, there is only one device per card (for
151 example, ethernet cards, modems). In other cases, there may be 119 example, ethernet cards, modems). In other cases, there may be
@@ -180,18 +148,16 @@ typedef struct local_info_t {
180 148
181======================================================================*/ 149======================================================================*/
182 150
183static dev_link_t *sedlbauer_attach(void) 151static int sedlbauer_attach(struct pcmcia_device *p_dev)
184{ 152{
185 local_info_t *local; 153 local_info_t *local;
186 dev_link_t *link; 154 dev_link_t *link;
187 client_reg_t client_reg;
188 int ret;
189 155
190 DEBUG(0, "sedlbauer_attach()\n"); 156 DEBUG(0, "sedlbauer_attach()\n");
191 157
192 /* Allocate space for private device-specific data */ 158 /* Allocate space for private device-specific data */
193 local = kmalloc(sizeof(local_info_t), GFP_KERNEL); 159 local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
194 if (!local) return NULL; 160 if (!local) return -ENOMEM;
195 memset(local, 0, sizeof(local_info_t)); 161 memset(local, 0, sizeof(local_info_t));
196 local->cardnr = -1; 162 local->cardnr = -1;
197 link = &local->link; link->priv = local; 163 link = &local->link; link->priv = local;
@@ -221,20 +187,13 @@ static dev_link_t *sedlbauer_attach(void)
221 link->conf.Vcc = 50; 187 link->conf.Vcc = 50;
222 link->conf.IntType = INT_MEMORY_AND_IO; 188 link->conf.IntType = INT_MEMORY_AND_IO;
223 189
224 /* Register with Card Services */ 190 link->handle = p_dev;
225 link->next = dev_list; 191 p_dev->instance = link;
226 dev_list = link; 192
227 client_reg.dev_info = &dev_info; 193 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
228 client_reg.Version = 0x0210; 194 sedlbauer_config(link);
229 client_reg.event_callback_args.client_data = link;
230 ret = pcmcia_register_client(&link->handle, &client_reg);
231 if (ret != CS_SUCCESS) {
232 cs_error(link->handle, RegisterClient, ret);
233 sedlbauer_detach(link);
234 return NULL;
235 }
236 195
237 return link; 196 return 0;
238} /* sedlbauer_attach */ 197} /* sedlbauer_attach */
239 198
240/*====================================================================== 199/*======================================================================
@@ -246,39 +205,17 @@ static dev_link_t *sedlbauer_attach(void)
246 205
247======================================================================*/ 206======================================================================*/
248 207
249static void sedlbauer_detach(dev_link_t *link) 208static void sedlbauer_detach(struct pcmcia_device *p_dev)
250{ 209{
251 dev_link_t **linkp; 210 dev_link_t *link = dev_to_instance(p_dev);
252 211
253 DEBUG(0, "sedlbauer_detach(0x%p)\n", link); 212 DEBUG(0, "sedlbauer_detach(0x%p)\n", link);
254
255 /* Locate device structure */
256 for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
257 if (*linkp == link) break;
258 if (*linkp == NULL)
259 return;
260 213
261 /*
262 If the device is currently configured and active, we won't
263 actually delete it yet. Instead, it is marked so that when
264 the release() function is called, that will trigger a proper
265 detach().
266 */
267 if (link->state & DEV_CONFIG) { 214 if (link->state & DEV_CONFIG) {
268#ifdef PCMCIA_DEBUG 215 ((local_info_t *)link->priv)->stop = 1;
269 printk(KERN_DEBUG "sedlbauer_cs: detach postponed, '%s' " 216 sedlbauer_release(link);
270 "still locked\n", link->dev->dev_name);
271#endif
272 link->state |= DEV_STALE_LINK;
273 return;
274 } 217 }
275 218
276 /* Break the link with Card Services */
277 if (link->handle)
278 pcmcia_deregister_client(link->handle);
279
280 /* Unlink device structure, and free it */
281 *linkp = link->next;
282 /* This points to the parent local_info_t struct */ 219 /* This points to the parent local_info_t struct */
283 kfree(link->priv); 220 kfree(link->priv);
284} /* sedlbauer_detach */ 221} /* sedlbauer_detach */
@@ -547,68 +484,34 @@ static void sedlbauer_release(dev_link_t *link)
547 if (link->irq.AssignedIRQ) 484 if (link->irq.AssignedIRQ)
548 pcmcia_release_irq(link->handle, &link->irq); 485 pcmcia_release_irq(link->handle, &link->irq);
549 link->state &= ~DEV_CONFIG; 486 link->state &= ~DEV_CONFIG;
550
551 if (link->state & DEV_STALE_LINK)
552 sedlbauer_detach(link);
553
554} /* sedlbauer_release */ 487} /* sedlbauer_release */
555 488
556/*====================================================================== 489static int sedlbauer_suspend(struct pcmcia_device *p_dev)
557
558 The card status event handler. Mostly, this schedules other
559 stuff to run after an event is received.
560
561 When a CARD_REMOVAL event is received, we immediately set a
562 private flag to block future accesses to this device. All the
563 functions that actually access the device should check this flag
564 to make sure the card is still present.
565
566======================================================================*/
567
568static int sedlbauer_event(event_t event, int priority,
569 event_callback_args_t *args)
570{ 490{
571 dev_link_t *link = args->client_data; 491 dev_link_t *link = dev_to_instance(p_dev);
572 local_info_t *dev = link->priv; 492 local_info_t *dev = link->priv;
573 493
574 DEBUG(1, "sedlbauer_event(0x%06x)\n", event);
575
576 switch (event) {
577 case CS_EVENT_CARD_REMOVAL:
578 link->state &= ~DEV_PRESENT;
579 if (link->state & DEV_CONFIG) {
580 ((local_info_t *)link->priv)->stop = 1;
581 sedlbauer_release(link);
582 }
583 break;
584 case CS_EVENT_CARD_INSERTION:
585 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
586 sedlbauer_config(link);
587 break;
588 case CS_EVENT_PM_SUSPEND:
589 link->state |= DEV_SUSPEND; 494 link->state |= DEV_SUSPEND;
590 /* Fall through... */
591 case CS_EVENT_RESET_PHYSICAL:
592 /* Mark the device as stopped, to block IO until later */
593 dev->stop = 1; 495 dev->stop = 1;
594 if (link->state & DEV_CONFIG) 496 if (link->state & DEV_CONFIG)
595 pcmcia_release_configuration(link->handle); 497 pcmcia_release_configuration(link->handle);
596 break; 498
597 case CS_EVENT_PM_RESUME: 499 return 0;
500}
501
502static int sedlbauer_resume(struct pcmcia_device *p_dev)
503{
504 dev_link_t *link = dev_to_instance(p_dev);
505 local_info_t *dev = link->priv;
506
598 link->state &= ~DEV_SUSPEND; 507 link->state &= ~DEV_SUSPEND;
599 /* Fall through... */
600 case CS_EVENT_CARD_RESET:
601 if (link->state & DEV_CONFIG) 508 if (link->state & DEV_CONFIG)
602 pcmcia_request_configuration(link->handle, &link->conf); 509 pcmcia_request_configuration(link->handle, &link->conf);
603 dev->stop = 0; 510 dev->stop = 0;
604 /* 511
605 In a normal driver, additional code may go here to restore 512 return 0;
606 the device state and restart IO. 513}
607 */ 514
608 break;
609 }
610 return 0;
611} /* sedlbauer_event */
612 515
613static struct pcmcia_device_id sedlbauer_ids[] = { 516static struct pcmcia_device_id sedlbauer_ids[] = {
614 PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "speed star II", "V 3.1", 0x81fb79f5, 0xf3612e1d, 0x6b95c78a), 517 PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "speed star II", "V 3.1", 0x81fb79f5, 0xf3612e1d, 0x6b95c78a),
@@ -627,10 +530,11 @@ static struct pcmcia_driver sedlbauer_driver = {
627 .drv = { 530 .drv = {
628 .name = "sedlbauer_cs", 531 .name = "sedlbauer_cs",
629 }, 532 },
630 .attach = sedlbauer_attach, 533 .probe = sedlbauer_attach,
631 .event = sedlbauer_event, 534 .remove = sedlbauer_detach,
632 .detach = sedlbauer_detach,
633 .id_table = sedlbauer_ids, 535 .id_table = sedlbauer_ids,
536 .suspend = sedlbauer_suspend,
537 .resume = sedlbauer_resume,
634}; 538};
635 539
636static int __init init_sedlbauer_cs(void) 540static int __init init_sedlbauer_cs(void)
@@ -641,7 +545,6 @@ static int __init init_sedlbauer_cs(void)
641static void __exit exit_sedlbauer_cs(void) 545static void __exit exit_sedlbauer_cs(void)
642{ 546{
643 pcmcia_unregister_driver(&sedlbauer_driver); 547 pcmcia_unregister_driver(&sedlbauer_driver);
644 BUG_ON(dev_list != NULL);
645} 548}
646 549
647module_init(init_sedlbauer_cs); 550module_init(init_sedlbauer_cs);