diff options
-rw-r--r-- | drivers/usb/gadget/Makefile | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/composite.c | 47 | ||||
-rw-r--r-- | include/linux/usb/composite.h | 52 |
3 files changed, 83 insertions, 18 deletions
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 8b4acfd92aa3..fef41f5d6e8d 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile | |||
@@ -6,7 +6,7 @@ ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG | |||
6 | obj-$(CONFIG_USB_GADGET) += udc-core.o | 6 | obj-$(CONFIG_USB_GADGET) += udc-core.o |
7 | obj-$(CONFIG_USB_LIBCOMPOSITE) += libcomposite.o | 7 | obj-$(CONFIG_USB_LIBCOMPOSITE) += libcomposite.o |
8 | libcomposite-y := usbstring.o config.o epautoconf.o | 8 | libcomposite-y := usbstring.o config.o epautoconf.o |
9 | libcomposite-y += composite.o | 9 | libcomposite-y += composite.o functions.o |
10 | obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o | 10 | obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o |
11 | obj-$(CONFIG_USB_NET2272) += net2272.o | 11 | obj-$(CONFIG_USB_NET2272) += net2272.o |
12 | obj-$(CONFIG_USB_NET2280) += net2280.o | 12 | obj-$(CONFIG_USB_NET2280) += net2280.o |
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)) { |
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index dc512c9432d7..3834e3330b23 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h | |||
@@ -77,6 +77,8 @@ struct usb_configuration; | |||
77 | * in interface or class descriptors; endpoints; I/O buffers; and so on. | 77 | * in interface or class descriptors; endpoints; I/O buffers; and so on. |
78 | * @unbind: Reverses @bind; called as a side effect of unregistering the | 78 | * @unbind: Reverses @bind; called as a side effect of unregistering the |
79 | * driver which added this function. | 79 | * driver which added this function. |
80 | * @free_func: free the struct usb_function. | ||
81 | * @mod: (internal) points to the module that created this structure. | ||
80 | * @set_alt: (REQUIRED) Reconfigures altsettings; function drivers may | 82 | * @set_alt: (REQUIRED) Reconfigures altsettings; function drivers may |
81 | * initialize usb_ep.driver data at this time (when it is used). | 83 | * initialize usb_ep.driver data at this time (when it is used). |
82 | * Note that setting an interface to its current altsetting resets | 84 | * Note that setting an interface to its current altsetting resets |
@@ -116,6 +118,7 @@ struct usb_configuration; | |||
116 | * two or more distinct instances within the same configuration, providing | 118 | * two or more distinct instances within the same configuration, providing |
117 | * several independent logical data links to a USB host. | 119 | * several independent logical data links to a USB host. |
118 | */ | 120 | */ |
121 | |||
119 | struct usb_function { | 122 | struct usb_function { |
120 | const char *name; | 123 | const char *name; |
121 | struct usb_gadget_strings **strings; | 124 | struct usb_gadget_strings **strings; |
@@ -136,6 +139,8 @@ struct usb_function { | |||
136 | struct usb_function *); | 139 | struct usb_function *); |
137 | void (*unbind)(struct usb_configuration *, | 140 | void (*unbind)(struct usb_configuration *, |
138 | struct usb_function *); | 141 | struct usb_function *); |
142 | void (*free_func)(struct usb_function *f); | ||
143 | struct module *mod; | ||
139 | 144 | ||
140 | /* runtime state management */ | 145 | /* runtime state management */ |
141 | int (*set_alt)(struct usb_function *, | 146 | int (*set_alt)(struct usb_function *, |
@@ -432,6 +437,53 @@ static inline u16 get_default_bcdDevice(void) | |||
432 | return bcdDevice; | 437 | return bcdDevice; |
433 | } | 438 | } |
434 | 439 | ||
440 | struct usb_function_driver { | ||
441 | const char *name; | ||
442 | struct module *mod; | ||
443 | struct list_head list; | ||
444 | struct usb_function_instance *(*alloc_inst)(void); | ||
445 | struct usb_function *(*alloc_func)(struct usb_function_instance *inst); | ||
446 | }; | ||
447 | |||
448 | struct usb_function_instance { | ||
449 | struct usb_function_driver *fd; | ||
450 | void (*free_func_inst)(struct usb_function_instance *inst); | ||
451 | }; | ||
452 | |||
453 | void usb_function_unregister(struct usb_function_driver *f); | ||
454 | int usb_function_register(struct usb_function_driver *newf); | ||
455 | void usb_put_function_instance(struct usb_function_instance *fi); | ||
456 | void usb_put_function(struct usb_function *f); | ||
457 | struct usb_function_instance *usb_get_function_instance(const char *name); | ||
458 | struct usb_function *usb_get_function(struct usb_function_instance *fi); | ||
459 | |||
460 | struct usb_configuration *usb_get_config(struct usb_composite_dev *cdev, | ||
461 | int val); | ||
462 | int usb_add_config_only(struct usb_composite_dev *cdev, | ||
463 | struct usb_configuration *config); | ||
464 | |||
465 | #define DECLARE_USB_FUNCTION(_name, _inst_alloc, _func_alloc) \ | ||
466 | static struct usb_function_driver _name ## usb_func = { \ | ||
467 | .name = __stringify(_name), \ | ||
468 | .mod = THIS_MODULE, \ | ||
469 | .alloc_inst = _inst_alloc, \ | ||
470 | .alloc_func = _func_alloc, \ | ||
471 | }; \ | ||
472 | MODULE_ALIAS("usbfunc:"__stringify(_name)); | ||
473 | |||
474 | #define DECLARE_USB_FUNCTION_INIT(_name, _inst_alloc, _func_alloc) \ | ||
475 | DECLARE_USB_FUNCTION(_name, _inst_alloc, _func_alloc) \ | ||
476 | static int __init _name ## mod_init(void) \ | ||
477 | { \ | ||
478 | return usb_function_register(&_name ## usb_func); \ | ||
479 | } \ | ||
480 | static void __exit _name ## mod_exit(void) \ | ||
481 | { \ | ||
482 | usb_function_unregister(&_name ## usb_func); \ | ||
483 | } \ | ||
484 | module_init(_name ## mod_init); \ | ||
485 | module_exit(_name ## mod_exit) | ||
486 | |||
435 | /* messaging utils */ | 487 | /* messaging utils */ |
436 | #define DBG(d, fmt, args...) \ | 488 | #define DBG(d, fmt, args...) \ |
437 | dev_dbg(&(d)->gadget->dev , fmt , ## args) | 489 | dev_dbg(&(d)->gadget->dev , fmt , ## args) |