diff options
Diffstat (limited to 'drivers/base/firmware_class.c')
| -rw-r--r-- | drivers/base/firmware_class.c | 79 |
1 files changed, 50 insertions, 29 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 652281402c92..5bfa2e9a7c26 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c | |||
| @@ -28,6 +28,7 @@ enum { | |||
| 28 | FW_STATUS_DONE, | 28 | FW_STATUS_DONE, |
| 29 | FW_STATUS_ABORT, | 29 | FW_STATUS_ABORT, |
| 30 | FW_STATUS_READY, | 30 | FW_STATUS_READY, |
| 31 | FW_STATUS_READY_NOHOTPLUG, | ||
| 31 | }; | 32 | }; |
| 32 | 33 | ||
| 33 | static int loading_timeout = 10; /* In seconds */ | 34 | static int loading_timeout = 10; /* In seconds */ |
| @@ -344,7 +345,7 @@ error_kfree: | |||
| 344 | 345 | ||
| 345 | static int | 346 | static int |
| 346 | fw_setup_class_device(struct firmware *fw, struct class_device **class_dev_p, | 347 | fw_setup_class_device(struct firmware *fw, struct class_device **class_dev_p, |
| 347 | const char *fw_name, struct device *device) | 348 | const char *fw_name, struct device *device, int hotplug) |
| 348 | { | 349 | { |
| 349 | struct class_device *class_dev; | 350 | struct class_device *class_dev; |
| 350 | struct firmware_priv *fw_priv; | 351 | struct firmware_priv *fw_priv; |
| @@ -376,7 +377,10 @@ fw_setup_class_device(struct firmware *fw, struct class_device **class_dev_p, | |||
| 376 | goto error_unreg; | 377 | goto error_unreg; |
| 377 | } | 378 | } |
| 378 | 379 | ||
| 379 | set_bit(FW_STATUS_READY, &fw_priv->status); | 380 | if (hotplug) |
| 381 | set_bit(FW_STATUS_READY, &fw_priv->status); | ||
| 382 | else | ||
| 383 | set_bit(FW_STATUS_READY_NOHOTPLUG, &fw_priv->status); | ||
| 380 | *class_dev_p = class_dev; | 384 | *class_dev_p = class_dev; |
| 381 | goto out; | 385 | goto out; |
| 382 | 386 | ||
| @@ -386,21 +390,9 @@ out: | |||
| 386 | return retval; | 390 | return retval; |
| 387 | } | 391 | } |
| 388 | 392 | ||
| 389 | /** | 393 | static int |
| 390 | * request_firmware: - request firmware to hotplug and wait for it | 394 | _request_firmware(const struct firmware **firmware_p, const char *name, |
| 391 | * Description: | 395 | struct device *device, int hotplug) |
| 392 | * @firmware will be used to return a firmware image by the name | ||
| 393 | * of @name for device @device. | ||
| 394 | * | ||
| 395 | * Should be called from user context where sleeping is allowed. | ||
| 396 | * | ||
| 397 | * @name will be use as $FIRMWARE in the hotplug environment and | ||
| 398 | * should be distinctive enough not to be confused with any other | ||
| 399 | * firmware image for this or any other device. | ||
| 400 | **/ | ||
| 401 | int | ||
| 402 | request_firmware(const struct firmware **firmware_p, const char *name, | ||
| 403 | struct device *device) | ||
| 404 | { | 396 | { |
| 405 | struct class_device *class_dev; | 397 | struct class_device *class_dev; |
| 406 | struct firmware_priv *fw_priv; | 398 | struct firmware_priv *fw_priv; |
| @@ -419,22 +411,25 @@ request_firmware(const struct firmware **firmware_p, const char *name, | |||
| 419 | } | 411 | } |
| 420 | memset(firmware, 0, sizeof (*firmware)); | 412 | memset(firmware, 0, sizeof (*firmware)); |
| 421 | 413 | ||
| 422 | retval = fw_setup_class_device(firmware, &class_dev, name, device); | 414 | retval = fw_setup_class_device(firmware, &class_dev, name, device, |
| 415 | hotplug); | ||
| 423 | if (retval) | 416 | if (retval) |
| 424 | goto error_kfree_fw; | 417 | goto error_kfree_fw; |
| 425 | 418 | ||
| 426 | fw_priv = class_get_devdata(class_dev); | 419 | fw_priv = class_get_devdata(class_dev); |
| 427 | 420 | ||
| 428 | if (loading_timeout > 0) { | 421 | if (hotplug) { |
| 429 | fw_priv->timeout.expires = jiffies + loading_timeout * HZ; | 422 | if (loading_timeout > 0) { |
| 430 | add_timer(&fw_priv->timeout); | 423 | fw_priv->timeout.expires = jiffies + loading_timeout * HZ; |
| 431 | } | 424 | add_timer(&fw_priv->timeout); |
| 432 | 425 | } | |
| 433 | kobject_hotplug(&class_dev->kobj, KOBJ_ADD); | ||
| 434 | wait_for_completion(&fw_priv->completion); | ||
| 435 | set_bit(FW_STATUS_DONE, &fw_priv->status); | ||
| 436 | 426 | ||
| 437 | del_timer_sync(&fw_priv->timeout); | 427 | kobject_hotplug(&class_dev->kobj, KOBJ_ADD); |
| 428 | wait_for_completion(&fw_priv->completion); | ||
| 429 | set_bit(FW_STATUS_DONE, &fw_priv->status); | ||
| 430 | del_timer_sync(&fw_priv->timeout); | ||
| 431 | } else | ||
| 432 | wait_for_completion(&fw_priv->completion); | ||
| 438 | 433 | ||
| 439 | down(&fw_lock); | 434 | down(&fw_lock); |
| 440 | if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status)) { | 435 | if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status)) { |
| @@ -455,6 +450,26 @@ out: | |||
| 455 | } | 450 | } |
| 456 | 451 | ||
| 457 | /** | 452 | /** |
| 453 | * request_firmware: - request firmware to hotplug and wait for it | ||
| 454 | * Description: | ||
| 455 | * @firmware will be used to return a firmware image by the name | ||
| 456 | * of @name for device @device. | ||
| 457 | * | ||
| 458 | * Should be called from user context where sleeping is allowed. | ||
| 459 | * | ||
| 460 | * @name will be use as $FIRMWARE in the hotplug environment and | ||
| 461 | * should be distinctive enough not to be confused with any other | ||
| 462 | * firmware image for this or any other device. | ||
| 463 | **/ | ||
| 464 | int | ||
| 465 | request_firmware(const struct firmware **firmware_p, const char *name, | ||
| 466 | struct device *device) | ||
| 467 | { | ||
| 468 | int hotplug = 1; | ||
| 469 | return _request_firmware(firmware_p, name, device, hotplug); | ||
| 470 | } | ||
| 471 | |||
| 472 | /** | ||
| 458 | * release_firmware: - release the resource associated with a firmware image | 473 | * release_firmware: - release the resource associated with a firmware image |
| 459 | **/ | 474 | **/ |
| 460 | void | 475 | void |
| @@ -491,6 +506,7 @@ struct firmware_work { | |||
| 491 | struct device *device; | 506 | struct device *device; |
| 492 | void *context; | 507 | void *context; |
| 493 | void (*cont)(const struct firmware *fw, void *context); | 508 | void (*cont)(const struct firmware *fw, void *context); |
| 509 | int hotplug; | ||
| 494 | }; | 510 | }; |
| 495 | 511 | ||
| 496 | static int | 512 | static int |
| @@ -503,7 +519,8 @@ request_firmware_work_func(void *arg) | |||
| 503 | return 0; | 519 | return 0; |
| 504 | } | 520 | } |
| 505 | daemonize("%s/%s", "firmware", fw_work->name); | 521 | daemonize("%s/%s", "firmware", fw_work->name); |
| 506 | request_firmware(&fw, fw_work->name, fw_work->device); | 522 | _request_firmware(&fw, fw_work->name, fw_work->device, |
| 523 | fw_work->hotplug); | ||
| 507 | fw_work->cont(fw, fw_work->context); | 524 | fw_work->cont(fw, fw_work->context); |
| 508 | release_firmware(fw); | 525 | release_firmware(fw); |
| 509 | module_put(fw_work->module); | 526 | module_put(fw_work->module); |
| @@ -518,6 +535,9 @@ request_firmware_work_func(void *arg) | |||
| 518 | * Asynchronous variant of request_firmware() for contexts where | 535 | * Asynchronous variant of request_firmware() for contexts where |
| 519 | * it is not possible to sleep. | 536 | * it is not possible to sleep. |
| 520 | * | 537 | * |
| 538 | * @hotplug invokes hotplug event to copy the firmware image if this flag | ||
| 539 | * is non-zero else the firmware copy must be done manually. | ||
| 540 | * | ||
| 521 | * @cont will be called asynchronously when the firmware request is over. | 541 | * @cont will be called asynchronously when the firmware request is over. |
| 522 | * | 542 | * |
| 523 | * @context will be passed over to @cont. | 543 | * @context will be passed over to @cont. |
| @@ -527,7 +547,7 @@ request_firmware_work_func(void *arg) | |||
| 527 | **/ | 547 | **/ |
| 528 | int | 548 | int |
| 529 | request_firmware_nowait( | 549 | request_firmware_nowait( |
| 530 | struct module *module, | 550 | struct module *module, int hotplug, |
| 531 | const char *name, struct device *device, void *context, | 551 | const char *name, struct device *device, void *context, |
| 532 | void (*cont)(const struct firmware *fw, void *context)) | 552 | void (*cont)(const struct firmware *fw, void *context)) |
| 533 | { | 553 | { |
| @@ -548,6 +568,7 @@ request_firmware_nowait( | |||
| 548 | .device = device, | 568 | .device = device, |
| 549 | .context = context, | 569 | .context = context, |
| 550 | .cont = cont, | 570 | .cont = cont, |
| 571 | .hotplug = hotplug, | ||
| 551 | }; | 572 | }; |
| 552 | 573 | ||
| 553 | ret = kernel_thread(request_firmware_work_func, fw_work, | 574 | ret = kernel_thread(request_firmware_work_func, fw_work, |
