aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/pcmcia/driver.txt30
-rw-r--r--drivers/pcmcia/ds.c113
-rw-r--r--include/pcmcia/ds.h6
3 files changed, 148 insertions, 1 deletions
diff --git a/Documentation/pcmcia/driver.txt b/Documentation/pcmcia/driver.txt
new file mode 100644
index 000000000000..0ac167920778
--- /dev/null
+++ b/Documentation/pcmcia/driver.txt
@@ -0,0 +1,30 @@
1PCMCIA Driver
2-------------
3
4
5sysfs
6-----
7
8New PCMCIA IDs may be added to a device driver pcmcia_device_id table at
9runtime as shown below:
10
11echo "match_flags manf_id card_id func_id function device_no \
12prod_id_hash[0] prod_id_hash[1] prod_id_hash[2] prod_id_hash[3]" > \
13/sys/bus/pcmcia/drivers/{driver}/new_id
14
15All fields are passed in as hexadecimal values (no leading 0x).
16The meaning is described in the PCMCIA specification, the match_flags is
17a bitwise or-ed combination from PCMCIA_DEV_ID_MATCH_* constants
18defined in include/linux/mod_devicetable.h.
19
20Once added, the driver probe routine will be invoked for any unclaimed
21PCMCIA device listed in its (newly updated) pcmcia_device_id list.
22
23A common use-case is to add a new device according to the manufacturer ID
24and the card ID (form the manf_id and card_id file in the device tree).
25For this, just use:
26
27echo "0x3 manf_id card_id 0 0 0 0 0 0 0" > \
28 /sys/bus/pcmcia/drivers/{driver}/new_id
29
30after loading the driver.
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 18e111e12339..143c6efc478a 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -234,6 +234,89 @@ static void pcmcia_check_driver(struct pcmcia_driver *p_drv)
234/*======================================================================*/ 234/*======================================================================*/
235 235
236 236
237struct pcmcia_dynid {
238 struct list_head node;
239 struct pcmcia_device_id id;
240};
241
242/**
243 * pcmcia_store_new_id - add a new PCMCIA device ID to this driver and re-probe devices
244 * @driver: target device driver
245 * @buf: buffer for scanning device ID data
246 * @count: input size
247 *
248 * Adds a new dynamic PCMCIA device ID to this driver,
249 * and causes the driver to probe for all devices again.
250 */
251static ssize_t
252pcmcia_store_new_id(struct device_driver *driver, const char *buf, size_t count)
253{
254 struct pcmcia_dynid *dynid;
255 struct pcmcia_driver *pdrv = to_pcmcia_drv(driver);
256 __u16 match_flags, manf_id, card_id;
257 __u8 func_id, function, device_no;
258 __u32 prod_id_hash[4] = {0, 0, 0, 0};
259 int fields=0;
260 int retval = 0;
261
262 fields = sscanf(buf, "%hx %hx %hx %hhx %hhx %hhx %x %x %x %x",
263 &match_flags, &manf_id, &card_id, &func_id, &function, &device_no,
264 &prod_id_hash[0], &prod_id_hash[1], &prod_id_hash[2], &prod_id_hash[3]);
265 if (fields < 6)
266 return -EINVAL;
267
268 dynid = kzalloc(sizeof(struct pcmcia_dynid), GFP_KERNEL);
269 if (!dynid)
270 return -ENOMEM;
271
272 INIT_LIST_HEAD(&dynid->node);
273 dynid->id.match_flags = match_flags;
274 dynid->id.manf_id = manf_id;
275 dynid->id.card_id = card_id;
276 dynid->id.func_id = func_id;
277 dynid->id.function = function;
278 dynid->id.device_no = device_no;
279 memcpy(dynid->id.prod_id_hash, prod_id_hash, sizeof(__u32) * 4);
280
281 spin_lock(&pdrv->dynids.lock);
282 list_add_tail(&pdrv->dynids.list, &dynid->node);
283 spin_unlock(&pdrv->dynids.lock);
284
285 if (get_driver(&pdrv->drv)) {
286 retval = driver_attach(&pdrv->drv);
287 put_driver(&pdrv->drv);
288 }
289
290 if (retval)
291 return retval;
292 return count;
293}
294static DRIVER_ATTR(new_id, S_IWUSR, NULL, pcmcia_store_new_id);
295
296static void
297pcmcia_free_dynids(struct pcmcia_driver *drv)
298{
299 struct pcmcia_dynid *dynid, *n;
300
301 spin_lock(&drv->dynids.lock);
302 list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) {
303 list_del(&dynid->node);
304 kfree(dynid);
305 }
306 spin_unlock(&drv->dynids.lock);
307}
308
309static int
310pcmcia_create_newid_file(struct pcmcia_driver *drv)
311{
312 int error = 0;
313 if (drv->probe != NULL)
314 error = sysfs_create_file(&drv->drv.kobj,
315 &driver_attr_new_id.attr);
316 return error;
317}
318
319
237/** 320/**
238 * pcmcia_register_driver - register a PCMCIA driver with the bus core 321 * pcmcia_register_driver - register a PCMCIA driver with the bus core
239 * 322 *
@@ -241,6 +324,8 @@ static void pcmcia_check_driver(struct pcmcia_driver *p_drv)
241 */ 324 */
242int pcmcia_register_driver(struct pcmcia_driver *driver) 325int pcmcia_register_driver(struct pcmcia_driver *driver)
243{ 326{
327 int error;
328
244 if (!driver) 329 if (!driver)
245 return -EINVAL; 330 return -EINVAL;
246 331
@@ -249,10 +334,20 @@ int pcmcia_register_driver(struct pcmcia_driver *driver)
249 /* initialize common fields */ 334 /* initialize common fields */
250 driver->drv.bus = &pcmcia_bus_type; 335 driver->drv.bus = &pcmcia_bus_type;
251 driver->drv.owner = driver->owner; 336 driver->drv.owner = driver->owner;
337 spin_lock_init(&driver->dynids.lock);
338 INIT_LIST_HEAD(&driver->dynids.list);
252 339
253 ds_dbg(3, "registering driver %s\n", driver->drv.name); 340 ds_dbg(3, "registering driver %s\n", driver->drv.name);
254 341
255 return driver_register(&driver->drv); 342 error = driver_register(&driver->drv);
343 if (error < 0)
344 return error;
345
346 error = pcmcia_create_newid_file(driver);
347 if (error)
348 driver_unregister(&driver->drv);
349
350 return error;
256} 351}
257EXPORT_SYMBOL(pcmcia_register_driver); 352EXPORT_SYMBOL(pcmcia_register_driver);
258 353
@@ -263,6 +358,7 @@ void pcmcia_unregister_driver(struct pcmcia_driver *driver)
263{ 358{
264 ds_dbg(3, "unregistering driver %s\n", driver->drv.name); 359 ds_dbg(3, "unregistering driver %s\n", driver->drv.name);
265 driver_unregister(&driver->drv); 360 driver_unregister(&driver->drv);
361 pcmcia_free_dynids(driver);
266} 362}
267EXPORT_SYMBOL(pcmcia_unregister_driver); 363EXPORT_SYMBOL(pcmcia_unregister_driver);
268 364
@@ -927,6 +1023,21 @@ static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) {
927 struct pcmcia_device * p_dev = to_pcmcia_dev(dev); 1023 struct pcmcia_device * p_dev = to_pcmcia_dev(dev);
928 struct pcmcia_driver * p_drv = to_pcmcia_drv(drv); 1024 struct pcmcia_driver * p_drv = to_pcmcia_drv(drv);
929 struct pcmcia_device_id *did = p_drv->id_table; 1025 struct pcmcia_device_id *did = p_drv->id_table;
1026 struct pcmcia_dynid *dynid;
1027
1028 /* match dynamic devices first */
1029 spin_lock(&p_drv->dynids.lock);
1030 list_for_each_entry(dynid, &p_drv->dynids.list, node) {
1031 ds_dbg(3, "trying to match %s to %s\n", dev->bus_id,
1032 drv->name);
1033 if (pcmcia_devmatch(p_dev, &dynid->id)) {
1034 ds_dbg(0, "matched %s to %s\n", dev->bus_id,
1035 drv->name);
1036 spin_unlock(&p_drv->dynids.lock);
1037 return 1;
1038 }
1039 }
1040 spin_unlock(&p_drv->dynids.lock);
930 1041
931#ifdef CONFIG_PCMCIA_IOCTL 1042#ifdef CONFIG_PCMCIA_IOCTL
932 /* matching by cardmgr */ 1043 /* matching by cardmgr */
diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h
index 8c339f5678cf..90ef552c42dd 100644
--- a/include/pcmcia/ds.h
+++ b/include/pcmcia/ds.h
@@ -108,6 +108,11 @@ typedef struct dev_node_t {
108struct pcmcia_socket; 108struct pcmcia_socket;
109struct config_t; 109struct config_t;
110 110
111struct pcmcia_dynids {
112 spinlock_t lock;
113 struct list_head list;
114};
115
111struct pcmcia_driver { 116struct pcmcia_driver {
112 int (*probe) (struct pcmcia_device *dev); 117 int (*probe) (struct pcmcia_device *dev);
113 void (*remove) (struct pcmcia_device *dev); 118 void (*remove) (struct pcmcia_device *dev);
@@ -118,6 +123,7 @@ struct pcmcia_driver {
118 struct module *owner; 123 struct module *owner;
119 struct pcmcia_device_id *id_table; 124 struct pcmcia_device_id *id_table;
120 struct device_driver drv; 125 struct device_driver drv;
126 struct pcmcia_dynids dynids;
121}; 127};
122 128
123/* driver registration */ 129/* driver registration */