blob: 4e5c14c7240e1c1be95c177d2a6b29d037820f94 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* $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
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#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
38MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Teles PCMCIA cards");
39MODULE_AUTHOR("Christof Petig, christof.petig@wtal.de, Karsten Keil, kkeil@suse.de");
40MODULE_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
51static int pc_debug = PCMCIA_DEBUG;
52module_param(pc_debug, int, 0);
53#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args);
54static 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
64static int protocol = 2; /* EURO-ISDN Default */
65module_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
78static void teles_cs_config(dev_link_t *link);
79static void teles_cs_release(dev_link_t *link);
Linus Torvalds1da177e2005-04-16 15:20:36 -070080
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
Dominik Brodowskicc3b4862005-11-14 21:23:14 +010087static void teles_detach(struct pcmcia_device *p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070088
89/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 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
Linus Torvalds1da177e2005-04-16 15:20:36 -070099/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 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
114typedef 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
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100133static int teles_attach(struct pcmcia_device *p_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 dev_link_t *link;
136 local_info_t *local;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137
138 DEBUG(0, "teles_attach()\n");
139
140 /* Allocate space for private device-specific data */
141 local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100142 if (!local) return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 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
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100167 link->handle = p_dev;
168 p_dev->instance = link;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100170 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
171 teles_cs_config(link);
172
173 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174} /* 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
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100185static void teles_detach(struct pcmcia_device *p_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186{
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100187 dev_link_t *link = dev_to_instance(p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 local_info_t *info = link->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
190 DEBUG(0, "teles_detach(0x%p)\n", link);
191
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100192 if (link->state & DEV_CONFIG) {
Dominik Brodowskib4635812005-11-14 21:25:35 +0100193 info->busy = 1;
194 teles_cs_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 }
196
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 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======================================================================*/
208static 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
216static 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
224static 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
232static 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;
349cs_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
362static 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
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100386static 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
399static 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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412
Dominik Brodowski0a10d732005-06-27 16:28:24 -0700413static struct pcmcia_device_id teles_ids[] = {
414 PCMCIA_DEVICE_PROD_ID12("TELES", "S0/PC", 0x67b50eae, 0xe9e70119),
415 PCMCIA_DEVICE_NULL,
416};
417MODULE_DEVICE_TABLE(pcmcia, teles_ids);
418
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419static struct pcmcia_driver teles_cs_driver = {
420 .owner = THIS_MODULE,
421 .drv = {
422 .name = "teles_cs",
423 },
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100424 .probe = teles_attach,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100425 .remove = teles_detach,
Dominik Brodowski0a10d732005-06-27 16:28:24 -0700426 .id_table = teles_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100427 .suspend = teles_suspend,
428 .resume = teles_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429};
430
431static int __init init_teles_cs(void)
432{
433 return pcmcia_register_driver(&teles_cs_driver);
434}
435
436static void __exit exit_teles_cs(void)
437{
438 pcmcia_unregister_driver(&teles_cs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439}
440
441module_init(init_teles_cs);
442module_exit(exit_teles_cs);