diff options
Diffstat (limited to 'drivers/usb/gadget/f_acm.c')
-rw-r--r-- | drivers/usb/gadget/f_acm.c | 39 |
1 files changed, 30 insertions, 9 deletions
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c index 7953948bfe4a..400e1ebe6976 100644 --- a/drivers/usb/gadget/f_acm.c +++ b/drivers/usb/gadget/f_acm.c | |||
@@ -4,6 +4,8 @@ | |||
4 | * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com) | 4 | * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com) |
5 | * Copyright (C) 2008 by David Brownell | 5 | * Copyright (C) 2008 by David Brownell |
6 | * Copyright (C) 2008 by Nokia Corporation | 6 | * Copyright (C) 2008 by Nokia Corporation |
7 | * Copyright (C) 2009 by Samsung Electronics | ||
8 | * Author: Michal Nazarewicz (m.nazarewicz@samsung.com) | ||
7 | * | 9 | * |
8 | * This software is distributed under the terms of the GNU General | 10 | * This software is distributed under the terms of the GNU General |
9 | * Public License ("GPL") as published by the Free Software Foundation, | 11 | * Public License ("GPL") as published by the Free Software Foundation, |
@@ -12,6 +14,7 @@ | |||
12 | 14 | ||
13 | /* #define VERBOSE_DEBUG */ | 15 | /* #define VERBOSE_DEBUG */ |
14 | 16 | ||
17 | #include <linux/slab.h> | ||
15 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
16 | #include <linux/device.h> | 19 | #include <linux/device.h> |
17 | 20 | ||
@@ -99,6 +102,20 @@ static inline struct f_acm *port_to_acm(struct gserial *p) | |||
99 | 102 | ||
100 | /* interface and class descriptors: */ | 103 | /* interface and class descriptors: */ |
101 | 104 | ||
105 | static struct usb_interface_assoc_descriptor | ||
106 | acm_iad_descriptor = { | ||
107 | .bLength = sizeof acm_iad_descriptor, | ||
108 | .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, | ||
109 | |||
110 | /* .bFirstInterface = DYNAMIC, */ | ||
111 | .bInterfaceCount = 2, // control + data | ||
112 | .bFunctionClass = USB_CLASS_COMM, | ||
113 | .bFunctionSubClass = USB_CDC_SUBCLASS_ACM, | ||
114 | .bFunctionProtocol = USB_CDC_PROTO_NONE, | ||
115 | /* .iFunction = DYNAMIC */ | ||
116 | }; | ||
117 | |||
118 | |||
102 | static struct usb_interface_descriptor acm_control_interface_desc __initdata = { | 119 | static struct usb_interface_descriptor acm_control_interface_desc __initdata = { |
103 | .bLength = USB_DT_INTERFACE_SIZE, | 120 | .bLength = USB_DT_INTERFACE_SIZE, |
104 | .bDescriptorType = USB_DT_INTERFACE, | 121 | .bDescriptorType = USB_DT_INTERFACE, |
@@ -178,6 +195,7 @@ static struct usb_endpoint_descriptor acm_fs_out_desc __initdata = { | |||
178 | }; | 195 | }; |
179 | 196 | ||
180 | static struct usb_descriptor_header *acm_fs_function[] __initdata = { | 197 | static struct usb_descriptor_header *acm_fs_function[] __initdata = { |
198 | (struct usb_descriptor_header *) &acm_iad_descriptor, | ||
181 | (struct usb_descriptor_header *) &acm_control_interface_desc, | 199 | (struct usb_descriptor_header *) &acm_control_interface_desc, |
182 | (struct usb_descriptor_header *) &acm_header_desc, | 200 | (struct usb_descriptor_header *) &acm_header_desc, |
183 | (struct usb_descriptor_header *) &acm_call_mgmt_descriptor, | 201 | (struct usb_descriptor_header *) &acm_call_mgmt_descriptor, |
@@ -216,6 +234,7 @@ static struct usb_endpoint_descriptor acm_hs_out_desc __initdata = { | |||
216 | }; | 234 | }; |
217 | 235 | ||
218 | static struct usb_descriptor_header *acm_hs_function[] __initdata = { | 236 | static struct usb_descriptor_header *acm_hs_function[] __initdata = { |
237 | (struct usb_descriptor_header *) &acm_iad_descriptor, | ||
219 | (struct usb_descriptor_header *) &acm_control_interface_desc, | 238 | (struct usb_descriptor_header *) &acm_control_interface_desc, |
220 | (struct usb_descriptor_header *) &acm_header_desc, | 239 | (struct usb_descriptor_header *) &acm_header_desc, |
221 | (struct usb_descriptor_header *) &acm_call_mgmt_descriptor, | 240 | (struct usb_descriptor_header *) &acm_call_mgmt_descriptor, |
@@ -232,11 +251,13 @@ static struct usb_descriptor_header *acm_hs_function[] __initdata = { | |||
232 | 251 | ||
233 | #define ACM_CTRL_IDX 0 | 252 | #define ACM_CTRL_IDX 0 |
234 | #define ACM_DATA_IDX 1 | 253 | #define ACM_DATA_IDX 1 |
254 | #define ACM_IAD_IDX 2 | ||
235 | 255 | ||
236 | /* static strings, in UTF-8 */ | 256 | /* static strings, in UTF-8 */ |
237 | static struct usb_string acm_string_defs[] = { | 257 | static struct usb_string acm_string_defs[] = { |
238 | [ACM_CTRL_IDX].s = "CDC Abstract Control Model (ACM)", | 258 | [ACM_CTRL_IDX].s = "CDC Abstract Control Model (ACM)", |
239 | [ACM_DATA_IDX].s = "CDC ACM Data", | 259 | [ACM_DATA_IDX].s = "CDC ACM Data", |
260 | [ACM_IAD_IDX ].s = "CDC Serial", | ||
240 | { /* ZEROES END LIST */ }, | 261 | { /* ZEROES END LIST */ }, |
241 | }; | 262 | }; |
242 | 263 | ||
@@ -432,7 +453,7 @@ static void acm_disable(struct usb_function *f) | |||
432 | * @length: size of data | 453 | * @length: size of data |
433 | * Context: irqs blocked, acm->lock held, acm_notify_req non-null | 454 | * Context: irqs blocked, acm->lock held, acm_notify_req non-null |
434 | * | 455 | * |
435 | * Returns zero on sucess or a negative errno. | 456 | * Returns zero on success or a negative errno. |
436 | * | 457 | * |
437 | * See section 6.3.5 of the CDC 1.1 specification for information | 458 | * See section 6.3.5 of the CDC 1.1 specification for information |
438 | * about the only notification we issue: SerialState change. | 459 | * about the only notification we issue: SerialState change. |
@@ -563,6 +584,7 @@ acm_bind(struct usb_configuration *c, struct usb_function *f) | |||
563 | if (status < 0) | 584 | if (status < 0) |
564 | goto fail; | 585 | goto fail; |
565 | acm->ctrl_id = status; | 586 | acm->ctrl_id = status; |
587 | acm_iad_descriptor.bFirstInterface = status; | ||
566 | 588 | ||
567 | acm_control_interface_desc.bInterfaceNumber = status; | 589 | acm_control_interface_desc.bInterfaceNumber = status; |
568 | acm_union_desc .bMasterInterface0 = status; | 590 | acm_union_desc .bMasterInterface0 = status; |
@@ -681,14 +703,6 @@ acm_unbind(struct usb_configuration *c, struct usb_function *f) | |||
681 | /* Some controllers can't support CDC ACM ... */ | 703 | /* Some controllers can't support CDC ACM ... */ |
682 | static inline bool can_support_cdc(struct usb_configuration *c) | 704 | static inline bool can_support_cdc(struct usb_configuration *c) |
683 | { | 705 | { |
684 | /* SH3 doesn't support multiple interfaces */ | ||
685 | if (gadget_is_sh(c->cdev->gadget)) | ||
686 | return false; | ||
687 | |||
688 | /* sa1100 doesn't have a third interrupt endpoint */ | ||
689 | if (gadget_is_sa1100(c->cdev->gadget)) | ||
690 | return false; | ||
691 | |||
692 | /* everything else is *probably* fine ... */ | 706 | /* everything else is *probably* fine ... */ |
693 | return true; | 707 | return true; |
694 | } | 708 | } |
@@ -732,6 +746,13 @@ int __init acm_bind_config(struct usb_configuration *c, u8 port_num) | |||
732 | acm_string_defs[ACM_DATA_IDX].id = status; | 746 | acm_string_defs[ACM_DATA_IDX].id = status; |
733 | 747 | ||
734 | acm_data_interface_desc.iInterface = status; | 748 | acm_data_interface_desc.iInterface = status; |
749 | |||
750 | status = usb_string_id(c->cdev); | ||
751 | if (status < 0) | ||
752 | return status; | ||
753 | acm_string_defs[ACM_IAD_IDX].id = status; | ||
754 | |||
755 | acm_iad_descriptor.iFunction = status; | ||
735 | } | 756 | } |
736 | 757 | ||
737 | /* allocate and initialize one new instance */ | 758 | /* allocate and initialize one new instance */ |