blob: 0a8c1da10b4b1c30af1b04284fdf8bf8b2791f78 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* $Id: avm_cs.c,v 1.4.6.3 2001/09/23 22:24:33 kai Exp $
2 *
3 * A PCMCIA client driver for AVM B1/M1/M2
4 *
5 * Copyright 1999 by Carsten Paeth <calle@calle.de>
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include <linux/module.h>
13#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/sched.h>
16#include <linux/ptrace.h>
17#include <linux/slab.h>
18#include <linux/string.h>
19#include <linux/tty.h>
20#include <linux/serial.h>
21#include <linux/major.h>
22#include <asm/io.h>
23#include <asm/system.h>
24
Linus Torvalds1da177e2005-04-16 15:20:36 -070025#include <pcmcia/cs_types.h>
26#include <pcmcia/cs.h>
27#include <pcmcia/cistpl.h>
28#include <pcmcia/ciscode.h>
29#include <pcmcia/ds.h>
30#include <pcmcia/cisreg.h>
31
32#include <linux/skbuff.h>
33#include <linux/capi.h>
34#include <linux/b1lli.h>
35#include <linux/b1pcmcia.h>
36
37/*====================================================================*/
38
39MODULE_DESCRIPTION("CAPI4Linux: PCMCIA client driver for AVM B1/M1/M2");
40MODULE_AUTHOR("Carsten Paeth");
41MODULE_LICENSE("GPL");
42
43/*====================================================================*/
44
45/*
46 The event() function is this driver's Card Services event handler.
47 It will be called by Card Services when an appropriate card status
48 event is received. The config() and release() entry points are
49 used to configure or release a socket, in response to card insertion
50 and ejection events. They are invoked from the skeleton event
51 handler.
52*/
53
54static void avmcs_config(dev_link_t *link);
55static void avmcs_release(dev_link_t *link);
56static int avmcs_event(event_t event, int priority,
57 event_callback_args_t *args);
58
59/*
60 The attach() and detach() entry points are used to create and destroy
61 "instances" of the driver, where each instance represents everything
62 needed to manage one actual PCMCIA card.
63*/
64
65static dev_link_t *avmcs_attach(void);
Dominik Brodowskicc3b4862005-11-14 21:23:14 +010066static void avmcs_detach(struct pcmcia_device *p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
68/*
69 The dev_info variable is the "key" that is used to match up this
70 device driver with appropriate cards, through the card configuration
71 database.
72*/
73
74static dev_info_t dev_info = "avm_cs";
75
76/*
77 A linked list of "instances" of the skeleton device. Each actual
78 PCMCIA card corresponds to one device instance, and is described
79 by one dev_link_t structure (defined in ds.h).
80
81 You may not want to use a linked list for this -- for example, the
82 memory card driver uses an array of dev_link_t pointers, where minor
83 device numbers are used to derive the corresponding array index.
84*/
85
Linus Torvalds1da177e2005-04-16 15:20:36 -070086/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 A driver needs to provide a dev_node_t structure for each device
88 on a card. In some cases, there is only one device per card (for
89 example, ethernet cards, modems). In other cases, there may be
90 many actual or logical devices (SCSI adapters, memory cards with
91 multiple partitions). The dev_node_t structures need to be kept
92 in a linked list starting at the 'dev' field of a dev_link_t
93 structure. We allocate them in the card's private data structure,
94 because they generally can't be allocated dynamically.
95*/
96
97typedef struct local_info_t {
98 dev_node_t node;
99} local_info_t;
100
101/*======================================================================
102
103 avmcs_attach() creates an "instance" of the driver, allocating
104 local data structures for one device. The device is registered
105 with Card Services.
106
107 The dev_link structure is initialized, but we don't actually
108 configure the card at this point -- we wait until we receive a
109 card insertion event.
110
111======================================================================*/
112
113static dev_link_t *avmcs_attach(void)
114{
115 client_reg_t client_reg;
116 dev_link_t *link;
117 local_info_t *local;
118 int ret;
119
120 /* Initialize the dev_link_t structure */
121 link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
122 if (!link)
123 goto err;
124 memset(link, 0, sizeof(struct dev_link_t));
125
126 /* The io structure describes IO port mapping */
127 link->io.NumPorts1 = 16;
128 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
129 link->io.NumPorts2 = 0;
130
131 /* Interrupt setup */
132 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
133 link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
134
135 link->irq.IRQInfo1 = IRQ_LEVEL_ID;
136
137 /* General socket configuration */
138 link->conf.Attributes = CONF_ENABLE_IRQ;
139 link->conf.Vcc = 50;
140 link->conf.IntType = INT_MEMORY_AND_IO;
141 link->conf.ConfigIndex = 1;
142 link->conf.Present = PRESENT_OPTION;
143
144 /* Allocate space for private device-specific data */
145 local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
146 if (!local)
147 goto err_kfree;
148 memset(local, 0, sizeof(local_info_t));
149 link->priv = local;
150
151 /* Register with Card Services */
Dominik Brodowskib4635812005-11-14 21:25:35 +0100152 link->next = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 client_reg.dev_info = &dev_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 client_reg.Version = 0x0210;
155 client_reg.event_callback_args.client_data = link;
156 ret = pcmcia_register_client(&link->handle, &client_reg);
157 if (ret != 0) {
158 cs_error(link->handle, RegisterClient, ret);
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100159 avmcs_detach(link->handle);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 goto err;
161 }
162 return link;
163
164 err_kfree:
165 kfree(link);
166 err:
167 return NULL;
168} /* avmcs_attach */
169
170/*======================================================================
171
172 This deletes a driver "instance". The device is de-registered
173 with Card Services. If it has been released, all local data
174 structures are freed. Otherwise, the structures will be freed
175 when the device is released.
176
177======================================================================*/
178
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100179static void avmcs_detach(struct pcmcia_device *p_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180{
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100181 dev_link_t *link = dev_to_instance(p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100183 if (link->state & DEV_CONFIG)
184 avmcs_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185
Jesper Juhl3c7208f2005-11-07 01:01:29 -0800186 kfree(link->priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 kfree(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188} /* avmcs_detach */
189
190/*======================================================================
191
192 avmcs_config() is scheduled to run after a CARD_INSERTION event
193 is received, to configure the PCMCIA socket, and to make the
194 ethernet device available to the system.
195
196======================================================================*/
197
198static int get_tuple(client_handle_t handle, tuple_t *tuple,
199 cisparse_t *parse)
200{
201 int i = pcmcia_get_tuple_data(handle, tuple);
202 if (i != CS_SUCCESS) return i;
203 return pcmcia_parse_tuple(handle, tuple, parse);
204}
205
206static int first_tuple(client_handle_t handle, tuple_t *tuple,
207 cisparse_t *parse)
208{
209 int i = pcmcia_get_first_tuple(handle, tuple);
210 if (i != CS_SUCCESS) return i;
211 return get_tuple(handle, tuple, parse);
212}
213
214static int next_tuple(client_handle_t handle, tuple_t *tuple,
215 cisparse_t *parse)
216{
217 int i = pcmcia_get_next_tuple(handle, tuple);
218 if (i != CS_SUCCESS) return i;
219 return get_tuple(handle, tuple, parse);
220}
221
222static void avmcs_config(dev_link_t *link)
223{
224 client_handle_t handle;
225 tuple_t tuple;
226 cisparse_t parse;
227 cistpl_cftable_entry_t *cf = &parse.cftable_entry;
228 local_info_t *dev;
229 int i;
230 u_char buf[64];
231 char devname[128];
232 int cardtype;
233 int (*addcard)(unsigned int port, unsigned irq);
234
235 handle = link->handle;
236 dev = link->priv;
237
238 /*
239 This reads the card's CONFIG tuple to find its configuration
240 registers.
241 */
242 do {
243 tuple.DesiredTuple = CISTPL_CONFIG;
244 i = pcmcia_get_first_tuple(handle, &tuple);
245 if (i != CS_SUCCESS) break;
246 tuple.TupleData = buf;
247 tuple.TupleDataMax = 64;
248 tuple.TupleOffset = 0;
249 i = pcmcia_get_tuple_data(handle, &tuple);
250 if (i != CS_SUCCESS) break;
251 i = pcmcia_parse_tuple(handle, &tuple, &parse);
252 if (i != CS_SUCCESS) break;
253 link->conf.ConfigBase = parse.config.base;
254 } while (0);
255 if (i != CS_SUCCESS) {
256 cs_error(link->handle, ParseTuple, i);
257 link->state &= ~DEV_CONFIG_PENDING;
258 return;
259 }
260
261 /* Configure card */
262 link->state |= DEV_CONFIG;
263
264 do {
265
266 tuple.Attributes = 0;
267 tuple.TupleData = buf;
268 tuple.TupleDataMax = 254;
269 tuple.TupleOffset = 0;
270 tuple.DesiredTuple = CISTPL_VERS_1;
271
272 devname[0] = 0;
273 if( !first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 1 ) {
274 strlcpy(devname,parse.version_1.str + parse.version_1.ofs[1],
275 sizeof(devname));
276 }
277 /*
278 * find IO port
279 */
280 tuple.TupleData = (cisdata_t *)buf;
281 tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
282 tuple.Attributes = 0;
283 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
284 i = first_tuple(handle, &tuple, &parse);
285 while (i == CS_SUCCESS) {
286 if (cf->io.nwin > 0) {
287 link->conf.ConfigIndex = cf->index;
288 link->io.BasePort1 = cf->io.win[0].base;
289 link->io.NumPorts1 = cf->io.win[0].len;
290 link->io.NumPorts2 = 0;
291 printk(KERN_INFO "avm_cs: testing i/o %#x-%#x\n",
292 link->io.BasePort1,
293 link->io.BasePort1+link->io.NumPorts1-1);
294 i = pcmcia_request_io(link->handle, &link->io);
295 if (i == CS_SUCCESS) goto found_port;
296 }
297 i = next_tuple(handle, &tuple, &parse);
298 }
299
300found_port:
301 if (i != CS_SUCCESS) {
302 cs_error(link->handle, RequestIO, i);
303 break;
304 }
305
306 /*
307 * allocate an interrupt line
308 */
309 i = pcmcia_request_irq(link->handle, &link->irq);
310 if (i != CS_SUCCESS) {
311 cs_error(link->handle, RequestIRQ, i);
312 pcmcia_release_io(link->handle, &link->io);
313 break;
314 }
315
316 /*
317 * configure the PCMCIA socket
318 */
319 i = pcmcia_request_configuration(link->handle, &link->conf);
320 if (i != CS_SUCCESS) {
321 cs_error(link->handle, RequestConfiguration, i);
322 pcmcia_release_io(link->handle, &link->io);
323 pcmcia_release_irq(link->handle, &link->irq);
324 break;
325 }
326
327 } while (0);
328
329 /* At this point, the dev_node_t structure(s) should be
330 initialized and arranged in a linked list at link->dev. */
331
332 if (devname[0]) {
333 char *s = strrchr(devname, ' ');
334 if (!s)
335 s = devname;
336 else s++;
337 strcpy(dev->node.dev_name, s);
338 if (strcmp("M1", s) == 0) {
339 cardtype = AVM_CARDTYPE_M1;
340 } else if (strcmp("M2", s) == 0) {
341 cardtype = AVM_CARDTYPE_M2;
342 } else {
343 cardtype = AVM_CARDTYPE_B1;
344 }
345 } else {
346 strcpy(dev->node.dev_name, "b1");
347 cardtype = AVM_CARDTYPE_B1;
348 }
349
350 dev->node.major = 64;
351 dev->node.minor = 0;
352 link->dev = &dev->node;
353
354 link->state &= ~DEV_CONFIG_PENDING;
355 /* If any step failed, release any partially configured state */
356 if (i != 0) {
357 avmcs_release(link);
358 return;
359 }
360
361
362 switch (cardtype) {
363 case AVM_CARDTYPE_M1: addcard = b1pcmcia_addcard_m1; break;
364 case AVM_CARDTYPE_M2: addcard = b1pcmcia_addcard_m2; break;
365 default:
366 case AVM_CARDTYPE_B1: addcard = b1pcmcia_addcard_b1; break;
367 }
368 if ((i = (*addcard)(link->io.BasePort1, link->irq.AssignedIRQ)) < 0) {
369 printk(KERN_ERR "avm_cs: failed to add AVM-%s-Controller at i/o %#x, irq %d\n",
370 dev->node.dev_name, link->io.BasePort1, link->irq.AssignedIRQ);
371 avmcs_release(link);
372 return;
373 }
374 dev->node.minor = i;
375
376} /* avmcs_config */
377
378/*======================================================================
379
380 After a card is removed, avmcs_release() will unregister the net
381 device, and release the PCMCIA configuration. If the device is
382 still open, this will be postponed until it is closed.
383
384======================================================================*/
385
386static void avmcs_release(dev_link_t *link)
387{
388 b1pcmcia_delcard(link->io.BasePort1, link->irq.AssignedIRQ);
389
390 /* Unlink the device chain */
391 link->dev = NULL;
392
393 /* Don't bother checking to see if these succeed or not */
394 pcmcia_release_configuration(link->handle);
395 pcmcia_release_io(link->handle, &link->io);
396 pcmcia_release_irq(link->handle, &link->irq);
397 link->state &= ~DEV_CONFIG;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398} /* avmcs_release */
399
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100400static int avmcs_suspend(struct pcmcia_device *dev)
401{
402 dev_link_t *link = dev_to_instance(dev);
403
404 link->state |= DEV_SUSPEND;
405 if (link->state & DEV_CONFIG)
406 pcmcia_release_configuration(link->handle);
407
408 return 0;
409}
410
411static int avmcs_resume(struct pcmcia_device *dev)
412{
413 dev_link_t *link = dev_to_instance(dev);
414
415 link->state &= ~DEV_SUSPEND;
416 if (link->state & DEV_CONFIG)
417 pcmcia_request_configuration(link->handle, &link->conf);
418
419 return 0;
420}
421
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422/*======================================================================
423
424 The card status event handler. Mostly, this schedules other
425 stuff to run after an event is received. A CARD_REMOVAL event
426 also sets some flags to discourage the net drivers from trying
427 to talk to the card any more.
428
429 When a CARD_REMOVAL event is received, we immediately set a flag
430 to block future accesses to this device. All the functions that
431 actually access the device should check this flag to make sure
432 the card is still present.
433
434======================================================================*/
435
436static int avmcs_event(event_t event, int priority,
437 event_callback_args_t *args)
438{
439 dev_link_t *link = args->client_data;
440
441 switch (event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 case CS_EVENT_CARD_INSERTION:
443 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
444 avmcs_config(link);
445 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 }
447 return 0;
448} /* avmcs_event */
449
Dominik Brodowskia13bcf02005-06-27 16:28:35 -0700450static struct pcmcia_device_id avmcs_ids[] = {
451 PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN-Controller B1", 0x95d42008, 0x845dc335),
452 PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M1", 0x95d42008, 0x81e10430),
453 PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M2", 0x95d42008, 0x18e8558a),
454 PCMCIA_DEVICE_NULL
455};
456MODULE_DEVICE_TABLE(pcmcia, avmcs_ids);
457
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458static struct pcmcia_driver avmcs_driver = {
459 .owner = THIS_MODULE,
460 .drv = {
461 .name = "avm_cs",
462 },
463 .attach = avmcs_attach,
Dominik Brodowski1e212f32005-07-07 17:59:00 -0700464 .event = avmcs_event,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100465 .remove = avmcs_detach,
Dominik Brodowskia13bcf02005-06-27 16:28:35 -0700466 .id_table = avmcs_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100467 .suspend= avmcs_suspend,
468 .resume = avmcs_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469};
470
471static int __init avmcs_init(void)
472{
473 return pcmcia_register_driver(&avmcs_driver);
474}
475
476static void __exit avmcs_exit(void)
477{
478 pcmcia_unregister_driver(&avmcs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479}
480
481module_init(avmcs_init);
482module_exit(avmcs_exit);