Merge branch 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6
[pandora-kernel.git] / 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 int teles_cs_config(struct pcmcia_device *link);
79 static void teles_cs_release(struct pcmcia_device *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 struct pcmcia_device 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 struct pcmcia_device 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 struct pcmcia_device
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         struct pcmcia_device    *p_dev;
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_probe(struct pcmcia_device *link)
134 {
135     local_info_t *local;
136
137     DEBUG(0, "teles_attach()\n");
138
139     /* Allocate space for private device-specific data */
140     local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
141     if (!local) return -ENOMEM;
142     local->cardnr = -1;
143
144     local->p_dev = link;
145     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.IntType = INT_MEMORY_AND_IO;
165
166     return teles_cs_config(link);
167 } /* teles_attach */
168
169 /*======================================================================
170
171     This deletes a driver "instance".  The device is de-registered
172     with Card Services.  If it has been released, all local data
173     structures are freed.  Otherwise, the structures will be freed
174     when the device is released.
175
176 ======================================================================*/
177
178 static void teles_detach(struct pcmcia_device *link)
179 {
180         local_info_t *info = link->priv;
181
182         DEBUG(0, "teles_detach(0x%p)\n", link);
183
184         info->busy = 1;
185         teles_cs_release(link);
186
187         kfree(info);
188 } /* teles_detach */
189
190 /*======================================================================
191
192     teles_cs_config() is scheduled to run after a CARD_INSERTION event
193     is received, to configure the PCMCIA socket, and to make the
194     device available to the system.
195
196 ======================================================================*/
197 static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple,
198                      cisparse_t *parse)
199 {
200     int i = pcmcia_get_tuple_data(handle, tuple);
201     if (i != CS_SUCCESS) return i;
202     return pcmcia_parse_tuple(handle, tuple, parse);
203 }
204
205 static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple,
206                      cisparse_t *parse)
207 {
208     int i = pcmcia_get_first_tuple(handle, tuple);
209     if (i != CS_SUCCESS) return i;
210     return get_tuple(handle, tuple, parse);
211 }
212
213 static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple,
214                      cisparse_t *parse)
215 {
216     int i = pcmcia_get_next_tuple(handle, tuple);
217     if (i != CS_SUCCESS) return i;
218     return get_tuple(handle, tuple, parse);
219 }
220
221 static int teles_cs_config(struct pcmcia_device *link)
222 {
223     tuple_t tuple;
224     cisparse_t parse;
225     local_info_t *dev;
226     int i, j, last_fn;
227     u_short buf[128];
228     cistpl_cftable_entry_t *cf = &parse.cftable_entry;
229     IsdnCard_t icard;
230
231     DEBUG(0, "teles_config(0x%p)\n", link);
232     dev = link->priv;
233
234     tuple.TupleData = (cisdata_t *)buf;
235     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
236     tuple.Attributes = 0;
237     tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
238     i = first_tuple(link, &tuple, &parse);
239     while (i == CS_SUCCESS) {
240         if ( (cf->io.nwin > 0) && cf->io.win[0].base) {
241             printk(KERN_INFO "(teles_cs: looks like the 96 model)\n");
242             link->conf.ConfigIndex = cf->index;
243             link->io.BasePort1 = cf->io.win[0].base;
244             i = pcmcia_request_io(link, &link->io);
245             if (i == CS_SUCCESS) break;
246         } else {
247           printk(KERN_INFO "(teles_cs: looks like the 97 model)\n");
248           link->conf.ConfigIndex = cf->index;
249           for (i = 0, j = 0x2f0; j > 0x100; j -= 0x10) {
250             link->io.BasePort1 = j;
251             i = pcmcia_request_io(link, &link->io);
252             if (i == CS_SUCCESS) break;
253           }
254           break;
255         }
256         i = next_tuple(link, &tuple, &parse);
257     }
258
259     if (i != CS_SUCCESS) {
260         last_fn = RequestIO;
261         goto cs_failed;
262     }
263
264     i = pcmcia_request_irq(link, &link->irq);
265     if (i != CS_SUCCESS) {
266         link->irq.AssignedIRQ = 0;
267         last_fn = RequestIRQ;
268         goto cs_failed;
269     }
270
271     i = pcmcia_request_configuration(link, &link->conf);
272     if (i != CS_SUCCESS) {
273       last_fn = RequestConfiguration;
274       goto cs_failed;
275     }
276
277     /* At this point, the dev_node_t structure(s) should be
278        initialized and arranged in a linked list at link->dev. *//*  */
279     sprintf(dev->node.dev_name, "teles");
280     dev->node.major = dev->node.minor = 0x0;
281
282     link->dev_node = &dev->node;
283
284     /* Finally, report what we've done */
285     printk(KERN_INFO "%s: index 0x%02x:",
286            dev->node.dev_name, link->conf.ConfigIndex);
287     if (link->conf.Attributes & CONF_ENABLE_IRQ)
288         printk(", irq %d", link->irq.AssignedIRQ);
289     if (link->io.NumPorts1)
290         printk(", io 0x%04x-0x%04x", link->io.BasePort1,
291                link->io.BasePort1+link->io.NumPorts1-1);
292     if (link->io.NumPorts2)
293         printk(" & 0x%04x-0x%04x", link->io.BasePort2,
294                link->io.BasePort2+link->io.NumPorts2-1);
295     printk("\n");
296
297     icard.para[0] = link->irq.AssignedIRQ;
298     icard.para[1] = link->io.BasePort1;
299     icard.protocol = protocol;
300     icard.typ = ISDN_CTYPE_TELESPCMCIA;
301     
302     i = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->busy), &icard);
303     if (i < 0) {
304         printk(KERN_ERR "teles_cs: failed to initialize Teles PCMCIA %d at i/o %#x\n",
305                 i, link->io.BasePort1);
306         teles_cs_release(link);
307         return -ENODEV;
308     }
309
310     ((local_info_t*)link->priv)->cardnr = i;
311     return 0;
312
313 cs_failed:
314     cs_error(link, last_fn, i);
315     teles_cs_release(link);
316     return -ENODEV;
317 } /* teles_cs_config */
318
319 /*======================================================================
320
321     After a card is removed, teles_cs_release() will unregister the net
322     device, and release the PCMCIA configuration.  If the device is
323     still open, this will be postponed until it is closed.
324
325 ======================================================================*/
326
327 static void teles_cs_release(struct pcmcia_device *link)
328 {
329     local_info_t *local = link->priv;
330
331     DEBUG(0, "teles_cs_release(0x%p)\n", link);
332
333     if (local) {
334         if (local->cardnr >= 0) {
335             /* no unregister function with hisax */
336             HiSax_closecard(local->cardnr);
337         }
338     }
339
340     pcmcia_disable_device(link);
341 } /* teles_cs_release */
342
343 static int teles_suspend(struct pcmcia_device *link)
344 {
345         local_info_t *dev = link->priv;
346
347         dev->busy = 1;
348
349         return 0;
350 }
351
352 static int teles_resume(struct pcmcia_device *link)
353 {
354         local_info_t *dev = link->priv;
355
356         dev->busy = 0;
357
358         return 0;
359 }
360
361
362 static struct pcmcia_device_id teles_ids[] = {
363         PCMCIA_DEVICE_PROD_ID12("TELES", "S0/PC", 0x67b50eae, 0xe9e70119),
364         PCMCIA_DEVICE_NULL,
365 };
366 MODULE_DEVICE_TABLE(pcmcia, teles_ids);
367
368 static struct pcmcia_driver teles_cs_driver = {
369         .owner          = THIS_MODULE,
370         .drv            = {
371                 .name   = "teles_cs",
372         },
373         .probe          = teles_probe,
374         .remove         = teles_detach,
375         .id_table       = teles_ids,
376         .suspend        = teles_suspend,
377         .resume         = teles_resume,
378 };
379
380 static int __init init_teles_cs(void)
381 {
382         return pcmcia_register_driver(&teles_cs_driver);
383 }
384
385 static void __exit exit_teles_cs(void)
386 {
387         pcmcia_unregister_driver(&teles_cs_driver);
388 }
389
390 module_init(init_teles_cs);
391 module_exit(exit_teles_cs);