/* * Copyright (c) 2015 Brian Swetland * Copyright (c) 2008 Google, Inc. * * Use of this source code is governed by a MIT-style * license that can be found in the LICENSE file or at * https://opensource.org/licenses/MIT */ #include #include #include #include #include "udc-common.h" static udc_descriptor_t *udc_descriptor_alloc(unsigned type, unsigned num, unsigned len) { struct udc_descriptor *desc; if ((len > 255) || (len < 2) || (num > 255) || (type > 255)) return 0; if (!(desc = malloc(sizeof(struct udc_descriptor) + len))) return 0; desc->next = 0; desc->tag = (type << 8) | num; desc->len = len; desc->data[0] = len; desc->data[1] = type; return desc; } static udc_descriptor_t langid_list = { .tag = 0x0300, .len = 4, .data = { 0x04, TYPE_STRING, 0x09, 0x04 }, // EN_US }; static struct udc_descriptor *desc_list = &langid_list; static unsigned next_string_id = 1; udc_descriptor_t *udc_descriptor_find(unsigned tag) { udc_descriptor_t *desc = desc_list; while (desc != NULL) { if (desc->tag == tag) { return desc; } desc = desc->next; } printf("cant find %08x\n", tag); return NULL; } static void udc_descriptor_register(struct udc_descriptor *desc) { desc->next = desc_list; desc_list = desc; } static unsigned udc_string_desc_alloc(const char *str) { unsigned len; struct udc_descriptor *desc; unsigned char *data; if (next_string_id > 255) return 0; if (!str) return 0; len = strlen(str); desc = udc_descriptor_alloc(TYPE_STRING, next_string_id, len * 2 + 2); if (!desc) return 0; next_string_id++; /* expand ascii string to utf16 */ data = desc->data + 2; while (len-- > 0) { *data++ = *str++; *data++ = 0; } udc_descriptor_register(desc); return desc->tag & 0xff; } static unsigned udc_ifc_desc_size(udc_gadget_t *g) { return 9 + g->ifc_endpoints * 7; } static void udc_ifc_desc_fill(udc_gadget_t *g, unsigned ifcn, unsigned char *data) { unsigned n; data[0] = 0x09; data[1] = TYPE_INTERFACE; data[2] = ifcn; // ifc number data[3] = 0x00; // alt number data[4] = g->ifc_endpoints; data[5] = g->ifc_class; data[6] = g->ifc_subclass; data[7] = g->ifc_protocol; data[8] = udc_string_desc_alloc(g->ifc_string); data += 9; for (n = 0; n < g->ifc_endpoints; n++) { udc_ept_desc_fill(g->ept[n], data); data += 7; } } void udc_create_descriptors(udc_device_t *device, udc_gadget_t *gadgetlist) { udc_descriptor_t *desc; udc_gadget_t *gadget; unsigned size; uint8_t *data, *p; uint8_t n; // create our device descriptor desc = udc_descriptor_alloc(TYPE_DEVICE, 0, 18); data = desc->data; data[2] = 0x00; // usb spec rev 2.00 data[3] = 0x02; data[4] = 0x00; // class data[5] = 0x00; // subclass data[6] = 0x00; // protocol data[7] = 0x40; // max packet size on ept 0 data[8] = device->vendor_id; data[9] = device->vendor_id >> 8; data[10] = device->product_id; data[11] = device->product_id >> 8; data[12] = device->version_id; data[13] = device->version_id >> 8; data[14] = udc_string_desc_alloc(device->manufacturer); data[15] = udc_string_desc_alloc(device->product); data[16] = udc_string_desc_alloc(device->serialno); data[17] = 1; // number of configurations udc_descriptor_register(desc); // create our configuration descriptor size = 9; n = 0; for (gadget = gadgetlist; gadget; gadget = gadget->next) { size += udc_ifc_desc_size(gadget); n++; } desc = udc_descriptor_alloc(TYPE_CONFIGURATION, 0, size); data = desc->data; data[0] = 0x09; data[2] = size; data[3] = size >> 8; data[4] = n; // number of interfaces data[5] = 0x01; // configuration value data[6] = 0x00; // configuration string data[7] = 0x80; // attributes data[8] = 0x80; // max power (250ma) -- todo fix this n = 0; p = data + 9; for (gadget = gadgetlist; gadget; gadget = gadget->next) { udc_ifc_desc_fill(gadget, n++, p); p += udc_ifc_desc_size(gadget); } udc_descriptor_register(desc); }