1
2
3
4
5
6
7
8
9
10
11
12#include <linux/errno.h>
13#include <linux/slab.h>
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/list.h>
17#include <linux/string.h>
18#include <linux/device.h>
19
20#include <linux/usb/ch9.h>
21#include <linux/usb/gadget.h>
22#include <linux/usb/composite.h>
23
24
25
26
27
28
29
30
31
32
33
34
35
36int
37usb_descriptor_fillbuf(void *buf, unsigned buflen,
38 const struct usb_descriptor_header **src)
39{
40 u8 *dest = buf;
41
42 if (!src)
43 return -EINVAL;
44
45
46 for (; NULL != *src; src++) {
47 unsigned len = (*src)->bLength;
48
49 if (len > buflen)
50 return -EINVAL;
51 memcpy(dest, *src, len);
52 buflen -= len;
53 dest += len;
54 }
55 return dest - (u8 *)buf;
56}
57EXPORT_SYMBOL_GPL(usb_descriptor_fillbuf);
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79int usb_gadget_config_buf(
80 const struct usb_config_descriptor *config,
81 void *buf,
82 unsigned length,
83 const struct usb_descriptor_header **desc
84)
85{
86 struct usb_config_descriptor *cp = buf;
87 int len;
88
89
90 if (length < USB_DT_CONFIG_SIZE || !desc)
91 return -EINVAL;
92 *cp = *config;
93
94
95 len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf,
96 length - USB_DT_CONFIG_SIZE, desc);
97 if (len < 0)
98 return len;
99 len += USB_DT_CONFIG_SIZE;
100 if (len > 0xffff)
101 return -EINVAL;
102
103
104 cp->bLength = USB_DT_CONFIG_SIZE;
105 cp->bDescriptorType = USB_DT_CONFIG;
106 cp->wTotalLength = cpu_to_le16(len);
107 cp->bmAttributes |= USB_CONFIG_ATT_ONE;
108 return len;
109}
110EXPORT_SYMBOL_GPL(usb_gadget_config_buf);
111
112
113
114
115
116
117
118
119
120
121
122
123
124struct usb_descriptor_header **
125usb_copy_descriptors(struct usb_descriptor_header **src)
126{
127 struct usb_descriptor_header **tmp;
128 unsigned bytes;
129 unsigned n_desc;
130 void *mem;
131 struct usb_descriptor_header **ret;
132
133
134 for (bytes = 0, n_desc = 0, tmp = src; *tmp; tmp++, n_desc++)
135 bytes += (*tmp)->bLength;
136 bytes += (n_desc + 1) * sizeof(*tmp);
137
138 mem = kmalloc(bytes, GFP_KERNEL);
139 if (!mem)
140 return NULL;
141
142
143
144
145
146 tmp = mem;
147 ret = mem;
148 mem += (n_desc + 1) * sizeof(*tmp);
149 while (*src) {
150 memcpy(mem, *src, (*src)->bLength);
151 *tmp = mem;
152 tmp++;
153 mem += (*src)->bLength;
154 src++;
155 }
156 *tmp = NULL;
157
158 return ret;
159}
160EXPORT_SYMBOL_GPL(usb_copy_descriptors);
161
162int usb_assign_descriptors(struct usb_function *f,
163 struct usb_descriptor_header **fs,
164 struct usb_descriptor_header **hs,
165 struct usb_descriptor_header **ss)
166{
167 struct usb_gadget *g = f->config->cdev->gadget;
168
169 if (fs) {
170 f->fs_descriptors = usb_copy_descriptors(fs);
171 if (!f->fs_descriptors)
172 goto err;
173 }
174 if (hs && gadget_is_dualspeed(g)) {
175 f->hs_descriptors = usb_copy_descriptors(hs);
176 if (!f->hs_descriptors)
177 goto err;
178 }
179 if (ss && gadget_is_superspeed(g)) {
180 f->ss_descriptors = usb_copy_descriptors(ss);
181 if (!f->ss_descriptors)
182 goto err;
183 }
184 return 0;
185err:
186 usb_free_all_descriptors(f);
187 return -ENOMEM;
188}
189EXPORT_SYMBOL_GPL(usb_assign_descriptors);
190
191void usb_free_all_descriptors(struct usb_function *f)
192{
193 usb_free_descriptors(f->fs_descriptors);
194 usb_free_descriptors(f->hs_descriptors);
195 usb_free_descriptors(f->ss_descriptors);
196}
197EXPORT_SYMBOL_GPL(usb_free_all_descriptors);
198