1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38#include <linux/kernel.h>
39#include <linux/module.h>
40#include <linux/init.h>
41#include <linux/ptrace.h>
42#include <linux/slab.h>
43#include <linux/string.h>
44#include <linux/timer.h>
45#include <linux/ioport.h>
46#include <asm/io.h>
47#include <asm/system.h>
48
49#include <pcmcia/cs_types.h>
50#include <pcmcia/cs.h>
51#include <pcmcia/cistpl.h>
52#include <pcmcia/cisreg.h>
53#include <pcmcia/ds.h>
54#include "hisax_cfg.h"
55
56MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Sedlbauer cards");
57MODULE_AUTHOR("Marcus Niemann");
58MODULE_LICENSE("Dual MPL/GPL");
59
60
61
62
63
64
65
66
67
68#ifdef PCMCIA_DEBUG
69static int pc_debug = PCMCIA_DEBUG;
70module_param(pc_debug, int, 0);
71#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args);
72static char *version =
73"sedlbauer_cs.c 1.1a 2001/01/28 15:04:04 (M.Niemann)";
74#else
75#define DEBUG(n, args...)
76#endif
77
78
79
80
81
82
83static int protocol = 2;
84module_param(protocol, int, 0);
85
86
87
88
89
90
91
92
93
94
95
96
97static int sedlbauer_config(struct pcmcia_device *link);
98static void sedlbauer_release(struct pcmcia_device *link);
99
100
101
102
103
104
105
106static void sedlbauer_detach(struct pcmcia_device *p_dev);
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131typedef struct local_info_t {
132 struct pcmcia_device *p_dev;
133 dev_node_t node;
134 int stop;
135 int cardnr;
136} local_info_t;
137
138
139
140
141
142
143
144
145
146
147
148
149
150static int sedlbauer_probe(struct pcmcia_device *link)
151{
152 local_info_t *local;
153
154 DEBUG(0, "sedlbauer_attach()\n");
155
156
157 local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
158 if (!local) return -ENOMEM;
159 local->cardnr = -1;
160
161 local->p_dev = link;
162 link->priv = local;
163
164
165 link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
166 link->irq.IRQInfo1 = IRQ_LEVEL_ID;
167 link->irq.Handler = NULL;
168
169
170
171
172
173
174
175
176
177
178
179
180 link->io.NumPorts1 = 8;
181 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
182 link->io.IOAddrLines = 3;
183
184 link->conf.Attributes = 0;
185 link->conf.IntType = INT_MEMORY_AND_IO;
186
187 return sedlbauer_config(link);
188}
189
190
191
192
193
194
195
196
197
198
199static void sedlbauer_detach(struct pcmcia_device *link)
200{
201 DEBUG(0, "sedlbauer_detach(0x%p)\n", link);
202
203 ((local_info_t *)link->priv)->stop = 1;
204 sedlbauer_release(link);
205
206
207 kfree(link->priv);
208}
209
210
211
212
213
214
215
216
217#define CS_CHECK(fn, ret) \
218do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
219
220static int sedlbauer_config_check(struct pcmcia_device *p_dev,
221 cistpl_cftable_entry_t *cfg,
222 cistpl_cftable_entry_t *dflt,
223 unsigned int vcc,
224 void *priv_data)
225{
226 win_req_t *req = priv_data;
227
228 if (cfg->index == 0)
229 return -ENODEV;
230
231
232 if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
233 p_dev->conf.Attributes |= CONF_ENABLE_SPKR;
234 p_dev->conf.Status = CCSR_AUDIO_ENA;
235 }
236
237
238
239 if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
240 if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
241 return -ENODEV;
242 } else if (dflt->vcc.present & (1<<CISTPL_POWER_VNOM)) {
243 if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM]/10000)
244 return -ENODEV;
245 }
246
247 if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
248 p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
249 else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM))
250 p_dev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM]/10000;
251
252
253 if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1)
254 p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
255
256
257 p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
258 if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
259 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
260 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
261 if (!(io->flags & CISTPL_IO_8BIT))
262 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
263 if (!(io->flags & CISTPL_IO_16BIT))
264 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
265 p_dev->io.BasePort1 = io->win[0].base;
266 p_dev->io.NumPorts1 = io->win[0].len;
267 if (io->nwin > 1) {
268 p_dev->io.Attributes2 = p_dev->io.Attributes1;
269 p_dev->io.BasePort2 = io->win[1].base;
270 p_dev->io.NumPorts2 = io->win[1].len;
271 }
272
273 if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
274 return -ENODEV;
275 }
276
277
278
279
280
281
282
283
284
285
286
287
288 if ((cfg->mem.nwin > 0) || (dflt->mem.nwin > 0)) {
289 cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &dflt->mem;
290 memreq_t map;
291 req->Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
292 req->Attributes |= WIN_ENABLE;
293 req->Base = mem->win[0].host_addr;
294 req->Size = mem->win[0].len;
295 req->AccessSpeed = 0;
296 if (pcmcia_request_window(&p_dev, req, &p_dev->win) != 0)
297 return -ENODEV;
298 map.Page = 0;
299 map.CardOffset = mem->win[0].card_addr;
300 if (pcmcia_map_mem_page(p_dev->win, &map) != 0)
301 return -ENODEV;
302 }
303 return 0;
304}
305
306
307
308static int sedlbauer_config(struct pcmcia_device *link)
309{
310 local_info_t *dev = link->priv;
311 win_req_t *req;
312 int last_fn, last_ret;
313 IsdnCard_t icard;
314
315 DEBUG(0, "sedlbauer_config(0x%p)\n", link);
316
317 req = kzalloc(sizeof(win_req_t), GFP_KERNEL);
318 if (!req)
319 return -ENOMEM;
320
321
322
323
324
325
326
327
328
329
330
331
332
333 last_ret = pcmcia_loop_config(link, sedlbauer_config_check, req);
334 if (last_ret)
335 goto failed;
336
337
338
339
340
341
342 if (link->conf.Attributes & CONF_ENABLE_IRQ)
343 CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
344
345
346
347
348
349
350 CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
351
352
353
354
355
356 sprintf(dev->node.dev_name, "sedlbauer");
357 dev->node.major = dev->node.minor = 0;
358 link->dev_node = &dev->node;
359
360
361 printk(KERN_INFO "%s: index 0x%02x:",
362 dev->node.dev_name, link->conf.ConfigIndex);
363 if (link->conf.Vpp)
364 printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10);
365 if (link->conf.Attributes & CONF_ENABLE_IRQ)
366 printk(", irq %d", link->irq.AssignedIRQ);
367 if (link->io.NumPorts1)
368 printk(", io 0x%04x-0x%04x", link->io.BasePort1,
369 link->io.BasePort1+link->io.NumPorts1-1);
370 if (link->io.NumPorts2)
371 printk(" & 0x%04x-0x%04x", link->io.BasePort2,
372 link->io.BasePort2+link->io.NumPorts2-1);
373 if (link->win)
374 printk(", mem 0x%06lx-0x%06lx", req->Base,
375 req->Base+req->Size-1);
376 printk("\n");
377
378 icard.para[0] = link->irq.AssignedIRQ;
379 icard.para[1] = link->io.BasePort1;
380 icard.protocol = protocol;
381 icard.typ = ISDN_CTYPE_SEDLBAUER_PCMCIA;
382
383 last_ret = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->stop), &icard);
384 if (last_ret < 0) {
385 printk(KERN_ERR "sedlbauer_cs: failed to initialize SEDLBAUER PCMCIA %d at i/o %#x\n",
386 last_ret, link->io.BasePort1);
387 sedlbauer_release(link);
388 return -ENODEV;
389 } else
390 ((local_info_t*)link->priv)->cardnr = last_ret;
391
392 return 0;
393
394cs_failed:
395 cs_error(link, last_fn, last_ret);
396failed:
397 sedlbauer_release(link);
398 return -ENODEV;
399
400}
401
402
403
404
405
406
407
408
409
410static void sedlbauer_release(struct pcmcia_device *link)
411{
412 local_info_t *local = link->priv;
413 DEBUG(0, "sedlbauer_release(0x%p)\n", link);
414
415 if (local) {
416 if (local->cardnr >= 0) {
417
418 HiSax_closecard(local->cardnr);
419 }
420 }
421
422 pcmcia_disable_device(link);
423}
424
425static int sedlbauer_suspend(struct pcmcia_device *link)
426{
427 local_info_t *dev = link->priv;
428
429 dev->stop = 1;
430
431 return 0;
432}
433
434static int sedlbauer_resume(struct pcmcia_device *link)
435{
436 local_info_t *dev = link->priv;
437
438 dev->stop = 0;
439
440 return 0;
441}
442
443
444static struct pcmcia_device_id sedlbauer_ids[] = {
445 PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "speed star II", "V 3.1", 0x81fb79f5, 0xf3612e1d, 0x6b95c78a),
446 PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D67", 0x81fb79f5, 0xe4e9bc12, 0x397b7e90),
447 PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D98", 0x81fb79f5, 0xe4e9bc12, 0x2e5c7fce),
448 PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", " (C) 93-94 VK", 0x81fb79f5, 0xe4e9bc12, 0x8db143fe),
449 PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", " (c) 93-95 VK", 0x81fb79f5, 0xe4e9bc12, 0xb391ab4c),
450 PCMCIA_DEVICE_PROD_ID12("HST High Soft Tech GmbH", "Saphir II B", 0xd79e0b84, 0x21d083ae),
451
452 PCMCIA_DEVICE_NULL
453};
454MODULE_DEVICE_TABLE(pcmcia, sedlbauer_ids);
455
456static struct pcmcia_driver sedlbauer_driver = {
457 .owner = THIS_MODULE,
458 .drv = {
459 .name = "sedlbauer_cs",
460 },
461 .probe = sedlbauer_probe,
462 .remove = sedlbauer_detach,
463 .id_table = sedlbauer_ids,
464 .suspend = sedlbauer_suspend,
465 .resume = sedlbauer_resume,
466};
467
468static int __init init_sedlbauer_cs(void)
469{
470 return pcmcia_register_driver(&sedlbauer_driver);
471}
472
473static void __exit exit_sedlbauer_cs(void)
474{
475 pcmcia_unregister_driver(&sedlbauer_driver);
476}
477
478module_init(init_sedlbauer_cs);
479module_exit(exit_sedlbauer_cs);
480