1
2
3
4
5
6
7
8
9
10
11
12#include <linux/module.h>
13
14
15#include <linux/kernel.h>
16#include <linux/init.h>
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
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
33
34
35
36
37
38
39
40#ifdef PCMCIA_DEBUG
41static int pc_debug = PCMCIA_DEBUG;
42module_param(pc_debug, int, 0);
43#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args);
44static char *version =
45"avma1_cs.c 1.00 1998/01/23 10:00:00 (Carsten Paeth)";
46#else
47#define DEBUG(n, args...)
48#endif
49
50
51
52
53
54static int isdnprot = 2;
55
56module_param(isdnprot, int, 0);
57
58
59
60
61
62
63
64
65
66
67
68
69static int avma1cs_config(struct pcmcia_device *link);
70static void avma1cs_release(struct pcmcia_device *link);
71
72
73
74
75
76
77
78static void avma1cs_detach(struct pcmcia_device *p_dev);
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102typedef struct local_info_t {
103 dev_node_t node;
104} local_info_t;
105
106
107
108
109
110
111
112
113
114
115
116
117
118static int avma1cs_probe(struct pcmcia_device *p_dev)
119{
120 local_info_t *local;
121
122 DEBUG(0, "avma1cs_attach()\n");
123
124
125 local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
126 if (!local)
127 return -ENOMEM;
128
129 p_dev->priv = local;
130
131
132 p_dev->io.NumPorts1 = 16;
133 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
134 p_dev->io.NumPorts2 = 16;
135 p_dev->io.Attributes2 = IO_DATA_PATH_WIDTH_16;
136 p_dev->io.IOAddrLines = 5;
137
138
139 p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
140 p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
141
142 p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
143
144
145 p_dev->conf.Attributes = CONF_ENABLE_IRQ;
146 p_dev->conf.IntType = INT_MEMORY_AND_IO;
147 p_dev->conf.ConfigIndex = 1;
148 p_dev->conf.Present = PRESENT_OPTION;
149
150 return avma1cs_config(p_dev);
151}
152
153
154
155
156
157
158
159
160
161
162static void avma1cs_detach(struct pcmcia_device *link)
163{
164 DEBUG(0, "avma1cs_detach(0x%p)\n", link);
165 avma1cs_release(link);
166 kfree(link->priv);
167}
168
169
170
171
172
173
174
175
176
177static int avma1cs_configcheck(struct pcmcia_device *p_dev,
178 cistpl_cftable_entry_t *cf,
179 cistpl_cftable_entry_t *dflt,
180 unsigned int vcc,
181 void *priv_data)
182{
183 if (cf->io.nwin <= 0)
184 return -ENODEV;
185
186 p_dev->io.BasePort1 = cf->io.win[0].base;
187 p_dev->io.NumPorts1 = cf->io.win[0].len;
188 p_dev->io.NumPorts2 = 0;
189 printk(KERN_INFO "avma1_cs: testing i/o %#x-%#x\n",
190 p_dev->io.BasePort1,
191 p_dev->io.BasePort1+p_dev->io.NumPorts1-1);
192 return pcmcia_request_io(p_dev, &p_dev->io);
193}
194
195
196static int avma1cs_config(struct pcmcia_device *link)
197{
198 local_info_t *dev;
199 int i;
200 char devname[128];
201 IsdnCard_t icard;
202 int busy = 0;
203
204 dev = link->priv;
205
206 DEBUG(0, "avma1cs_config(0x%p)\n", link);
207
208 devname[0] = 0;
209 if (link->prod_id[1])
210 strlcpy(devname, link->prod_id[1], sizeof(devname));
211
212 if (pcmcia_loop_config(link, avma1cs_configcheck, NULL))
213 return -ENODEV;
214
215 do {
216
217
218
219 i = pcmcia_request_irq(link, &link->irq);
220 if (i != 0) {
221 cs_error(link, RequestIRQ, i);
222
223 pcmcia_disable_device(link);
224 break;
225 }
226
227
228
229
230 i = pcmcia_request_configuration(link, &link->conf);
231 if (i != 0) {
232 cs_error(link, RequestConfiguration, i);
233 pcmcia_disable_device(link);
234 break;
235 }
236
237 } while (0);
238
239
240
241
242 strcpy(dev->node.dev_name, "A1");
243 dev->node.major = 45;
244 dev->node.minor = 0;
245 link->dev_node = &dev->node;
246
247
248 if (i != 0) {
249 avma1cs_release(link);
250 return -ENODEV;
251 }
252
253 printk(KERN_NOTICE "avma1_cs: checking at i/o %#x, irq %d\n",
254 link->io.BasePort1, link->irq.AssignedIRQ);
255
256 icard.para[0] = link->irq.AssignedIRQ;
257 icard.para[1] = link->io.BasePort1;
258 icard.protocol = isdnprot;
259 icard.typ = ISDN_CTYPE_A1_PCMCIA;
260
261 i = hisax_init_pcmcia(link, &busy, &icard);
262 if (i < 0) {
263 printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 PCMCIA %d at i/o %#x\n", i, link->io.BasePort1);
264 avma1cs_release(link);
265 return -ENODEV;
266 }
267 dev->node.minor = i;
268
269 return 0;
270}
271
272
273
274
275
276
277
278
279
280static void avma1cs_release(struct pcmcia_device *link)
281{
282 local_info_t *local = link->priv;
283
284 DEBUG(0, "avma1cs_release(0x%p)\n", link);
285
286
287 HiSax_closecard(local->node.minor);
288
289 pcmcia_disable_device(link);
290}
291
292
293static struct pcmcia_device_id avma1cs_ids[] = {
294 PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb),
295 PCMCIA_DEVICE_PROD_ID12("ISDN", "CARD", 0x8d9761c8, 0x01c5aa7b),
296 PCMCIA_DEVICE_NULL
297};
298MODULE_DEVICE_TABLE(pcmcia, avma1cs_ids);
299
300static struct pcmcia_driver avma1cs_driver = {
301 .owner = THIS_MODULE,
302 .drv = {
303 .name = "avma1_cs",
304 },
305 .probe = avma1cs_probe,
306 .remove = avma1cs_detach,
307 .id_table = avma1cs_ids,
308};
309
310
311
312static int __init init_avma1_cs(void)
313{
314 return(pcmcia_register_driver(&avma1cs_driver));
315}
316
317static void __exit exit_avma1_cs(void)
318{
319 pcmcia_unregister_driver(&avma1cs_driver);
320}
321
322module_init(init_avma1_cs);
323module_exit(exit_avma1_cs);
324