[PATCH] libata: convert dev->id to pointer
[linux-2.6] / drivers / isdn / hisax / teles_cs.c
1 /* $Id: teles_cs.c,v 1.1.2.2 2004/01/25 15:07:06 keil Exp $ */
2 /*======================================================================
3
4     A teles S0 PCMCIA client driver
5
6     Based on skeleton by David Hinds, dhinds@allegro.stanford.edu
7     Written by Christof Petig, christof.petig@wtal.de
8     
9     Also inspired by ELSA PCMCIA driver 
10     by Klaus Lichtenwalder <Lichtenwalder@ACM.org>
11     
12     Extentions to new hisax_pcmcia by Karsten Keil
13
14     minor changes to be compatible with kernel 2.4.x
15     by Jan.Schubert@GMX.li
16
17 ======================================================================*/
18
19 #include <linux/kernel.h>
20 #include <linux/module.h>
21 #include <linux/init.h>
22 #include <linux/sched.h>
23 #include <linux/ptrace.h>
24 #include <linux/slab.h>
25 #include <linux/string.h>
26 #include <linux/timer.h>
27 #include <linux/ioport.h>
28 #include <asm/io.h>
29 #include <asm/system.h>
30
31 #include <pcmcia/cs_types.h>
32 #include <pcmcia/cs.h>
33 #include <pcmcia/cistpl.h>
34 #include <pcmcia/cisreg.h>
35 #include <pcmcia/ds.h>
36 #include "hisax_cfg.h"
37
38 MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Teles PCMCIA cards");
39 MODULE_AUTHOR("Christof Petig, christof.petig@wtal.de, Karsten Keil, kkeil@suse.de");
40 MODULE_LICENSE("GPL");
41
42 /*
43    All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
44    you do not define PCMCIA_DEBUG at all, all the debug code will be
45    left out.  If you compile with PCMCIA_DEBUG=0, the debug code will
46    be present but disabled -- but it can then be enabled for specific
47    modules at load time with a 'pc_debug=#' option to insmod.
48 */
49
50 #ifdef PCMCIA_DEBUG
51 static int pc_debug = PCMCIA_DEBUG;
52 module_param(pc_debug, int, 0);
53 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args);
54 static char *version =
55 "teles_cs.c 2.10 2002/07/30 22:23:34 kkeil";
56 #else
57 #define DEBUG(n, args...)
58 #endif
59
60 /*====================================================================*/
61
62 /* Parameters that can be set with 'insmod' */
63
64 static int protocol = 2;        /* EURO-ISDN Default */
65 module_param(protocol, int, 0);
66
67 /*====================================================================*/
68
69 /*
70    The event() function is this driver's Card Services event handler.
71    It will be called by Card Services when an appropriate card status
72    event is received.  The config() and release() entry points are
73    used to configure or release a socket, in response to card insertion
74    and ejection events.  They are invoked from the teles_cs event
75    handler.
76 */
77
78 static void teles_cs_config(dev_link_t *link);
79 static void teles_cs_release(dev_link_t *link);
80
81 /*
82    The attach() and detach() entry points are used to create and destroy
83    "instances" of the driver, where each instance represents everything
84    needed to manage one actual PCMCIA card.
85 */
86
87 static void teles_detach(struct pcmcia_device *p_dev);
88
89 /*
90    A linked list of "instances" of the teles_cs device.  Each actual
91    PCMCIA card corresponds to one device instance, and is described
92    by one dev_link_t structure (defined in ds.h).
93
94    You may not want to use a linked list for this -- for example, the
95    memory card driver uses an array of dev_link_t pointers, where minor
96    device numbers are used to derive the corresponding array index.
97 */
98
99 /*
100    A driver needs to provide a dev_node_t structure for each device
101    on a card.  In some cases, there is only one device per card (for
102    example, ethernet cards, modems).  In other cases, there may be
103    many actual or logical devices (SCSI adapters, memory cards with
104    multiple partitions).  The dev_node_t structures need to be kept
105    in a linked list starting at the 'dev' field of a dev_link_t
106    structure.  We allocate them in the card's private data structure,
107    because they generally shouldn't be allocated dynamically.
108    In this case, we also provide a flag to indicate if a device is
109    "stopped" due to a power management event, or card ejection.  The
110    device IO routines can use a flag like this to throttle IO to a
111    card that is not ready to accept it.
112 */
113
114 typedef struct local_info_t {
115     dev_link_t          link;
116     dev_node_t          node;
117     int                 busy;
118     int                 cardnr;
119 } local_info_t;
120
121 /*======================================================================
122
123     teles_attach() creates an "instance" of the driver, allocatingx
124     local data structures for one device.  The device is registered
125     with Card Services.
126
127     The dev_link structure is initialized, but we don't actually
128     configure the card at this point -- we wait until we receive a
129     card insertion event.
130
131 ======================================================================*/
132
133 static int teles_attach(struct pcmcia_device *p_dev)
134 {
135     dev_link_t *link;
136     local_info_t *local;
137
138     DEBUG(0, "teles_attach()\n");
139
140     /* Allocate space for private device-specific data */
141     local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
142     if (!local) return -ENOMEM;
143     memset(local, 0, sizeof(local_info_t));
144     local->cardnr = -1;
145     link = &local->link; link->priv = local;
146
147     /* Interrupt setup */
148     link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
149     link->irq.IRQInfo1 = IRQ_LEVEL_ID|IRQ_SHARE_ID;
150     link->irq.Handler = NULL;
151
152     /*
153       General socket configuration defaults can go here.  In this
154       client, we assume very little, and rely on the CIS for almost
155       everything.  In most clients, many details (i.e., number, sizes,
156       and attributes of IO windows) are fixed by the nature of the
157       device, and can be hard-wired here.
158     */
159     link->io.NumPorts1 = 96;
160     link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
161     link->io.IOAddrLines = 5;
162
163     link->conf.Attributes = CONF_ENABLE_IRQ;
164     link->conf.Vcc = 50;
165     link->conf.IntType = INT_MEMORY_AND_IO;
166
167     link->handle = p_dev;
168     p_dev->instance = link;
169
170     link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
171     teles_cs_config(link);
172
173     return 0;
174 } /* teles_attach */
175
176 /*======================================================================
177
178     This deletes a driver "instance".  The device is de-registered
179     with Card Services.  If it has been released, all local data
180     structures are freed.  Otherwise, the structures will be freed
181     when the device is released.
182
183 ======================================================================*/
184
185 static void teles_detach(struct pcmcia_device *p_dev)
186 {
187     dev_link_t *link = dev_to_instance(p_dev);
188     local_info_t *info = link->priv;
189
190     DEBUG(0, "teles_detach(0x%p)\n", link);
191
192     if (link->state & DEV_CONFIG) {
193             info->busy = 1;
194             teles_cs_release(link);
195     }
196
197     kfree(info);
198
199 } /* teles_detach */
200
201 /*======================================================================
202
203     teles_cs_config() is scheduled to run after a CARD_INSERTION event
204     is received, to configure the PCMCIA socket, and to make the
205     device available to the system.
206
207 ======================================================================*/
208 static int get_tuple(client_handle_t handle, tuple_t *tuple,
209                      cisparse_t *parse)
210 {
211     int i = pcmcia_get_tuple_data(handle, tuple);
212     if (i != CS_SUCCESS) return i;
213     return pcmcia_parse_tuple(handle, tuple, parse);
214 }
215
216 static int first_tuple(client_handle_t handle, tuple_t *tuple,
217                      cisparse_t *parse)
218 {
219     int i = pcmcia_get_first_tuple(handle, tuple);
220     if (i != CS_SUCCESS) return i;
221     return get_tuple(handle, tuple, parse);
222 }
223
224 static int next_tuple(client_handle_t handle, tuple_t *tuple,
225                      cisparse_t *parse)
226 {
227     int i = pcmcia_get_next_tuple(handle, tuple);
228     if (i != CS_SUCCESS) return i;
229     return get_tuple(handle, tuple, parse);
230 }
231
232 static void teles_cs_config(dev_link_t *link)
233 {
234     client_handle_t handle;
235     tuple_t tuple;
236     cisparse_t parse;
237     local_info_t *dev;
238     int i, j, last_fn;
239     u_short buf[128];
240     cistpl_cftable_entry_t *cf = &parse.cftable_entry;
241     IsdnCard_t icard;
242
243     DEBUG(0, "teles_config(0x%p)\n", link);
244     handle = link->handle;
245     dev = link->priv;
246
247     /*
248        This reads the card's CONFIG tuple to find its configuration
249        registers.
250     */
251     tuple.DesiredTuple = CISTPL_CONFIG;
252     tuple.TupleData = (cisdata_t *)buf;
253     tuple.TupleDataMax = 255;
254     tuple.TupleOffset = 0;
255     tuple.Attributes = 0;
256     i = first_tuple(handle, &tuple, &parse);
257     if (i != CS_SUCCESS) {
258         last_fn = ParseTuple;
259         goto cs_failed;
260     }
261     link->conf.ConfigBase = parse.config.base;
262     link->conf.Present = parse.config.rmask[0];
263
264     /* Configure card */
265     link->state |= DEV_CONFIG;
266
267     tuple.TupleData = (cisdata_t *)buf;
268     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
269     tuple.Attributes = 0;
270     tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
271     i = first_tuple(handle, &tuple, &parse);
272     while (i == CS_SUCCESS) {
273         if ( (cf->io.nwin > 0) && cf->io.win[0].base) {
274             printk(KERN_INFO "(teles_cs: looks like the 96 model)\n");
275             link->conf.ConfigIndex = cf->index;
276             link->io.BasePort1 = cf->io.win[0].base;
277             i = pcmcia_request_io(link->handle, &link->io);
278             if (i == CS_SUCCESS) break;
279         } else {
280           printk(KERN_INFO "(teles_cs: looks like the 97 model)\n");
281           link->conf.ConfigIndex = cf->index;
282           for (i = 0, j = 0x2f0; j > 0x100; j -= 0x10) {
283             link->io.BasePort1 = j;
284             i = pcmcia_request_io(link->handle, &link->io);
285             if (i == CS_SUCCESS) break;
286           }
287           break;
288         }
289         i = next_tuple(handle, &tuple, &parse);
290     }
291
292     if (i != CS_SUCCESS) {
293         last_fn = RequestIO;
294         goto cs_failed;
295     }
296
297     i = pcmcia_request_irq(link->handle, &link->irq);
298     if (i != CS_SUCCESS) {
299         link->irq.AssignedIRQ = 0;
300         last_fn = RequestIRQ;
301         goto cs_failed;
302     }
303
304     i = pcmcia_request_configuration(link->handle, &link->conf);
305     if (i != CS_SUCCESS) {
306       last_fn = RequestConfiguration;
307       goto cs_failed;
308     }
309
310     /* At this point, the dev_node_t structure(s) should be
311        initialized and arranged in a linked list at link->dev. *//*  */
312     sprintf(dev->node.dev_name, "teles");
313     dev->node.major = dev->node.minor = 0x0;
314
315     link->dev = &dev->node;
316
317     /* Finally, report what we've done */
318     printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d",
319            dev->node.dev_name, link->conf.ConfigIndex,
320            link->conf.Vcc/10, link->conf.Vcc%10);
321     if (link->conf.Vpp1)
322         printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
323     if (link->conf.Attributes & CONF_ENABLE_IRQ)
324         printk(", irq %d", link->irq.AssignedIRQ);
325     if (link->io.NumPorts1)
326         printk(", io 0x%04x-0x%04x", link->io.BasePort1,
327                link->io.BasePort1+link->io.NumPorts1-1);
328     if (link->io.NumPorts2)
329         printk(" & 0x%04x-0x%04x", link->io.BasePort2,
330                link->io.BasePort2+link->io.NumPorts2-1);
331     printk("\n");
332
333     link->state &= ~DEV_CONFIG_PENDING;
334
335     icard.para[0] = link->irq.AssignedIRQ;
336     icard.para[1] = link->io.BasePort1;
337     icard.protocol = protocol;
338     icard.typ = ISDN_CTYPE_TELESPCMCIA;
339     
340     i = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->busy), &icard);
341     if (i < 0) {
342         printk(KERN_ERR "teles_cs: failed to initialize Teles PCMCIA %d at i/o %#x\n",
343                 i, link->io.BasePort1);
344         teles_cs_release(link);
345     } else
346         ((local_info_t*)link->priv)->cardnr = i;
347
348     return;
349 cs_failed:
350     cs_error(link->handle, last_fn, i);
351     teles_cs_release(link);
352 } /* teles_cs_config */
353
354 /*======================================================================
355
356     After a card is removed, teles_cs_release() will unregister the net
357     device, and release the PCMCIA configuration.  If the device is
358     still open, this will be postponed until it is closed.
359
360 ======================================================================*/
361
362 static void teles_cs_release(dev_link_t *link)
363 {
364     local_info_t *local = link->priv;
365
366     DEBUG(0, "teles_cs_release(0x%p)\n", link);
367
368     if (local) {
369         if (local->cardnr >= 0) {
370             /* no unregister function with hisax */
371             HiSax_closecard(local->cardnr);
372         }
373     }
374     /* Unlink the device chain */
375     link->dev = NULL;
376
377     /* Don't bother checking to see if these succeed or not */
378     if (link->win)
379         pcmcia_release_window(link->win);
380     pcmcia_release_configuration(link->handle);
381     pcmcia_release_io(link->handle, &link->io);
382     pcmcia_release_irq(link->handle, &link->irq);
383     link->state &= ~DEV_CONFIG;
384 } /* teles_cs_release */
385
386 static int teles_suspend(struct pcmcia_device *p_dev)
387 {
388         dev_link_t *link = dev_to_instance(p_dev);
389         local_info_t *dev = link->priv;
390
391         link->state |= DEV_SUSPEND;
392         dev->busy = 1;
393         if (link->state & DEV_CONFIG)
394                 pcmcia_release_configuration(link->handle);
395
396         return 0;
397 }
398
399 static int teles_resume(struct pcmcia_device *p_dev)
400 {
401         dev_link_t *link = dev_to_instance(p_dev);
402         local_info_t *dev = link->priv;
403
404         link->state &= ~DEV_SUSPEND;
405         if (link->state & DEV_CONFIG)
406                 pcmcia_request_configuration(link->handle, &link->conf);
407         dev->busy = 0;
408
409         return 0;
410 }
411
412
413 static struct pcmcia_device_id teles_ids[] = {
414         PCMCIA_DEVICE_PROD_ID12("TELES", "S0/PC", 0x67b50eae, 0xe9e70119),
415         PCMCIA_DEVICE_NULL,
416 };
417 MODULE_DEVICE_TABLE(pcmcia, teles_ids);
418
419 static struct pcmcia_driver teles_cs_driver = {
420         .owner          = THIS_MODULE,
421         .drv            = {
422                 .name   = "teles_cs",
423         },
424         .probe          = teles_attach,
425         .remove         = teles_detach,
426         .id_table       = teles_ids,
427         .suspend        = teles_suspend,
428         .resume         = teles_resume,
429 };
430
431 static int __init init_teles_cs(void)
432 {
433         return pcmcia_register_driver(&teles_cs_driver);
434 }
435
436 static void __exit exit_teles_cs(void)
437 {
438         pcmcia_unregister_driver(&teles_cs_driver);
439 }
440
441 module_init(init_teles_cs);
442 module_exit(exit_teles_cs);