ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / isdn / hisax / sedlbauer_cs.c
1 /*======================================================================
2
3     A Sedlbauer PCMCIA client driver
4
5     This driver is for the Sedlbauer Speed Star and Speed Star II, 
6     which are ISDN PCMCIA Cards.
7     
8     The contents of this file are subject to the Mozilla Public
9     License Version 1.1 (the "License"); you may not use this file
10     except in compliance with the License. You may obtain a copy of
11     the License at http://www.mozilla.org/MPL/
12
13     Software distributed under the License is distributed on an "AS
14     IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
15     implied. See the License for the specific language governing
16     rights and limitations under the License.
17
18     The initial developer of the original code is David A. Hinds
19     <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
20     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
21
22     Modifications from dummy_cs.c are Copyright (C) 1999-2001 Marcus Niemann
23     <maniemann@users.sourceforge.net>. All Rights Reserved.
24
25     Alternatively, the contents of this file may be used under the
26     terms of the GNU General Public License version 2 (the "GPL"), in
27     which case the provisions of the GPL are applicable instead of the
28     above.  If you wish to allow the use of your version of this file
29     only under the terms of the GPL and not to allow others to use
30     your version of this file under the MPL, indicate your decision
31     by deleting the provisions above and replace them with the notice
32     and other provisions required by the GPL.  If you do not delete
33     the provisions above, a recipient may use your version of this
34     file under either the MPL or the GPL.
35     
36 ======================================================================*/
37
38 #include <linux/kernel.h>
39 #include <linux/module.h>
40 #include <linux/init.h>
41 #include <linux/sched.h>
42 #include <linux/ptrace.h>
43 #include <linux/slab.h>
44 #include <linux/string.h>
45 #include <linux/timer.h>
46 #include <linux/ioport.h>
47 #include <asm/io.h>
48 #include <asm/system.h>
49
50 #include <pcmcia/version.h>
51 #include <pcmcia/cs_types.h>
52 #include <pcmcia/cs.h>
53 #include <pcmcia/cistpl.h>
54 #include <pcmcia/cisreg.h>
55 #include <pcmcia/ds.h>
56 #include "hisax_cfg.h"
57
58 MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Sedlbauer cards");
59 MODULE_AUTHOR("Marcus Niemann");
60 MODULE_LICENSE("Dual MPL/GPL");
61
62 /*
63    All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
64    you do not define PCMCIA_DEBUG at all, all the debug code will be
65    left out.  If you compile with PCMCIA_DEBUG=0, the debug code will
66    be present but disabled -- but it can then be enabled for specific
67    modules at load time with a 'pc_debug=#' option to insmod.
68 */
69
70 #ifdef PCMCIA_DEBUG
71 static int pc_debug = PCMCIA_DEBUG;
72 MODULE_PARM(pc_debug, "i");
73 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); 
74 static char *version =
75 "sedlbauer_cs.c 1.1a 2001/01/28 15:04:04 (M.Niemann)";
76 #else
77 #define DEBUG(n, args...)
78 #endif
79
80
81 /*====================================================================*/
82
83 /* Parameters that can be set with 'insmod' */
84
85 /* The old way: bit map of interrupts to choose from */
86 /* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
87 static u_int irq_mask = 0xdeb8;
88 /* Newer, simpler way of listing specific interrupts */
89 static int irq_list[4] = { -1 };
90
91 MODULE_PARM(irq_mask, "i");
92 MODULE_PARM(irq_list, "1-4i");
93
94 static int protocol = 2;        /* EURO-ISDN Default */
95 MODULE_PARM(protocol, "i");
96
97 /*====================================================================*/
98
99 /*
100    The event() function is this driver's Card Services event handler.
101    It will be called by Card Services when an appropriate card status
102    event is received.  The config() and release() entry points are
103    used to configure or release a socket, in response to card
104    insertion and ejection events.  They are invoked from the sedlbauer
105    event handler. 
106 */
107
108 static void sedlbauer_config(dev_link_t *link);
109 static void sedlbauer_release(dev_link_t *link);
110 static int sedlbauer_event(event_t event, int priority,
111                        event_callback_args_t *args);
112
113 /*
114    The attach() and detach() entry points are used to create and destroy
115    "instances" of the driver, where each instance represents everything
116    needed to manage one actual PCMCIA card.
117 */
118
119 static dev_link_t *sedlbauer_attach(void);
120 static void sedlbauer_detach(dev_link_t *);
121
122 /*
123    You'll also need to prototype all the functions that will actually
124    be used to talk to your device.  See 'memory_cs' for a good example
125    of a fully self-sufficient driver; the other drivers rely more or
126    less on other parts of the kernel.
127 */
128
129 /*
130    The dev_info variable is the "key" that is used to match up this
131    device driver with appropriate cards, through the card configuration
132    database.
133 */
134
135 static dev_info_t dev_info = "sedlbauer_cs";
136
137 /*
138    A linked list of "instances" of the sedlbauer device.  Each actual
139    PCMCIA card corresponds to one device instance, and is described
140    by one dev_link_t structure (defined in ds.h).
141
142    You may not want to use a linked list for this -- for example, the
143    memory card driver uses an array of dev_link_t pointers, where minor
144    device numbers are used to derive the corresponding array index.
145 */
146
147 static dev_link_t *dev_list = NULL;
148
149 /*
150    A dev_link_t structure has fields for most things that are needed
151    to keep track of a socket, but there will usually be some device
152    specific information that also needs to be kept track of.  The
153    'priv' pointer in a dev_link_t structure can be used to point to
154    a device-specific private data structure, like this.
155
156    To simplify the data structure handling, we actually include the
157    dev_link_t structure in the device's private data structure.
158
159    A driver needs to provide a dev_node_t structure for each device
160    on a card.  In some cases, there is only one device per card (for
161    example, ethernet cards, modems).  In other cases, there may be
162    many actual or logical devices (SCSI adapters, memory cards with
163    multiple partitions).  The dev_node_t structures need to be kept
164    in a linked list starting at the 'dev' field of a dev_link_t
165    structure.  We allocate them in the card's private data structure,
166    because they generally shouldn't be allocated dynamically.
167
168    In this case, we also provide a flag to indicate if a device is
169    "stopped" due to a power management event, or card ejection.  The
170    device IO routines can use a flag like this to throttle IO to a
171    card that is not ready to accept it.
172 */
173    
174 typedef struct local_info_t {
175     dev_link_t          link;
176     dev_node_t          node;
177     int                 stop;
178     int                 cardnr;
179 } local_info_t;
180
181 /*======================================================================
182
183     sedlbauer_attach() creates an "instance" of the driver, allocating
184     local data structures for one device.  The device is registered
185     with Card Services.
186
187     The dev_link structure is initialized, but we don't actually
188     configure the card at this point -- we wait until we receive a
189     card insertion event.
190     
191 ======================================================================*/
192
193 static dev_link_t *sedlbauer_attach(void)
194 {
195     local_info_t *local;
196     dev_link_t *link;
197     client_reg_t client_reg;
198     int ret, i;
199     
200     DEBUG(0, "sedlbauer_attach()\n");
201
202     /* Allocate space for private device-specific data */
203     local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
204     if (!local) return NULL;
205     memset(local, 0, sizeof(local_info_t));
206     local->cardnr = -1;
207     link = &local->link; link->priv = local;
208     
209     /* Interrupt setup */
210     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
211     link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
212     if (irq_list[0] == -1)
213         link->irq.IRQInfo2 = irq_mask;
214     else
215         for (i = 0; i < 4; i++)
216             link->irq.IRQInfo2 |= 1 << irq_list[i];
217     link->irq.Handler = NULL;
218     
219     /*
220       General socket configuration defaults can go here.  In this
221       client, we assume very little, and rely on the CIS for almost
222       everything.  In most clients, many details (i.e., number, sizes,
223       and attributes of IO windows) are fixed by the nature of the
224       device, and can be hard-wired here.
225     */
226
227     /* from old sedl_cs 
228     */
229     /* The io structure describes IO port mapping */
230     link->io.NumPorts1 = 8;
231     link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
232     link->io.IOAddrLines = 3;
233
234
235     link->conf.Attributes = 0;
236     link->conf.Vcc = 50;
237     link->conf.IntType = INT_MEMORY_AND_IO;
238
239     /* Register with Card Services */
240     link->next = dev_list;
241     dev_list = link;
242     client_reg.dev_info = &dev_info;
243     client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
244     client_reg.EventMask =
245         CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
246         CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
247         CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
248     client_reg.event_handler = &sedlbauer_event;
249     client_reg.Version = 0x0210;
250     client_reg.event_callback_args.client_data = link;
251     ret = pcmcia_register_client(&link->handle, &client_reg);
252     if (ret != CS_SUCCESS) {
253         cs_error(link->handle, RegisterClient, ret);
254         sedlbauer_detach(link);
255         return NULL;
256     }
257
258     return link;
259 } /* sedlbauer_attach */
260
261 /*======================================================================
262
263     This deletes a driver "instance".  The device is de-registered
264     with Card Services.  If it has been released, all local data
265     structures are freed.  Otherwise, the structures will be freed
266     when the device is released.
267
268 ======================================================================*/
269
270 static void sedlbauer_detach(dev_link_t *link)
271 {
272     dev_link_t **linkp;
273
274     DEBUG(0, "sedlbauer_detach(0x%p)\n", link);
275     
276     /* Locate device structure */
277     for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
278         if (*linkp == link) break;
279     if (*linkp == NULL)
280         return;
281
282     /*
283        If the device is currently configured and active, we won't
284        actually delete it yet.  Instead, it is marked so that when
285        the release() function is called, that will trigger a proper
286        detach().
287     */
288     if (link->state & DEV_CONFIG) {
289 #ifdef PCMCIA_DEBUG
290         printk(KERN_DEBUG "sedlbauer_cs: detach postponed, '%s' "
291                "still locked\n", link->dev->dev_name);
292 #endif
293         link->state |= DEV_STALE_LINK;
294         return;
295     }
296
297     /* Break the link with Card Services */
298     if (link->handle)
299         pcmcia_deregister_client(link->handle);
300     
301     /* Unlink device structure, and free it */
302     *linkp = link->next;
303     /* This points to the parent local_info_t struct */
304     kfree(link->priv);
305 } /* sedlbauer_detach */
306
307 /*======================================================================
308
309     sedlbauer_config() is scheduled to run after a CARD_INSERTION event
310     is received, to configure the PCMCIA socket, and to make the
311     device available to the system.
312     
313 ======================================================================*/
314 #define CS_CHECK(fn, ret) \
315 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
316
317 static void sedlbauer_config(dev_link_t *link)
318 {
319     client_handle_t handle = link->handle;
320     local_info_t *dev = link->priv;
321     tuple_t tuple;
322     cisparse_t parse;
323     int last_fn, last_ret;
324     u8 buf[64];
325     config_info_t conf;
326     win_req_t req;
327     memreq_t map;
328     IsdnCard_t  icard;
329
330     DEBUG(0, "sedlbauer_config(0x%p)\n", link);
331
332     /*
333        This reads the card's CONFIG tuple to find its configuration
334        registers.
335     */
336     tuple.DesiredTuple = CISTPL_CONFIG;
337     tuple.Attributes = 0;
338     tuple.TupleData = buf;
339     tuple.TupleDataMax = sizeof(buf);
340     tuple.TupleOffset = 0;
341     CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
342     CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
343     CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
344     link->conf.ConfigBase = parse.config.base;
345     link->conf.Present = parse.config.rmask[0];
346     
347     /* Configure card */
348     link->state |= DEV_CONFIG;
349
350     /* Look up the current Vcc */
351     CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf));
352     link->conf.Vcc = conf.Vcc;
353
354     /*
355       In this loop, we scan the CIS for configuration table entries,
356       each of which describes a valid card configuration, including
357       voltage, IO window, memory window, and interrupt settings.
358
359       We make no assumptions about the card to be configured: we use
360       just the information available in the CIS.  In an ideal world,
361       this would work for any PCMCIA card, but it requires a complete
362       and accurate CIS.  In practice, a driver usually "knows" most of
363       these things without consulting the CIS, and most client drivers
364       will only use the CIS to fill in implementation-defined details.
365     */
366     tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
367     CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
368     while (1) {
369         cistpl_cftable_entry_t dflt = { 0 };
370         cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
371         if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
372                 pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
373             goto next_entry;
374
375         if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
376         if (cfg->index == 0) goto next_entry;
377         link->conf.ConfigIndex = cfg->index;
378         
379         /* Does this card need audio output? */
380         if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
381             link->conf.Attributes |= CONF_ENABLE_SPKR;
382             link->conf.Status = CCSR_AUDIO_ENA;
383         }
384         
385         /* Use power settings for Vcc and Vpp if present */
386         /*  Note that the CIS values need to be rescaled */
387         if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
388             if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
389                 goto next_entry;
390         } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
391             if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000)
392                 goto next_entry;
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 = (cfg->io.nwin) ? &cfg->io : &dflt.io;
410             link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
411             if (!(io->flags & CISTPL_IO_8BIT))
412                 link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
413             if (!(io->flags & CISTPL_IO_16BIT))
414                 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
415 /* new in dummy.cs 2001/01/28 MN 
416             link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
417 */
418             link->io.BasePort1 = io->win[0].base;
419             link->io.NumPorts1 = io->win[0].len;
420             if (io->nwin > 1) {
421                 link->io.Attributes2 = link->io.Attributes1;
422                 link->io.BasePort2 = io->win[1].base;
423                 link->io.NumPorts2 = io->win[1].len;
424             }
425             /* This reserves IO space but doesn't actually enable it */
426             if (pcmcia_request_io(link->handle, &link->io) != 0)
427                 goto next_entry;
428         }
429
430         /*
431           Now set up a common memory window, if needed.  There is room
432           in the dev_link_t structure for one memory window handle,
433           but if the base addresses need to be saved, or if multiple
434           windows are needed, the info should go in the private data
435           structure for this device.
436
437           Note that the memory window base is a physical address, and
438           needs to be mapped to virtual space with ioremap() before it
439           is used.
440         */
441         if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) {
442             cistpl_mem_t *mem =
443                 (cfg->mem.nwin) ? &cfg->mem : &dflt.mem;
444             req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
445             req.Attributes |= WIN_ENABLE;
446             req.Base = mem->win[0].host_addr;
447             req.Size = mem->win[0].len;
448 /* new in dummy.cs 2001/01/28 MN 
449             if (req.Size < 0x1000)
450                 req.Size = 0x1000;
451 */
452             req.AccessSpeed = 0;
453             if (pcmcia_request_window(&link->handle, &req, &link->win) != 0)
454                 goto next_entry;
455             map.Page = 0; map.CardOffset = mem->win[0].card_addr;
456             if (pcmcia_map_mem_page(link->win, &map) != 0)
457                 goto next_entry;
458         }
459         /* If we got this far, we're cool! */
460         break;
461         
462     next_entry:
463 /* new in dummy.cs 2001/01/28 MN 
464         if (link->io.NumPorts1)
465            pcmcia_release_io(link->handle, &link->io);
466 */
467         CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
468     }
469     
470     /*
471        Allocate an interrupt line.  Note that this does not assign a
472        handler to the interrupt, unless the 'Handler' member of the
473        irq structure is initialized.
474     */
475     if (link->conf.Attributes & CONF_ENABLE_IRQ)
476         CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
477         
478     /*
479        This actually configures the PCMCIA socket -- setting up
480        the I/O windows and the interrupt mapping, and putting the
481        card and host interface into "Memory and IO" mode.
482     */
483     CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
484
485     /*
486       At this point, the dev_node_t structure(s) need to be
487       initialized and arranged in a linked list at link->dev.
488     */
489     sprintf(dev->node.dev_name, "sedlbauer");
490     dev->node.major = dev->node.minor = 0;
491     link->dev = &dev->node;
492
493     /* Finally, report what we've done */
494     printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d",
495            dev->node.dev_name, link->conf.ConfigIndex,
496            link->conf.Vcc/10, link->conf.Vcc%10);
497     if (link->conf.Vpp1)
498         printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
499     if (link->conf.Attributes & CONF_ENABLE_IRQ)
500         printk(", irq %d", link->irq.AssignedIRQ);
501     if (link->io.NumPorts1)
502         printk(", io 0x%04x-0x%04x", link->io.BasePort1,
503                link->io.BasePort1+link->io.NumPorts1-1);
504     if (link->io.NumPorts2)
505         printk(" & 0x%04x-0x%04x", link->io.BasePort2,
506                link->io.BasePort2+link->io.NumPorts2-1);
507     if (link->win)
508         printk(", mem 0x%06lx-0x%06lx", req.Base,
509                req.Base+req.Size-1);
510     printk("\n");
511     
512     link->state &= ~DEV_CONFIG_PENDING;
513
514     icard.para[0] = link->irq.AssignedIRQ;
515     icard.para[1] = link->io.BasePort1;
516     icard.protocol = protocol;
517     icard.typ = ISDN_CTYPE_SEDLBAUER_PCMCIA;
518     
519     last_ret = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->stop), &icard);
520     if (last_ret < 0) {
521         printk(KERN_ERR "sedlbauer_cs: failed to initialize SEDLBAUER PCMCIA %d at i/o %#x\n",
522                 last_ret, link->io.BasePort1);
523         sedlbauer_release(link);
524     } else
525         ((local_info_t*)link->priv)->cardnr = last_ret;
526
527     return;
528
529 cs_failed:
530     cs_error(link->handle, last_fn, last_ret);
531     sedlbauer_release(link);
532
533 } /* sedlbauer_config */
534
535 /*======================================================================
536
537     After a card is removed, sedlbauer_release() will unregister the
538     device, and release the PCMCIA configuration.  If the device is
539     still open, this will be postponed until it is closed.
540     
541 ======================================================================*/
542
543 static void sedlbauer_release(dev_link_t *link)
544 {
545     local_info_t *local = link->priv;
546     DEBUG(0, "sedlbauer_release(0x%p)\n", link);
547
548     if (local) {
549         if (local->cardnr >= 0) {
550             /* no unregister function with hisax */
551             HiSax_closecard(local->cardnr);
552         }
553     }
554     /* Unlink the device chain */
555     link->dev = NULL;
556
557     /*
558       In a normal driver, additional code may be needed to release
559       other kernel data structures associated with this device. 
560     */
561     
562     /* Don't bother checking to see if these succeed or not */
563     if (link->win)
564         pcmcia_release_window(link->win);
565     pcmcia_release_configuration(link->handle);
566     if (link->io.NumPorts1)
567         pcmcia_release_io(link->handle, &link->io);
568     if (link->irq.AssignedIRQ)
569         pcmcia_release_irq(link->handle, &link->irq);
570     link->state &= ~DEV_CONFIG;
571     
572     if (link->state & DEV_STALE_LINK)
573         sedlbauer_detach(link);
574     
575 } /* sedlbauer_release */
576
577 /*======================================================================
578
579     The card status event handler.  Mostly, this schedules other
580     stuff to run after an event is received.
581
582     When a CARD_REMOVAL event is received, we immediately set a
583     private flag to block future accesses to this device.  All the
584     functions that actually access the device should check this flag
585     to make sure the card is still present.
586     
587 ======================================================================*/
588
589 static int sedlbauer_event(event_t event, int priority,
590                        event_callback_args_t *args)
591 {
592     dev_link_t *link = args->client_data;
593     local_info_t *dev = link->priv;
594     
595     DEBUG(1, "sedlbauer_event(0x%06x)\n", event);
596     
597     switch (event) {
598     case CS_EVENT_CARD_REMOVAL:
599         link->state &= ~DEV_PRESENT;
600         if (link->state & DEV_CONFIG) {
601             ((local_info_t *)link->priv)->stop = 1;
602             sedlbauer_release(link);
603         }
604         break;
605     case CS_EVENT_CARD_INSERTION:
606         link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
607         sedlbauer_config(link);
608         break;
609     case CS_EVENT_PM_SUSPEND:
610         link->state |= DEV_SUSPEND;
611         /* Fall through... */
612     case CS_EVENT_RESET_PHYSICAL:
613         /* Mark the device as stopped, to block IO until later */
614         dev->stop = 1;
615         if (link->state & DEV_CONFIG)
616             pcmcia_release_configuration(link->handle);
617         break;
618     case CS_EVENT_PM_RESUME:
619         link->state &= ~DEV_SUSPEND;
620         /* Fall through... */
621     case CS_EVENT_CARD_RESET:
622         if (link->state & DEV_CONFIG)
623             pcmcia_request_configuration(link->handle, &link->conf);
624         dev->stop = 0;
625         /*
626           In a normal driver, additional code may go here to restore
627           the device state and restart IO. 
628         */
629         break;
630     }
631     return 0;
632 } /* sedlbauer_event */
633
634 static struct pcmcia_driver sedlbauer_driver = {
635         .owner          = THIS_MODULE,
636         .drv            = {
637                 .name   = "sedlbauer_cs",
638         },
639         .attach         = sedlbauer_attach,
640         .detach         = sedlbauer_detach,
641 };
642
643 static int __init init_sedlbauer_cs(void)
644 {
645         return pcmcia_register_driver(&sedlbauer_driver);
646 }
647
648 static void __exit exit_sedlbauer_cs(void)
649 {
650         pcmcia_unregister_driver(&sedlbauer_driver);
651
652         /* XXX: this really needs to move into generic code.. */
653         while (dev_list != NULL) {
654                 if (dev_list->state & DEV_CONFIG)
655                         sedlbauer_release(dev_list);
656                 sedlbauer_detach(dev_list);
657         }
658 }
659
660 module_init(init_sedlbauer_cs);
661 module_exit(exit_sedlbauer_cs);