]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/isdn/hisax/avma1_cs.c
pcmcia: re-work pcmcia_request_irq()
[net-next-2.6.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>
1da177e4
LT
17#include <linux/ptrace.h>
18#include <linux/slab.h>
19#include <linux/string.h>
20#include <asm/io.h>
21#include <asm/system.h>
22
1da177e4
LT
23#include <pcmcia/cs_types.h>
24#include <pcmcia/cs.h>
25#include <pcmcia/cistpl.h>
26#include <pcmcia/ds.h>
27#include "hisax_cfg.h"
28
29MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for AVM A1/Fritz!PCMCIA cards");
30MODULE_AUTHOR("Carsten Paeth");
31MODULE_LICENSE("GPL");
32
1da177e4
LT
33
34/*====================================================================*/
35
36/* Parameters that can be set with 'insmod' */
37
38static int isdnprot = 2;
39
40module_param(isdnprot, int, 0);
41
42/*====================================================================*/
43
44/*
45 The event() function is this driver's Card Services event handler.
46 It will be called by Card Services when an appropriate card status
47 event is received. The config() and release() entry points are
48 used to configure or release a socket, in response to card insertion
49 and ejection events. They are invoked from the skeleton event
50 handler.
51*/
52
a465870a 53static int avma1cs_config(struct pcmcia_device *link) __devinit ;
fba395ee 54static void avma1cs_release(struct pcmcia_device *link);
1da177e4
LT
55
56/*
57 The attach() and detach() entry points are used to create and destroy
58 "instances" of the driver, where each instance represents everything
59 needed to manage one actual PCMCIA card.
60*/
61
a465870a 62static void avma1cs_detach(struct pcmcia_device *p_dev) __devexit ;
1da177e4 63
1da177e4
LT
64
65/*
66 A linked list of "instances" of the skeleton device. Each actual
67 PCMCIA card corresponds to one device instance, and is described
fba395ee 68 by one struct pcmcia_device structure (defined in ds.h).
1da177e4
LT
69
70 You may not want to use a linked list for this -- for example, the
fba395ee 71 memory card driver uses an array of struct pcmcia_device pointers, where minor
1da177e4
LT
72 device numbers are used to derive the corresponding array index.
73*/
74
1da177e4 75/*
1da177e4
LT
76 A driver needs to provide a dev_node_t structure for each device
77 on a card. In some cases, there is only one device per card (for
78 example, ethernet cards, modems). In other cases, there may be
79 many actual or logical devices (SCSI adapters, memory cards with
80 multiple partitions). The dev_node_t structures need to be kept
fba395ee 81 in a linked list starting at the 'dev' field of a struct pcmcia_device
1da177e4
LT
82 structure. We allocate them in the card's private data structure,
83 because they generally can't be allocated dynamically.
84*/
85
86typedef struct local_info_t {
87 dev_node_t node;
88} local_info_t;
89
90/*======================================================================
91
92 avma1cs_attach() creates an "instance" of the driver, allocating
93 local data structures for one device. The device is registered
94 with Card Services.
95
96 The dev_link structure is initialized, but we don't actually
97 configure the card at this point -- we wait until we receive a
98 card insertion event.
99
100======================================================================*/
101
a465870a 102static int __devinit avma1cs_probe(struct pcmcia_device *p_dev)
1da177e4 103{
1da177e4 104 local_info_t *local;
f8cfa618 105
e773cfe1 106 dev_dbg(&p_dev->dev, "avma1cs_attach()\n");
1da177e4 107
1da177e4 108 /* Allocate space for private device-specific data */
41f96935 109 local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
fd238232 110 if (!local)
f8cfa618 111 return -ENOMEM;
fd238232 112
fd238232 113 p_dev->priv = local;
1da177e4
LT
114
115 /* The io structure describes IO port mapping */
fd238232
DB
116 p_dev->io.NumPorts1 = 16;
117 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
118 p_dev->io.NumPorts2 = 16;
119 p_dev->io.Attributes2 = IO_DATA_PATH_WIDTH_16;
120 p_dev->io.IOAddrLines = 5;
1da177e4 121
1da177e4 122 /* General socket configuration */
fd238232
DB
123 p_dev->conf.Attributes = CONF_ENABLE_IRQ;
124 p_dev->conf.IntType = INT_MEMORY_AND_IO;
125 p_dev->conf.ConfigIndex = 1;
126 p_dev->conf.Present = PRESENT_OPTION;
f8cfa618 127
15b99ac1 128 return avma1cs_config(p_dev);
1da177e4
LT
129} /* avma1cs_attach */
130
131/*======================================================================
132
133 This deletes a driver "instance". The device is de-registered
134 with Card Services. If it has been released, all local data
135 structures are freed. Otherwise, the structures will be freed
136 when the device is released.
137
138======================================================================*/
139
a465870a 140static void __devexit avma1cs_detach(struct pcmcia_device *link)
1da177e4 141{
e773cfe1 142 dev_dbg(&link->dev, "avma1cs_detach(0x%p)\n", link);
e2d40963
DB
143 avma1cs_release(link);
144 kfree(link->priv);
1da177e4
LT
145} /* avma1cs_detach */
146
147/*======================================================================
148
149 avma1cs_config() is scheduled to run after a CARD_INSERTION event
150 is received, to configure the PCMCIA socket, and to make the
151 ethernet device available to the system.
152
153======================================================================*/
154
5fcd4da0 155static int avma1cs_configcheck(struct pcmcia_device *p_dev,
8e2fc39d
DB
156 cistpl_cftable_entry_t *cf,
157 cistpl_cftable_entry_t *dflt,
ad913c11 158 unsigned int vcc,
8e2fc39d 159 void *priv_data)
1da177e4 160{
5fcd4da0
DB
161 if (cf->io.nwin <= 0)
162 return -ENODEV;
163
5fcd4da0
DB
164 p_dev->io.BasePort1 = cf->io.win[0].base;
165 p_dev->io.NumPorts1 = cf->io.win[0].len;
166 p_dev->io.NumPorts2 = 0;
167 printk(KERN_INFO "avma1_cs: testing i/o %#x-%#x\n",
168 p_dev->io.BasePort1,
169 p_dev->io.BasePort1+p_dev->io.NumPorts1-1);
170 return pcmcia_request_io(p_dev, &p_dev->io);
1da177e4
LT
171}
172
1da177e4 173
a465870a 174static int __devinit avma1cs_config(struct pcmcia_device *link)
1da177e4 175{
1da177e4 176 local_info_t *dev;
eb14120f 177 int i = -1;
1da177e4
LT
178 char devname[128];
179 IsdnCard_t icard;
180 int busy = 0;
fba395ee 181
1da177e4
LT
182 dev = link->priv;
183
e773cfe1 184 dev_dbg(&link->dev, "avma1cs_config(0x%p)\n", link);
1da177e4 185
5fcd4da0
DB
186 devname[0] = 0;
187 if (link->prod_id[1])
188 strlcpy(devname, link->prod_id[1], sizeof(devname));
a9606fd3 189
5fcd4da0
DB
190 if (pcmcia_loop_config(link, avma1cs_configcheck, NULL))
191 return -ENODEV;
1da177e4 192
5fcd4da0 193 do {
1da177e4
LT
194 /*
195 * allocate an interrupt line
196 */
eb14120f 197 if (!link->irq) {
50db3fdb 198 /* undo */
fba395ee 199 pcmcia_disable_device(link);
1da177e4
LT
200 break;
201 }
50db3fdb 202
1da177e4
LT
203 /*
204 * configure the PCMCIA socket
205 */
fba395ee 206 i = pcmcia_request_configuration(link, &link->conf);
4c89e88b 207 if (i != 0) {
fba395ee 208 pcmcia_disable_device(link);
1da177e4
LT
209 break;
210 }
211
212 } while (0);
213
214 /* At this point, the dev_node_t structure(s) should be
215 initialized and arranged in a linked list at link->dev. */
216
217 strcpy(dev->node.dev_name, "A1");
218 dev->node.major = 45;
219 dev->node.minor = 0;
fd238232 220 link->dev_node = &dev->node;
e2d40963 221
1da177e4
LT
222 /* If any step failed, release any partially configured state */
223 if (i != 0) {
224 avma1cs_release(link);
15b99ac1 225 return -ENODEV;
1da177e4
LT
226 }
227
228 printk(KERN_NOTICE "avma1_cs: checking at i/o %#x, irq %d\n",
eb14120f 229 link->io.BasePort1, link->irq);
1da177e4 230
eb14120f 231 icard.para[0] = link->irq;
1da177e4
LT
232 icard.para[1] = link->io.BasePort1;
233 icard.protocol = isdnprot;
234 icard.typ = ISDN_CTYPE_A1_PCMCIA;
235
236 i = hisax_init_pcmcia(link, &busy, &icard);
237 if (i < 0) {
238 printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 PCMCIA %d at i/o %#x\n", i, link->io.BasePort1);
239 avma1cs_release(link);
15b99ac1 240 return -ENODEV;
1da177e4
LT
241 }
242 dev->node.minor = i;
243
15b99ac1 244 return 0;
1da177e4
LT
245} /* avma1cs_config */
246
247/*======================================================================
248
249 After a card is removed, avma1cs_release() will unregister the net
250 device, and release the PCMCIA configuration. If the device is
251 still open, this will be postponed until it is closed.
252
253======================================================================*/
254
fba395ee 255static void avma1cs_release(struct pcmcia_device *link)
1da177e4 256{
5f2a71fc 257 local_info_t *local = link->priv;
1da177e4 258
e773cfe1 259 dev_dbg(&link->dev, "avma1cs_release(0x%p)\n", link);
1da177e4 260
5f2a71fc
DB
261 /* now unregister function with hisax */
262 HiSax_closecard(local->node.minor);
1da177e4 263
fba395ee 264 pcmcia_disable_device(link);
1da177e4
LT
265} /* avma1cs_release */
266
1da177e4 267
c594c12c
DB
268static struct pcmcia_device_id avma1cs_ids[] = {
269 PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb),
270 PCMCIA_DEVICE_PROD_ID12("ISDN", "CARD", 0x8d9761c8, 0x01c5aa7b),
271 PCMCIA_DEVICE_NULL
272};
273MODULE_DEVICE_TABLE(pcmcia, avma1cs_ids);
274
1da177e4
LT
275static struct pcmcia_driver avma1cs_driver = {
276 .owner = THIS_MODULE,
277 .drv = {
278 .name = "avma1_cs",
279 },
15b99ac1 280 .probe = avma1cs_probe,
a465870a 281 .remove = __devexit_p(avma1cs_detach),
c594c12c 282 .id_table = avma1cs_ids,
1da177e4 283};
8661bb5b 284
1da177e4
LT
285/*====================================================================*/
286
287static int __init init_avma1_cs(void)
288{
289 return(pcmcia_register_driver(&avma1cs_driver));
290}
291
292static void __exit exit_avma1_cs(void)
293{
294 pcmcia_unregister_driver(&avma1cs_driver);
1da177e4
LT
295}
296
297module_init(init_avma1_cs);
298module_exit(exit_avma1_cs);