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