blob: f796dcd64dcb8d35bcb8a19f715202dc73f73459 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * ds.c -- 16-bit PCMCIA core support
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * The initial developer of the original code is David A. Hinds
9 * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
10 * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
11 *
12 * (C) 1999 David A. Hinds
13 * (C) 2003 - 2004 Dominik Brodowski
14 */
15
16#include <linux/config.h>
17#include <linux/module.h>
18#include <linux/moduleparam.h>
19#include <linux/init.h>
20#include <linux/kernel.h>
21#include <linux/major.h>
22#include <linux/string.h>
23#include <linux/errno.h>
24#include <linux/slab.h>
25#include <linux/mm.h>
26#include <linux/fcntl.h>
27#include <linux/sched.h>
28#include <linux/smp_lock.h>
29#include <linux/timer.h>
30#include <linux/ioctl.h>
31#include <linux/proc_fs.h>
32#include <linux/poll.h>
33#include <linux/pci.h>
34#include <linux/list.h>
35#include <linux/delay.h>
36#include <linux/kref.h>
37#include <linux/workqueue.h>
Dominik Brodowski840c2ac2005-06-27 16:28:04 -070038#include <linux/crc32.h>
Dominik Brodowskidaa95172005-06-27 16:28:14 -070039#include <linux/firmware.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
41#include <asm/atomic.h>
42
43#define IN_CARD_SERVICES
44#include <pcmcia/version.h>
45#include <pcmcia/cs_types.h>
46#include <pcmcia/cs.h>
47#include <pcmcia/bulkmem.h>
48#include <pcmcia/cistpl.h>
49#include <pcmcia/ds.h>
50#include <pcmcia/ss.h>
51
52#include "cs_internal.h"
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070053#include "ds_internal.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
55/*====================================================================*/
56
57/* Module parameters */
58
59MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
60MODULE_DESCRIPTION("PCMCIA Driver Services");
61MODULE_LICENSE("GPL");
62
63#ifdef DEBUG
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070064int ds_pc_debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66module_param_named(pc_debug, ds_pc_debug, int, 0644);
67
68#define ds_dbg(lvl, fmt, arg...) do { \
69 if (ds_pc_debug > (lvl)) \
70 printk(KERN_DEBUG "ds: " fmt , ## arg); \
71} while (0)
72#else
73#define ds_dbg(lvl, fmt, arg...) do { } while (0)
74#endif
75
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070076spinlock_t pcmcia_dev_list_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
Dominik Brodowskidc109492005-06-27 16:28:50 -070078static int unbind_request(struct pcmcia_socket *s);
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
80/*====================================================================*/
81
82/* code which was in cs.c before */
83
84/* String tables for error messages */
85
86typedef struct lookup_t {
87 int key;
88 char *msg;
89} lookup_t;
90
91static const lookup_t error_table[] = {
92 { CS_SUCCESS, "Operation succeeded" },
93 { CS_BAD_ADAPTER, "Bad adapter" },
94 { CS_BAD_ATTRIBUTE, "Bad attribute", },
95 { CS_BAD_BASE, "Bad base address" },
96 { CS_BAD_EDC, "Bad EDC" },
97 { CS_BAD_IRQ, "Bad IRQ" },
98 { CS_BAD_OFFSET, "Bad offset" },
99 { CS_BAD_PAGE, "Bad page number" },
100 { CS_READ_FAILURE, "Read failure" },
101 { CS_BAD_SIZE, "Bad size" },
102 { CS_BAD_SOCKET, "Bad socket" },
103 { CS_BAD_TYPE, "Bad type" },
104 { CS_BAD_VCC, "Bad Vcc" },
105 { CS_BAD_VPP, "Bad Vpp" },
106 { CS_BAD_WINDOW, "Bad window" },
107 { CS_WRITE_FAILURE, "Write failure" },
108 { CS_NO_CARD, "No card present" },
109 { CS_UNSUPPORTED_FUNCTION, "Usupported function" },
110 { CS_UNSUPPORTED_MODE, "Unsupported mode" },
111 { CS_BAD_SPEED, "Bad speed" },
112 { CS_BUSY, "Resource busy" },
113 { CS_GENERAL_FAILURE, "General failure" },
114 { CS_WRITE_PROTECTED, "Write protected" },
115 { CS_BAD_ARG_LENGTH, "Bad argument length" },
116 { CS_BAD_ARGS, "Bad arguments" },
117 { CS_CONFIGURATION_LOCKED, "Configuration locked" },
118 { CS_IN_USE, "Resource in use" },
119 { CS_NO_MORE_ITEMS, "No more items" },
120 { CS_OUT_OF_RESOURCE, "Out of resource" },
121 { CS_BAD_HANDLE, "Bad handle" },
122 { CS_BAD_TUPLE, "Bad CIS tuple" }
123};
124
125
126static const lookup_t service_table[] = {
127 { AccessConfigurationRegister, "AccessConfigurationRegister" },
128 { AddSocketServices, "AddSocketServices" },
129 { AdjustResourceInfo, "AdjustResourceInfo" },
130 { CheckEraseQueue, "CheckEraseQueue" },
131 { CloseMemory, "CloseMemory" },
132 { DeregisterClient, "DeregisterClient" },
133 { DeregisterEraseQueue, "DeregisterEraseQueue" },
134 { GetCardServicesInfo, "GetCardServicesInfo" },
135 { GetClientInfo, "GetClientInfo" },
136 { GetConfigurationInfo, "GetConfigurationInfo" },
137 { GetEventMask, "GetEventMask" },
138 { GetFirstClient, "GetFirstClient" },
139 { GetFirstRegion, "GetFirstRegion" },
140 { GetFirstTuple, "GetFirstTuple" },
141 { GetNextClient, "GetNextClient" },
142 { GetNextRegion, "GetNextRegion" },
143 { GetNextTuple, "GetNextTuple" },
144 { GetStatus, "GetStatus" },
145 { GetTupleData, "GetTupleData" },
146 { MapMemPage, "MapMemPage" },
147 { ModifyConfiguration, "ModifyConfiguration" },
148 { ModifyWindow, "ModifyWindow" },
149 { OpenMemory, "OpenMemory" },
150 { ParseTuple, "ParseTuple" },
151 { ReadMemory, "ReadMemory" },
152 { RegisterClient, "RegisterClient" },
153 { RegisterEraseQueue, "RegisterEraseQueue" },
154 { RegisterMTD, "RegisterMTD" },
155 { ReleaseConfiguration, "ReleaseConfiguration" },
156 { ReleaseIO, "ReleaseIO" },
157 { ReleaseIRQ, "ReleaseIRQ" },
158 { ReleaseWindow, "ReleaseWindow" },
159 { RequestConfiguration, "RequestConfiguration" },
160 { RequestIO, "RequestIO" },
161 { RequestIRQ, "RequestIRQ" },
162 { RequestSocketMask, "RequestSocketMask" },
163 { RequestWindow, "RequestWindow" },
164 { ResetCard, "ResetCard" },
165 { SetEventMask, "SetEventMask" },
166 { ValidateCIS, "ValidateCIS" },
167 { WriteMemory, "WriteMemory" },
168 { BindDevice, "BindDevice" },
169 { BindMTD, "BindMTD" },
170 { ReportError, "ReportError" },
171 { SuspendCard, "SuspendCard" },
172 { ResumeCard, "ResumeCard" },
173 { EjectCard, "EjectCard" },
174 { InsertCard, "InsertCard" },
175 { ReplaceCIS, "ReplaceCIS" }
176};
177
178
Dominik Brodowskie94e15f2005-06-27 16:28:15 -0700179static int pcmcia_report_error(client_handle_t handle, error_info_t *err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180{
181 int i;
182 char *serv;
183
184 if (CHECK_HANDLE(handle))
185 printk(KERN_NOTICE);
186 else {
187 struct pcmcia_device *p_dev = handle_to_pdev(handle);
188 printk(KERN_NOTICE "%s: ", p_dev->dev.bus_id);
189 }
190
191 for (i = 0; i < ARRAY_SIZE(service_table); i++)
192 if (service_table[i].key == err->func)
193 break;
194 if (i < ARRAY_SIZE(service_table))
195 serv = service_table[i].msg;
196 else
197 serv = "Unknown service number";
198
199 for (i = 0; i < ARRAY_SIZE(error_table); i++)
200 if (error_table[i].key == err->retcode)
201 break;
202 if (i < ARRAY_SIZE(error_table))
203 printk("%s: %s\n", serv, error_table[i].msg);
204 else
205 printk("%s: Unknown error code %#x\n", serv, err->retcode);
206
207 return CS_SUCCESS;
208} /* report_error */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209
210/* end of code which was in cs.c before */
211
212/*======================================================================*/
213
214void cs_error(client_handle_t handle, int func, int ret)
215{
216 error_info_t err = { func, ret };
217 pcmcia_report_error(handle, &err);
218}
219EXPORT_SYMBOL(cs_error);
220
Dominik Brodowski23a83bf2005-06-27 16:28:07 -0700221
222static void pcmcia_check_driver(struct pcmcia_driver *p_drv)
223{
224 struct pcmcia_device_id *did = p_drv->id_table;
225 unsigned int i;
226 u32 hash;
227
228 while (did && did->match_flags) {
229 for (i=0; i<4; i++) {
230 if (!did->prod_id[i])
231 continue;
232
233 hash = crc32(0, did->prod_id[i], strlen(did->prod_id[i]));
234 if (hash == did->prod_id_hash[i])
235 continue;
236
237 printk(KERN_DEBUG "pcmcia: %s: invalid hash for "
238 "product string \"%s\": is 0x%x, should "
239 "be 0x%x\n", p_drv->drv.name, did->prod_id[i],
240 did->prod_id_hash[i], hash);
Dominik Brodowski5085cb22005-06-27 16:28:45 -0700241 printk(KERN_DEBUG "pcmcia: see "
242 "Documentation/pcmcia/devicetable.txt for "
243 "details\n");
Dominik Brodowski23a83bf2005-06-27 16:28:07 -0700244 }
245 did++;
246 }
247
248 return;
249}
250
Dominik Brodowskidaa95172005-06-27 16:28:14 -0700251
252#ifdef CONFIG_PCMCIA_LOAD_CIS
253
254/**
255 * pcmcia_load_firmware - load CIS from userspace if device-provided is broken
256 * @dev - the pcmcia device which needs a CIS override
257 * @filename - requested filename in /lib/firmware/cis/
258 *
259 * This uses the in-kernel firmware loading mechanism to use a "fake CIS" if
260 * the one provided by the card is broken. The firmware files reside in
261 * /lib/firmware/cis/ in userspace.
262 */
263static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
264{
265 struct pcmcia_socket *s = dev->socket;
266 const struct firmware *fw;
267 char path[20];
268 int ret=-ENOMEM;
269 cisdump_t *cis;
270
271 if (!filename)
272 return -EINVAL;
273
274 ds_dbg(1, "trying to load firmware %s\n", filename);
275
276 if (strlen(filename) > 14)
277 return -EINVAL;
278
279 snprintf(path, 20, "%s", filename);
280
281 if (request_firmware(&fw, path, &dev->dev) == 0) {
282 if (fw->size >= CISTPL_MAX_CIS_SIZE)
283 goto release;
284
285 cis = kmalloc(sizeof(cisdump_t), GFP_KERNEL);
286 if (!cis)
287 goto release;
288
289 memset(cis, 0, sizeof(cisdump_t));
290
291 cis->Length = fw->size + 1;
292 memcpy(cis->Data, fw->data, fw->size);
293
294 if (!pcmcia_replace_cis(s, cis))
295 ret = 0;
296 }
297 release:
298 release_firmware(fw);
299
300 return (ret);
301}
302
303#else /* !CONFIG_PCMCIA_LOAD_CIS */
304
305static inline int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
306{
307 return -ENODEV;
308}
309
310#endif
311
312
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313/*======================================================================*/
314
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316/**
317 * pcmcia_register_driver - register a PCMCIA driver with the bus core
318 *
319 * Registers a PCMCIA driver with the PCMCIA bus core.
320 */
321static int pcmcia_device_probe(struct device *dev);
322static int pcmcia_device_remove(struct device * dev);
323
324int pcmcia_register_driver(struct pcmcia_driver *driver)
325{
326 if (!driver)
327 return -EINVAL;
328
Dominik Brodowski23a83bf2005-06-27 16:28:07 -0700329 pcmcia_check_driver(driver);
330
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 /* initialize common fields */
332 driver->drv.bus = &pcmcia_bus_type;
333 driver->drv.owner = driver->owner;
334 driver->drv.probe = pcmcia_device_probe;
335 driver->drv.remove = pcmcia_device_remove;
336
337 return driver_register(&driver->drv);
338}
339EXPORT_SYMBOL(pcmcia_register_driver);
340
341/**
342 * pcmcia_unregister_driver - unregister a PCMCIA driver with the bus core
343 */
344void pcmcia_unregister_driver(struct pcmcia_driver *driver)
345{
346 driver_unregister(&driver->drv);
347}
348EXPORT_SYMBOL(pcmcia_unregister_driver);
349
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
351/* pcmcia_device handling */
352
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700353struct pcmcia_device * pcmcia_get_dev(struct pcmcia_device *p_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354{
355 struct device *tmp_dev;
356 tmp_dev = get_device(&p_dev->dev);
357 if (!tmp_dev)
358 return NULL;
359 return to_pcmcia_dev(tmp_dev);
360}
361
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700362void pcmcia_put_dev(struct pcmcia_device *p_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363{
364 if (p_dev)
365 put_device(&p_dev->dev);
366}
367
368static void pcmcia_release_dev(struct device *dev)
369{
370 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
371 ds_dbg(1, "releasing dev %p\n", p_dev);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700372 pcmcia_put_socket(p_dev->socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 kfree(p_dev);
374}
375
376
377static int pcmcia_device_probe(struct device * dev)
378{
379 struct pcmcia_device *p_dev;
380 struct pcmcia_driver *p_drv;
381 int ret = 0;
382
383 dev = get_device(dev);
384 if (!dev)
385 return -ENODEV;
386
387 p_dev = to_pcmcia_dev(dev);
388 p_drv = to_pcmcia_drv(dev->driver);
389
390 if (!try_module_get(p_drv->owner)) {
391 ret = -EINVAL;
392 goto put_dev;
393 }
394
395 if (p_drv->attach) {
396 p_dev->instance = p_drv->attach();
397 if ((!p_dev->instance) || (p_dev->client.state & CLIENT_UNBOUND)) {
398 printk(KERN_NOTICE "ds: unable to create instance "
399 "of '%s'!\n", p_drv->drv.name);
400 ret = -EINVAL;
401 }
402 }
403
404 if (ret)
405 module_put(p_drv->owner);
406 put_dev:
407 if ((ret) || !(p_drv->attach))
408 put_device(dev);
409 return (ret);
410}
411
412
413static int pcmcia_device_remove(struct device * dev)
414{
415 struct pcmcia_device *p_dev;
416 struct pcmcia_driver *p_drv;
417
418 /* detach the "instance" */
419 p_dev = to_pcmcia_dev(dev);
420 p_drv = to_pcmcia_drv(dev->driver);
421
422 if (p_drv) {
423 if ((p_drv->detach) && (p_dev->instance)) {
424 p_drv->detach(p_dev->instance);
425 /* from pcmcia_probe_device */
426 put_device(&p_dev->dev);
427 }
428 module_put(p_drv->owner);
429 }
430
431 return 0;
432}
433
434
435
436/*
437 * pcmcia_device_query -- determine information about a pcmcia device
438 */
439static int pcmcia_device_query(struct pcmcia_device *p_dev)
440{
441 cistpl_manfid_t manf_id;
442 cistpl_funcid_t func_id;
443 cistpl_vers_1_t vers1;
444 unsigned int i;
445
446 if (!pccard_read_tuple(p_dev->socket, p_dev->func,
447 CISTPL_MANFID, &manf_id)) {
448 p_dev->manf_id = manf_id.manf;
449 p_dev->card_id = manf_id.card;
450 p_dev->has_manf_id = 1;
451 p_dev->has_card_id = 1;
452 }
453
454 if (!pccard_read_tuple(p_dev->socket, p_dev->func,
455 CISTPL_FUNCID, &func_id)) {
456 p_dev->func_id = func_id.func;
457 p_dev->has_func_id = 1;
458 } else {
459 /* rule of thumb: cards with no FUNCID, but with
460 * common memory device geometry information, are
461 * probably memory cards (from pcmcia-cs) */
462 cistpl_device_geo_t devgeo;
463 if (!pccard_read_tuple(p_dev->socket, p_dev->func,
464 CISTPL_DEVICE_GEO, &devgeo)) {
465 ds_dbg(0, "mem device geometry probably means "
466 "FUNCID_MEMORY\n");
467 p_dev->func_id = CISTPL_FUNCID_MEMORY;
468 p_dev->has_func_id = 1;
469 }
470 }
471
472 if (!pccard_read_tuple(p_dev->socket, p_dev->func, CISTPL_VERS_1,
473 &vers1)) {
474 for (i=0; i < vers1.ns; i++) {
475 char *tmp;
476 unsigned int length;
477
478 tmp = vers1.str + vers1.ofs[i];
479
480 length = strlen(tmp) + 1;
481 if ((length < 3) || (length > 255))
482 continue;
483
484 p_dev->prod_id[i] = kmalloc(sizeof(char) * length,
485 GFP_KERNEL);
486 if (!p_dev->prod_id[i])
487 continue;
488
489 p_dev->prod_id[i] = strncpy(p_dev->prod_id[i],
490 tmp, length);
491 }
492 }
493
494 return 0;
495}
496
497
498/* device_add_lock is needed to avoid double registration by cardmgr and kernel.
499 * Serializes pcmcia_device_add; will most likely be removed in future.
500 *
501 * While it has the caveat that adding new PCMCIA devices inside(!) device_register()
502 * won't work, this doesn't matter much at the moment: the driver core doesn't
503 * support it either.
504 */
505static DECLARE_MUTEX(device_add_lock);
506
Dominik Brodowskidc109492005-06-27 16:28:50 -0700507struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int function)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508{
509 struct pcmcia_device *p_dev;
510 unsigned long flags;
511
Dominik Brodowskidc109492005-06-27 16:28:50 -0700512 s = pcmcia_get_socket(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 if (!s)
514 return NULL;
515
516 down(&device_add_lock);
517
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700518 /* max of 2 devices per card */
519 if (s->device_count == 2)
520 goto err_put;
521
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
523 if (!p_dev)
524 goto err_put;
525 memset(p_dev, 0, sizeof(struct pcmcia_device));
526
Dominik Brodowskidc109492005-06-27 16:28:50 -0700527 p_dev->socket = s;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 p_dev->device_no = (s->device_count++);
529 p_dev->func = function;
530
531 p_dev->dev.bus = &pcmcia_bus_type;
Dominik Brodowskidc109492005-06-27 16:28:50 -0700532 p_dev->dev.parent = s->dev.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 p_dev->dev.release = pcmcia_release_dev;
534 sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no);
535
536 /* compat */
537 p_dev->client.client_magic = CLIENT_MAGIC;
Dominik Brodowskidc109492005-06-27 16:28:50 -0700538 p_dev->client.Socket = s;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 p_dev->client.Function = function;
540 p_dev->client.state = CLIENT_UNBOUND;
541
542 /* Add to the list in pcmcia_bus_socket */
543 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
544 list_add_tail(&p_dev->socket_device_list, &s->devices_list);
545 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
546
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700547 pcmcia_device_query(p_dev);
548
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 if (device_register(&p_dev->dev)) {
550 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
551 list_del(&p_dev->socket_device_list);
552 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
553
554 goto err_free;
555 }
556
557 up(&device_add_lock);
558
559 return p_dev;
560
561 err_free:
562 kfree(p_dev);
563 s->device_count--;
564 err_put:
565 up(&device_add_lock);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700566 pcmcia_put_socket(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
568 return NULL;
569}
570
571
572static int pcmcia_card_add(struct pcmcia_socket *s)
573{
574 cisinfo_t cisinfo;
575 cistpl_longlink_mfc_t mfc;
576 unsigned int no_funcs, i;
577 int ret = 0;
578
579 if (!(s->resource_setup_done))
580 return -EAGAIN; /* try again, but later... */
581
582 pcmcia_validate_mem(s);
583 ret = pccard_validate_cis(s, BIND_FN_ALL, &cisinfo);
584 if (ret || !cisinfo.Chains) {
585 ds_dbg(0, "invalid CIS or invalid resources\n");
586 return -ENODEV;
587 }
588
589 if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC, &mfc))
590 no_funcs = mfc.nfn;
591 else
592 no_funcs = 1;
593
594 /* this doesn't handle multifunction devices on one pcmcia function
595 * yet. */
596 for (i=0; i < no_funcs; i++)
Dominik Brodowskidc109492005-06-27 16:28:50 -0700597 pcmcia_device_add(s, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598
599 return (ret);
600}
601
602
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700603static void pcmcia_delayed_add_pseudo_device(void *data)
604{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700605 struct pcmcia_socket *s = data;
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700606 pcmcia_device_add(s, 0);
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700607 s->pcmcia_state.device_add_pending = 0;
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700608}
609
Dominik Brodowskidc109492005-06-27 16:28:50 -0700610static inline void pcmcia_add_pseudo_device(struct pcmcia_socket *s)
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700611{
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700612 if (!s->pcmcia_state.device_add_pending) {
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700613 schedule_work(&s->device_add);
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700614 s->pcmcia_state.device_add_pending = 1;
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700615 }
616 return;
617}
618
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700619static int pcmcia_requery(struct device *dev, void * _data)
Dominik Brodowskiff1fa9e2005-06-27 16:28:09 -0700620{
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700621 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
622 if (!p_dev->dev.driver)
623 pcmcia_device_query(p_dev);
624
625 return 0;
626}
627
628static void pcmcia_bus_rescan(struct pcmcia_socket *skt)
629{
630 int no_devices=0;
631 unsigned long flags;
632
Dominik Brodowskiff1fa9e2005-06-27 16:28:09 -0700633 /* must be called with skt_sem held */
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700634 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700635 if (list_empty(&skt->devices_list))
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700636 no_devices=1;
637 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
638
639 /* if no devices were added for this socket yet because of
640 * missing resource information or other trouble, we need to
641 * do this now. */
642 if (no_devices) {
643 int ret = pcmcia_card_add(skt);
644 if (ret)
645 return;
646 }
647
648 /* some device information might have changed because of a CIS
649 * update or because we can finally read it correctly... so
650 * determine it again, overwriting old values if necessary. */
651 bus_for_each_dev(&pcmcia_bus_type, NULL, NULL, pcmcia_requery);
652
653 /* we re-scan all devices, not just the ones connected to this
654 * socket. This does not matter, though. */
Dominik Brodowskia5b55772005-06-27 16:28:10 -0700655 bus_rescan_devices(&pcmcia_bus_type);
Dominik Brodowskiff1fa9e2005-06-27 16:28:09 -0700656}
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700657
658static inline int pcmcia_devmatch(struct pcmcia_device *dev,
659 struct pcmcia_device_id *did)
660{
661 if (did->match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID) {
662 if ((!dev->has_manf_id) || (dev->manf_id != did->manf_id))
663 return 0;
664 }
665
666 if (did->match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID) {
667 if ((!dev->has_card_id) || (dev->card_id != did->card_id))
668 return 0;
669 }
670
671 if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION) {
672 if (dev->func != did->function)
673 return 0;
674 }
675
676 if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1) {
677 if (!dev->prod_id[0])
678 return 0;
679 if (strcmp(did->prod_id[0], dev->prod_id[0]))
680 return 0;
681 }
682
683 if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2) {
684 if (!dev->prod_id[1])
685 return 0;
686 if (strcmp(did->prod_id[1], dev->prod_id[1]))
687 return 0;
688 }
689
690 if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3) {
691 if (!dev->prod_id[2])
692 return 0;
693 if (strcmp(did->prod_id[2], dev->prod_id[2]))
694 return 0;
695 }
696
697 if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4) {
698 if (!dev->prod_id[3])
699 return 0;
700 if (strcmp(did->prod_id[3], dev->prod_id[3]))
701 return 0;
702 }
703
704 if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) {
705 /* handle pseudo multifunction devices:
706 * there are at most two pseudo multifunction devices.
707 * if we're matching against the first, schedule a
708 * call which will then check whether there are two
709 * pseudo devices, and if not, add the second one.
710 */
711 if (dev->device_no == 0)
Dominik Brodowskidc109492005-06-27 16:28:50 -0700712 pcmcia_add_pseudo_device(dev->socket);
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700713
714 if (dev->device_no != did->device_no)
715 return 0;
716 }
717
718 if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID) {
719 if ((!dev->has_func_id) || (dev->func_id != did->func_id))
720 return 0;
721
722 /* if this is a pseudo-multi-function device,
723 * we need explicit matches */
724 if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO)
725 return 0;
726 if (dev->device_no)
727 return 0;
728
729 /* also, FUNC_ID matching needs to be activated by userspace
730 * after it has re-checked that there is no possible module
731 * with a prod_id/manf_id/card_id match.
732 */
733 if (!dev->allow_func_id_match)
734 return 0;
735 }
736
Dominik Brodowskiea7b3882005-06-27 16:28:07 -0700737 if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) {
Dominik Brodowskidaa95172005-06-27 16:28:14 -0700738 if (!dev->socket->fake_cis)
739 pcmcia_load_firmware(dev, did->cisfile);
740
741 if (!dev->socket->fake_cis)
Dominik Brodowskiea7b3882005-06-27 16:28:07 -0700742 return 0;
Dominik Brodowskiea7b3882005-06-27 16:28:07 -0700743 }
744
Dominik Brodowskif602ff72005-06-27 16:28:09 -0700745 if (did->match_flags & PCMCIA_DEV_ID_MATCH_ANONYMOUS) {
746 int i;
747 for (i=0; i<4; i++)
748 if (dev->prod_id[i])
749 return 0;
750 if (dev->has_manf_id || dev->has_card_id || dev->has_func_id)
751 return 0;
752 }
753
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700754 dev->dev.driver_data = (void *) did;
755
756 return 1;
757}
758
759
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) {
761 struct pcmcia_device * p_dev = to_pcmcia_dev(dev);
762 struct pcmcia_driver * p_drv = to_pcmcia_drv(drv);
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700763 struct pcmcia_device_id *did = p_drv->id_table;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
765 /* matching by cardmgr */
766 if (p_dev->cardmgr == p_drv)
767 return 1;
768
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700769 while (did && did->match_flags) {
770 if (pcmcia_devmatch(p_dev, did))
771 return 1;
772 did++;
773 }
774
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 return 0;
776}
777
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700778#ifdef CONFIG_HOTPLUG
779
780static int pcmcia_bus_hotplug(struct device *dev, char **envp, int num_envp,
781 char *buffer, int buffer_size)
782{
783 struct pcmcia_device *p_dev;
784 int i, length = 0;
785 u32 hash[4] = { 0, 0, 0, 0};
786
787 if (!dev)
788 return -ENODEV;
789
790 p_dev = to_pcmcia_dev(dev);
791
792 /* calculate hashes */
793 for (i=0; i<4; i++) {
794 if (!p_dev->prod_id[i])
795 continue;
796 hash[i] = crc32(0, p_dev->prod_id[i], strlen(p_dev->prod_id[i]));
797 }
798
799 i = 0;
800
801 if (add_hotplug_env_var(envp, num_envp, &i,
802 buffer, buffer_size, &length,
803 "SOCKET_NO=%u",
804 p_dev->socket->sock))
805 return -ENOMEM;
806
807 if (add_hotplug_env_var(envp, num_envp, &i,
808 buffer, buffer_size, &length,
809 "DEVICE_NO=%02X",
810 p_dev->device_no))
811 return -ENOMEM;
812
813 if (add_hotplug_env_var(envp, num_envp, &i,
814 buffer, buffer_size, &length,
815 "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
816 "pa%08Xpb%08Xpc%08Xpd%08X",
817 p_dev->has_manf_id ? p_dev->manf_id : 0,
818 p_dev->has_card_id ? p_dev->card_id : 0,
819 p_dev->has_func_id ? p_dev->func_id : 0,
820 p_dev->func,
821 p_dev->device_no,
822 hash[0],
823 hash[1],
824 hash[2],
825 hash[3]))
826 return -ENOMEM;
827
828 envp[i] = NULL;
829
830 return 0;
831}
832
833#else
834
835static int pcmcia_bus_hotplug(struct device *dev, char **envp, int num_envp,
836 char *buffer, int buffer_size)
837{
838 return -ENODEV;
839}
840
841#endif
842
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843/************************ per-device sysfs output ***************************/
844
845#define pcmcia_device_attr(field, test, format) \
Yani Ioannoue404e272005-05-17 06:42:58 -0400846static ssize_t field##_show (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847{ \
848 struct pcmcia_device *p_dev = to_pcmcia_dev(dev); \
849 return p_dev->test ? sprintf (buf, format, p_dev->field) : -ENODEV; \
850}
851
852#define pcmcia_device_stringattr(name, field) \
Yani Ioannoue404e272005-05-17 06:42:58 -0400853static ssize_t name##_show (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854{ \
855 struct pcmcia_device *p_dev = to_pcmcia_dev(dev); \
856 return p_dev->field ? sprintf (buf, "%s\n", p_dev->field) : -ENODEV; \
857}
858
859pcmcia_device_attr(func, socket, "0x%02x\n");
860pcmcia_device_attr(func_id, has_func_id, "0x%02x\n");
861pcmcia_device_attr(manf_id, has_manf_id, "0x%04x\n");
862pcmcia_device_attr(card_id, has_card_id, "0x%04x\n");
863pcmcia_device_stringattr(prod_id1, prod_id[0]);
864pcmcia_device_stringattr(prod_id2, prod_id[1]);
865pcmcia_device_stringattr(prod_id3, prod_id[2]);
866pcmcia_device_stringattr(prod_id4, prod_id[3]);
867
Dominik Brodowskia5b55772005-06-27 16:28:10 -0700868
869static ssize_t pcmcia_store_allow_func_id_match (struct device * dev, struct device_attribute *attr,
870 const char * buf, size_t count)
871{
872 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
873 if (!count)
874 return -EINVAL;
875
876 down(&p_dev->socket->skt_sem);
877 p_dev->allow_func_id_match = 1;
878 up(&p_dev->socket->skt_sem);
879
880 bus_rescan_devices(&pcmcia_bus_type);
881
882 return count;
883}
884
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885static struct device_attribute pcmcia_dev_attrs[] = {
886 __ATTR(function, 0444, func_show, NULL),
887 __ATTR_RO(func_id),
888 __ATTR_RO(manf_id),
889 __ATTR_RO(card_id),
890 __ATTR_RO(prod_id1),
891 __ATTR_RO(prod_id2),
892 __ATTR_RO(prod_id3),
893 __ATTR_RO(prod_id4),
Dominik Brodowskia5b55772005-06-27 16:28:10 -0700894 __ATTR(allow_func_id_match, 0200, NULL, pcmcia_store_allow_func_id_match),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 __ATTR_NULL,
896};
897
898
899/*======================================================================
900
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 The card status event handler.
902
903======================================================================*/
904
905struct send_event_data {
906 struct pcmcia_socket *skt;
907 event_t event;
908 int priority;
909};
910
911static int send_event_callback(struct device *dev, void * _data)
912{
913 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
914 struct send_event_data *data = _data;
915
916 /* we get called for all sockets, but may only pass the event
917 * for drivers _on the affected socket_ */
918 if (p_dev->socket != data->skt)
919 return 0;
920
921 if (p_dev->client.state & (CLIENT_UNBOUND|CLIENT_STALE))
922 return 0;
923
924 if (p_dev->client.EventMask & data->event)
925 return EVENT(&p_dev->client, data->event, data->priority);
926
927 return 0;
928}
929
930static int send_event(struct pcmcia_socket *s, event_t event, int priority)
931{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 struct send_event_data private;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933
934 private.skt = s;
935 private.event = event;
936 private.priority = priority;
937
Dominik Brodowskidc109492005-06-27 16:28:50 -0700938 return bus_for_each_dev(&pcmcia_bus_type, NULL, &private, send_event_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939} /* send_event */
940
941
942/* Normally, the event is passed to individual drivers after
943 * informing userspace. Only for CS_EVENT_CARD_REMOVAL this
944 * is inversed to maintain historic compatibility.
945 */
946
947static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
948{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700949 struct pcmcia_socket *s = pcmcia_get_socket(skt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 int ret = 0;
951
952 ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n",
Dominik Brodowskidc109492005-06-27 16:28:50 -0700953 event, priority, skt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954
955 switch (event) {
956
957 case CS_EVENT_CARD_REMOVAL:
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700958 s->pcmcia_state.present = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 send_event(skt, event, priority);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700960 unbind_request(skt);
961 handle_event(skt, event);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 break;
963
964 case CS_EVENT_CARD_INSERTION:
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700965 s->pcmcia_state.present = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 pcmcia_card_add(skt);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700967 handle_event(skt, event);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 break;
969
970 case CS_EVENT_EJECTION_REQUEST:
971 ret = send_event(skt, event, priority);
972 break;
973
974 default:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700975 handle_event(skt, event);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 send_event(skt, event, priority);
977 break;
978 }
979
Dominik Brodowskidc109492005-06-27 16:28:50 -0700980 pcmcia_put_socket(s);
981
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 return 0;
983} /* ds_event */
984
985
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
987int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
988{
989 client_t *client = NULL;
Dominik Brodowskidc109492005-06-27 16:28:50 -0700990 struct pcmcia_socket *s = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 struct pcmcia_device *p_dev = NULL;
992
993 /* Look for unbound client with matching dev_info */
994 down_read(&pcmcia_socket_list_rwsem);
995 list_for_each_entry(s, &pcmcia_socket_list, socket_list) {
996 unsigned long flags;
997
998 if (s->state & SOCKET_CARDBUS)
999 continue;
1000
Dominik Brodowskidc109492005-06-27 16:28:50 -07001001 s = pcmcia_get_socket(s);
1002 if (!s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 continue;
1004 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
Dominik Brodowskidc109492005-06-27 16:28:50 -07001005 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 struct pcmcia_driver *p_drv;
1007 p_dev = pcmcia_get_dev(p_dev);
1008 if (!p_dev)
1009 continue;
1010 if (!(p_dev->client.state & CLIENT_UNBOUND) ||
1011 (!p_dev->dev.driver)) {
1012 pcmcia_put_dev(p_dev);
1013 continue;
1014 }
1015 p_drv = to_pcmcia_drv(p_dev->dev.driver);
1016 if (!strncmp(p_drv->drv.name, (char *)req->dev_info, DEV_NAME_LEN)) {
1017 client = &p_dev->client;
1018 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
1019 goto found;
1020 }
1021 pcmcia_put_dev(p_dev);
1022 }
1023 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
Dominik Brodowskidc109492005-06-27 16:28:50 -07001024 pcmcia_put_socket(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 }
1026 found:
1027 up_read(&pcmcia_socket_list_rwsem);
1028 if (!p_dev || !client)
1029 return -ENODEV;
1030
Dominik Brodowskidc109492005-06-27 16:28:50 -07001031 pcmcia_put_socket(s); /* safe, as we already hold a reference from bind_device */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
1033 *handle = client;
1034 client->state &= ~CLIENT_UNBOUND;
1035 client->Socket = s;
1036 client->EventMask = req->EventMask;
1037 client->event_handler = req->event_handler;
1038 client->event_callback_args = req->event_callback_args;
1039 client->event_callback_args.client_handle = client;
1040
1041 if (s->state & SOCKET_CARDBUS)
1042 client->state |= CLIENT_CARDBUS;
1043
1044 if ((!(s->state & SOCKET_CARDBUS)) && (s->functions == 0) &&
1045 (client->Function != BIND_FN_ALL)) {
1046 cistpl_longlink_mfc_t mfc;
1047 if (pccard_read_tuple(s, client->Function, CISTPL_LONGLINK_MFC, &mfc)
1048 == CS_SUCCESS)
1049 s->functions = mfc.nfn;
1050 else
1051 s->functions = 1;
1052 s->config = kmalloc(sizeof(config_t) * s->functions,
1053 GFP_KERNEL);
1054 if (!s->config)
1055 goto out_no_resource;
1056 memset(s->config, 0, sizeof(config_t) * s->functions);
1057 }
1058
1059 ds_dbg(1, "register_client(): client 0x%p, dev %s\n",
1060 client, p_dev->dev.bus_id);
1061 if (client->EventMask & CS_EVENT_REGISTRATION_COMPLETE)
1062 EVENT(client, CS_EVENT_REGISTRATION_COMPLETE, CS_EVENT_PRI_LOW);
1063
1064 if ((s->state & (SOCKET_PRESENT|SOCKET_CARDBUS)) == SOCKET_PRESENT) {
1065 if (client->EventMask & CS_EVENT_CARD_INSERTION)
1066 EVENT(client, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
1067 }
1068
1069 return CS_SUCCESS;
1070
1071 out_no_resource:
1072 pcmcia_put_dev(p_dev);
1073 return CS_OUT_OF_RESOURCE;
1074} /* register_client */
1075EXPORT_SYMBOL(pcmcia_register_client);
1076
1077
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078/* unbind _all_ devices attached to a given pcmcia_bus_socket. The
1079 * drivers have been called with EVENT_CARD_REMOVAL before.
1080 */
Dominik Brodowskidc109492005-06-27 16:28:50 -07001081static int unbind_request(struct pcmcia_socket *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082{
1083 struct pcmcia_device *p_dev;
1084 unsigned long flags;
1085
Dominik Brodowskidc109492005-06-27 16:28:50 -07001086 ds_dbg(2, "unbind_request(%d)\n", s->sock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087
1088 s->device_count = 0;
1089
1090 for (;;) {
1091 /* unregister all pcmcia_devices registered with this socket*/
1092 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
1093 if (list_empty(&s->devices_list)) {
1094 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
1095 return 0;
1096 }
1097 p_dev = list_entry((&s->devices_list)->next, struct pcmcia_device, socket_device_list);
1098 list_del(&p_dev->socket_device_list);
1099 p_dev->client.state |= CLIENT_STALE;
1100 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
1101
1102 device_unregister(&p_dev->dev);
1103 }
1104
1105 return 0;
1106} /* unbind_request */
1107
1108int pcmcia_deregister_client(client_handle_t handle)
1109{
1110 struct pcmcia_socket *s;
1111 int i;
1112 struct pcmcia_device *p_dev = handle_to_pdev(handle);
1113
1114 if (CHECK_HANDLE(handle))
1115 return CS_BAD_HANDLE;
1116
1117 s = SOCKET(handle);
1118 ds_dbg(1, "deregister_client(%p)\n", handle);
1119
1120 if (handle->state & (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED))
1121 goto warn_out;
1122 for (i = 0; i < MAX_WIN; i++)
1123 if (handle->state & CLIENT_WIN_REQ(i))
1124 goto warn_out;
1125
1126 if (handle->state & CLIENT_STALE) {
1127 handle->client_magic = 0;
1128 handle->state &= ~CLIENT_STALE;
1129 pcmcia_put_dev(p_dev);
1130 } else {
1131 handle->state = CLIENT_UNBOUND;
1132 handle->event_handler = NULL;
1133 }
1134
1135 return CS_SUCCESS;
1136 warn_out:
1137 printk(KERN_WARNING "ds: deregister_client was called too early.\n");
1138 return CS_IN_USE;
1139} /* deregister_client */
1140EXPORT_SYMBOL(pcmcia_deregister_client);
1141
Dominik Brodowski90c6cdd2005-06-27 16:28:49 -07001142static struct pcmcia_callback pcmcia_bus_callback = {
1143 .owner = THIS_MODULE,
1144 .event = ds_event,
1145 .requery = pcmcia_bus_rescan,
1146};
1147
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev)
1149{
1150 struct pcmcia_socket *socket = class_get_devdata(class_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 int ret;
1152
Dominik Brodowskidc109492005-06-27 16:28:50 -07001153 socket = pcmcia_get_socket(socket);
1154 if (!socket) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 printk(KERN_ERR "PCMCIA obtaining reference to socket %p failed\n", socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 return -ENODEV;
1157 }
1158
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 /*
1160 * Ugly. But we want to wait for the socket threads to have started up.
1161 * We really should let the drivers themselves drive some of this..
1162 */
1163 msleep(250);
1164
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001165#ifdef CONFIG_PCMCIA_IOCTL
Dominik Brodowskidc109492005-06-27 16:28:50 -07001166 init_waitqueue_head(&socket->queue);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001167#endif
Dominik Brodowskidc109492005-06-27 16:28:50 -07001168 INIT_LIST_HEAD(&socket->devices_list);
1169 INIT_WORK(&socket->device_add, pcmcia_delayed_add_pseudo_device, socket);
1170 memset(&socket->pcmcia_state, 0, sizeof(u8));
1171 socket->device_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172
Dominik Brodowski90c6cdd2005-06-27 16:28:49 -07001173 ret = pccard_register_pcmcia(socket, &pcmcia_bus_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 if (ret) {
1175 printk(KERN_ERR "PCMCIA registration PCCard core failed for socket %p\n", socket);
Dominik Brodowskidc109492005-06-27 16:28:50 -07001176 pcmcia_put_socket(socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 return (ret);
1178 }
1179
1180 return 0;
1181}
1182
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183static void pcmcia_bus_remove_socket(struct class_device *class_dev)
1184{
1185 struct pcmcia_socket *socket = class_get_devdata(class_dev);
1186
Dominik Brodowskidc109492005-06-27 16:28:50 -07001187 if (!socket)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 return;
1189
Dominik Brodowskidc109492005-06-27 16:28:50 -07001190 socket->pcmcia_state.dead = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 pccard_register_pcmcia(socket, NULL);
1192
Dominik Brodowskidc109492005-06-27 16:28:50 -07001193 pcmcia_put_socket(socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194
1195 return;
1196}
1197
1198
1199/* the pcmcia_bus_interface is used to handle pcmcia socket devices */
1200static struct class_interface pcmcia_bus_interface = {
1201 .class = &pcmcia_socket_class,
1202 .add = &pcmcia_bus_add_socket,
1203 .remove = &pcmcia_bus_remove_socket,
1204};
1205
1206
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001207struct bus_type pcmcia_bus_type = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 .name = "pcmcia",
Dominik Brodowski840c2ac2005-06-27 16:28:04 -07001209 .hotplug = pcmcia_bus_hotplug,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 .match = pcmcia_bus_match,
1211 .dev_attrs = pcmcia_dev_attrs,
1212};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213
1214
1215static int __init init_pcmcia_bus(void)
1216{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 spin_lock_init(&pcmcia_dev_list_lock);
1218
1219 bus_register(&pcmcia_bus_type);
1220 class_interface_register(&pcmcia_bus_interface);
1221
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001222 pcmcia_setup_ioctl();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223
1224 return 0;
1225}
1226fs_initcall(init_pcmcia_bus); /* one level after subsys_initcall so that
1227 * pcmcia_socket_class is already registered */
1228
1229
1230static void __exit exit_pcmcia_bus(void)
1231{
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001232 pcmcia_cleanup_ioctl();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001234 class_interface_unregister(&pcmcia_bus_interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235
1236 bus_unregister(&pcmcia_bus_type);
1237}
1238module_exit(exit_pcmcia_bus);
1239
1240
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241MODULE_ALIAS("ds");