diff options
Diffstat (limited to 'drivers/isdn/hardware')
-rw-r--r-- | drivers/isdn/hardware/avm/avm_cs.c | 185 |
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 | ||
54 | static void avmcs_config(dev_link_t *link); | 54 | static int avmcs_config(struct pcmcia_device *link); |
55 | static void avmcs_release(dev_link_t *link); | 55 | static 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 | ||
102 | static int avmcs_attach(struct pcmcia_device *p_dev) | 102 | static 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 | ||
161 | static void avmcs_detach(struct pcmcia_device *p_dev) | 145 | static 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 | ||
180 | static int get_tuple(client_handle_t handle, tuple_t *tuple, | 159 | static 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 | ||
188 | static int first_tuple(client_handle_t handle, tuple_t *tuple, | 167 | static 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 | ||
196 | static int next_tuple(client_handle_t handle, tuple_t *tuple, | 175 | static 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 | ||
204 | static void avmcs_config(dev_link_t *link) | 183 | static 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 | ||
282 | found_port: | 255 | found_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 | ||
368 | static void avmcs_release(dev_link_t *link) | 341 | static 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 | ||
382 | static 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 | |||
393 | static 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 | ||
419 | static struct pcmcia_device_id avmcs_ids[] = { | 348 | static 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 | ||
439 | static int __init avmcs_init(void) | 366 | static int __init avmcs_init(void) |