Lines 46-52
Link Here
|
46 |
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) |
46 |
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) |
47 |
#define PCMCIA_IRQ_INFO2 |
47 |
#define PCMCIA_IRQ_INFO2 |
48 |
#endif |
48 |
#endif |
49 |
#define NEW_PCMCIA_DRV |
|
|
50 |
|
49 |
|
51 |
/*====================================================================*/ |
50 |
/*====================================================================*/ |
52 |
MODULE_LICENSE("GPL"); |
51 |
MODULE_LICENSE("GPL"); |
Lines 111-123
Link Here
|
111 |
handler. |
110 |
handler. |
112 |
*/ |
111 |
*/ |
113 |
|
112 |
|
114 |
static void cs_config(dev_link_t *); |
113 |
static int cs_config(struct pcmcia_device *link); |
115 |
static void cs_release(dev_link_t *); |
114 |
static void cs_release(struct pcmcia_device *link); |
116 |
#ifdef NEW_PCMCIA_DRV |
115 |
|
117 |
static void cs_detach(struct pcmcia_device *p_dev); |
|
|
118 |
static int cs_attach(struct pcmcia_device *p_dev); |
119 |
#else |
120 |
static int cs_event(event_t event, int priority, event_callback_args_t *); |
121 |
|
116 |
|
122 |
/* |
117 |
/* |
123 |
The attach() and detach() entry points are used to create and destroy |
118 |
The attach() and detach() entry points are used to create and destroy |
Lines 125-172
Link Here
|
125 |
needed to manage one actual PCMCIA card. |
120 |
needed to manage one actual PCMCIA card. |
126 |
*/ |
121 |
*/ |
127 |
|
122 |
|
128 |
static dev_link_t * cs_attach(void); |
123 |
static void cs_detach(struct pcmcia_device *p_dev); |
129 |
static void cs_detach(dev_link_t *); |
|
|
130 |
/* |
131 |
The dev_info variable is the "key" that is used to match up this |
132 |
device driver with appropriate cards, through the card configuration |
133 |
database. |
134 |
*/ |
135 |
|
124 |
|
136 |
static dev_info_t dev_info = "fcpcmcia_cs"; |
|
|
137 |
|
125 |
|
138 |
/* |
126 |
/* |
139 |
A linked list of "instances" of the skeleton device. Each actual |
127 |
A linked list of "instances" of the skeleton device. Each actual |
140 |
PCMCIA card corresponds to one device instance, and is described |
128 |
PCMCIA card corresponds to one device instance, and is described |
141 |
by one dev_link_t structure (defined in ds.h). |
129 |
by one struct pcmcia_device structure (defined in ds.h). |
142 |
|
130 |
|
143 |
You may not want to use a linked list for this -- for example, the |
131 |
You may not want to use a linked list for this -- for example, the |
144 |
memory card driver uses an array of dev_link_t pointers, where minor |
132 |
memory card driver uses an array of struct pcmcia_device pointers, where minor |
145 |
device numbers are used to derive the corresponding array index. |
133 |
device numbers are used to derive the corresponding array index. |
146 |
*/ |
134 |
*/ |
147 |
|
135 |
|
148 |
static dev_link_t *dev_list = NULL; |
|
|
149 |
|
136 |
|
150 |
#endif |
|
|
151 |
/* |
137 |
/* |
152 |
A dev_link_t structure has fields for most things that are needed |
|
|
153 |
to keep track of a socket, but there will usually be some device |
154 |
specific information that also needs to be kept track of. The |
155 |
'priv' pointer in a dev_link_t structure can be used to point to |
156 |
a device-specific private data structure, like this. |
157 |
|
158 |
A driver needs to provide a dev_node_t structure for each device |
138 |
A driver needs to provide a dev_node_t structure for each device |
159 |
on a card. In some cases, there is only one device per card (for |
139 |
on a card. In some cases, there is only one device per card (for |
160 |
example, ethernet cards, modems). In other cases, there may be |
140 |
example, ethernet cards, modems). In other cases, there may be |
161 |
many actual or logical devices (SCSI adapters, memory cards with |
141 |
many actual or logical devices (SCSI adapters, memory cards with |
162 |
multiple partitions). The dev_node_t structures need to be kept |
142 |
multiple partitions). The dev_node_t structures need to be kept |
163 |
in a linked list starting at the 'dev' field of a dev_link_t |
143 |
in a linked list starting at the 'dev' field of a struct pcmcia_device |
164 |
structure. We allocate them in the card's private data structure, |
144 |
structure. We allocate them in the card's private data structure, |
165 |
because they generally can't be allocated dynamically. |
145 |
because they generally can't be allocated dynamically. |
166 |
*/ |
146 |
*/ |
167 |
|
147 |
|
168 |
typedef struct local_info_t { |
148 |
typedef struct local_info_t { |
169 |
dev_node_t node; |
149 |
dev_node_t node; |
170 |
} local_info_t; |
150 |
} local_info_t; |
171 |
|
151 |
|
172 |
/*====================================================================== |
152 |
/*====================================================================== |
Lines 181-281
Link Here
|
181 |
|
161 |
|
182 |
======================================================================*/ |
162 |
======================================================================*/ |
183 |
|
163 |
|
184 |
#ifdef NEW_PCMCIA_DRV |
164 |
static int cs_probe(struct pcmcia_device *p_dev) |
185 |
static int cs_attach(struct pcmcia_device *p_dev) |
|
|
186 |
{ |
165 |
{ |
187 |
#else |
166 |
local_info_t *local; |
188 |
static dev_link_t *cs_attach(void) |
|
|
189 |
{ |
190 |
client_reg_t client_reg; |
191 |
int ret; |
192 |
#endif |
193 |
dev_link_t *link; |
194 |
local_info_t *local; |
195 |
#if defined (PCMCIA_IRQ_INFO2) |
167 |
#if defined (PCMCIA_IRQ_INFO2) |
196 |
int i; |
168 |
int i; |
197 |
#endif |
169 |
#endif |
198 |
|
170 |
|
199 |
NOTE("Attaching device...\n"); |
171 |
NOTE("Attaching device...\n"); |
200 |
|
172 |
|
201 |
/* Initialize the dev_link_t structure */ |
173 |
/* The io structure describes IO port mapping */ |
202 |
link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); |
174 |
p_dev->io.NumPorts1 = 16; |
203 |
if (!link) |
175 |
p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; |
204 |
goto err; |
176 |
p_dev->io.NumPorts2 = 0; |
205 |
memset(link, 0, sizeof(struct dev_link_t)); |
|
|
206 |
|
207 |
/* The io structure describes IO port mapping */ |
208 |
link->io.NumPorts1 = 16; |
209 |
link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; |
210 |
link->io.NumPorts2 = 0; |
211 |
|
177 |
|
212 |
/* Interrupt setup */ |
178 |
/* Interrupt setup */ |
213 |
link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; |
179 |
p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; |
214 |
|
180 |
|
215 |
#if defined (PCMCIA_IRQ_INFO2) |
181 |
#if defined (PCMCIA_IRQ_INFO2) |
216 |
link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; |
182 |
p_dev->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; |
217 |
if (irq_list_count > 0) { |
183 |
if (irq_list_count > 0) { |
218 |
for (i = 0; (i < irq_list_count) && (irq_list[i] > 0); i++) |
184 |
for (i = 0; (i < irq_list_count) && (irq_list[i] > 0); i++) |
219 |
link->irq.IRQInfo2 |= 1 << irq_list[i]; |
185 |
p_dev->irq.IRQInfo2 |= 1 << irq_list[i]; |
220 |
} else { |
186 |
} else { |
221 |
for (i = 0; (i < irq_list_count) && (default_irq_list[i] > 0); i++) |
187 |
for (i = 0; (i < irq_list_count) && (default_irq_list[i] > 0); i++) |
222 |
link->irq.IRQInfo2 |= 1 << default_irq_list[i]; |
188 |
p_dev->irq.IRQInfo2 |= 1 << default_irq_list[i]; |
223 |
} |
189 |
} |
224 |
#else |
190 |
#else |
225 |
link->irq.IRQInfo1 = IRQ_LEVEL_ID; |
191 |
p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; |
226 |
#endif |
192 |
#endif |
227 |
|
193 |
|
228 |
/* General socket configuration */ |
194 |
/* General socket configuration */ |
229 |
link->conf.Attributes = CONF_ENABLE_IRQ; |
195 |
p_dev->conf.Attributes = CONF_ENABLE_IRQ; |
230 |
link->conf.Vcc = 50; |
196 |
p_dev->conf.IntType = INT_MEMORY_AND_IO; |
231 |
link->conf.IntType = INT_MEMORY_AND_IO; |
197 |
p_dev->conf.ConfigIndex = 1; |
232 |
link->conf.ConfigIndex = 1; |
198 |
p_dev->conf.Present = PRESENT_OPTION; |
233 |
link->conf.Present = PRESENT_OPTION; |
199 |
|
234 |
|
200 |
/* Allocate space for private device-specific data */ |
235 |
/* Allocate space for private device-specific data */ |
201 |
local = kmalloc(sizeof(local_info_t), GFP_KERNEL); |
236 |
local = kmalloc(sizeof(local_info_t), GFP_KERNEL); |
202 |
if (!local) |
237 |
if (!local) |
203 |
goto err_kfree; |
238 |
goto err_kfree; |
204 |
memset(local, 0, sizeof(local_info_t)); |
239 |
memset(local, 0, sizeof(local_info_t)); |
205 |
p_dev->priv = local; |
240 |
link->priv = local; |
206 |
return cs_config(p_dev); |
241 |
|
207 |
|
242 |
#ifdef NEW_PCMCIA_DRV |
208 |
err_kfree: |
243 |
link->handle = p_dev; |
209 |
return -ENOMEM; |
244 |
p_dev->instance = link; |
|
|
245 |
link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
246 |
cs_config(link); |
247 |
return 0; |
248 |
#else |
249 |
/* Register with Card Services */ |
250 |
link->next = dev_list; |
251 |
dev_list = link; |
252 |
client_reg.dev_info = &dev_info; |
253 |
#if 0 |
254 |
client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; |
255 |
client_reg.EventMask = |
256 |
CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | |
257 |
CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | |
258 |
CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; |
259 |
client_reg.event_handler = &cs_event; |
260 |
#endif |
261 |
client_reg.Version = 0x0210; |
262 |
client_reg.event_callback_args.client_data = link; |
263 |
ret = pcmcia_register_client(&link->handle, &client_reg); |
264 |
if (ret != 0) { |
265 |
cs_error(link->handle, RegisterClient, ret); |
266 |
cs_detach(link); |
267 |
goto err; |
268 |
} |
269 |
return link; |
270 |
#endif |
271 |
err_kfree: |
272 |
kfree(link); |
273 |
err: |
274 |
#ifdef NEW_PCMCIA_DRV |
275 |
return -EINVAL; |
276 |
#else |
277 |
return NULL; |
278 |
#endif |
279 |
} /* cs_attach */ |
210 |
} /* cs_attach */ |
280 |
|
211 |
|
281 |
/*====================================================================== |
212 |
/*====================================================================== |
Lines 286-332
Link Here
|
286 |
when the device is released. |
217 |
when the device is released. |
287 |
|
218 |
|
288 |
======================================================================*/ |
219 |
======================================================================*/ |
289 |
#ifdef NEW_PCMCIA_DRV |
|
|
290 |
static void cs_detach(struct pcmcia_device *p_dev) |
291 |
{ |
292 |
dev_link_t *link = dev_to_instance(p_dev); |
293 |
|
220 |
|
294 |
if (link->state & DEV_CONFIG) |
221 |
static void cs_detach(struct pcmcia_device *link) |
295 |
cs_release(link); |
|
|
296 |
#else |
297 |
static void cs_detach(dev_link_t *link) |
298 |
{ |
222 |
{ |
299 |
dev_link_t **linkp; |
223 |
cs_release(link); |
300 |
|
224 |
kfree(link->priv); |
301 |
NOTE("Detaching device...\n"); |
225 |
} |
302 |
|
|
|
303 |
/* Locate device structure */ |
304 |
for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) |
305 |
if (*linkp == link) break; |
306 |
if (*linkp == NULL) |
307 |
return; |
308 |
|
309 |
/* |
310 |
If the device is currently configured and active, we won't |
311 |
actually delete it yet. Instead, it is marked so that when |
312 |
the release() function is called, that will trigger a proper |
313 |
detach(). |
314 |
*/ |
315 |
if (link->state & DEV_CONFIG) { |
316 |
link->state |= DEV_STALE_LINK; |
317 |
return; |
318 |
} |
319 |
|
320 |
/* Break the link with Card Services */ |
321 |
if (link->handle) |
322 |
pcmcia_deregister_client(link->handle); |
323 |
|
324 |
/* Unlink device structure, free pieces */ |
325 |
*linkp = link->next; |
326 |
#endif |
327 |
kfree(link->priv); |
328 |
kfree(link); |
329 |
} /* cs_detach */ |
330 |
|
226 |
|
331 |
/*====================================================================== |
227 |
/*====================================================================== |
332 |
|
228 |
|
Lines 336-349
Link Here
|
336 |
|
232 |
|
337 |
======================================================================*/ |
233 |
======================================================================*/ |
338 |
|
234 |
|
339 |
static int get_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) |
235 |
static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple, |
|
|
236 |
cisparse_t *parse) |
340 |
{ |
237 |
{ |
341 |
int i = pcmcia_get_tuple_data(handle, tuple); |
238 |
int i = pcmcia_get_tuple_data(handle, tuple); |
342 |
if (i != CS_SUCCESS) return i; |
239 |
if (i != CS_SUCCESS) return i; |
343 |
return pcmcia_parse_tuple(handle, tuple, parse); |
240 |
return pcmcia_parse_tuple(handle, tuple, parse); |
344 |
} |
241 |
} |
345 |
|
242 |
|
346 |
static int first_tuple(client_handle_t handle, tuple_t *tuple, |
243 |
static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple, |
347 |
cisparse_t *parse) |
244 |
cisparse_t *parse) |
348 |
{ |
245 |
{ |
349 |
int i = pcmcia_get_first_tuple(handle, tuple); |
246 |
int i = pcmcia_get_first_tuple(handle, tuple); |
Lines 351-357
Link Here
|
351 |
return get_tuple(handle, tuple, parse); |
248 |
return get_tuple(handle, tuple, parse); |
352 |
} |
249 |
} |
353 |
|
250 |
|
354 |
static int next_tuple(client_handle_t handle, tuple_t *tuple, |
251 |
static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple, |
355 |
cisparse_t *parse) |
252 |
cisparse_t *parse) |
356 |
{ |
253 |
{ |
357 |
int i = pcmcia_get_next_tuple(handle, tuple); |
254 |
int i = pcmcia_get_next_tuple(handle, tuple); |
Lines 359-367
Link Here
|
359 |
return get_tuple(handle, tuple, parse); |
256 |
return get_tuple(handle, tuple, parse); |
360 |
} |
257 |
} |
361 |
|
258 |
|
362 |
static void cs_config(dev_link_t *link) |
259 |
static int cs_config(struct pcmcia_device *link) |
363 |
{ |
260 |
{ |
364 |
client_handle_t handle; |
|
|
365 |
tuple_t tuple; |
261 |
tuple_t tuple; |
366 |
cisparse_t parse; |
262 |
cisparse_t parse; |
367 |
cistpl_cftable_entry_t *cf = &parse.cftable_entry; |
263 |
cistpl_cftable_entry_t *cf = &parse.cftable_entry; |
Lines 369-375
Link Here
|
369 |
int i; |
265 |
int i; |
370 |
u_char buf[64]; |
266 |
u_char buf[64]; |
371 |
char devname[128]; |
267 |
char devname[128]; |
372 |
handle = link->handle; |
|
|
373 |
dev = link->priv; |
268 |
dev = link->priv; |
374 |
|
269 |
|
375 |
/* |
270 |
/* |
Lines 378-402
Link Here
|
378 |
*/ |
273 |
*/ |
379 |
do { |
274 |
do { |
380 |
tuple.DesiredTuple = CISTPL_CONFIG; |
275 |
tuple.DesiredTuple = CISTPL_CONFIG; |
381 |
i = pcmcia_get_first_tuple(handle, &tuple); |
276 |
i = pcmcia_get_first_tuple(link, &tuple); |
382 |
if (i != CS_SUCCESS) break; |
277 |
if (i != CS_SUCCESS) break; |
383 |
tuple.TupleData = buf; |
278 |
tuple.TupleData = buf; |
384 |
tuple.TupleDataMax = 64; |
279 |
tuple.TupleDataMax = 64; |
385 |
tuple.TupleOffset = 0; |
280 |
tuple.TupleOffset = 0; |
386 |
i = pcmcia_get_tuple_data(handle, &tuple); |
281 |
i = pcmcia_get_tuple_data(link, &tuple); |
387 |
if (i != CS_SUCCESS) break; |
282 |
if (i != CS_SUCCESS) break; |
388 |
i = pcmcia_parse_tuple(handle, &tuple, &parse); |
283 |
i = pcmcia_parse_tuple(link, &tuple, &parse); |
389 |
if (i != CS_SUCCESS) break; |
284 |
if (i != CS_SUCCESS) break; |
390 |
link->conf.ConfigBase = parse.config.base; |
285 |
link->conf.ConfigBase = parse.config.base; |
391 |
} while (0); |
286 |
} while (0); |
392 |
if (i != CS_SUCCESS) { |
287 |
if (i != CS_SUCCESS) { |
393 |
cs_error(link->handle, ParseTuple, i); |
288 |
cs_error(link, ParseTuple, i); |
394 |
link->state &= ~DEV_CONFIG_PENDING; |
289 |
return -ENODEV; |
395 |
return; |
|
|
396 |
} |
290 |
} |
397 |
|
|
|
398 |
/* Configure card */ |
399 |
link->state |= DEV_CONFIG; |
400 |
|
291 |
|
401 |
do { |
292 |
do { |
402 |
|
293 |
|
Lines 407-413
Link Here
|
407 |
tuple.DesiredTuple = CISTPL_VERS_1; |
298 |
tuple.DesiredTuple = CISTPL_VERS_1; |
408 |
|
299 |
|
409 |
devname[0] = 0; |
300 |
devname[0] = 0; |
410 |
if( !first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 1 ) { |
301 |
if( !first_tuple(link, &tuple, &parse) && parse.version_1.ns > 1 ) { |
411 |
strlcpy(devname,parse.version_1.str + parse.version_1.ofs[1], |
302 |
strlcpy(devname,parse.version_1.str + parse.version_1.ofs[1], |
412 |
sizeof(devname)); |
303 |
sizeof(devname)); |
413 |
} |
304 |
} |
Lines 418-424
Link Here
|
418 |
tuple.TupleOffset = 0; tuple.TupleDataMax = 255; |
309 |
tuple.TupleOffset = 0; tuple.TupleDataMax = 255; |
419 |
tuple.Attributes = 0; |
310 |
tuple.Attributes = 0; |
420 |
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; |
311 |
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; |
421 |
i = first_tuple(handle, &tuple, &parse); |
312 |
i = first_tuple(link, &tuple, &parse); |
422 |
while (i == CS_SUCCESS) { |
313 |
while (i == CS_SUCCESS) { |
423 |
if (cf->io.nwin > 0) { |
314 |
if (cf->io.nwin > 0) { |
424 |
link->conf.ConfigIndex = cf->index; |
315 |
link->conf.ConfigIndex = cf->index; |
Lines 428-463
Link Here
|
428 |
NOTE("testing i/o %#x-%#x\n", |
319 |
NOTE("testing i/o %#x-%#x\n", |
429 |
link->io.BasePort1, |
320 |
link->io.BasePort1, |
430 |
link->io.BasePort1+link->io.NumPorts1-1); |
321 |
link->io.BasePort1+link->io.NumPorts1-1); |
431 |
i = pcmcia_request_io(link->handle, &link->io); |
322 |
i = pcmcia_request_io(link, &link->io); |
432 |
if (i == CS_SUCCESS) goto found_port; |
323 |
if (i == CS_SUCCESS) goto found_port; |
433 |
} |
324 |
} |
434 |
i = next_tuple(handle, &tuple, &parse); |
325 |
i = next_tuple(link, &tuple, &parse); |
435 |
} |
326 |
} |
436 |
|
327 |
|
437 |
found_port: |
328 |
found_port: |
438 |
if (i != CS_SUCCESS) { |
329 |
if (i != CS_SUCCESS) { |
439 |
cs_error(link->handle, RequestIO, i); |
330 |
cs_error(link, RequestIO, i); |
440 |
break; |
331 |
break; |
441 |
} |
332 |
} |
442 |
|
333 |
|
443 |
/* |
334 |
/* |
444 |
* allocate an interrupt line |
335 |
* allocate an interrupt line |
445 |
*/ |
336 |
*/ |
446 |
i = pcmcia_request_irq(link->handle, &link->irq); |
337 |
i = pcmcia_request_irq(link, &link->irq); |
447 |
if (i != CS_SUCCESS) { |
338 |
if (i != CS_SUCCESS) { |
448 |
cs_error(link->handle, RequestIRQ, i); |
339 |
cs_error(link, RequestIRQ, i); |
449 |
pcmcia_release_io(link->handle, &link->io); |
340 |
/* undo */ |
|
|
341 |
pcmcia_disable_device(link); |
450 |
break; |
342 |
break; |
451 |
} |
343 |
} |
452 |
|
344 |
|
453 |
/* |
345 |
/* |
454 |
* configure the PCMCIA socket |
346 |
* configure the PCMCIA socket |
455 |
*/ |
347 |
*/ |
456 |
i = pcmcia_request_configuration(link->handle, &link->conf); |
348 |
i = pcmcia_request_configuration(link, &link->conf); |
457 |
if (i != CS_SUCCESS) { |
349 |
if (i != CS_SUCCESS) { |
458 |
cs_error(link->handle, RequestConfiguration, i); |
350 |
cs_error(link, RequestConfiguration, i); |
459 |
pcmcia_release_io(link->handle, &link->io); |
351 |
pcmcia_disable_device(link); |
460 |
pcmcia_release_irq(link->handle, &link->irq); |
|
|
461 |
break; |
352 |
break; |
462 |
} |
353 |
} |
463 |
|
354 |
|
Lines 469-482
Link Here
|
469 |
strcpy(dev->node.dev_name, "A1"); |
360 |
strcpy(dev->node.dev_name, "A1"); |
470 |
dev->node.major = 64; |
361 |
dev->node.major = 64; |
471 |
dev->node.minor = 0; |
362 |
dev->node.minor = 0; |
472 |
link->dev = &dev->node; |
363 |
|
473 |
|
364 |
link->dev_node = &dev->node; |
474 |
link->state &= ~DEV_CONFIG_PENDING; |
|
|
475 |
/* If any step failed, release any partially configured state */ |
365 |
/* If any step failed, release any partially configured state */ |
476 |
if (i != 0) { |
366 |
if (i != 0) { |
477 |
ERROR("Failed to setup controller, releasing link...\n"); |
367 |
ERROR("Failed to setup controller, releasing link...\n"); |
478 |
cs_release(link); |
368 |
cs_release(link); |
479 |
return; |
369 |
return -ENODEV; |
480 |
} |
370 |
} |
481 |
NOTE("Ready to call card driver for '%s'...\n", devname); |
371 |
NOTE("Ready to call card driver for '%s'...\n", devname); |
482 |
|
372 |
|
Lines 488-494
Link Here
|
488 |
link->irq.AssignedIRQ |
378 |
link->irq.AssignedIRQ |
489 |
); |
379 |
); |
490 |
cs_release(link); |
380 |
cs_release(link); |
491 |
return; |
381 |
return -ENODEV; |
492 |
} |
382 |
} |
493 |
dev->node.minor = i; |
383 |
dev->node.minor = i; |
494 |
|
384 |
|
Lines 498-503
Link Here
|
498 |
link->io.BasePort1, |
388 |
link->io.BasePort1, |
499 |
link->irq.AssignedIRQ |
389 |
link->irq.AssignedIRQ |
500 |
); |
390 |
); |
|
|
391 |
return 0; |
501 |
} /* cs_config */ |
392 |
} /* cs_config */ |
502 |
|
393 |
|
503 |
/*====================================================================== |
394 |
/*====================================================================== |
Lines 508-603
Link Here
|
508 |
|
399 |
|
509 |
======================================================================*/ |
400 |
======================================================================*/ |
510 |
|
401 |
|
511 |
static void cs_release(dev_link_t *link) |
402 |
static void cs_release(struct pcmcia_device *link) |
512 |
{ |
403 |
{ |
513 |
fcpcmcia_delcard(link->io.BasePort1, link->irq.AssignedIRQ); |
404 |
fcpcmcia_delcard(link->io.BasePort1, link->irq.AssignedIRQ); |
514 |
|
405 |
|
515 |
/* Unlink the device chain */ |
406 |
pcmcia_disable_device(link); |
516 |
link->dev = NULL; |
|
|
517 |
|
518 |
/* Don't bother checking to see if these succeed or not */ |
519 |
pcmcia_release_configuration(link->handle); |
520 |
pcmcia_release_io(link->handle, &link->io); |
521 |
pcmcia_release_irq(link->handle, &link->irq); |
522 |
link->state &= ~DEV_CONFIG; |
523 |
|
524 |
#ifndef NEW_PCMCIA_DRV |
525 |
if (link->state & DEV_STALE_LINK) |
526 |
cs_detach(link); |
527 |
#endif |
528 |
} /* cs_release */ |
407 |
} /* cs_release */ |
529 |
|
408 |
|
530 |
#ifdef NEW_PCMCIA_DRV |
|
|
531 |
static int cs_suspend(struct pcmcia_device *dev) |
532 |
{ |
533 |
dev_link_t *link = dev_to_instance(dev); |
534 |
|
535 |
link->state |= DEV_SUSPEND; |
536 |
if (link->state & DEV_CONFIG) |
537 |
pcmcia_release_configuration(link->handle); |
538 |
|
539 |
return 0; |
540 |
} |
541 |
|
542 |
static int cs_resume(struct pcmcia_device *dev) |
543 |
{ |
544 |
dev_link_t *link = dev_to_instance(dev); |
545 |
|
546 |
link->state &= ~DEV_SUSPEND; |
547 |
if (link->state & DEV_CONFIG) |
548 |
pcmcia_request_configuration(link->handle, &link->conf); |
549 |
|
550 |
return 0; |
551 |
} |
552 |
#else |
553 |
/*====================================================================== |
554 |
|
555 |
The card status event handler. Mostly, this schedules other |
556 |
stuff to run after an event is received. A CARD_REMOVAL event |
557 |
also sets some flags to discourage the net drivers from trying |
558 |
to talk to the card any more. |
559 |
|
560 |
When a CARD_REMOVAL event is received, we immediately set a flag |
561 |
to block future accesses to this device. All the functions that |
562 |
actually access the device should check this flag to make sure |
563 |
the card is still present. |
564 |
|
565 |
======================================================================*/ |
566 |
|
567 |
static int cs_event(event_t event, int priority, event_callback_args_t *args) |
568 |
{ |
569 |
dev_link_t *link = args->client_data; |
570 |
|
571 |
LOG("Card service event: %x\n", event); |
572 |
switch (event) { |
573 |
case CS_EVENT_CARD_REMOVAL: |
574 |
link->state &= ~DEV_PRESENT; |
575 |
if (link->state & DEV_CONFIG) |
576 |
cs_release(link); |
577 |
break; |
578 |
case CS_EVENT_CARD_INSERTION: |
579 |
link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
580 |
cs_config(link); |
581 |
break; |
582 |
case CS_EVENT_PM_SUSPEND: |
583 |
link->state |= DEV_SUSPEND; |
584 |
/* Fall through... */ |
585 |
case CS_EVENT_RESET_PHYSICAL: |
586 |
if (link->state & DEV_CONFIG) |
587 |
pcmcia_release_configuration(link->handle); |
588 |
break; |
589 |
case CS_EVENT_PM_RESUME: |
590 |
link->state &= ~DEV_SUSPEND; |
591 |
/* Fall through... */ |
592 |
case CS_EVENT_CARD_RESET: |
593 |
if (link->state & DEV_CONFIG) |
594 |
pcmcia_request_configuration(link->handle, &link->conf); |
595 |
break; |
596 |
} |
597 |
return 0; |
598 |
} /* cs_event */ |
599 |
#endif |
600 |
|
601 |
static struct pcmcia_device_id fcpcmcia_ids[] = { |
409 |
static struct pcmcia_device_id fcpcmcia_ids[] = { |
602 |
PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb), |
410 |
PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb), |
603 |
PCMCIA_DEVICE_PROD_ID12("ISDN", "CARD", 0x8d9761c8, 0x01c5aa7b), |
411 |
PCMCIA_DEVICE_PROD_ID12("ISDN", "CARD", 0x8d9761c8, 0x01c5aa7b), |
Lines 610-626
Link Here
|
610 |
.drv = { |
418 |
.drv = { |
611 |
.name = "fcpcmcia_cs", |
419 |
.name = "fcpcmcia_cs", |
612 |
}, |
420 |
}, |
613 |
#ifdef NEW_PCMCIA_DRV |
421 |
.probe = cs_probe, |
614 |
.probe = cs_attach, |
422 |
.remove = cs_detach, |
615 |
.remove = cs_detach, |
423 |
.id_table = fcpcmcia_ids, |
616 |
.suspend= cs_suspend, |
424 |
|
617 |
.resume = cs_resume, |
|
|
618 |
#else |
619 |
.attach = cs_attach, |
620 |
.detach = cs_detach, |
621 |
.event = cs_event, |
622 |
#endif |
623 |
.id_table = fcpcmcia_ids, |
624 |
}; |
425 |
}; |
625 |
|
426 |
|
626 |
static int __init cs_init(void) |
427 |
static int __init cs_init(void) |
Lines 631-636
Link Here
|
631 |
static void __exit cs_exit(void) |
432 |
static void __exit cs_exit(void) |
632 |
{ |
433 |
{ |
633 |
pcmcia_unregister_driver(&cs_driver); |
434 |
pcmcia_unregister_driver(&cs_driver); |
|
|
435 |
|
634 |
} |
436 |
} |
635 |
|
437 |
|
636 |
module_init(cs_init); |
438 |
module_init(cs_init); |