Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * usb/gadget/config.c -- simplify building config descriptors | |
3 | * | |
4 | * Copyright (C) 2003 David Brownell | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 2 of the License, or | |
9 | * (at your option) any later version. | |
1da177e4 LT |
10 | */ |
11 | ||
12 | #include <linux/errno.h> | |
5a0e3ad6 | 13 | #include <linux/slab.h> |
1da177e4 | 14 | #include <linux/kernel.h> |
0ba16dea | 15 | #include <linux/module.h> |
1da177e4 LT |
16 | #include <linux/list.h> |
17 | #include <linux/string.h> | |
18 | #include <linux/device.h> | |
19 | ||
5f848137 | 20 | #include <linux/usb/ch9.h> |
9454a57a | 21 | #include <linux/usb/gadget.h> |
10287bae | 22 | #include <linux/usb/composite.h> |
d1606dfb | 23 | #include <linux/usb/otg.h> |
1da177e4 LT |
24 | |
25 | /** | |
26 | * usb_descriptor_fillbuf - fill buffer with descriptors | |
27 | * @buf: Buffer to be filled | |
28 | * @buflen: Size of buf | |
29 | * @src: Array of descriptor pointers, terminated by null pointer. | |
30 | * | |
31 | * Copies descriptors into the buffer, returning the length or a | |
32 | * negative error code if they can't all be copied. Useful when | |
33 | * assembling descriptors for an associated set of interfaces used | |
34 | * as part of configuring a composite device; or in other cases where | |
35 | * sets of descriptors need to be marshaled. | |
36 | */ | |
37 | int | |
38 | usb_descriptor_fillbuf(void *buf, unsigned buflen, | |
39 | const struct usb_descriptor_header **src) | |
40 | { | |
41 | u8 *dest = buf; | |
42 | ||
43 | if (!src) | |
44 | return -EINVAL; | |
45 | ||
46 | /* fill buffer from src[] until null descriptor ptr */ | |
a9475226 | 47 | for (; NULL != *src; src++) { |
1da177e4 LT |
48 | unsigned len = (*src)->bLength; |
49 | ||
50 | if (len > buflen) | |
51 | return -EINVAL; | |
52 | memcpy(dest, *src, len); | |
53 | buflen -= len; | |
54 | dest += len; | |
55 | } | |
56 | return dest - (u8 *)buf; | |
57 | } | |
0ba16dea | 58 | EXPORT_SYMBOL_GPL(usb_descriptor_fillbuf); |
1da177e4 LT |
59 | |
60 | /** | |
61 | * usb_gadget_config_buf - builts a complete configuration descriptor | |
62 | * @config: Header for the descriptor, including characteristics such | |
63 | * as power requirements and number of interfaces. | |
64 | * @desc: Null-terminated vector of pointers to the descriptors (interface, | |
65 | * endpoint, etc) defining all functions in this device configuration. | |
66 | * @buf: Buffer for the resulting configuration descriptor. | |
67 | * @length: Length of buffer. If this is not big enough to hold the | |
68 | * entire configuration descriptor, an error code will be returned. | |
69 | * | |
70 | * This copies descriptors into the response buffer, building a descriptor | |
71 | * for that configuration. It returns the buffer length or a negative | |
72 | * status code. The config.wTotalLength field is set to match the length | |
73 | * of the result, but other descriptor fields (including power usage and | |
74 | * interface count) must be set by the caller. | |
75 | * | |
76 | * Gadget drivers could use this when constructing a config descriptor | |
77 | * in response to USB_REQ_GET_DESCRIPTOR. They will need to patch the | |
78 | * resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed. | |
79 | */ | |
80 | int usb_gadget_config_buf( | |
81 | const struct usb_config_descriptor *config, | |
82 | void *buf, | |
83 | unsigned length, | |
84 | const struct usb_descriptor_header **desc | |
85 | ) | |
86 | { | |
87 | struct usb_config_descriptor *cp = buf; | |
88 | int len; | |
89 | ||
90 | /* config descriptor first */ | |
91 | if (length < USB_DT_CONFIG_SIZE || !desc) | |
92 | return -EINVAL; | |
a4c39c41 | 93 | *cp = *config; |
1da177e4 LT |
94 | |
95 | /* then interface/endpoint/class/vendor/... */ | |
96 | len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf, | |
97 | length - USB_DT_CONFIG_SIZE, desc); | |
98 | if (len < 0) | |
99 | return len; | |
100 | len += USB_DT_CONFIG_SIZE; | |
101 | if (len > 0xffff) | |
102 | return -EINVAL; | |
103 | ||
104 | /* patch up the config descriptor */ | |
105 | cp->bLength = USB_DT_CONFIG_SIZE; | |
106 | cp->bDescriptorType = USB_DT_CONFIG; | |
107 | cp->wTotalLength = cpu_to_le16(len); | |
108 | cp->bmAttributes |= USB_CONFIG_ATT_ONE; | |
109 | return len; | |
110 | } | |
0ba16dea | 111 | EXPORT_SYMBOL_GPL(usb_gadget_config_buf); |
1da177e4 | 112 | |
a4c39c41 DB |
113 | /** |
114 | * usb_copy_descriptors - copy a vector of USB descriptors | |
115 | * @src: null-terminated vector to copy | |
116 | * Context: initialization code, which may sleep | |
117 | * | |
118 | * This makes a copy of a vector of USB descriptors. Its primary use | |
119 | * is to support usb_function objects which can have multiple copies, | |
120 | * each needing different descriptors. Functions may have static | |
121 | * tables of descriptors, which are used as templates and customized | |
122 | * with identifiers (for interfaces, strings, endpoints, and more) | |
123 | * as needed by a given function instance. | |
124 | */ | |
28824b18 | 125 | struct usb_descriptor_header ** |
a4c39c41 DB |
126 | usb_copy_descriptors(struct usb_descriptor_header **src) |
127 | { | |
128 | struct usb_descriptor_header **tmp; | |
129 | unsigned bytes; | |
130 | unsigned n_desc; | |
131 | void *mem; | |
132 | struct usb_descriptor_header **ret; | |
133 | ||
134 | /* count descriptors and their sizes; then add vector size */ | |
135 | for (bytes = 0, n_desc = 0, tmp = src; *tmp; tmp++, n_desc++) | |
136 | bytes += (*tmp)->bLength; | |
137 | bytes += (n_desc + 1) * sizeof(*tmp); | |
138 | ||
139 | mem = kmalloc(bytes, GFP_KERNEL); | |
140 | if (!mem) | |
141 | return NULL; | |
142 | ||
143 | /* fill in pointers starting at "tmp", | |
144 | * to descriptors copied starting at "mem"; | |
145 | * and return "ret" | |
146 | */ | |
147 | tmp = mem; | |
148 | ret = mem; | |
149 | mem += (n_desc + 1) * sizeof(*tmp); | |
150 | while (*src) { | |
151 | memcpy(mem, *src, (*src)->bLength); | |
152 | *tmp = mem; | |
153 | tmp++; | |
154 | mem += (*src)->bLength; | |
155 | src++; | |
156 | } | |
157 | *tmp = NULL; | |
158 | ||
159 | return ret; | |
160 | } | |
0ba16dea | 161 | EXPORT_SYMBOL_GPL(usb_copy_descriptors); |
10287bae SAS |
162 | |
163 | int usb_assign_descriptors(struct usb_function *f, | |
164 | struct usb_descriptor_header **fs, | |
165 | struct usb_descriptor_header **hs, | |
166 | struct usb_descriptor_header **ss) | |
167 | { | |
168 | struct usb_gadget *g = f->config->cdev->gadget; | |
169 | ||
170 | if (fs) { | |
171 | f->fs_descriptors = usb_copy_descriptors(fs); | |
172 | if (!f->fs_descriptors) | |
173 | goto err; | |
174 | } | |
175 | if (hs && gadget_is_dualspeed(g)) { | |
176 | f->hs_descriptors = usb_copy_descriptors(hs); | |
177 | if (!f->hs_descriptors) | |
178 | goto err; | |
179 | } | |
180 | if (ss && gadget_is_superspeed(g)) { | |
181 | f->ss_descriptors = usb_copy_descriptors(ss); | |
182 | if (!f->ss_descriptors) | |
183 | goto err; | |
184 | } | |
185 | return 0; | |
186 | err: | |
187 | usb_free_all_descriptors(f); | |
188 | return -ENOMEM; | |
189 | } | |
190 | EXPORT_SYMBOL_GPL(usb_assign_descriptors); | |
191 | ||
192 | void usb_free_all_descriptors(struct usb_function *f) | |
193 | { | |
194 | usb_free_descriptors(f->fs_descriptors); | |
195 | usb_free_descriptors(f->hs_descriptors); | |
196 | usb_free_descriptors(f->ss_descriptors); | |
197 | } | |
198 | EXPORT_SYMBOL_GPL(usb_free_all_descriptors); | |
d1606dfb LJ |
199 | |
200 | struct usb_descriptor_header *usb_otg_descriptor_alloc( | |
201 | struct usb_gadget *gadget) | |
202 | { | |
203 | struct usb_descriptor_header *otg_desc; | |
204 | unsigned length = 0; | |
205 | ||
206 | if (gadget->otg_caps && (gadget->otg_caps->otg_rev >= 0x0200)) | |
207 | length = sizeof(struct usb_otg20_descriptor); | |
208 | else | |
209 | length = sizeof(struct usb_otg_descriptor); | |
210 | ||
211 | otg_desc = kzalloc(length, GFP_KERNEL); | |
212 | return otg_desc; | |
213 | } | |
214 | EXPORT_SYMBOL_GPL(usb_otg_descriptor_alloc); | |
215 | ||
216 | int usb_otg_descriptor_init(struct usb_gadget *gadget, | |
217 | struct usb_descriptor_header *otg_desc) | |
218 | { | |
219 | struct usb_otg_descriptor *otg1x_desc; | |
220 | struct usb_otg20_descriptor *otg20_desc; | |
221 | struct usb_otg_caps *otg_caps = gadget->otg_caps; | |
222 | u8 otg_attributes = 0; | |
223 | ||
224 | if (!otg_desc) | |
225 | return -EINVAL; | |
226 | ||
227 | if (otg_caps && otg_caps->otg_rev) { | |
228 | if (otg_caps->hnp_support) | |
229 | otg_attributes |= USB_OTG_HNP; | |
230 | if (otg_caps->srp_support) | |
231 | otg_attributes |= USB_OTG_SRP; | |
232 | if (otg_caps->adp_support && (otg_caps->otg_rev >= 0x0200)) | |
233 | otg_attributes |= USB_OTG_ADP; | |
234 | } else { | |
235 | otg_attributes = USB_OTG_SRP | USB_OTG_HNP; | |
236 | } | |
237 | ||
238 | if (otg_caps && (otg_caps->otg_rev >= 0x0200)) { | |
239 | otg20_desc = (struct usb_otg20_descriptor *)otg_desc; | |
240 | otg20_desc->bLength = sizeof(struct usb_otg20_descriptor); | |
241 | otg20_desc->bDescriptorType = USB_DT_OTG; | |
242 | otg20_desc->bmAttributes = otg_attributes; | |
243 | otg20_desc->bcdOTG = cpu_to_le16(otg_caps->otg_rev); | |
244 | } else { | |
245 | otg1x_desc = (struct usb_otg_descriptor *)otg_desc; | |
246 | otg1x_desc->bLength = sizeof(struct usb_otg_descriptor); | |
247 | otg1x_desc->bDescriptorType = USB_DT_OTG; | |
248 | otg1x_desc->bmAttributes = otg_attributes; | |
249 | } | |
250 | ||
251 | return 0; | |
252 | } | |
253 | EXPORT_SYMBOL_GPL(usb_otg_descriptor_init); |