aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pcmcia
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pcmcia')
-rw-r--r--drivers/pcmcia/ds.c113
1 files changed, 112 insertions, 1 deletions
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 */