diff options
author | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2012-12-23 15:10:00 -0500 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2013-01-21 13:52:40 -0500 |
commit | de53c25447117eae6b3f8952f663f08a09e0dbb7 (patch) | |
tree | 3474ccbad34a526bd9a6826e4512162e4801cafb /drivers/usb/gadget/composite.c | |
parent | 78f46f09a80a39fe646fe415a21435f2a05df6c2 (diff) |
usb: gadget: add some infracture to register/unregister functions
This patch provides an infrastructure to register & unregister a USB
function. This allows to turn a function into a module and avoid the
'#include "f_.*.c"' magic and we get a clear API / cut between the bare
gadget and its functions.
The concept is simple:
Each function defines the DECLARE_USB_FUNCTION_INIT macro whith an unique
name of the function and two allocation functions.
- one to create an "instance". The instance holds the current configuration
set. In case there are two usb_configudations with one function there will
be one instance and two usb_functions
- one to create an "function" from the instance.
The name of the instance is used to automaticaly load the module if it the
instance is not yet available.
The usb_function callbacks are slightly modified and extended:
- usb_get_function()
creates a struct usb_function inclunding all pointers (bind,
unbind,…). It uses the "instance" to map its configuration. So we can
have _two_ struct usb_function, one for each usb_configuration.
- ->unbind()
Since the struct usb_function was not allocated in ->bind() it should
not kfree()d here. This function should only reverse what happens in
->bind() that is request cleanup and the cleanup of allocated
descriptors.
- ->free_func()
a simple kfree() of the struct usb_function
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/gadget/composite.c')
-rw-r--r-- | drivers/usb/gadget/composite.c | 47 |
1 files changed, 30 insertions, 17 deletions
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 9db000013f5d..4aa0e4652228 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c | |||
@@ -683,6 +683,31 @@ done: | |||
683 | return result; | 683 | return result; |
684 | } | 684 | } |
685 | 685 | ||
686 | int usb_add_config_only(struct usb_composite_dev *cdev, | ||
687 | struct usb_configuration *config) | ||
688 | { | ||
689 | struct usb_configuration *c; | ||
690 | |||
691 | if (!config->bConfigurationValue) | ||
692 | return -EINVAL; | ||
693 | |||
694 | /* Prevent duplicate configuration identifiers */ | ||
695 | list_for_each_entry(c, &cdev->configs, list) { | ||
696 | if (c->bConfigurationValue == config->bConfigurationValue) | ||
697 | return -EBUSY; | ||
698 | } | ||
699 | |||
700 | config->cdev = cdev; | ||
701 | list_add_tail(&config->list, &cdev->configs); | ||
702 | |||
703 | INIT_LIST_HEAD(&config->functions); | ||
704 | config->next_interface_id = 0; | ||
705 | memset(config->interface, 0, sizeof(config->interface)); | ||
706 | |||
707 | return 0; | ||
708 | } | ||
709 | EXPORT_SYMBOL_GPL(usb_add_config_only); | ||
710 | |||
686 | /** | 711 | /** |
687 | * usb_add_config() - add a configuration to a device. | 712 | * usb_add_config() - add a configuration to a device. |
688 | * @cdev: wraps the USB gadget | 713 | * @cdev: wraps the USB gadget |
@@ -703,30 +728,18 @@ int usb_add_config(struct usb_composite_dev *cdev, | |||
703 | int (*bind)(struct usb_configuration *)) | 728 | int (*bind)(struct usb_configuration *)) |
704 | { | 729 | { |
705 | int status = -EINVAL; | 730 | int status = -EINVAL; |
706 | struct usb_configuration *c; | 731 | |
732 | if (!bind) | ||
733 | goto done; | ||
707 | 734 | ||
708 | DBG(cdev, "adding config #%u '%s'/%p\n", | 735 | DBG(cdev, "adding config #%u '%s'/%p\n", |
709 | config->bConfigurationValue, | 736 | config->bConfigurationValue, |
710 | config->label, config); | 737 | config->label, config); |
711 | 738 | ||
712 | if (!config->bConfigurationValue || !bind) | 739 | status = usb_add_config_only(cdev, config); |
740 | if (status) | ||
713 | goto done; | 741 | goto done; |
714 | 742 | ||
715 | /* Prevent duplicate configuration identifiers */ | ||
716 | list_for_each_entry(c, &cdev->configs, list) { | ||
717 | if (c->bConfigurationValue == config->bConfigurationValue) { | ||
718 | status = -EBUSY; | ||
719 | goto done; | ||
720 | } | ||
721 | } | ||
722 | |||
723 | config->cdev = cdev; | ||
724 | list_add_tail(&config->list, &cdev->configs); | ||
725 | |||
726 | INIT_LIST_HEAD(&config->functions); | ||
727 | config->next_interface_id = 0; | ||
728 | memset(config->interface, 0, sizeof(config->interface)); | ||
729 | |||
730 | status = bind(config); | 743 | status = bind(config); |
731 | if (status < 0) { | 744 | if (status < 0) { |
732 | while (!list_empty(&config->functions)) { | 745 | while (!list_empty(&config->functions)) { |