]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/isdn/hisax/avma1_cs.c
[PATCH] pcmcia: remove dev_link_t and client_handle_t indirection
[mirror_ubuntu-artful-kernel.git] / drivers / isdn / hisax / avma1_cs.c
CommitLineData
1da177e4
LT
1/*
2 * PCMCIA client driver for AVM A1 / Fritz!PCMCIA
3 *
4 * Author Carsten Paeth
5 * Copyright 1998-2001 by Carsten Paeth <calle@calle.in-berlin.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
14
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/sched.h>
18#include <linux/ptrace.h>
19#include <linux/slab.h>
20#include <linux/string.h>
21#include <asm/io.h>
22#include <asm/system.h>
23
1da177e4
LT
24#include <pcmcia/cs_types.h>
25#include <pcmcia/cs.h>
26#include <pcmcia/cistpl.h>
27#include <pcmcia/ds.h>
28#include "hisax_cfg.h"
29
30MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for AVM A1/Fritz!PCMCIA cards");
31MODULE_AUTHOR("Carsten Paeth");
32MODULE_LICENSE("GPL");
33
34/*
35 All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If
36 you do not define PCMCIA_DEBUG at all, all the debug code will be
37 left out. If you compile with PCMCIA_DEBUG=0, the debug code will
38 be present but disabled -- but it can then be enabled for specific
39 modules at load time with a 'pc_debug=#' option to insmod.
40*/
41#ifdef PCMCIA_DEBUG
42static int pc_debug = PCMCIA_DEBUG;
43module_param(pc_debug, int, 0);
44#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args);
45static char *version =
46"avma1_cs.c 1.00 1998/01/23 10:00:00 (Carsten Paeth)";
47#else
48#define DEBUG(n, args...)
49#endif
50
51/*====================================================================*/
52
53/* Parameters that can be set with 'insmod' */
54
55static int isdnprot = 2;
56
57module_param(isdnprot, int, 0);
58
59/*====================================================================*/
60
61/*
62 The event() function is this driver's Card Services event handler.
63 It will be called by Card Services when an appropriate card status
64 event is received. The config() and release() entry points are
65 used to configure or release a socket, in response to card insertion
66 and ejection events. They are invoked from the skeleton event
67 handler.
68*/
69
fba395ee
DB
70static void avma1cs_config(struct pcmcia_device *link);
71static void avma1cs_release(struct pcmcia_device *link);
1da177e4
LT
72
73/*
74 The attach() and detach() entry points are used to create and destroy
75 "instances" of the driver, where each instance represents everything
76 needed to manage one actual PCMCIA card.
77*/
78
cc3b4866 79static void avma1cs_detach(struct pcmcia_device *p_dev);
1da177e4 80
1da177e4
LT
81
82/*
83 A linked list of "instances" of the skeleton device. Each actual
84 PCMCIA card corresponds to one device instance, and is described
fba395ee 85 by one struct pcmcia_device structure (defined in ds.h).
1da177e4
LT
86
87 You may not want to use a linked list for this -- for example, the
fba395ee 88 memory card driver uses an array of struct pcmcia_device pointers, where minor
1da177e4
LT
89 device numbers are used to derive the corresponding array index.
90*/
91
1da177e4 92/*
1da177e4
LT
93 A driver needs to provide a dev_node_t structure for each device
94 on a card. In some cases, there is only one device per card (for
95 example, ethernet cards, modems). In other cases, there may be
96 many actual or logical devices (SCSI adapters, memory cards with
97 multiple partitions). The dev_node_t structures need to be kept
fba395ee 98 in a linked list starting at the 'dev' field of a struct pcmcia_device
1da177e4
LT
99 structure. We allocate them in the card's private data structure,
100 because they generally can't be allocated dynamically.
101*/
102
103typedef struct local_info_t {
104 dev_node_t node;
105} local_info_t;
106
107/*======================================================================
108
109 avma1cs_attach() creates an "instance" of the driver, allocating
110 local data structures for one device. The device is registered
111 with Card Services.
112
113 The dev_link structure is initialized, but we don't actually
114 configure the card at this point -- we wait until we receive a
115 card insertion event.
116
117======================================================================*/
118
f8cfa618 119static int avma1cs_attach(struct pcmcia_device *p_dev)
1da177e4 120{
1da177e4 121 local_info_t *local;
f8cfa618 122
1da177e4
LT
123 DEBUG(0, "avma1cs_attach()\n");
124
1da177e4
LT
125 /* Allocate space for private device-specific data */
126 local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
fd238232 127 if (!local)
f8cfa618 128 return -ENOMEM;
fd238232 129
1da177e4 130 memset(local, 0, sizeof(local_info_t));
fd238232 131 p_dev->priv = local;
1da177e4
LT
132
133 /* The io structure describes IO port mapping */
fd238232
DB
134 p_dev->io.NumPorts1 = 16;
135 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
136 p_dev->io.NumPorts2 = 16;
137 p_dev->io.Attributes2 = IO_DATA_PATH_WIDTH_16;
138 p_dev->io.IOAddrLines = 5;
1da177e4
LT
139
140 /* Interrupt setup */
fd238232
DB
141 p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
142 p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
1da177e4 143
fd238232 144 p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
1da177e4
LT
145
146 /* General socket configuration */
fd238232
DB
147 p_dev->conf.Attributes = CONF_ENABLE_IRQ;
148 p_dev->conf.IntType = INT_MEMORY_AND_IO;
149 p_dev->conf.ConfigIndex = 1;
150 p_dev->conf.Present = PRESENT_OPTION;
f8cfa618 151
fd238232
DB
152 p_dev->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
153 avma1cs_config(p_dev);
1da177e4 154
f8cfa618 155 return 0;
1da177e4
LT
156} /* avma1cs_attach */
157
158/*======================================================================
159
160 This deletes a driver "instance". The device is de-registered
161 with Card Services. If it has been released, all local data
162 structures are freed. Otherwise, the structures will be freed
163 when the device is released.
164
165======================================================================*/
166
fba395ee 167static void avma1cs_detach(struct pcmcia_device *link)
1da177e4 168{
1da177e4 169 DEBUG(0, "avma1cs_detach(0x%p)\n", link);
cc3b4866 170
cc3b4866
DB
171 if (link->state & DEV_CONFIG)
172 avma1cs_release(link);
1da177e4 173
3c7208f2 174 kfree(link->priv);
1da177e4
LT
175} /* avma1cs_detach */
176
177/*======================================================================
178
179 avma1cs_config() is scheduled to run after a CARD_INSERTION event
180 is received, to configure the PCMCIA socket, and to make the
181 ethernet device available to the system.
182
183======================================================================*/
184
fba395ee 185static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple,
1da177e4
LT
186 cisparse_t *parse)
187{
188 int i = pcmcia_get_tuple_data(handle, tuple);
189 if (i != CS_SUCCESS) return i;
190 return pcmcia_parse_tuple(handle, tuple, parse);
191}
192
fba395ee 193static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple,
1da177e4
LT
194 cisparse_t *parse)
195{
196 int i = pcmcia_get_first_tuple(handle, tuple);
197 if (i != CS_SUCCESS) return i;
198 return get_tuple(handle, tuple, parse);
199}
200
fba395ee 201static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple,
1da177e4
LT
202 cisparse_t *parse)
203{
204 int i = pcmcia_get_next_tuple(handle, tuple);
205 if (i != CS_SUCCESS) return i;
206 return get_tuple(handle, tuple, parse);
207}
208
fba395ee 209static void avma1cs_config(struct pcmcia_device *link)
1da177e4 210{
1da177e4
LT
211 tuple_t tuple;
212 cisparse_t parse;
213 cistpl_cftable_entry_t *cf = &parse.cftable_entry;
214 local_info_t *dev;
215 int i;
216 u_char buf[64];
217 char devname[128];
218 IsdnCard_t icard;
219 int busy = 0;
fba395ee 220
1da177e4
LT
221 dev = link->priv;
222
223 DEBUG(0, "avma1cs_config(0x%p)\n", link);
224
225 /*
226 This reads the card's CONFIG tuple to find its configuration
227 registers.
228 */
229 do {
230 tuple.DesiredTuple = CISTPL_CONFIG;
fba395ee 231 i = pcmcia_get_first_tuple(link, &tuple);
1da177e4
LT
232 if (i != CS_SUCCESS) break;
233 tuple.TupleData = buf;
234 tuple.TupleDataMax = 64;
235 tuple.TupleOffset = 0;
fba395ee 236 i = pcmcia_get_tuple_data(link, &tuple);
1da177e4 237 if (i != CS_SUCCESS) break;
fba395ee 238 i = pcmcia_parse_tuple(link, &tuple, &parse);
1da177e4
LT
239 if (i != CS_SUCCESS) break;
240 link->conf.ConfigBase = parse.config.base;
241 } while (0);
242 if (i != CS_SUCCESS) {
fba395ee 243 cs_error(link, ParseTuple, i);
1da177e4
LT
244 link->state &= ~DEV_CONFIG_PENDING;
245 return;
246 }
247
248 /* Configure card */
249 link->state |= DEV_CONFIG;
250
251 do {
252
253 tuple.Attributes = 0;
254 tuple.TupleData = buf;
255 tuple.TupleDataMax = 254;
256 tuple.TupleOffset = 0;
257 tuple.DesiredTuple = CISTPL_VERS_1;
258
259 devname[0] = 0;
fba395ee 260 if( !first_tuple(link, &tuple, &parse) && parse.version_1.ns > 1 ) {
1da177e4
LT
261 strlcpy(devname,parse.version_1.str + parse.version_1.ofs[1],
262 sizeof(devname));
263 }
264 /*
265 * find IO port
266 */
267 tuple.TupleData = (cisdata_t *)buf;
268 tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
269 tuple.Attributes = 0;
270 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
fba395ee 271 i = first_tuple(link, &tuple, &parse);
1da177e4
LT
272 while (i == CS_SUCCESS) {
273 if (cf->io.nwin > 0) {
274 link->conf.ConfigIndex = cf->index;
275 link->io.BasePort1 = cf->io.win[0].base;
276 link->io.NumPorts1 = cf->io.win[0].len;
277 link->io.NumPorts2 = 0;
278 printk(KERN_INFO "avma1_cs: testing i/o %#x-%#x\n",
279 link->io.BasePort1,
280 link->io.BasePort1+link->io.NumPorts1 - 1);
fba395ee 281 i = pcmcia_request_io(link, &link->io);
1da177e4
LT
282 if (i == CS_SUCCESS) goto found_port;
283 }
fba395ee 284 i = next_tuple(link, &tuple, &parse);
1da177e4
LT
285 }
286
287found_port:
288 if (i != CS_SUCCESS) {
fba395ee 289 cs_error(link, RequestIO, i);
1da177e4
LT
290 break;
291 }
292
293 /*
294 * allocate an interrupt line
295 */
fba395ee 296 i = pcmcia_request_irq(link, &link->irq);
1da177e4 297 if (i != CS_SUCCESS) {
fba395ee 298 cs_error(link, RequestIRQ, i);
50db3fdb 299 /* undo */
fba395ee 300 pcmcia_disable_device(link);
1da177e4
LT
301 break;
302 }
50db3fdb 303
1da177e4
LT
304 /*
305 * configure the PCMCIA socket
306 */
fba395ee 307 i = pcmcia_request_configuration(link, &link->conf);
1da177e4 308 if (i != CS_SUCCESS) {
fba395ee
DB
309 cs_error(link, RequestConfiguration, i);
310 pcmcia_disable_device(link);
1da177e4
LT
311 break;
312 }
313
314 } while (0);
315
316 /* At this point, the dev_node_t structure(s) should be
317 initialized and arranged in a linked list at link->dev. */
318
319 strcpy(dev->node.dev_name, "A1");
320 dev->node.major = 45;
321 dev->node.minor = 0;
fd238232 322 link->dev_node = &dev->node;
1da177e4
LT
323
324 link->state &= ~DEV_CONFIG_PENDING;
325 /* If any step failed, release any partially configured state */
326 if (i != 0) {
327 avma1cs_release(link);
328 return;
329 }
330
331 printk(KERN_NOTICE "avma1_cs: checking at i/o %#x, irq %d\n",
332 link->io.BasePort1, link->irq.AssignedIRQ);
333
334 icard.para[0] = link->irq.AssignedIRQ;
335 icard.para[1] = link->io.BasePort1;
336 icard.protocol = isdnprot;
337 icard.typ = ISDN_CTYPE_A1_PCMCIA;
338
339 i = hisax_init_pcmcia(link, &busy, &icard);
340 if (i < 0) {
341 printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 PCMCIA %d at i/o %#x\n", i, link->io.BasePort1);
342 avma1cs_release(link);
343 return;
344 }
345 dev->node.minor = i;
346
347} /* avma1cs_config */
348
349/*======================================================================
350
351 After a card is removed, avma1cs_release() will unregister the net
352 device, and release the PCMCIA configuration. If the device is
353 still open, this will be postponed until it is closed.
354
355======================================================================*/
356
fba395ee 357static void avma1cs_release(struct pcmcia_device *link)
1da177e4 358{
5f2a71fc 359 local_info_t *local = link->priv;
1da177e4 360
5f2a71fc 361 DEBUG(0, "avma1cs_release(0x%p)\n", link);
1da177e4 362
5f2a71fc
DB
363 /* now unregister function with hisax */
364 HiSax_closecard(local->node.minor);
1da177e4 365
fba395ee 366 pcmcia_disable_device(link);
1da177e4
LT
367} /* avma1cs_release */
368
1da177e4 369
c594c12c
DB
370static struct pcmcia_device_id avma1cs_ids[] = {
371 PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb),
372 PCMCIA_DEVICE_PROD_ID12("ISDN", "CARD", 0x8d9761c8, 0x01c5aa7b),
373 PCMCIA_DEVICE_NULL
374};
375MODULE_DEVICE_TABLE(pcmcia, avma1cs_ids);
376
1da177e4
LT
377static struct pcmcia_driver avma1cs_driver = {
378 .owner = THIS_MODULE,
379 .drv = {
380 .name = "avma1_cs",
381 },
f8cfa618 382 .probe = avma1cs_attach,
cc3b4866 383 .remove = avma1cs_detach,
c594c12c 384 .id_table = avma1cs_ids,
1da177e4 385};
8661bb5b 386
1da177e4
LT
387/*====================================================================*/
388
389static int __init init_avma1_cs(void)
390{
391 return(pcmcia_register_driver(&avma1cs_driver));
392}
393
394static void __exit exit_avma1_cs(void)
395{
396 pcmcia_unregister_driver(&avma1cs_driver);
1da177e4
LT
397}
398
399module_init(init_avma1_cs);
400module_exit(exit_avma1_cs);