diff options
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r-- | drivers/usb/gadget/Kconfig | 4 | ||||
-rw-r--r-- | drivers/usb/gadget/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/acm_ms.c | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/cdc2.c | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/f_acm.c | 141 | ||||
-rw-r--r-- | drivers/usb/gadget/multi.c | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/nokia.c | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/serial.c | 83 | ||||
-rw-r--r-- | drivers/usb/gadget/u_serial.h | 5 |
9 files changed, 186 insertions, 55 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 8aefbbddf2a7..b61c72fc305a 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig | |||
@@ -500,6 +500,9 @@ config USB_LIBCOMPOSITE | |||
500 | tristate | 500 | tristate |
501 | depends on USB_GADGET | 501 | depends on USB_GADGET |
502 | 502 | ||
503 | config USB_F_ACM | ||
504 | tristate | ||
505 | |||
503 | config USB_F_SS_LB | 506 | config USB_F_SS_LB |
504 | tristate | 507 | tristate |
505 | 508 | ||
@@ -758,6 +761,7 @@ config USB_GADGET_TARGET | |||
758 | config USB_G_SERIAL | 761 | config USB_G_SERIAL |
759 | tristate "Serial Gadget (with CDC ACM and CDC OBEX support)" | 762 | tristate "Serial Gadget (with CDC ACM and CDC OBEX support)" |
760 | select USB_U_SERIAL | 763 | select USB_U_SERIAL |
764 | select USB_F_ACM | ||
761 | select USB_LIBCOMPOSITE | 765 | select USB_LIBCOMPOSITE |
762 | help | 766 | help |
763 | The Serial Gadget talks to the Linux-USB generic serial driver. | 767 | The Serial Gadget talks to the Linux-USB generic serial driver. |
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index b88ee775de6b..97a13c349cc5 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile | |||
@@ -76,6 +76,7 @@ obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o | |||
76 | obj-$(CONFIG_USB_GADGET_TARGET) += tcm_usb_gadget.o | 76 | obj-$(CONFIG_USB_GADGET_TARGET) += tcm_usb_gadget.o |
77 | 77 | ||
78 | # USB Functions | 78 | # USB Functions |
79 | obj-$(CONFIG_USB_F_ACM) += f_acm.o | ||
79 | f_ss_lb-y := f_loopback.o f_sourcesink.o | 80 | f_ss_lb-y := f_loopback.o f_sourcesink.o |
80 | obj-$(CONFIG_USB_F_SS_LB) += f_ss_lb.o | 81 | obj-$(CONFIG_USB_F_SS_LB) += f_ss_lb.o |
81 | obj-$(CONFIG_USB_U_SERIAL) += u_serial.o | 82 | obj-$(CONFIG_USB_U_SERIAL) += u_serial.o |
diff --git a/drivers/usb/gadget/acm_ms.c b/drivers/usb/gadget/acm_ms.c index eb0fbdae5ccb..4105a06582f8 100644 --- a/drivers/usb/gadget/acm_ms.c +++ b/drivers/usb/gadget/acm_ms.c | |||
@@ -40,7 +40,7 @@ | |||
40 | * the runtime footprint, and giving us at least some parts of what | 40 | * the runtime footprint, and giving us at least some parts of what |
41 | * a "gcc --combine ... part1.c part2.c part3.c ... " build would. | 41 | * a "gcc --combine ... part1.c part2.c part3.c ... " build would. |
42 | */ | 42 | */ |
43 | 43 | #define USB_FACM_INCLUDED | |
44 | #include "f_acm.c" | 44 | #include "f_acm.c" |
45 | #include "f_mass_storage.c" | 45 | #include "f_mass_storage.c" |
46 | 46 | ||
diff --git a/drivers/usb/gadget/cdc2.c b/drivers/usb/gadget/cdc2.c index 16911a5aeb03..13b17f0b2da1 100644 --- a/drivers/usb/gadget/cdc2.c +++ b/drivers/usb/gadget/cdc2.c | |||
@@ -42,7 +42,7 @@ USB_GADGET_COMPOSITE_OPTIONS(); | |||
42 | * the runtime footprint, and giving us at least some parts of what | 42 | * the runtime footprint, and giving us at least some parts of what |
43 | * a "gcc --combine ... part1.c part2.c part3.c ... " build would. | 43 | * a "gcc --combine ... part1.c part2.c part3.c ... " build would. |
44 | */ | 44 | */ |
45 | 45 | #define USB_FACM_INCLUDED | |
46 | #include "f_acm.c" | 46 | #include "f_acm.c" |
47 | #include "f_ecm.c" | 47 | #include "f_ecm.c" |
48 | #include "u_ether.c" | 48 | #include "u_ether.c" |
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c index 3178fa70916e..3ea7dc89b43d 100644 --- a/drivers/usb/gadget/f_acm.c +++ b/drivers/usb/gadget/f_acm.c | |||
@@ -16,7 +16,9 @@ | |||
16 | 16 | ||
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
19 | #include <linux/module.h> | ||
19 | #include <linux/device.h> | 20 | #include <linux/device.h> |
21 | #include <linux/err.h> | ||
20 | 22 | ||
21 | #include "u_serial.h" | 23 | #include "u_serial.h" |
22 | #include "gadget_chips.h" | 24 | #include "gadget_chips.h" |
@@ -608,6 +610,22 @@ acm_bind(struct usb_configuration *c, struct usb_function *f) | |||
608 | int status; | 610 | int status; |
609 | struct usb_ep *ep; | 611 | struct usb_ep *ep; |
610 | 612 | ||
613 | /* REVISIT might want instance-specific strings to help | ||
614 | * distinguish instances ... | ||
615 | */ | ||
616 | |||
617 | /* maybe allocate device-global string IDs, and patch descriptors */ | ||
618 | if (acm_string_defs[0].id == 0) { | ||
619 | status = usb_string_ids_tab(c->cdev, acm_string_defs); | ||
620 | if (status < 0) | ||
621 | return status; | ||
622 | acm_control_interface_desc.iInterface = | ||
623 | acm_string_defs[ACM_CTRL_IDX].id; | ||
624 | acm_data_interface_desc.iInterface = | ||
625 | acm_string_defs[ACM_DATA_IDX].id; | ||
626 | acm_iad_descriptor.iFunction = acm_string_defs[ACM_IAD_IDX].id; | ||
627 | } | ||
628 | |||
611 | /* allocate instance-specific interface IDs, and patch descriptors */ | 629 | /* allocate instance-specific interface IDs, and patch descriptors */ |
612 | status = usb_interface_id(c, f); | 630 | status = usb_interface_id(c, f); |
613 | if (status < 0) | 631 | if (status < 0) |
@@ -700,14 +718,41 @@ fail: | |||
700 | return status; | 718 | return status; |
701 | } | 719 | } |
702 | 720 | ||
721 | static struct f_acm *acm_alloc_basic_func(void) | ||
722 | { | ||
723 | struct f_acm *acm; | ||
724 | |||
725 | acm = kzalloc(sizeof(*acm), GFP_KERNEL); | ||
726 | if (!acm) | ||
727 | return NULL; | ||
728 | |||
729 | spin_lock_init(&acm->lock); | ||
730 | |||
731 | acm->port.connect = acm_connect; | ||
732 | acm->port.disconnect = acm_disconnect; | ||
733 | acm->port.send_break = acm_send_break; | ||
734 | |||
735 | acm->port.func.name = "acm"; | ||
736 | acm->port.func.strings = acm_strings; | ||
737 | /* descriptors are per-instance copies */ | ||
738 | acm->port.func.bind = acm_bind; | ||
739 | acm->port.func.set_alt = acm_set_alt; | ||
740 | acm->port.func.setup = acm_setup; | ||
741 | acm->port.func.disable = acm_disable; | ||
742 | |||
743 | return acm; | ||
744 | } | ||
745 | |||
746 | #ifdef USB_FACM_INCLUDED | ||
703 | static void | 747 | static void |
704 | acm_unbind(struct usb_configuration *c, struct usb_function *f) | 748 | acm_old_unbind(struct usb_configuration *c, struct usb_function *f) |
705 | { | 749 | { |
706 | struct f_acm *acm = func_to_acm(f); | 750 | struct f_acm *acm = func_to_acm(f); |
707 | 751 | ||
708 | acm_string_defs[0].id = 0; | 752 | acm_string_defs[0].id = 0; |
709 | usb_free_all_descriptors(f); | 753 | usb_free_all_descriptors(f); |
710 | gs_free_req(acm->notify, acm->notify_req); | 754 | if (acm->notify_req) |
755 | gs_free_req(acm->notify, acm->notify_req); | ||
711 | kfree(acm); | 756 | kfree(acm); |
712 | } | 757 | } |
713 | 758 | ||
@@ -725,46 +770,74 @@ int acm_bind_config(struct usb_configuration *c, u8 port_num) | |||
725 | struct f_acm *acm; | 770 | struct f_acm *acm; |
726 | int status; | 771 | int status; |
727 | 772 | ||
728 | /* REVISIT might want instance-specific strings to help | ||
729 | * distinguish instances ... | ||
730 | */ | ||
731 | |||
732 | /* maybe allocate device-global string IDs, and patch descriptors */ | ||
733 | if (acm_string_defs[0].id == 0) { | ||
734 | status = usb_string_ids_tab(c->cdev, acm_string_defs); | ||
735 | if (status < 0) | ||
736 | return status; | ||
737 | acm_control_interface_desc.iInterface = | ||
738 | acm_string_defs[ACM_CTRL_IDX].id; | ||
739 | acm_data_interface_desc.iInterface = | ||
740 | acm_string_defs[ACM_DATA_IDX].id; | ||
741 | acm_iad_descriptor.iFunction = acm_string_defs[ACM_IAD_IDX].id; | ||
742 | } | ||
743 | |||
744 | /* allocate and initialize one new instance */ | 773 | /* allocate and initialize one new instance */ |
745 | acm = kzalloc(sizeof *acm, GFP_KERNEL); | 774 | acm = acm_alloc_basic_func(); |
746 | if (!acm) | 775 | if (!acm) |
747 | return -ENOMEM; | 776 | return -ENOMEM; |
748 | 777 | ||
749 | spin_lock_init(&acm->lock); | ||
750 | |||
751 | acm->port_num = port_num; | 778 | acm->port_num = port_num; |
752 | 779 | acm->port.func.unbind = acm_old_unbind; | |
753 | acm->port.connect = acm_connect; | ||
754 | acm->port.disconnect = acm_disconnect; | ||
755 | acm->port.send_break = acm_send_break; | ||
756 | |||
757 | acm->port.func.name = "acm"; | ||
758 | acm->port.func.strings = acm_strings; | ||
759 | /* descriptors are per-instance copies */ | ||
760 | acm->port.func.bind = acm_bind; | ||
761 | acm->port.func.unbind = acm_unbind; | ||
762 | acm->port.func.set_alt = acm_set_alt; | ||
763 | acm->port.func.setup = acm_setup; | ||
764 | acm->port.func.disable = acm_disable; | ||
765 | 780 | ||
766 | status = usb_add_function(c, &acm->port.func); | 781 | status = usb_add_function(c, &acm->port.func); |
767 | if (status) | 782 | if (status) |
768 | kfree(acm); | 783 | kfree(acm); |
769 | return status; | 784 | return status; |
770 | } | 785 | } |
786 | |||
787 | #else | ||
788 | |||
789 | static void acm_unbind(struct usb_configuration *c, struct usb_function *f) | ||
790 | { | ||
791 | struct f_acm *acm = func_to_acm(f); | ||
792 | |||
793 | acm_string_defs[0].id = 0; | ||
794 | usb_free_all_descriptors(f); | ||
795 | if (acm->notify_req) | ||
796 | gs_free_req(acm->notify, acm->notify_req); | ||
797 | } | ||
798 | |||
799 | static void acm_free_func(struct usb_function *f) | ||
800 | { | ||
801 | struct f_acm *acm = func_to_acm(f); | ||
802 | |||
803 | kfree(acm); | ||
804 | } | ||
805 | |||
806 | static struct usb_function *acm_alloc_func(struct usb_function_instance *fi) | ||
807 | { | ||
808 | struct f_serial_opts *opts; | ||
809 | struct f_acm *acm; | ||
810 | |||
811 | acm = acm_alloc_basic_func(); | ||
812 | if (!acm) | ||
813 | return ERR_PTR(-ENOMEM); | ||
814 | |||
815 | opts = container_of(fi, struct f_serial_opts, func_inst); | ||
816 | acm->port_num = opts->port_num; | ||
817 | acm->port.func.unbind = acm_unbind; | ||
818 | acm->port.func.free_func = acm_free_func; | ||
819 | |||
820 | return &acm->port.func; | ||
821 | } | ||
822 | |||
823 | static void acm_free_instance(struct usb_function_instance *fi) | ||
824 | { | ||
825 | struct f_serial_opts *opts; | ||
826 | |||
827 | opts = container_of(fi, struct f_serial_opts, func_inst); | ||
828 | kfree(opts); | ||
829 | } | ||
830 | |||
831 | static struct usb_function_instance *acm_alloc_instance(void) | ||
832 | { | ||
833 | struct f_serial_opts *opts; | ||
834 | |||
835 | opts = kzalloc(sizeof(*opts), GFP_KERNEL); | ||
836 | if (!opts) | ||
837 | return ERR_PTR(-ENOMEM); | ||
838 | opts->func_inst.free_func_inst = acm_free_instance; | ||
839 | return &opts->func_inst; | ||
840 | } | ||
841 | DECLARE_USB_FUNCTION_INIT(acm, acm_alloc_instance, acm_alloc_func); | ||
842 | MODULE_LICENSE("GPL"); | ||
843 | #endif | ||
diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c index 9ca0ac0334e7..24b0f5630d44 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/multi.c | |||
@@ -41,7 +41,7 @@ MODULE_LICENSE("GPL"); | |||
41 | * a "gcc --combine ... part1.c part2.c part3.c ... " build would. | 41 | * a "gcc --combine ... part1.c part2.c part3.c ... " build would. |
42 | */ | 42 | */ |
43 | #include "f_mass_storage.c" | 43 | #include "f_mass_storage.c" |
44 | 44 | #define USB_FACM_INCLUDED | |
45 | #include "f_acm.c" | 45 | #include "f_acm.c" |
46 | 46 | ||
47 | #include "f_ecm.c" | 47 | #include "f_ecm.c" |
diff --git a/drivers/usb/gadget/nokia.c b/drivers/usb/gadget/nokia.c index 084d0d7cb8fa..def37403989a 100644 --- a/drivers/usb/gadget/nokia.c +++ b/drivers/usb/gadget/nokia.c | |||
@@ -37,6 +37,7 @@ | |||
37 | * the runtime footprint, and giving us at least some parts of what | 37 | * the runtime footprint, and giving us at least some parts of what |
38 | * a "gcc --combine ... part1.c part2.c part3.c ... " build would. | 38 | * a "gcc --combine ... part1.c part2.c part3.c ... " build would. |
39 | */ | 39 | */ |
40 | #define USB_FACM_INCLUDED | ||
40 | #include "f_acm.c" | 41 | #include "f_acm.c" |
41 | #include "f_ecm.c" | 42 | #include "f_ecm.c" |
42 | #include "f_obex.c" | 43 | #include "f_obex.c" |
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index a883562f6a89..68d7bb06ebcb 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c | |||
@@ -36,7 +36,6 @@ | |||
36 | * the runtime footprint, and giving us at least some parts of what | 36 | * the runtime footprint, and giving us at least some parts of what |
37 | * a "gcc --combine ... part1.c part2.c part3.c ... " build would. | 37 | * a "gcc --combine ... part1.c part2.c part3.c ... " build would. |
38 | */ | 38 | */ |
39 | #include "f_acm.c" | ||
40 | #include "f_obex.c" | 39 | #include "f_obex.c" |
41 | #include "f_serial.c" | 40 | #include "f_serial.c" |
42 | 41 | ||
@@ -129,16 +128,6 @@ MODULE_PARM_DESC(n_ports, "number of ports to create, default=1"); | |||
129 | /*-------------------------------------------------------------------------*/ | 128 | /*-------------------------------------------------------------------------*/ |
130 | static unsigned char tty_lines[MAX_U_SERIAL_PORTS]; | 129 | static unsigned char tty_lines[MAX_U_SERIAL_PORTS]; |
131 | 130 | ||
132 | static int __init serial_bind_acm_config(struct usb_configuration *c) | ||
133 | { | ||
134 | unsigned i; | ||
135 | int status = 0; | ||
136 | |||
137 | for (i = 0; i < n_ports && status == 0; i++) | ||
138 | status = acm_bind_config(c, tty_lines[i]); | ||
139 | return status; | ||
140 | } | ||
141 | |||
142 | static int __init serial_bind_obex_config(struct usb_configuration *c) | 131 | static int __init serial_bind_obex_config(struct usb_configuration *c) |
143 | { | 132 | { |
144 | unsigned i; | 133 | unsigned i; |
@@ -166,13 +155,58 @@ static struct usb_configuration serial_config_driver = { | |||
166 | .bmAttributes = USB_CONFIG_ATT_SELFPOWER, | 155 | .bmAttributes = USB_CONFIG_ATT_SELFPOWER, |
167 | }; | 156 | }; |
168 | 157 | ||
169 | static int gs_unbind(struct usb_composite_dev *cdev) | 158 | static struct usb_function_instance *fi_serial[MAX_U_SERIAL_PORTS]; |
159 | static struct usb_function *f_serial[MAX_U_SERIAL_PORTS]; | ||
160 | |||
161 | static int serial_register_ports(struct usb_composite_dev *cdev, | ||
162 | struct usb_configuration *c, const char *f_name) | ||
170 | { | 163 | { |
171 | int i; | 164 | int i; |
165 | int ret; | ||
166 | |||
167 | ret = usb_add_config_only(cdev, c); | ||
168 | if (ret) | ||
169 | goto out; | ||
170 | |||
171 | for (i = 0; i < n_ports; i++) { | ||
172 | struct f_serial_opts *opts; | ||
173 | |||
174 | fi_serial[i] = usb_get_function_instance(f_name); | ||
175 | if (IS_ERR(fi_serial[i])) { | ||
176 | ret = PTR_ERR(fi_serial[i]); | ||
177 | goto fail; | ||
178 | } | ||
179 | opts = container_of(fi_serial[i], struct f_serial_opts, func_inst); | ||
180 | opts->port_num = tty_lines[i]; | ||
181 | |||
182 | f_serial[i] = usb_get_function(fi_serial[i]); | ||
183 | if (IS_ERR(f_serial[i])) { | ||
184 | ret = PTR_ERR(f_serial[i]); | ||
185 | goto err_get_func; | ||
186 | } | ||
187 | |||
188 | ret = usb_add_function(c, f_serial[i]); | ||
189 | if (ret) | ||
190 | goto err_add_func; | ||
191 | } | ||
172 | 192 | ||
173 | for (i = 0; i < n_ports; i++) | ||
174 | gserial_free_line(tty_lines[i]); | ||
175 | return 0; | 193 | return 0; |
194 | |||
195 | err_add_func: | ||
196 | usb_put_function(f_serial[i]); | ||
197 | err_get_func: | ||
198 | usb_put_function_instance(fi_serial[i]); | ||
199 | |||
200 | fail: | ||
201 | i--; | ||
202 | while (i >= 0) { | ||
203 | usb_remove_function(c, f_serial[i]); | ||
204 | usb_put_function(f_serial[i]); | ||
205 | usb_put_function_instance(fi_serial[i]); | ||
206 | i--; | ||
207 | } | ||
208 | out: | ||
209 | return ret; | ||
176 | } | 210 | } |
177 | 211 | ||
178 | static int __init gs_bind(struct usb_composite_dev *cdev) | 212 | static int __init gs_bind(struct usb_composite_dev *cdev) |
@@ -204,10 +238,11 @@ static int __init gs_bind(struct usb_composite_dev *cdev) | |||
204 | } | 238 | } |
205 | 239 | ||
206 | /* register our configuration */ | 240 | /* register our configuration */ |
207 | if (use_acm) | 241 | if (use_acm) { |
208 | status = usb_add_config(cdev, &serial_config_driver, | 242 | status = serial_register_ports(cdev, &serial_config_driver, |
209 | serial_bind_acm_config); | 243 | "acm"); |
210 | else if (use_obex) | 244 | usb_ep_autoconfig_reset(cdev->gadget); |
245 | } else if (use_obex) | ||
211 | status = usb_add_config(cdev, &serial_config_driver, | 246 | status = usb_add_config(cdev, &serial_config_driver, |
212 | serial_bind_obex_config); | 247 | serial_bind_obex_config); |
213 | else | 248 | else |
@@ -228,6 +263,18 @@ fail: | |||
228 | return status; | 263 | return status; |
229 | } | 264 | } |
230 | 265 | ||
266 | static int gs_unbind(struct usb_composite_dev *cdev) | ||
267 | { | ||
268 | int i; | ||
269 | |||
270 | for (i = 0; i < n_ports; i++) { | ||
271 | usb_put_function(f_serial[i]); | ||
272 | usb_put_function_instance(fi_serial[i]); | ||
273 | gserial_free_line(tty_lines[i]); | ||
274 | } | ||
275 | return 0; | ||
276 | } | ||
277 | |||
231 | static __refdata struct usb_composite_driver gserial_driver = { | 278 | static __refdata struct usb_composite_driver gserial_driver = { |
232 | .name = "g_serial", | 279 | .name = "g_serial", |
233 | .dev = &device_desc, | 280 | .dev = &device_desc, |
diff --git a/drivers/usb/gadget/u_serial.h b/drivers/usb/gadget/u_serial.h index f06ee9a5db51..66ce73a00509 100644 --- a/drivers/usb/gadget/u_serial.h +++ b/drivers/usb/gadget/u_serial.h | |||
@@ -17,6 +17,11 @@ | |||
17 | 17 | ||
18 | #define MAX_U_SERIAL_PORTS 4 | 18 | #define MAX_U_SERIAL_PORTS 4 |
19 | 19 | ||
20 | struct f_serial_opts { | ||
21 | struct usb_function_instance func_inst; | ||
22 | u8 port_num; | ||
23 | }; | ||
24 | |||
20 | /* | 25 | /* |
21 | * One non-multiplexed "serial" I/O port ... there can be several of these | 26 | * One non-multiplexed "serial" I/O port ... there can be several of these |
22 | * on any given USB peripheral device, if it provides enough endpoints. | 27 | * on any given USB peripheral device, if it provides enough endpoints. |