1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/init.h>
22#include <linux/ptrace.h>
23#include <linux/slab.h>
24#include <linux/string.h>
25#include <linux/timer.h>
26#include <linux/ioport.h>
27#include <asm/io.h>
28#include <asm/system.h>
29
30#include <pcmcia/cs_types.h>
31#include <pcmcia/cs.h>
32#include <pcmcia/cistpl.h>
33#include <pcmcia/cisreg.h>
34#include <pcmcia/ds.h>
35#include "hisax_cfg.h"
36
37MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Teles PCMCIA cards");
38MODULE_AUTHOR("Christof Petig, christof.petig@wtal.de, Karsten Keil, kkeil@suse.de");
39MODULE_LICENSE("GPL");
40
41
42
43
44
45
46
47
48
49#ifdef PCMCIA_DEBUG
50static int pc_debug = PCMCIA_DEBUG;
51module_param(pc_debug, int, 0);
52#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args);
53static char *version =
54"teles_cs.c 2.10 2002/07/30 22:23:34 kkeil";
55#else
56#define DEBUG(n, args...)
57#endif
58
59
60
61
62
63static int protocol = 2;
64module_param(protocol, int, 0);
65
66
67
68
69
70
71
72
73
74
75
76
77static int teles_cs_config(struct pcmcia_device *link);
78static void teles_cs_release(struct pcmcia_device *link);
79
80
81
82
83
84
85
86static void teles_detach(struct pcmcia_device *p_dev);
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113typedef struct local_info_t {
114 struct pcmcia_device *p_dev;
115 dev_node_t node;
116 int busy;
117 int cardnr;
118} local_info_t;
119
120
121
122
123
124
125
126
127
128
129
130
131
132static int teles_probe(struct pcmcia_device *link)
133{
134 local_info_t *local;
135
136 DEBUG(0, "teles_attach()\n");
137
138
139 local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
140 if (!local) return -ENOMEM;
141 local->cardnr = -1;
142
143 local->p_dev = link;
144 link->priv = local;
145
146
147 link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
148 link->irq.IRQInfo1 = IRQ_LEVEL_ID|IRQ_SHARE_ID;
149 link->irq.Handler = NULL;
150
151
152
153
154
155
156
157
158 link->io.NumPorts1 = 96;
159 link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
160 link->io.IOAddrLines = 5;
161
162 link->conf.Attributes = CONF_ENABLE_IRQ;
163 link->conf.IntType = INT_MEMORY_AND_IO;
164
165 return teles_cs_config(link);
166}
167
168
169
170
171
172
173
174
175
176
177static void teles_detach(struct pcmcia_device *link)
178{
179 local_info_t *info = link->priv;
180
181 DEBUG(0, "teles_detach(0x%p)\n", link);
182
183 info->busy = 1;
184 teles_cs_release(link);
185
186 kfree(info);
187}
188
189
190
191
192
193
194
195
196
197static int teles_cs_configcheck(struct pcmcia_device *p_dev,
198 cistpl_cftable_entry_t *cf,
199 cistpl_cftable_entry_t *dflt,
200 unsigned int vcc,
201 void *priv_data)
202{
203 int j;
204
205 if ((cf->io.nwin > 0) && cf->io.win[0].base) {
206 printk(KERN_INFO "(teles_cs: looks like the 96 model)\n");
207 p_dev->io.BasePort1 = cf->io.win[0].base;
208 if (!pcmcia_request_io(p_dev, &p_dev->io))
209 return 0;
210 } else {
211 printk(KERN_INFO "(teles_cs: looks like the 97 model)\n");
212 for (j = 0x2f0; j > 0x100; j -= 0x10) {
213 p_dev->io.BasePort1 = j;
214 if (!pcmcia_request_io(p_dev, &p_dev->io))
215 return 0;
216 }
217 }
218 return -ENODEV;
219}
220
221static int teles_cs_config(struct pcmcia_device *link)
222{
223 local_info_t *dev;
224 int i, last_fn;
225 IsdnCard_t icard;
226
227 DEBUG(0, "teles_config(0x%p)\n", link);
228 dev = link->priv;
229
230 i = pcmcia_loop_config(link, teles_cs_configcheck, NULL);
231 if (i != 0) {
232 last_fn = RequestIO;
233 goto cs_failed;
234 }
235
236 i = pcmcia_request_irq(link, &link->irq);
237 if (i != 0) {
238 link->irq.AssignedIRQ = 0;
239 last_fn = RequestIRQ;
240 goto cs_failed;
241 }
242
243 i = pcmcia_request_configuration(link, &link->conf);
244 if (i != 0) {
245 last_fn = RequestConfiguration;
246 goto cs_failed;
247 }
248
249
250
251 sprintf(dev->node.dev_name, "teles");
252 dev->node.major = dev->node.minor = 0x0;
253
254 link->dev_node = &dev->node;
255
256
257 printk(KERN_INFO "%s: index 0x%02x:",
258 dev->node.dev_name, link->conf.ConfigIndex);
259 if (link->conf.Attributes & CONF_ENABLE_IRQ)
260 printk(", irq %d", link->irq.AssignedIRQ);
261 if (link->io.NumPorts1)
262 printk(", io 0x%04x-0x%04x", link->io.BasePort1,
263 link->io.BasePort1+link->io.NumPorts1-1);
264 if (link->io.NumPorts2)
265 printk(" & 0x%04x-0x%04x", link->io.BasePort2,
266 link->io.BasePort2+link->io.NumPorts2-1);
267 printk("\n");
268
269 icard.para[0] = link->irq.AssignedIRQ;
270 icard.para[1] = link->io.BasePort1;
271 icard.protocol = protocol;
272 icard.typ = ISDN_CTYPE_TELESPCMCIA;
273
274 i = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->busy), &icard);
275 if (i < 0) {
276 printk(KERN_ERR "teles_cs: failed to initialize Teles PCMCIA %d at i/o %#x\n",
277 i, link->io.BasePort1);
278 teles_cs_release(link);
279 return -ENODEV;
280 }
281
282 ((local_info_t*)link->priv)->cardnr = i;
283 return 0;
284
285cs_failed:
286 cs_error(link, last_fn, i);
287 teles_cs_release(link);
288 return -ENODEV;
289}
290
291
292
293
294
295
296
297
298
299static void teles_cs_release(struct pcmcia_device *link)
300{
301 local_info_t *local = link->priv;
302
303 DEBUG(0, "teles_cs_release(0x%p)\n", link);
304
305 if (local) {
306 if (local->cardnr >= 0) {
307
308 HiSax_closecard(local->cardnr);
309 }
310 }
311
312 pcmcia_disable_device(link);
313}
314
315static int teles_suspend(struct pcmcia_device *link)
316{
317 local_info_t *dev = link->priv;
318
319 dev->busy = 1;
320
321 return 0;
322}
323
324static int teles_resume(struct pcmcia_device *link)
325{
326 local_info_t *dev = link->priv;
327
328 dev->busy = 0;
329
330 return 0;
331}
332
333
334static struct pcmcia_device_id teles_ids[] = {
335 PCMCIA_DEVICE_PROD_ID12("TELES", "S0/PC", 0x67b50eae, 0xe9e70119),
336 PCMCIA_DEVICE_NULL,
337};
338MODULE_DEVICE_TABLE(pcmcia, teles_ids);
339
340static struct pcmcia_driver teles_cs_driver = {
341 .owner = THIS_MODULE,
342 .drv = {
343 .name = "teles_cs",
344 },
345 .probe = teles_probe,
346 .remove = teles_detach,
347 .id_table = teles_ids,
348 .suspend = teles_suspend,
349 .resume = teles_resume,
350};
351
352static int __init init_teles_cs(void)
353{
354 return pcmcia_register_driver(&teles_cs_driver);
355}
356
357static void __exit exit_teles_cs(void)
358{
359 pcmcia_unregister_driver(&teles_cs_driver);
360}
361
362module_init(init_teles_cs);
363module_exit(exit_teles_cs);
364