1 /*
2 * Copyright (c) 2015 Brian Swetland
3 * Copyright (c) 2008 Google, Inc.
4 *
5 * Use of this source code is governed by a MIT-style
6 * license that can be found in the LICENSE file or at
7 * https://opensource.org/licenses/MIT
8 */
9
10 #include <malloc.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <dev/udc.h>
14
15 #include "udc-common.h"
16
udc_descriptor_alloc(unsigned type,unsigned num,unsigned len)17 static udc_descriptor_t *udc_descriptor_alloc(unsigned type, unsigned num, unsigned len) {
18 struct udc_descriptor *desc;
19 if ((len > 255) || (len < 2) || (num > 255) || (type > 255))
20 return 0;
21
22 if (!(desc = malloc(sizeof(struct udc_descriptor) + len)))
23 return 0;
24
25 desc->next = 0;
26 desc->tag = (type << 8) | num;
27 desc->len = len;
28 desc->data[0] = len;
29 desc->data[1] = type;
30
31 return desc;
32 }
33
34 static udc_descriptor_t langid_list = {
35 .tag = 0x0300,
36 .len = 4,
37 .data = { 0x04, TYPE_STRING, 0x09, 0x04 }, // EN_US
38 };
39
40 static struct udc_descriptor *desc_list = &langid_list;
41 static unsigned next_string_id = 1;
42
udc_descriptor_find(unsigned tag)43 udc_descriptor_t *udc_descriptor_find(unsigned tag) {
44 udc_descriptor_t *desc = desc_list;
45 while (desc != NULL) {
46 if (desc->tag == tag) {
47 return desc;
48 }
49 desc = desc->next;
50 }
51 printf("cant find %08x\n", tag);
52 return NULL;
53 }
54
udc_descriptor_register(struct udc_descriptor * desc)55 static void udc_descriptor_register(struct udc_descriptor *desc) {
56 desc->next = desc_list;
57 desc_list = desc;
58 }
59
udc_string_desc_alloc(const char * str)60 static unsigned udc_string_desc_alloc(const char *str) {
61 unsigned len;
62 struct udc_descriptor *desc;
63 unsigned char *data;
64
65 if (next_string_id > 255)
66 return 0;
67
68 if (!str)
69 return 0;
70
71 len = strlen(str);
72 desc = udc_descriptor_alloc(TYPE_STRING, next_string_id, len * 2 + 2);
73 if (!desc)
74 return 0;
75 next_string_id++;
76
77 /* expand ascii string to utf16 */
78 data = desc->data + 2;
79 while (len-- > 0) {
80 *data++ = *str++;
81 *data++ = 0;
82 }
83
84 udc_descriptor_register(desc);
85 return desc->tag & 0xff;
86 }
87
88
udc_ifc_desc_size(udc_gadget_t * g)89 static unsigned udc_ifc_desc_size(udc_gadget_t *g) {
90 return 9 + g->ifc_endpoints * 7;
91 }
92
udc_ifc_desc_fill(udc_gadget_t * g,unsigned ifcn,unsigned char * data)93 static void udc_ifc_desc_fill(udc_gadget_t *g, unsigned ifcn, unsigned char *data) {
94 unsigned n;
95
96 data[0] = 0x09;
97 data[1] = TYPE_INTERFACE;
98 data[2] = ifcn; // ifc number
99 data[3] = 0x00; // alt number
100 data[4] = g->ifc_endpoints;
101 data[5] = g->ifc_class;
102 data[6] = g->ifc_subclass;
103 data[7] = g->ifc_protocol;
104 data[8] = udc_string_desc_alloc(g->ifc_string);
105
106 data += 9;
107 for (n = 0; n < g->ifc_endpoints; n++) {
108 udc_ept_desc_fill(g->ept[n], data);
109 data += 7;
110 }
111 }
112
udc_create_descriptors(udc_device_t * device,udc_gadget_t * gadgetlist)113 void udc_create_descriptors(udc_device_t *device, udc_gadget_t *gadgetlist) {
114 udc_descriptor_t *desc;
115 udc_gadget_t *gadget;
116 unsigned size;
117 uint8_t *data, *p;
118 uint8_t n;
119
120 // create our device descriptor
121 desc = udc_descriptor_alloc(TYPE_DEVICE, 0, 18);
122 data = desc->data;
123 data[2] = 0x00; // usb spec rev 2.00
124 data[3] = 0x02;
125 data[4] = 0x00; // class
126 data[5] = 0x00; // subclass
127 data[6] = 0x00; // protocol
128 data[7] = 0x40; // max packet size on ept 0
129 data[8] = device->vendor_id;
130 data[9] = device->vendor_id >> 8;
131 data[10] = device->product_id;
132 data[11] = device->product_id >> 8;
133 data[12] = device->version_id;
134 data[13] = device->version_id >> 8;
135 data[14] = udc_string_desc_alloc(device->manufacturer);
136 data[15] = udc_string_desc_alloc(device->product);
137 data[16] = udc_string_desc_alloc(device->serialno);
138 data[17] = 1; // number of configurations
139 udc_descriptor_register(desc);
140
141 // create our configuration descriptor
142 size = 9;
143 n = 0;
144 for (gadget = gadgetlist; gadget; gadget = gadget->next) {
145 size += udc_ifc_desc_size(gadget);
146 n++;
147 }
148 desc = udc_descriptor_alloc(TYPE_CONFIGURATION, 0, size);
149 data = desc->data;
150 data[0] = 0x09;
151 data[2] = size;
152 data[3] = size >> 8;
153 data[4] = n; // number of interfaces
154 data[5] = 0x01; // configuration value
155 data[6] = 0x00; // configuration string
156 data[7] = 0x80; // attributes
157 data[8] = 0x80; // max power (250ma) -- todo fix this
158
159 n = 0;
160 p = data + 9;
161 for (gadget = gadgetlist; gadget; gadget = gadget->next) {
162 udc_ifc_desc_fill(gadget, n++, p);
163 p += udc_ifc_desc_size(gadget);
164 }
165 udc_descriptor_register(desc);
166 }
167