root / hw / usb-desc.c @ acdf01ef
History | View | Annotate | Download (10.2 kB)
1 | 37fb59d3 | Gerd Hoffmann | #include "usb.h" |
---|---|---|---|
2 | 37fb59d3 | Gerd Hoffmann | #include "usb-desc.h" |
3 | 37fb59d3 | Gerd Hoffmann | #include "trace.h" |
4 | 37fb59d3 | Gerd Hoffmann | |
5 | 37fb59d3 | Gerd Hoffmann | /* ------------------------------------------------------------------ */
|
6 | 37fb59d3 | Gerd Hoffmann | |
7 | 37fb59d3 | Gerd Hoffmann | static uint8_t usb_lo(uint16_t val)
|
8 | 37fb59d3 | Gerd Hoffmann | { |
9 | 37fb59d3 | Gerd Hoffmann | return val & 0xff; |
10 | 37fb59d3 | Gerd Hoffmann | } |
11 | 37fb59d3 | Gerd Hoffmann | |
12 | 37fb59d3 | Gerd Hoffmann | static uint8_t usb_hi(uint16_t val)
|
13 | 37fb59d3 | Gerd Hoffmann | { |
14 | 37fb59d3 | Gerd Hoffmann | return (val >> 8) & 0xff; |
15 | 37fb59d3 | Gerd Hoffmann | } |
16 | 37fb59d3 | Gerd Hoffmann | |
17 | 37fb59d3 | Gerd Hoffmann | int usb_desc_device(const USBDescID *id, const USBDescDevice *dev, |
18 | 37fb59d3 | Gerd Hoffmann | uint8_t *dest, size_t len) |
19 | 37fb59d3 | Gerd Hoffmann | { |
20 | 37fb59d3 | Gerd Hoffmann | uint8_t bLength = 0x12;
|
21 | 37fb59d3 | Gerd Hoffmann | |
22 | 37fb59d3 | Gerd Hoffmann | if (len < bLength) {
|
23 | 37fb59d3 | Gerd Hoffmann | return -1; |
24 | 37fb59d3 | Gerd Hoffmann | } |
25 | 37fb59d3 | Gerd Hoffmann | |
26 | 37fb59d3 | Gerd Hoffmann | dest[0x00] = bLength;
|
27 | 37fb59d3 | Gerd Hoffmann | dest[0x01] = USB_DT_DEVICE;
|
28 | 37fb59d3 | Gerd Hoffmann | |
29 | 37fb59d3 | Gerd Hoffmann | dest[0x02] = usb_lo(dev->bcdUSB);
|
30 | 37fb59d3 | Gerd Hoffmann | dest[0x03] = usb_hi(dev->bcdUSB);
|
31 | 37fb59d3 | Gerd Hoffmann | dest[0x04] = dev->bDeviceClass;
|
32 | 37fb59d3 | Gerd Hoffmann | dest[0x05] = dev->bDeviceSubClass;
|
33 | 37fb59d3 | Gerd Hoffmann | dest[0x06] = dev->bDeviceProtocol;
|
34 | 37fb59d3 | Gerd Hoffmann | dest[0x07] = dev->bMaxPacketSize0;
|
35 | 37fb59d3 | Gerd Hoffmann | |
36 | 37fb59d3 | Gerd Hoffmann | dest[0x08] = usb_lo(id->idVendor);
|
37 | 37fb59d3 | Gerd Hoffmann | dest[0x09] = usb_hi(id->idVendor);
|
38 | 37fb59d3 | Gerd Hoffmann | dest[0x0a] = usb_lo(id->idProduct);
|
39 | 37fb59d3 | Gerd Hoffmann | dest[0x0b] = usb_hi(id->idProduct);
|
40 | 37fb59d3 | Gerd Hoffmann | dest[0x0c] = usb_lo(id->bcdDevice);
|
41 | 37fb59d3 | Gerd Hoffmann | dest[0x0d] = usb_hi(id->bcdDevice);
|
42 | 37fb59d3 | Gerd Hoffmann | dest[0x0e] = id->iManufacturer;
|
43 | 37fb59d3 | Gerd Hoffmann | dest[0x0f] = id->iProduct;
|
44 | 37fb59d3 | Gerd Hoffmann | dest[0x10] = id->iSerialNumber;
|
45 | 37fb59d3 | Gerd Hoffmann | |
46 | 37fb59d3 | Gerd Hoffmann | dest[0x11] = dev->bNumConfigurations;
|
47 | 37fb59d3 | Gerd Hoffmann | |
48 | 37fb59d3 | Gerd Hoffmann | return bLength;
|
49 | 37fb59d3 | Gerd Hoffmann | } |
50 | 37fb59d3 | Gerd Hoffmann | |
51 | 25620cba | Gerd Hoffmann | int usb_desc_device_qualifier(const USBDescDevice *dev, |
52 | 25620cba | Gerd Hoffmann | uint8_t *dest, size_t len) |
53 | 25620cba | Gerd Hoffmann | { |
54 | 25620cba | Gerd Hoffmann | uint8_t bLength = 0x0a;
|
55 | 25620cba | Gerd Hoffmann | |
56 | 25620cba | Gerd Hoffmann | if (len < bLength) {
|
57 | 25620cba | Gerd Hoffmann | return -1; |
58 | 25620cba | Gerd Hoffmann | } |
59 | 25620cba | Gerd Hoffmann | |
60 | 25620cba | Gerd Hoffmann | dest[0x00] = bLength;
|
61 | 25620cba | Gerd Hoffmann | dest[0x01] = USB_DT_DEVICE_QUALIFIER;
|
62 | 25620cba | Gerd Hoffmann | |
63 | 25620cba | Gerd Hoffmann | dest[0x02] = usb_lo(dev->bcdUSB);
|
64 | 25620cba | Gerd Hoffmann | dest[0x03] = usb_hi(dev->bcdUSB);
|
65 | 25620cba | Gerd Hoffmann | dest[0x04] = dev->bDeviceClass;
|
66 | 25620cba | Gerd Hoffmann | dest[0x05] = dev->bDeviceSubClass;
|
67 | 25620cba | Gerd Hoffmann | dest[0x06] = dev->bDeviceProtocol;
|
68 | 25620cba | Gerd Hoffmann | dest[0x07] = dev->bMaxPacketSize0;
|
69 | 25620cba | Gerd Hoffmann | dest[0x08] = dev->bNumConfigurations;
|
70 | 25620cba | Gerd Hoffmann | dest[0x09] = 0; /* reserved */ |
71 | 25620cba | Gerd Hoffmann | |
72 | 25620cba | Gerd Hoffmann | return bLength;
|
73 | 25620cba | Gerd Hoffmann | } |
74 | 25620cba | Gerd Hoffmann | |
75 | 37fb59d3 | Gerd Hoffmann | int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len) |
76 | 37fb59d3 | Gerd Hoffmann | { |
77 | 37fb59d3 | Gerd Hoffmann | uint8_t bLength = 0x09;
|
78 | 37fb59d3 | Gerd Hoffmann | uint16_t wTotalLength = 0;
|
79 | 37fb59d3 | Gerd Hoffmann | int i, rc, count;
|
80 | 37fb59d3 | Gerd Hoffmann | |
81 | 37fb59d3 | Gerd Hoffmann | if (len < bLength) {
|
82 | 37fb59d3 | Gerd Hoffmann | return -1; |
83 | 37fb59d3 | Gerd Hoffmann | } |
84 | 37fb59d3 | Gerd Hoffmann | |
85 | 37fb59d3 | Gerd Hoffmann | dest[0x00] = bLength;
|
86 | 37fb59d3 | Gerd Hoffmann | dest[0x01] = USB_DT_CONFIG;
|
87 | 37fb59d3 | Gerd Hoffmann | dest[0x04] = conf->bNumInterfaces;
|
88 | 37fb59d3 | Gerd Hoffmann | dest[0x05] = conf->bConfigurationValue;
|
89 | 37fb59d3 | Gerd Hoffmann | dest[0x06] = conf->iConfiguration;
|
90 | 37fb59d3 | Gerd Hoffmann | dest[0x07] = conf->bmAttributes;
|
91 | 37fb59d3 | Gerd Hoffmann | dest[0x08] = conf->bMaxPower;
|
92 | 37fb59d3 | Gerd Hoffmann | wTotalLength += bLength; |
93 | 37fb59d3 | Gerd Hoffmann | |
94 | 37fb59d3 | Gerd Hoffmann | count = conf->nif ? conf->nif : conf->bNumInterfaces; |
95 | 37fb59d3 | Gerd Hoffmann | for (i = 0; i < count; i++) { |
96 | 37fb59d3 | Gerd Hoffmann | rc = usb_desc_iface(conf->ifs + i, dest + wTotalLength, len - wTotalLength); |
97 | 37fb59d3 | Gerd Hoffmann | if (rc < 0) { |
98 | 37fb59d3 | Gerd Hoffmann | return rc;
|
99 | 37fb59d3 | Gerd Hoffmann | } |
100 | 37fb59d3 | Gerd Hoffmann | wTotalLength += rc; |
101 | 37fb59d3 | Gerd Hoffmann | } |
102 | 37fb59d3 | Gerd Hoffmann | |
103 | 37fb59d3 | Gerd Hoffmann | dest[0x02] = usb_lo(wTotalLength);
|
104 | 37fb59d3 | Gerd Hoffmann | dest[0x03] = usb_hi(wTotalLength);
|
105 | 37fb59d3 | Gerd Hoffmann | return wTotalLength;
|
106 | 37fb59d3 | Gerd Hoffmann | } |
107 | 37fb59d3 | Gerd Hoffmann | |
108 | 37fb59d3 | Gerd Hoffmann | int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len) |
109 | 37fb59d3 | Gerd Hoffmann | { |
110 | 37fb59d3 | Gerd Hoffmann | uint8_t bLength = 0x09;
|
111 | 37fb59d3 | Gerd Hoffmann | int i, rc, pos = 0; |
112 | 37fb59d3 | Gerd Hoffmann | |
113 | 37fb59d3 | Gerd Hoffmann | if (len < bLength) {
|
114 | 37fb59d3 | Gerd Hoffmann | return -1; |
115 | 37fb59d3 | Gerd Hoffmann | } |
116 | 37fb59d3 | Gerd Hoffmann | |
117 | 37fb59d3 | Gerd Hoffmann | dest[0x00] = bLength;
|
118 | 37fb59d3 | Gerd Hoffmann | dest[0x01] = USB_DT_INTERFACE;
|
119 | 37fb59d3 | Gerd Hoffmann | dest[0x02] = iface->bInterfaceNumber;
|
120 | 37fb59d3 | Gerd Hoffmann | dest[0x03] = iface->bAlternateSetting;
|
121 | 37fb59d3 | Gerd Hoffmann | dest[0x04] = iface->bNumEndpoints;
|
122 | 37fb59d3 | Gerd Hoffmann | dest[0x05] = iface->bInterfaceClass;
|
123 | 37fb59d3 | Gerd Hoffmann | dest[0x06] = iface->bInterfaceSubClass;
|
124 | 37fb59d3 | Gerd Hoffmann | dest[0x07] = iface->bInterfaceProtocol;
|
125 | 37fb59d3 | Gerd Hoffmann | dest[0x08] = iface->iInterface;
|
126 | 37fb59d3 | Gerd Hoffmann | pos += bLength; |
127 | 37fb59d3 | Gerd Hoffmann | |
128 | 37fb59d3 | Gerd Hoffmann | for (i = 0; i < iface->ndesc; i++) { |
129 | 37fb59d3 | Gerd Hoffmann | rc = usb_desc_other(iface->descs + i, dest + pos, len - pos); |
130 | 37fb59d3 | Gerd Hoffmann | if (rc < 0) { |
131 | 37fb59d3 | Gerd Hoffmann | return rc;
|
132 | 37fb59d3 | Gerd Hoffmann | } |
133 | 37fb59d3 | Gerd Hoffmann | pos += rc; |
134 | 37fb59d3 | Gerd Hoffmann | } |
135 | 37fb59d3 | Gerd Hoffmann | |
136 | 37fb59d3 | Gerd Hoffmann | for (i = 0; i < iface->bNumEndpoints; i++) { |
137 | 37fb59d3 | Gerd Hoffmann | rc = usb_desc_endpoint(iface->eps + i, dest + pos, len - pos); |
138 | 37fb59d3 | Gerd Hoffmann | if (rc < 0) { |
139 | 37fb59d3 | Gerd Hoffmann | return rc;
|
140 | 37fb59d3 | Gerd Hoffmann | } |
141 | 37fb59d3 | Gerd Hoffmann | pos += rc; |
142 | 37fb59d3 | Gerd Hoffmann | } |
143 | 37fb59d3 | Gerd Hoffmann | |
144 | 37fb59d3 | Gerd Hoffmann | return pos;
|
145 | 37fb59d3 | Gerd Hoffmann | } |
146 | 37fb59d3 | Gerd Hoffmann | |
147 | 37fb59d3 | Gerd Hoffmann | int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len) |
148 | 37fb59d3 | Gerd Hoffmann | { |
149 | 37fb59d3 | Gerd Hoffmann | uint8_t bLength = 0x07;
|
150 | 37fb59d3 | Gerd Hoffmann | |
151 | 37fb59d3 | Gerd Hoffmann | if (len < bLength) {
|
152 | 37fb59d3 | Gerd Hoffmann | return -1; |
153 | 37fb59d3 | Gerd Hoffmann | } |
154 | 37fb59d3 | Gerd Hoffmann | |
155 | 37fb59d3 | Gerd Hoffmann | dest[0x00] = bLength;
|
156 | 37fb59d3 | Gerd Hoffmann | dest[0x01] = USB_DT_ENDPOINT;
|
157 | 37fb59d3 | Gerd Hoffmann | dest[0x02] = ep->bEndpointAddress;
|
158 | 37fb59d3 | Gerd Hoffmann | dest[0x03] = ep->bmAttributes;
|
159 | 37fb59d3 | Gerd Hoffmann | dest[0x04] = usb_lo(ep->wMaxPacketSize);
|
160 | 37fb59d3 | Gerd Hoffmann | dest[0x05] = usb_hi(ep->wMaxPacketSize);
|
161 | 37fb59d3 | Gerd Hoffmann | dest[0x06] = ep->bInterval;
|
162 | 37fb59d3 | Gerd Hoffmann | |
163 | 37fb59d3 | Gerd Hoffmann | return bLength;
|
164 | 37fb59d3 | Gerd Hoffmann | } |
165 | 37fb59d3 | Gerd Hoffmann | |
166 | 37fb59d3 | Gerd Hoffmann | int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len) |
167 | 37fb59d3 | Gerd Hoffmann | { |
168 | 37fb59d3 | Gerd Hoffmann | int bLength = desc->length ? desc->length : desc->data[0]; |
169 | 37fb59d3 | Gerd Hoffmann | |
170 | 37fb59d3 | Gerd Hoffmann | if (len < bLength) {
|
171 | 37fb59d3 | Gerd Hoffmann | return -1; |
172 | 37fb59d3 | Gerd Hoffmann | } |
173 | 37fb59d3 | Gerd Hoffmann | |
174 | 37fb59d3 | Gerd Hoffmann | memcpy(dest, desc->data, bLength); |
175 | 37fb59d3 | Gerd Hoffmann | return bLength;
|
176 | 37fb59d3 | Gerd Hoffmann | } |
177 | 37fb59d3 | Gerd Hoffmann | |
178 | 132a3f55 | Gerd Hoffmann | /* ------------------------------------------------------------------ */
|
179 | 132a3f55 | Gerd Hoffmann | |
180 | 32d41919 | Gerd Hoffmann | static void usb_desc_setdefaults(USBDevice *dev) |
181 | a980a065 | Gerd Hoffmann | { |
182 | a980a065 | Gerd Hoffmann | const USBDesc *desc = dev->info->usb_desc;
|
183 | a980a065 | Gerd Hoffmann | |
184 | a980a065 | Gerd Hoffmann | assert(desc != NULL);
|
185 | 32d41919 | Gerd Hoffmann | switch (dev->speed) {
|
186 | 32d41919 | Gerd Hoffmann | case USB_SPEED_LOW:
|
187 | 32d41919 | Gerd Hoffmann | case USB_SPEED_FULL:
|
188 | 32d41919 | Gerd Hoffmann | dev->device = desc->full; |
189 | 32d41919 | Gerd Hoffmann | break;
|
190 | 32d41919 | Gerd Hoffmann | case USB_SPEED_HIGH:
|
191 | 32d41919 | Gerd Hoffmann | dev->device = desc->high; |
192 | 32d41919 | Gerd Hoffmann | break;
|
193 | 32d41919 | Gerd Hoffmann | } |
194 | a980a065 | Gerd Hoffmann | dev->config = dev->device->confs; |
195 | a980a065 | Gerd Hoffmann | } |
196 | a980a065 | Gerd Hoffmann | |
197 | 32d41919 | Gerd Hoffmann | void usb_desc_init(USBDevice *dev)
|
198 | 32d41919 | Gerd Hoffmann | { |
199 | 32d41919 | Gerd Hoffmann | dev->speed = USB_SPEED_FULL; |
200 | 32d41919 | Gerd Hoffmann | usb_desc_setdefaults(dev); |
201 | 32d41919 | Gerd Hoffmann | } |
202 | 32d41919 | Gerd Hoffmann | |
203 | 32d41919 | Gerd Hoffmann | void usb_desc_attach(USBDevice *dev)
|
204 | 32d41919 | Gerd Hoffmann | { |
205 | 32d41919 | Gerd Hoffmann | const USBDesc *desc = dev->info->usb_desc;
|
206 | 32d41919 | Gerd Hoffmann | |
207 | 32d41919 | Gerd Hoffmann | assert(desc != NULL);
|
208 | 32d41919 | Gerd Hoffmann | if (desc->high && (dev->port->speedmask & USB_SPEED_MASK_HIGH)) {
|
209 | 32d41919 | Gerd Hoffmann | dev->speed = USB_SPEED_HIGH; |
210 | 32d41919 | Gerd Hoffmann | } else if (desc->full && (dev->port->speedmask & USB_SPEED_MASK_FULL)) { |
211 | 32d41919 | Gerd Hoffmann | dev->speed = USB_SPEED_FULL; |
212 | 32d41919 | Gerd Hoffmann | } else {
|
213 | 32d41919 | Gerd Hoffmann | fprintf(stderr, "usb: port/device speed mismatch for \"%s\"\n",
|
214 | 32d41919 | Gerd Hoffmann | dev->info->product_desc); |
215 | 32d41919 | Gerd Hoffmann | return;
|
216 | 32d41919 | Gerd Hoffmann | } |
217 | 32d41919 | Gerd Hoffmann | usb_desc_setdefaults(dev); |
218 | 32d41919 | Gerd Hoffmann | } |
219 | 32d41919 | Gerd Hoffmann | |
220 | 132a3f55 | Gerd Hoffmann | void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str) |
221 | 132a3f55 | Gerd Hoffmann | { |
222 | 132a3f55 | Gerd Hoffmann | USBDescString *s; |
223 | 132a3f55 | Gerd Hoffmann | |
224 | 132a3f55 | Gerd Hoffmann | QLIST_FOREACH(s, &dev->strings, next) { |
225 | 132a3f55 | Gerd Hoffmann | if (s->index == index) {
|
226 | 132a3f55 | Gerd Hoffmann | break;
|
227 | 132a3f55 | Gerd Hoffmann | } |
228 | 132a3f55 | Gerd Hoffmann | } |
229 | 132a3f55 | Gerd Hoffmann | if (s == NULL) { |
230 | 132a3f55 | Gerd Hoffmann | s = qemu_mallocz(sizeof(*s));
|
231 | 132a3f55 | Gerd Hoffmann | s->index = index; |
232 | 132a3f55 | Gerd Hoffmann | QLIST_INSERT_HEAD(&dev->strings, s, next); |
233 | 132a3f55 | Gerd Hoffmann | } |
234 | 132a3f55 | Gerd Hoffmann | qemu_free(s->str); |
235 | 132a3f55 | Gerd Hoffmann | s->str = qemu_strdup(str); |
236 | 132a3f55 | Gerd Hoffmann | } |
237 | 132a3f55 | Gerd Hoffmann | |
238 | 132a3f55 | Gerd Hoffmann | const char *usb_desc_get_string(USBDevice *dev, uint8_t index) |
239 | 132a3f55 | Gerd Hoffmann | { |
240 | 132a3f55 | Gerd Hoffmann | USBDescString *s; |
241 | 132a3f55 | Gerd Hoffmann | |
242 | 132a3f55 | Gerd Hoffmann | QLIST_FOREACH(s, &dev->strings, next) { |
243 | 132a3f55 | Gerd Hoffmann | if (s->index == index) {
|
244 | 132a3f55 | Gerd Hoffmann | return s->str;
|
245 | 132a3f55 | Gerd Hoffmann | } |
246 | 132a3f55 | Gerd Hoffmann | } |
247 | 132a3f55 | Gerd Hoffmann | return NULL; |
248 | 132a3f55 | Gerd Hoffmann | } |
249 | 132a3f55 | Gerd Hoffmann | |
250 | 132a3f55 | Gerd Hoffmann | int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len) |
251 | 37fb59d3 | Gerd Hoffmann | { |
252 | 37fb59d3 | Gerd Hoffmann | uint8_t bLength, pos, i; |
253 | 132a3f55 | Gerd Hoffmann | const char *str; |
254 | 37fb59d3 | Gerd Hoffmann | |
255 | 37fb59d3 | Gerd Hoffmann | if (len < 4) { |
256 | 37fb59d3 | Gerd Hoffmann | return -1; |
257 | 37fb59d3 | Gerd Hoffmann | } |
258 | 37fb59d3 | Gerd Hoffmann | |
259 | 37fb59d3 | Gerd Hoffmann | if (index == 0) { |
260 | 37fb59d3 | Gerd Hoffmann | /* language ids */
|
261 | 37fb59d3 | Gerd Hoffmann | dest[0] = 4; |
262 | 37fb59d3 | Gerd Hoffmann | dest[1] = USB_DT_STRING;
|
263 | 37fb59d3 | Gerd Hoffmann | dest[2] = 0x09; |
264 | 37fb59d3 | Gerd Hoffmann | dest[3] = 0x04; |
265 | 37fb59d3 | Gerd Hoffmann | return 4; |
266 | 37fb59d3 | Gerd Hoffmann | } |
267 | 37fb59d3 | Gerd Hoffmann | |
268 | 132a3f55 | Gerd Hoffmann | str = usb_desc_get_string(dev, index); |
269 | 132a3f55 | Gerd Hoffmann | if (str == NULL) { |
270 | 132a3f55 | Gerd Hoffmann | str = dev->info->usb_desc->str[index]; |
271 | 132a3f55 | Gerd Hoffmann | if (str == NULL) { |
272 | 132a3f55 | Gerd Hoffmann | return 0; |
273 | 132a3f55 | Gerd Hoffmann | } |
274 | 37fb59d3 | Gerd Hoffmann | } |
275 | 132a3f55 | Gerd Hoffmann | |
276 | 132a3f55 | Gerd Hoffmann | bLength = strlen(str) * 2 + 2; |
277 | 37fb59d3 | Gerd Hoffmann | dest[0] = bLength;
|
278 | 37fb59d3 | Gerd Hoffmann | dest[1] = USB_DT_STRING;
|
279 | 37fb59d3 | Gerd Hoffmann | i = 0; pos = 2; |
280 | 37fb59d3 | Gerd Hoffmann | while (pos+1 < bLength && pos+1 < len) { |
281 | 132a3f55 | Gerd Hoffmann | dest[pos++] = str[i++]; |
282 | 37fb59d3 | Gerd Hoffmann | dest[pos++] = 0;
|
283 | 37fb59d3 | Gerd Hoffmann | } |
284 | 37fb59d3 | Gerd Hoffmann | return pos;
|
285 | 37fb59d3 | Gerd Hoffmann | } |
286 | 37fb59d3 | Gerd Hoffmann | |
287 | 37fb59d3 | Gerd Hoffmann | int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len) |
288 | 37fb59d3 | Gerd Hoffmann | { |
289 | 37fb59d3 | Gerd Hoffmann | const USBDesc *desc = dev->info->usb_desc;
|
290 | 25620cba | Gerd Hoffmann | const USBDescDevice *other_dev;
|
291 | 37fb59d3 | Gerd Hoffmann | uint8_t buf[256];
|
292 | 37fb59d3 | Gerd Hoffmann | uint8_t type = value >> 8;
|
293 | 37fb59d3 | Gerd Hoffmann | uint8_t index = value & 0xff;
|
294 | 37fb59d3 | Gerd Hoffmann | int ret = -1; |
295 | 37fb59d3 | Gerd Hoffmann | |
296 | 25620cba | Gerd Hoffmann | if (dev->speed == USB_SPEED_HIGH) {
|
297 | 25620cba | Gerd Hoffmann | other_dev = dev->info->usb_desc->full; |
298 | 25620cba | Gerd Hoffmann | } else {
|
299 | 25620cba | Gerd Hoffmann | other_dev = dev->info->usb_desc->high; |
300 | 25620cba | Gerd Hoffmann | } |
301 | 25620cba | Gerd Hoffmann | |
302 | 37fb59d3 | Gerd Hoffmann | switch(type) {
|
303 | 37fb59d3 | Gerd Hoffmann | case USB_DT_DEVICE:
|
304 | a980a065 | Gerd Hoffmann | ret = usb_desc_device(&desc->id, dev->device, buf, sizeof(buf));
|
305 | 37fb59d3 | Gerd Hoffmann | trace_usb_desc_device(dev->addr, len, ret); |
306 | 37fb59d3 | Gerd Hoffmann | break;
|
307 | 37fb59d3 | Gerd Hoffmann | case USB_DT_CONFIG:
|
308 | a980a065 | Gerd Hoffmann | if (index < dev->device->bNumConfigurations) {
|
309 | a980a065 | Gerd Hoffmann | ret = usb_desc_config(dev->device->confs + index, buf, sizeof(buf));
|
310 | 37fb59d3 | Gerd Hoffmann | } |
311 | 37fb59d3 | Gerd Hoffmann | trace_usb_desc_config(dev->addr, index, len, ret); |
312 | 37fb59d3 | Gerd Hoffmann | break;
|
313 | 37fb59d3 | Gerd Hoffmann | case USB_DT_STRING:
|
314 | 132a3f55 | Gerd Hoffmann | ret = usb_desc_string(dev, index, buf, sizeof(buf));
|
315 | 37fb59d3 | Gerd Hoffmann | trace_usb_desc_string(dev->addr, index, len, ret); |
316 | 37fb59d3 | Gerd Hoffmann | break;
|
317 | 25620cba | Gerd Hoffmann | |
318 | 25620cba | Gerd Hoffmann | case USB_DT_DEVICE_QUALIFIER:
|
319 | 25620cba | Gerd Hoffmann | if (other_dev != NULL) { |
320 | 25620cba | Gerd Hoffmann | ret = usb_desc_device_qualifier(other_dev, buf, sizeof(buf));
|
321 | 25620cba | Gerd Hoffmann | } |
322 | 25620cba | Gerd Hoffmann | trace_usb_desc_device_qualifier(dev->addr, len, ret); |
323 | 25620cba | Gerd Hoffmann | break;
|
324 | 25620cba | Gerd Hoffmann | case USB_DT_OTHER_SPEED_CONFIG:
|
325 | 25620cba | Gerd Hoffmann | if (other_dev != NULL && index < other_dev->bNumConfigurations) { |
326 | 25620cba | Gerd Hoffmann | ret = usb_desc_config(other_dev->confs + index, buf, sizeof(buf));
|
327 | 25620cba | Gerd Hoffmann | buf[0x01] = USB_DT_OTHER_SPEED_CONFIG;
|
328 | 25620cba | Gerd Hoffmann | } |
329 | 25620cba | Gerd Hoffmann | trace_usb_desc_other_speed_config(dev->addr, index, len, ret); |
330 | 25620cba | Gerd Hoffmann | break;
|
331 | 25620cba | Gerd Hoffmann | |
332 | 37fb59d3 | Gerd Hoffmann | default:
|
333 | 37fb59d3 | Gerd Hoffmann | fprintf(stderr, "%s: %d unknown type %d (len %zd)\n", __FUNCTION__,
|
334 | 37fb59d3 | Gerd Hoffmann | dev->addr, type, len); |
335 | 37fb59d3 | Gerd Hoffmann | break;
|
336 | 37fb59d3 | Gerd Hoffmann | } |
337 | 37fb59d3 | Gerd Hoffmann | |
338 | 37fb59d3 | Gerd Hoffmann | if (ret > 0) { |
339 | 37fb59d3 | Gerd Hoffmann | if (ret > len) {
|
340 | 37fb59d3 | Gerd Hoffmann | ret = len; |
341 | 37fb59d3 | Gerd Hoffmann | } |
342 | 37fb59d3 | Gerd Hoffmann | memcpy(dest, buf, ret); |
343 | 37fb59d3 | Gerd Hoffmann | } |
344 | 37fb59d3 | Gerd Hoffmann | return ret;
|
345 | 37fb59d3 | Gerd Hoffmann | } |
346 | 37fb59d3 | Gerd Hoffmann | |
347 | 37fb59d3 | Gerd Hoffmann | int usb_desc_handle_control(USBDevice *dev, int request, int value, |
348 | 37fb59d3 | Gerd Hoffmann | int index, int length, uint8_t *data) |
349 | 37fb59d3 | Gerd Hoffmann | { |
350 | 37fb59d3 | Gerd Hoffmann | const USBDesc *desc = dev->info->usb_desc;
|
351 | a980a065 | Gerd Hoffmann | int i, ret = -1; |
352 | 37fb59d3 | Gerd Hoffmann | |
353 | 37fb59d3 | Gerd Hoffmann | assert(desc != NULL);
|
354 | 37fb59d3 | Gerd Hoffmann | switch(request) {
|
355 | 41c6abbd | Gerd Hoffmann | case DeviceOutRequest | USB_REQ_SET_ADDRESS:
|
356 | 41c6abbd | Gerd Hoffmann | dev->addr = value; |
357 | 41c6abbd | Gerd Hoffmann | trace_usb_set_addr(dev->addr); |
358 | 41c6abbd | Gerd Hoffmann | ret = 0;
|
359 | 41c6abbd | Gerd Hoffmann | break;
|
360 | 41c6abbd | Gerd Hoffmann | |
361 | 37fb59d3 | Gerd Hoffmann | case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
|
362 | 37fb59d3 | Gerd Hoffmann | ret = usb_desc_get_descriptor(dev, value, data, length); |
363 | 37fb59d3 | Gerd Hoffmann | break;
|
364 | a980a065 | Gerd Hoffmann | |
365 | a980a065 | Gerd Hoffmann | case DeviceRequest | USB_REQ_GET_CONFIGURATION:
|
366 | a980a065 | Gerd Hoffmann | data[0] = dev->config->bConfigurationValue;
|
367 | a980a065 | Gerd Hoffmann | ret = 1;
|
368 | a980a065 | Gerd Hoffmann | break;
|
369 | a980a065 | Gerd Hoffmann | case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
|
370 | a980a065 | Gerd Hoffmann | for (i = 0; i < dev->device->bNumConfigurations; i++) { |
371 | a980a065 | Gerd Hoffmann | if (dev->device->confs[i].bConfigurationValue == value) {
|
372 | a980a065 | Gerd Hoffmann | dev->config = dev->device->confs + i; |
373 | a980a065 | Gerd Hoffmann | ret = 0;
|
374 | a980a065 | Gerd Hoffmann | } |
375 | a980a065 | Gerd Hoffmann | } |
376 | a980a065 | Gerd Hoffmann | trace_usb_set_config(dev->addr, value, ret); |
377 | a980a065 | Gerd Hoffmann | break;
|
378 | ed5a83dd | Gerd Hoffmann | |
379 | ed5a83dd | Gerd Hoffmann | case DeviceRequest | USB_REQ_GET_STATUS:
|
380 | ed5a83dd | Gerd Hoffmann | data[0] = 0; |
381 | ed5a83dd | Gerd Hoffmann | if (dev->config->bmAttributes & 0x40) { |
382 | ed5a83dd | Gerd Hoffmann | data[0] |= 1 << USB_DEVICE_SELF_POWERED; |
383 | ed5a83dd | Gerd Hoffmann | } |
384 | ed5a83dd | Gerd Hoffmann | if (dev->remote_wakeup) {
|
385 | ed5a83dd | Gerd Hoffmann | data[0] |= 1 << USB_DEVICE_REMOTE_WAKEUP; |
386 | ed5a83dd | Gerd Hoffmann | } |
387 | ed5a83dd | Gerd Hoffmann | data[1] = 0x00; |
388 | ed5a83dd | Gerd Hoffmann | ret = 2;
|
389 | ed5a83dd | Gerd Hoffmann | break;
|
390 | ed5a83dd | Gerd Hoffmann | case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
|
391 | ed5a83dd | Gerd Hoffmann | if (value == USB_DEVICE_REMOTE_WAKEUP) {
|
392 | ed5a83dd | Gerd Hoffmann | dev->remote_wakeup = 0;
|
393 | ed5a83dd | Gerd Hoffmann | ret = 0;
|
394 | ed5a83dd | Gerd Hoffmann | } |
395 | ed5a83dd | Gerd Hoffmann | trace_usb_clear_device_feature(dev->addr, value, ret); |
396 | ed5a83dd | Gerd Hoffmann | break;
|
397 | ed5a83dd | Gerd Hoffmann | case DeviceOutRequest | USB_REQ_SET_FEATURE:
|
398 | ed5a83dd | Gerd Hoffmann | if (value == USB_DEVICE_REMOTE_WAKEUP) {
|
399 | ed5a83dd | Gerd Hoffmann | dev->remote_wakeup = 1;
|
400 | ed5a83dd | Gerd Hoffmann | ret = 0;
|
401 | ed5a83dd | Gerd Hoffmann | } |
402 | ed5a83dd | Gerd Hoffmann | trace_usb_set_device_feature(dev->addr, value, ret); |
403 | ed5a83dd | Gerd Hoffmann | break;
|
404 | 37fb59d3 | Gerd Hoffmann | } |
405 | 37fb59d3 | Gerd Hoffmann | return ret;
|
406 | 37fb59d3 | Gerd Hoffmann | } |