diff options
author | Stephen Boyd <sboyd@codeaurora.org> | 2012-03-28 17:30:43 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rjw@sisk.pl> | 2012-03-28 17:30:43 -0400 |
commit | dddb5549da6b15ea8b9ce9ee0859c8d1fa268b5b (patch) | |
tree | ed085381d5934f8de96d0c63515a586507324466 /drivers/base/firmware_class.c | |
parent | 247bc03742545fec2f79939a3b9f738392a0f7b4 (diff) |
firmware_class: Reorganize fw_create_instance()
Recent patches to split up the three phases of request_firmware()
lead to a casting away of const in fw_create_instance(). We can
avoid this cast by splitting up fw_create_instance() a bit.
Make _request_firmware_setup() return a struct fw_priv and use
that struct instead of passing struct firmware to
_request_firmware(). Move the uevent and device file creation
bits to the loading phase and rename the function to
_request_firmware_load() to better reflect its purpose.
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'drivers/base/firmware_class.c')
-rw-r--r-- | drivers/base/firmware_class.c | 135 |
1 files changed, 62 insertions, 73 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 72c644b191a4..ae00a2fd280f 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c | |||
@@ -440,21 +440,19 @@ static void firmware_class_timeout(u_long data) | |||
440 | } | 440 | } |
441 | 441 | ||
442 | static struct firmware_priv * | 442 | static struct firmware_priv * |
443 | fw_create_instance(const struct firmware *firmware, const char *fw_name, | 443 | fw_create_instance(struct firmware *firmware, const char *fw_name, |
444 | struct device *device, bool uevent, bool nowait) | 444 | struct device *device, bool uevent, bool nowait) |
445 | { | 445 | { |
446 | struct firmware_priv *fw_priv; | 446 | struct firmware_priv *fw_priv; |
447 | struct device *f_dev; | 447 | struct device *f_dev; |
448 | int error; | ||
449 | 448 | ||
450 | fw_priv = kzalloc(sizeof(*fw_priv) + strlen(fw_name) + 1 , GFP_KERNEL); | 449 | fw_priv = kzalloc(sizeof(*fw_priv) + strlen(fw_name) + 1 , GFP_KERNEL); |
451 | if (!fw_priv) { | 450 | if (!fw_priv) { |
452 | dev_err(device, "%s: kmalloc failed\n", __func__); | 451 | dev_err(device, "%s: kmalloc failed\n", __func__); |
453 | error = -ENOMEM; | 452 | return ERR_PTR(-ENOMEM); |
454 | goto err_out; | ||
455 | } | 453 | } |
456 | 454 | ||
457 | fw_priv->fw = (struct firmware *)firmware; | 455 | fw_priv->fw = firmware; |
458 | fw_priv->nowait = nowait; | 456 | fw_priv->nowait = nowait; |
459 | strcpy(fw_priv->fw_id, fw_name); | 457 | strcpy(fw_priv->fw_id, fw_name); |
460 | init_completion(&fw_priv->completion); | 458 | init_completion(&fw_priv->completion); |
@@ -468,74 +466,37 @@ fw_create_instance(const struct firmware *firmware, const char *fw_name, | |||
468 | f_dev->parent = device; | 466 | f_dev->parent = device; |
469 | f_dev->class = &firmware_class; | 467 | f_dev->class = &firmware_class; |
470 | 468 | ||
471 | dev_set_uevent_suppress(f_dev, true); | ||
472 | |||
473 | /* Need to pin this module until class device is destroyed */ | ||
474 | __module_get(THIS_MODULE); | ||
475 | |||
476 | error = device_add(f_dev); | ||
477 | if (error) { | ||
478 | dev_err(device, "%s: device_register failed\n", __func__); | ||
479 | goto err_put_dev; | ||
480 | } | ||
481 | |||
482 | error = device_create_bin_file(f_dev, &firmware_attr_data); | ||
483 | if (error) { | ||
484 | dev_err(device, "%s: sysfs_create_bin_file failed\n", __func__); | ||
485 | goto err_del_dev; | ||
486 | } | ||
487 | |||
488 | error = device_create_file(f_dev, &dev_attr_loading); | ||
489 | if (error) { | ||
490 | dev_err(device, "%s: device_create_file failed\n", __func__); | ||
491 | goto err_del_bin_attr; | ||
492 | } | ||
493 | |||
494 | if (uevent) | ||
495 | dev_set_uevent_suppress(f_dev, false); | ||
496 | |||
497 | return fw_priv; | 469 | return fw_priv; |
498 | |||
499 | err_del_bin_attr: | ||
500 | device_remove_bin_file(f_dev, &firmware_attr_data); | ||
501 | err_del_dev: | ||
502 | device_del(f_dev); | ||
503 | err_put_dev: | ||
504 | put_device(f_dev); | ||
505 | err_out: | ||
506 | return ERR_PTR(error); | ||
507 | } | ||
508 | |||
509 | static void fw_destroy_instance(struct firmware_priv *fw_priv) | ||
510 | { | ||
511 | struct device *f_dev = &fw_priv->dev; | ||
512 | |||
513 | device_remove_file(f_dev, &dev_attr_loading); | ||
514 | device_remove_bin_file(f_dev, &firmware_attr_data); | ||
515 | device_unregister(f_dev); | ||
516 | } | 470 | } |
517 | 471 | ||
518 | static int _request_firmware_prepare(const struct firmware **firmware_p, | 472 | static struct firmware_priv * |
519 | const char *name, struct device *device) | 473 | _request_firmware_prepare(const struct firmware **firmware_p, const char *name, |
474 | struct device *device, bool uevent, bool nowait) | ||
520 | { | 475 | { |
521 | struct firmware *firmware; | 476 | struct firmware *firmware; |
477 | struct firmware_priv *fw_priv; | ||
522 | 478 | ||
523 | if (!firmware_p) | 479 | if (!firmware_p) |
524 | return -EINVAL; | 480 | return ERR_PTR(-EINVAL); |
525 | 481 | ||
526 | *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL); | 482 | *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL); |
527 | if (!firmware) { | 483 | if (!firmware) { |
528 | dev_err(device, "%s: kmalloc(struct firmware) failed\n", | 484 | dev_err(device, "%s: kmalloc(struct firmware) failed\n", |
529 | __func__); | 485 | __func__); |
530 | return -ENOMEM; | 486 | return ERR_PTR(-ENOMEM); |
531 | } | 487 | } |
532 | 488 | ||
533 | if (fw_get_builtin_firmware(firmware, name)) { | 489 | if (fw_get_builtin_firmware(firmware, name)) { |
534 | dev_dbg(device, "firmware: using built-in firmware %s\n", name); | 490 | dev_dbg(device, "firmware: using built-in firmware %s\n", name); |
535 | return 0; | 491 | return NULL; |
536 | } | 492 | } |
537 | 493 | ||
538 | return 1; | 494 | fw_priv = fw_create_instance(firmware, name, device, uevent, nowait); |
495 | if (IS_ERR(fw_priv)) { | ||
496 | release_firmware(firmware); | ||
497 | *firmware_p = NULL; | ||
498 | } | ||
499 | return fw_priv; | ||
539 | } | 500 | } |
540 | 501 | ||
541 | static void _request_firmware_cleanup(const struct firmware **firmware_p) | 502 | static void _request_firmware_cleanup(const struct firmware **firmware_p) |
@@ -544,21 +505,38 @@ static void _request_firmware_cleanup(const struct firmware **firmware_p) | |||
544 | *firmware_p = NULL; | 505 | *firmware_p = NULL; |
545 | } | 506 | } |
546 | 507 | ||
547 | static int _request_firmware(const struct firmware *firmware, | 508 | static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent, |
548 | const char *name, struct device *device, | 509 | long timeout) |
549 | bool uevent, bool nowait, long timeout) | ||
550 | { | 510 | { |
551 | struct firmware_priv *fw_priv; | ||
552 | int retval = 0; | 511 | int retval = 0; |
512 | struct device *f_dev = &fw_priv->dev; | ||
513 | |||
514 | dev_set_uevent_suppress(f_dev, true); | ||
553 | 515 | ||
554 | if (uevent) | 516 | /* Need to pin this module until class device is destroyed */ |
555 | dev_dbg(device, "firmware: requesting %s\n", name); | 517 | __module_get(THIS_MODULE); |
556 | 518 | ||
557 | fw_priv = fw_create_instance(firmware, name, device, uevent, nowait); | 519 | retval = device_add(f_dev); |
558 | if (IS_ERR(fw_priv)) | 520 | if (retval) { |
559 | return PTR_ERR(fw_priv); | 521 | dev_err(f_dev, "%s: device_register failed\n", __func__); |
522 | goto err_put_dev; | ||
523 | } | ||
524 | |||
525 | retval = device_create_bin_file(f_dev, &firmware_attr_data); | ||
526 | if (retval) { | ||
527 | dev_err(f_dev, "%s: sysfs_create_bin_file failed\n", __func__); | ||
528 | goto err_del_dev; | ||
529 | } | ||
530 | |||
531 | retval = device_create_file(f_dev, &dev_attr_loading); | ||
532 | if (retval) { | ||
533 | dev_err(f_dev, "%s: device_create_file failed\n", __func__); | ||
534 | goto err_del_bin_attr; | ||
535 | } | ||
560 | 536 | ||
561 | if (uevent) { | 537 | if (uevent) { |
538 | dev_set_uevent_suppress(f_dev, false); | ||
539 | dev_dbg(f_dev, "firmware: requesting %s\n", fw_priv->fw_id); | ||
562 | if (timeout != MAX_SCHEDULE_TIMEOUT) | 540 | if (timeout != MAX_SCHEDULE_TIMEOUT) |
563 | mod_timer(&fw_priv->timeout, | 541 | mod_timer(&fw_priv->timeout, |
564 | round_jiffies_up(jiffies + timeout)); | 542 | round_jiffies_up(jiffies + timeout)); |
@@ -577,7 +555,13 @@ static int _request_firmware(const struct firmware *firmware, | |||
577 | fw_priv->fw = NULL; | 555 | fw_priv->fw = NULL; |
578 | mutex_unlock(&fw_lock); | 556 | mutex_unlock(&fw_lock); |
579 | 557 | ||
580 | fw_destroy_instance(fw_priv); | 558 | device_remove_file(f_dev, &dev_attr_loading); |
559 | err_del_bin_attr: | ||
560 | device_remove_bin_file(f_dev, &firmware_attr_data); | ||
561 | err_del_dev: | ||
562 | device_del(f_dev); | ||
563 | err_put_dev: | ||
564 | put_device(f_dev); | ||
581 | return retval; | 565 | return retval; |
582 | } | 566 | } |
583 | 567 | ||
@@ -600,17 +584,19 @@ int | |||
600 | request_firmware(const struct firmware **firmware_p, const char *name, | 584 | request_firmware(const struct firmware **firmware_p, const char *name, |
601 | struct device *device) | 585 | struct device *device) |
602 | { | 586 | { |
587 | struct firmware_priv *fw_priv; | ||
603 | int ret; | 588 | int ret; |
604 | 589 | ||
605 | ret = _request_firmware_prepare(firmware_p, name, device); | 590 | fw_priv = _request_firmware_prepare(firmware_p, name, device, true, |
606 | if (ret <= 0) | 591 | false); |
607 | return ret; | 592 | if (IS_ERR_OR_NULL(fw_priv)) |
593 | return PTR_RET(fw_priv); | ||
608 | 594 | ||
609 | ret = usermodehelper_read_trylock(); | 595 | ret = usermodehelper_read_trylock(); |
610 | if (WARN_ON(ret)) { | 596 | if (WARN_ON(ret)) { |
611 | dev_err(device, "firmware: %s will not be loaded\n", name); | 597 | dev_err(device, "firmware: %s will not be loaded\n", name); |
612 | } else { | 598 | } else { |
613 | ret = _request_firmware(*firmware_p, name, device, true, false, | 599 | ret = _request_firmware_load(fw_priv, true, |
614 | firmware_loading_timeout()); | 600 | firmware_loading_timeout()); |
615 | usermodehelper_read_unlock(); | 601 | usermodehelper_read_unlock(); |
616 | } | 602 | } |
@@ -648,6 +634,7 @@ static int request_firmware_work_func(void *arg) | |||
648 | { | 634 | { |
649 | struct firmware_work *fw_work = arg; | 635 | struct firmware_work *fw_work = arg; |
650 | const struct firmware *fw; | 636 | const struct firmware *fw; |
637 | struct firmware_priv *fw_priv; | ||
651 | long timeout; | 638 | long timeout; |
652 | int ret; | 639 | int ret; |
653 | 640 | ||
@@ -656,14 +643,16 @@ static int request_firmware_work_func(void *arg) | |||
656 | return 0; | 643 | return 0; |
657 | } | 644 | } |
658 | 645 | ||
659 | ret = _request_firmware_prepare(&fw, fw_work->name, fw_work->device); | 646 | fw_priv = _request_firmware_prepare(&fw, fw_work->name, fw_work->device, |
660 | if (ret <= 0) | 647 | fw_work->uevent, true); |
648 | if (IS_ERR_OR_NULL(fw_priv)) { | ||
649 | ret = PTR_RET(fw_priv); | ||
661 | goto out; | 650 | goto out; |
651 | } | ||
662 | 652 | ||
663 | timeout = usermodehelper_read_lock_wait(firmware_loading_timeout()); | 653 | timeout = usermodehelper_read_lock_wait(firmware_loading_timeout()); |
664 | if (timeout) { | 654 | if (timeout) { |
665 | ret = _request_firmware(fw, fw_work->name, fw_work->device, | 655 | ret = _request_firmware_load(fw_priv, fw_work->uevent, timeout); |
666 | fw_work->uevent, true, timeout); | ||
667 | usermodehelper_read_unlock(); | 656 | usermodehelper_read_unlock(); |
668 | } else { | 657 | } else { |
669 | dev_dbg(fw_work->device, "firmware: %s loading timed out\n", | 658 | dev_dbg(fw_work->device, "firmware: %s loading timed out\n", |