aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn/hardware
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/isdn/hardware')
-rw-r--r--drivers/isdn/hardware/avm/avm_cs.c185
1 files changed, 56 insertions, 129 deletions
diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c
index 2a2b03ff096b..7bbfd85ab793 100644
--- a/drivers/isdn/hardware/avm/avm_cs.c
+++ b/drivers/isdn/hardware/avm/avm_cs.c
@@ -51,8 +51,8 @@ MODULE_LICENSE("GPL");
51 handler. 51 handler.
52*/ 52*/
53 53
54static void avmcs_config(dev_link_t *link); 54static int avmcs_config(struct pcmcia_device *link);
55static void avmcs_release(dev_link_t *link); 55static void avmcs_release(struct pcmcia_device *link);
56 56
57/* 57/*
58 The attach() and detach() entry points are used to create and destroy 58 The attach() and detach() entry points are used to create and destroy
@@ -65,10 +65,10 @@ static void avmcs_detach(struct pcmcia_device *p_dev);
65/* 65/*
66 A linked list of "instances" of the skeleton device. Each actual 66 A linked list of "instances" of the skeleton device. Each actual
67 PCMCIA card corresponds to one device instance, and is described 67 PCMCIA card corresponds to one device instance, and is described
68 by one dev_link_t structure (defined in ds.h). 68 by one struct pcmcia_device structure (defined in ds.h).
69 69
70 You may not want to use a linked list for this -- for example, the 70 You may not want to use a linked list for this -- for example, the
71 memory card driver uses an array of dev_link_t pointers, where minor 71 memory card driver uses an array of struct pcmcia_device pointers, where minor
72 device numbers are used to derive the corresponding array index. 72 device numbers are used to derive the corresponding array index.
73*/ 73*/
74 74
@@ -78,7 +78,7 @@ static void avmcs_detach(struct pcmcia_device *p_dev);
78 example, ethernet cards, modems). In other cases, there may be 78 example, ethernet cards, modems). In other cases, there may be
79 many actual or logical devices (SCSI adapters, memory cards with 79 many actual or logical devices (SCSI adapters, memory cards with
80 multiple partitions). The dev_node_t structures need to be kept 80 multiple partitions). The dev_node_t structures need to be kept
81 in a linked list starting at the 'dev' field of a dev_link_t 81 in a linked list starting at the 'dev' field of a struct pcmcia_device
82 structure. We allocate them in the card's private data structure, 82 structure. We allocate them in the card's private data structure,
83 because they generally can't be allocated dynamically. 83 because they generally can't be allocated dynamically.
84*/ 84*/
@@ -99,54 +99,38 @@ typedef struct local_info_t {
99 99
100======================================================================*/ 100======================================================================*/
101 101
102static int avmcs_attach(struct pcmcia_device *p_dev) 102static int avmcs_probe(struct pcmcia_device *p_dev)
103{ 103{
104 dev_link_t *link;
105 local_info_t *local; 104 local_info_t *local;
106 105
107 /* Initialize the dev_link_t structure */
108 link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
109 if (!link)
110 goto err;
111 memset(link, 0, sizeof(struct dev_link_t));
112
113 /* The io structure describes IO port mapping */ 106 /* The io structure describes IO port mapping */
114 link->io.NumPorts1 = 16; 107 p_dev->io.NumPorts1 = 16;
115 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; 108 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
116 link->io.NumPorts2 = 0; 109 p_dev->io.NumPorts2 = 0;
117 110
118 /* Interrupt setup */ 111 /* Interrupt setup */
119 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; 112 p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
120 link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; 113 p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
114
115 p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
121 116
122 link->irq.IRQInfo1 = IRQ_LEVEL_ID;
123
124 /* General socket configuration */ 117 /* General socket configuration */
125 link->conf.Attributes = CONF_ENABLE_IRQ; 118 p_dev->conf.Attributes = CONF_ENABLE_IRQ;
126 link->conf.Vcc = 50; 119 p_dev->conf.IntType = INT_MEMORY_AND_IO;
127 link->conf.IntType = INT_MEMORY_AND_IO; 120 p_dev->conf.ConfigIndex = 1;
128 link->conf.ConfigIndex = 1; 121 p_dev->conf.Present = PRESENT_OPTION;
129 link->conf.Present = PRESENT_OPTION;
130 122
131 /* Allocate space for private device-specific data */ 123 /* Allocate space for private device-specific data */
132 local = kmalloc(sizeof(local_info_t), GFP_KERNEL); 124 local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
133 if (!local) 125 if (!local)
134 goto err_kfree; 126 goto err;
135 memset(local, 0, sizeof(local_info_t)); 127 memset(local, 0, sizeof(local_info_t));
136 link->priv = local; 128 p_dev->priv = local;
137 129
138 link->handle = p_dev; 130 return avmcs_config(p_dev);
139 p_dev->instance = link;
140 131
141 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
142 avmcs_config(link);
143
144 return 0;
145
146 err_kfree:
147 kfree(link);
148 err: 132 err:
149 return -EINVAL; 133 return -ENOMEM;
150} /* avmcs_attach */ 134} /* avmcs_attach */
151 135
152/*====================================================================== 136/*======================================================================
@@ -158,15 +142,10 @@ static int avmcs_attach(struct pcmcia_device *p_dev)
158 142
159======================================================================*/ 143======================================================================*/
160 144
161static void avmcs_detach(struct pcmcia_device *p_dev) 145static void avmcs_detach(struct pcmcia_device *link)
162{ 146{
163 dev_link_t *link = dev_to_instance(p_dev);
164
165 if (link->state & DEV_CONFIG)
166 avmcs_release(link); 147 avmcs_release(link);
167 148 kfree(link->priv);
168 kfree(link->priv);
169 kfree(link);
170} /* avmcs_detach */ 149} /* avmcs_detach */
171 150
172/*====================================================================== 151/*======================================================================
@@ -177,7 +156,7 @@ static void avmcs_detach(struct pcmcia_device *p_dev)
177 156
178======================================================================*/ 157======================================================================*/
179 158
180static int get_tuple(client_handle_t handle, tuple_t *tuple, 159static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple,
181 cisparse_t *parse) 160 cisparse_t *parse)
182{ 161{
183 int i = pcmcia_get_tuple_data(handle, tuple); 162 int i = pcmcia_get_tuple_data(handle, tuple);
@@ -185,7 +164,7 @@ static int get_tuple(client_handle_t handle, tuple_t *tuple,
185 return pcmcia_parse_tuple(handle, tuple, parse); 164 return pcmcia_parse_tuple(handle, tuple, parse);
186} 165}
187 166
188static int first_tuple(client_handle_t handle, tuple_t *tuple, 167static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple,
189 cisparse_t *parse) 168 cisparse_t *parse)
190{ 169{
191 int i = pcmcia_get_first_tuple(handle, tuple); 170 int i = pcmcia_get_first_tuple(handle, tuple);
@@ -193,7 +172,7 @@ static int first_tuple(client_handle_t handle, tuple_t *tuple,
193 return get_tuple(handle, tuple, parse); 172 return get_tuple(handle, tuple, parse);
194} 173}
195 174
196static int next_tuple(client_handle_t handle, tuple_t *tuple, 175static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple,
197 cisparse_t *parse) 176 cisparse_t *parse)
198{ 177{
199 int i = pcmcia_get_next_tuple(handle, tuple); 178 int i = pcmcia_get_next_tuple(handle, tuple);
@@ -201,9 +180,8 @@ static int next_tuple(client_handle_t handle, tuple_t *tuple,
201 return get_tuple(handle, tuple, parse); 180 return get_tuple(handle, tuple, parse);
202} 181}
203 182
204static void avmcs_config(dev_link_t *link) 183static int avmcs_config(struct pcmcia_device *link)
205{ 184{
206 client_handle_t handle;
207 tuple_t tuple; 185 tuple_t tuple;
208 cisparse_t parse; 186 cisparse_t parse;
209 cistpl_cftable_entry_t *cf = &parse.cftable_entry; 187 cistpl_cftable_entry_t *cf = &parse.cftable_entry;
@@ -213,8 +191,7 @@ static void avmcs_config(dev_link_t *link)
213 char devname[128]; 191 char devname[128];
214 int cardtype; 192 int cardtype;
215 int (*addcard)(unsigned int port, unsigned irq); 193 int (*addcard)(unsigned int port, unsigned irq);
216 194
217 handle = link->handle;
218 dev = link->priv; 195 dev = link->priv;
219 196
220 /* 197 /*
@@ -223,25 +200,21 @@ static void avmcs_config(dev_link_t *link)
223 */ 200 */
224 do { 201 do {
225 tuple.DesiredTuple = CISTPL_CONFIG; 202 tuple.DesiredTuple = CISTPL_CONFIG;
226 i = pcmcia_get_first_tuple(handle, &tuple); 203 i = pcmcia_get_first_tuple(link, &tuple);
227 if (i != CS_SUCCESS) break; 204 if (i != CS_SUCCESS) break;
228 tuple.TupleData = buf; 205 tuple.TupleData = buf;
229 tuple.TupleDataMax = 64; 206 tuple.TupleDataMax = 64;
230 tuple.TupleOffset = 0; 207 tuple.TupleOffset = 0;
231 i = pcmcia_get_tuple_data(handle, &tuple); 208 i = pcmcia_get_tuple_data(link, &tuple);
232 if (i != CS_SUCCESS) break; 209 if (i != CS_SUCCESS) break;
233 i = pcmcia_parse_tuple(handle, &tuple, &parse); 210 i = pcmcia_parse_tuple(link, &tuple, &parse);
234 if (i != CS_SUCCESS) break; 211 if (i != CS_SUCCESS) break;
235 link->conf.ConfigBase = parse.config.base; 212 link->conf.ConfigBase = parse.config.base;
236 } while (0); 213 } while (0);
237 if (i != CS_SUCCESS) { 214 if (i != CS_SUCCESS) {
238 cs_error(link->handle, ParseTuple, i); 215 cs_error(link, ParseTuple, i);
239 link->state &= ~DEV_CONFIG_PENDING; 216 return -ENODEV;
240 return;
241 } 217 }
242
243 /* Configure card */
244 link->state |= DEV_CONFIG;
245 218
246 do { 219 do {
247 220
@@ -252,7 +225,7 @@ static void avmcs_config(dev_link_t *link)
252 tuple.DesiredTuple = CISTPL_VERS_1; 225 tuple.DesiredTuple = CISTPL_VERS_1;
253 226
254 devname[0] = 0; 227 devname[0] = 0;
255 if( !first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 1 ) { 228 if( !first_tuple(link, &tuple, &parse) && parse.version_1.ns > 1 ) {
256 strlcpy(devname,parse.version_1.str + parse.version_1.ofs[1], 229 strlcpy(devname,parse.version_1.str + parse.version_1.ofs[1],
257 sizeof(devname)); 230 sizeof(devname));
258 } 231 }
@@ -263,7 +236,7 @@ static void avmcs_config(dev_link_t *link)
263 tuple.TupleOffset = 0; tuple.TupleDataMax = 255; 236 tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
264 tuple.Attributes = 0; 237 tuple.Attributes = 0;
265 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; 238 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
266 i = first_tuple(handle, &tuple, &parse); 239 i = first_tuple(link, &tuple, &parse);
267 while (i == CS_SUCCESS) { 240 while (i == CS_SUCCESS) {
268 if (cf->io.nwin > 0) { 241 if (cf->io.nwin > 0) {
269 link->conf.ConfigIndex = cf->index; 242 link->conf.ConfigIndex = cf->index;
@@ -273,36 +246,36 @@ static void avmcs_config(dev_link_t *link)
273 printk(KERN_INFO "avm_cs: testing i/o %#x-%#x\n", 246 printk(KERN_INFO "avm_cs: testing i/o %#x-%#x\n",
274 link->io.BasePort1, 247 link->io.BasePort1,
275 link->io.BasePort1+link->io.NumPorts1-1); 248 link->io.BasePort1+link->io.NumPorts1-1);
276 i = pcmcia_request_io(link->handle, &link->io); 249 i = pcmcia_request_io(link, &link->io);
277 if (i == CS_SUCCESS) goto found_port; 250 if (i == CS_SUCCESS) goto found_port;
278 } 251 }
279 i = next_tuple(handle, &tuple, &parse); 252 i = next_tuple(link, &tuple, &parse);
280 } 253 }
281 254
282found_port: 255found_port:
283 if (i != CS_SUCCESS) { 256 if (i != CS_SUCCESS) {
284 cs_error(link->handle, RequestIO, i); 257 cs_error(link, RequestIO, i);
285 break; 258 break;
286 } 259 }
287 260
288 /* 261 /*
289 * allocate an interrupt line 262 * allocate an interrupt line
290 */ 263 */
291 i = pcmcia_request_irq(link->handle, &link->irq); 264 i = pcmcia_request_irq(link, &link->irq);
292 if (i != CS_SUCCESS) { 265 if (i != CS_SUCCESS) {
293 cs_error(link->handle, RequestIRQ, i); 266 cs_error(link, RequestIRQ, i);
294 pcmcia_release_io(link->handle, &link->io); 267 /* undo */
268 pcmcia_disable_device(link);
295 break; 269 break;
296 } 270 }
297 271
298 /* 272 /*
299 * configure the PCMCIA socket 273 * configure the PCMCIA socket
300 */ 274 */
301 i = pcmcia_request_configuration(link->handle, &link->conf); 275 i = pcmcia_request_configuration(link, &link->conf);
302 if (i != CS_SUCCESS) { 276 if (i != CS_SUCCESS) {
303 cs_error(link->handle, RequestConfiguration, i); 277 cs_error(link, RequestConfiguration, i);
304 pcmcia_release_io(link->handle, &link->io); 278 pcmcia_disable_device(link);
305 pcmcia_release_irq(link->handle, &link->irq);
306 break; 279 break;
307 } 280 }
308 281
@@ -331,13 +304,12 @@ found_port:
331 304
332 dev->node.major = 64; 305 dev->node.major = 64;
333 dev->node.minor = 0; 306 dev->node.minor = 0;
334 link->dev = &dev->node; 307 link->dev_node = &dev->node;
335 308
336 link->state &= ~DEV_CONFIG_PENDING;
337 /* If any step failed, release any partially configured state */ 309 /* If any step failed, release any partially configured state */
338 if (i != 0) { 310 if (i != 0) {
339 avmcs_release(link); 311 avmcs_release(link);
340 return; 312 return -ENODEV;
341 } 313 }
342 314
343 315
@@ -351,9 +323,10 @@ found_port:
351 printk(KERN_ERR "avm_cs: failed to add AVM-%s-Controller at i/o %#x, irq %d\n", 323 printk(KERN_ERR "avm_cs: failed to add AVM-%s-Controller at i/o %#x, irq %d\n",
352 dev->node.dev_name, link->io.BasePort1, link->irq.AssignedIRQ); 324 dev->node.dev_name, link->io.BasePort1, link->irq.AssignedIRQ);
353 avmcs_release(link); 325 avmcs_release(link);
354 return; 326 return -ENODEV;
355 } 327 }
356 dev->node.minor = i; 328 dev->node.minor = i;
329 return 0;
357 330
358} /* avmcs_config */ 331} /* avmcs_config */
359 332
@@ -365,56 +338,12 @@ found_port:
365 338
366======================================================================*/ 339======================================================================*/
367 340
368static void avmcs_release(dev_link_t *link) 341static void avmcs_release(struct pcmcia_device *link)
369{ 342{
370 b1pcmcia_delcard(link->io.BasePort1, link->irq.AssignedIRQ); 343 b1pcmcia_delcard(link->io.BasePort1, link->irq.AssignedIRQ);
371 344 pcmcia_disable_device(link);
372 /* Unlink the device chain */
373 link->dev = NULL;
374
375 /* Don't bother checking to see if these succeed or not */
376 pcmcia_release_configuration(link->handle);
377 pcmcia_release_io(link->handle, &link->io);
378 pcmcia_release_irq(link->handle, &link->irq);
379 link->state &= ~DEV_CONFIG;
380} /* avmcs_release */ 345} /* avmcs_release */
381 346
382static int avmcs_suspend(struct pcmcia_device *dev)
383{
384 dev_link_t *link = dev_to_instance(dev);
385
386 link->state |= DEV_SUSPEND;
387 if (link->state & DEV_CONFIG)
388 pcmcia_release_configuration(link->handle);
389
390 return 0;
391}
392
393static int avmcs_resume(struct pcmcia_device *dev)
394{
395 dev_link_t *link = dev_to_instance(dev);
396
397 link->state &= ~DEV_SUSPEND;
398 if (link->state & DEV_CONFIG)
399 pcmcia_request_configuration(link->handle, &link->conf);
400
401 return 0;
402}
403
404/*======================================================================
405
406 The card status event handler. Mostly, this schedules other
407 stuff to run after an event is received. A CARD_REMOVAL event
408 also sets some flags to discourage the net drivers from trying
409 to talk to the card any more.
410
411 When a CARD_REMOVAL event is received, we immediately set a flag
412 to block future accesses to this device. All the functions that
413 actually access the device should check this flag to make sure
414 the card is still present.
415
416======================================================================*/
417
418 347
419static struct pcmcia_device_id avmcs_ids[] = { 348static struct pcmcia_device_id avmcs_ids[] = {
420 PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN-Controller B1", 0x95d42008, 0x845dc335), 349 PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN-Controller B1", 0x95d42008, 0x845dc335),
@@ -429,11 +358,9 @@ static struct pcmcia_driver avmcs_driver = {
429 .drv = { 358 .drv = {
430 .name = "avm_cs", 359 .name = "avm_cs",
431 }, 360 },
432 .probe = avmcs_attach, 361 .probe = avmcs_probe,
433 .remove = avmcs_detach, 362 .remove = avmcs_detach,
434 .id_table = avmcs_ids, 363 .id_table = avmcs_ids,
435 .suspend= avmcs_suspend,
436 .resume = avmcs_resume,
437}; 364};
438 365
439static int __init avmcs_init(void) 366static int __init avmcs_init(void)