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/module.h>
39#include <linux/kernel.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
48#include <pcmcia/cistpl.h>
49#include <pcmcia/cisreg.h>
50#include <pcmcia/ds.h>
51#include "hisax_cfg.h"
52
53MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Elsa PCM cards");
54MODULE_AUTHOR("Klaus Lichtenwalder");
55MODULE_LICENSE("Dual MPL/GPL");
56
57
58
59
60
61
62static int protocol = 2;
63module_param(protocol, int, 0);
64
65static int elsa_cs_config(struct pcmcia_device *link);
66static void elsa_cs_release(struct pcmcia_device *link);
67static void elsa_cs_detach(struct pcmcia_device *p_dev);
68
69typedef struct local_info_t {
70 struct pcmcia_device *p_dev;
71 int busy;
72 int cardnr;
73} local_info_t;
74
75static int elsa_cs_probe(struct pcmcia_device *link)
76{
77 local_info_t *local;
78
79 dev_dbg(&link->dev, "elsa_cs_attach()\n");
80
81
82 local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
83 if (!local) return -ENOMEM;
84
85 local->p_dev = link;
86 link->priv = local;
87
88 local->cardnr = -1;
89
90 return elsa_cs_config(link);
91}
92
93static void elsa_cs_detach(struct pcmcia_device *link)
94{
95 local_info_t *info = link->priv;
96
97 dev_dbg(&link->dev, "elsa_cs_detach(0x%p)\n", link);
98
99 info->busy = 1;
100 elsa_cs_release(link);
101
102 kfree(info);
103}
104
105static int elsa_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data)
106{
107 int j;
108
109 p_dev->io_lines = 3;
110 p_dev->resource[0]->end = 8;
111 p_dev->resource[0]->flags &= IO_DATA_PATH_WIDTH;
112 p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
113
114 if ((p_dev->resource[0]->end) && p_dev->resource[0]->start) {
115 printk(KERN_INFO "(elsa_cs: looks like the 96 model)\n");
116 if (!pcmcia_request_io(p_dev))
117 return 0;
118 } else {
119 printk(KERN_INFO "(elsa_cs: looks like the 97 model)\n");
120 for (j = 0x2f0; j > 0x100; j -= 0x10) {
121 p_dev->resource[0]->start = j;
122 if (!pcmcia_request_io(p_dev))
123 return 0;
124 }
125 }
126 return -ENODEV;
127}
128
129static int elsa_cs_config(struct pcmcia_device *link)
130{
131 int i;
132 IsdnCard_t icard;
133
134 dev_dbg(&link->dev, "elsa_config(0x%p)\n", link);
135
136 link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
137
138 i = pcmcia_loop_config(link, elsa_cs_configcheck, NULL);
139 if (i != 0)
140 goto failed;
141
142 if (!link->irq)
143 goto failed;
144
145 i = pcmcia_enable_device(link);
146 if (i != 0)
147 goto failed;
148
149 icard.para[0] = link->irq;
150 icard.para[1] = link->resource[0]->start;
151 icard.protocol = protocol;
152 icard.typ = ISDN_CTYPE_ELSA_PCMCIA;
153
154 i = hisax_init_pcmcia(link, &(((local_info_t *)link->priv)->busy), &icard);
155 if (i < 0) {
156 printk(KERN_ERR "elsa_cs: failed to initialize Elsa "
157 "PCMCIA %d with %pR\n", i, link->resource[0]);
158 elsa_cs_release(link);
159 } else
160 ((local_info_t *)link->priv)->cardnr = i;
161
162 return 0;
163failed:
164 elsa_cs_release(link);
165 return -ENODEV;
166}
167
168static void elsa_cs_release(struct pcmcia_device *link)
169{
170 local_info_t *local = link->priv;
171
172 dev_dbg(&link->dev, "elsa_cs_release(0x%p)\n", link);
173
174 if (local) {
175 if (local->cardnr >= 0) {
176
177 HiSax_closecard(local->cardnr);
178 }
179 }
180
181 pcmcia_disable_device(link);
182}
183
184static int elsa_suspend(struct pcmcia_device *link)
185{
186 local_info_t *dev = link->priv;
187
188 dev->busy = 1;
189
190 return 0;
191}
192
193static int elsa_resume(struct pcmcia_device *link)
194{
195 local_info_t *dev = link->priv;
196
197 dev->busy = 0;
198
199 return 0;
200}
201
202static const struct pcmcia_device_id elsa_ids[] = {
203 PCMCIA_DEVICE_PROD_ID12("ELSA AG (Aachen, Germany)", "MicroLink ISDN/MC ", 0x983de2c4, 0x333ba257),
204 PCMCIA_DEVICE_PROD_ID12("ELSA GmbH, Aachen", "MicroLink ISDN/MC ", 0x639e5718, 0x333ba257),
205 PCMCIA_DEVICE_NULL
206};
207MODULE_DEVICE_TABLE(pcmcia, elsa_ids);
208
209static struct pcmcia_driver elsa_cs_driver = {
210 .owner = THIS_MODULE,
211 .name = "elsa_cs",
212 .probe = elsa_cs_probe,
213 .remove = elsa_cs_detach,
214 .id_table = elsa_ids,
215 .suspend = elsa_suspend,
216 .resume = elsa_resume,
217};
218module_pcmcia_driver(elsa_cs_driver);
219