1 /*
2 * Copyright (c) 2008-2015 Travis Geiselbrecht
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23 #include <debug.h>
24 #include <trace.h>
25 #include <err.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <list.h>
30 #include <dev/usbc.h>
31 #include <dev/usb.h>
32 #include <lk/init.h>
33
34 #define LOCAL_TRACE 0
35
36 #define MAX_STRINGS 8
37 static struct {
38 bool active;
39 uint8_t active_config;
40
41 usb_config *config;
42
43 struct list_node cb_list;
44
45 usb_string strings[MAX_STRINGS];
46 } usb;
47
48 typedef struct {
49 struct list_node node;
50 usb_callback_t cb;
51 void *cookie;
52 } usb_callback_container_t;
53
54 static void usb_do_callbacks(usb_callback_op_t op, const union usb_callback_args *args);
55
append_desc_data(usb_descriptor * desc,const void * dat,size_t len)56 static void append_desc_data(usb_descriptor *desc, const void *dat, size_t len)
57 {
58 uint8_t *ptr = malloc(desc->len + len);
59 if (!ptr) {
60 panic("append_desc_data malloc failed");
61 }
62 memcpy(ptr, desc->desc, desc->len);
63 memcpy(ptr + desc->len, dat, len);
64
65 /* free the old buffer if it wasn't marked static */
66 if ((desc->flags & USB_DESC_FLAG_STATIC) == 0)
67 free(desc->desc);
68 desc->flags &= ~USB_DESC_FLAG_STATIC;
69
70 desc->desc = ptr;
71 desc->len += len;
72 }
73
usb_get_current_iface_num(const usb_descriptor * desc)74 static uint8_t usb_get_current_iface_num(const usb_descriptor *desc)
75 {
76 DEBUG_ASSERT(desc);
77
78 return ((uint8_t *)desc->desc)[4];
79 }
80
usb_get_current_iface_num_highspeed(void)81 uint8_t usb_get_current_iface_num_highspeed(void)
82 {
83 return usb_get_current_iface_num(&usb.config->highspeed.config);
84 }
85
usb_get_current_iface_num_lowspeed(void)86 uint8_t usb_get_current_iface_num_lowspeed(void)
87 {
88 return usb_get_current_iface_num(&usb.config->lowspeed.config);
89 }
90
91 /* returns the interface number assigned */
usb_append_interface(usb_descriptor * desc,const uint8_t * int_descr,size_t len)92 static int usb_append_interface(usb_descriptor *desc, const uint8_t *int_descr, size_t len)
93 {
94 uint8_t *ptr = malloc(len);
95 if (!ptr) {
96 return ERR_NO_MEMORY;
97 }
98
99 // create a temporary copy of the interface
100 memcpy(ptr, int_descr, len);
101
102 // find the last interface used
103 int interface_num = usb_get_current_iface_num(desc); // current interface
104
105 // patch our interface descriptor with the new id
106 ptr[2] = interface_num;
107
108 // append it to our config descriptor
109 append_desc_data(desc, ptr, len);
110 free(ptr);
111
112 // patch the total length of the config descriptor and set the number of interfaces
113 ((uint16_t *)desc->desc)[1] += len;
114 interface_num++;
115 ((uint8_t *)desc->desc)[4] = interface_num;
116
117 DEBUG_ASSERT(interface_num > 0);
118 return interface_num - 1;
119 }
120
usb_append_interface_highspeed(const uint8_t * int_descr,size_t len)121 int usb_append_interface_highspeed(const uint8_t *int_descr, size_t len)
122 {
123 return usb_append_interface(&usb.config->highspeed.config, int_descr, len);
124 }
125
usb_append_interface_lowspeed(const uint8_t * int_descr,size_t len)126 int usb_append_interface_lowspeed(const uint8_t *int_descr, size_t len)
127 {
128 return usb_append_interface(&usb.config->lowspeed.config, int_descr, len);
129 }
130
usb_set_string_descriptor(usb_descriptor * desc,const char * string)131 void usb_set_string_descriptor(usb_descriptor *desc, const char *string)
132 {
133 int len = strlen(string);
134 ushort *data;
135 int datalen = len * 2 + 2;
136
137 data = malloc(datalen);
138
139 /* write length field */
140 data[0] = 0x0300 + datalen;
141
142 /* copy the string into the uint16_t based usb string */
143 int i;
144 for (i = 0; i < len; i++) {
145 data[i + 1] = string[i];
146 }
147
148 desc->desc = (void *)data;
149 desc->len = datalen;
150 }
151
set_usb_id(uint16_t vendor,uint16_t product)152 static void set_usb_id(uint16_t vendor, uint16_t product)
153 {
154 // patch the current configuration to with the vendor/product id
155 ((uint16_t *)usb.config->lowspeed.device.desc)[4] = vendor;
156 ((uint16_t *)usb.config->lowspeed.device.desc)[5] = product;
157
158 ((uint16_t *)usb.config->highspeed.device.desc)[4] = vendor;
159 ((uint16_t *)usb.config->highspeed.device.desc)[5] = product;
160 }
161
usb_add_string(const char * string,uint8_t id)162 status_t usb_add_string(const char *string, uint8_t id)
163 {
164 uint i;
165 size_t len = strlen(string);
166
167 uint16_t *strbuf = malloc(len * 2 + 2);
168 if (!strbuf) {
169 return ERR_NO_MEMORY;
170 }
171
172 /* build the usb string descriptor */
173 strbuf[0] = 0x300 | (len * 2 + 2);
174 for (i = 0; i < len; i++) {
175 strbuf[i + 1] = (uint16_t)string[i];
176 }
177
178 /* find a slot to put it */
179 for (i = 0; i < MAX_STRINGS; i++) {
180 if (usb.strings[i].id == 0) {
181 usb.strings[i].string.desc = strbuf;
182 usb.strings[i].string.len = len * 2 + 2;
183 usb.strings[i].id = id;
184 return NO_ERROR;
185 }
186 }
187
188 /* couldn't find a spot */
189 free(strbuf);
190 return ERR_NO_MEMORY;
191 }
192
usb_set_active_config(uint8_t config)193 static void usb_set_active_config(uint8_t config)
194 {
195 if (config != usb.active_config) {
196 usb.active_config = config;
197 if (usb.active_config != 0) {
198 printf("usb online\n");
199 usb_do_callbacks(USB_CB_ONLINE, NULL);
200 } else {
201 printf("usb offline\n");
202 usb_do_callbacks(USB_CB_OFFLINE, NULL);
203 }
204 }
205 }
206
usb_register_callback(usb_callback_t cb,void * cookie)207 status_t usb_register_callback(usb_callback_t cb, void *cookie)
208 {
209 DEBUG_ASSERT(cb);
210
211 usb_callback_container_t *c = malloc(sizeof(usb_callback_container_t));
212 if (!c) {
213 return ERR_NO_MEMORY;
214 }
215
216 c->cb = cb;
217 c->cookie = cookie;
218 list_add_tail(&usb.cb_list, &c->node);
219
220 return NO_ERROR;
221 }
222
usb_do_callbacks(usb_callback_op_t op,const union usb_callback_args * args)223 static void usb_do_callbacks(usb_callback_op_t op, const union usb_callback_args *args)
224 {
225 usb_callback_container_t *c;
226 list_for_every_entry(&usb.cb_list, c, usb_callback_container_t, node) {
227 c->cb(c->cookie, op, args);
228 }
229 }
230
usbc_callback(usb_callback_op_t op,const union usb_callback_args * args)231 status_t usbc_callback(usb_callback_op_t op, const union usb_callback_args *args)
232 {
233 LTRACEF("op %d, args %p\n", op, args);
234
235 /* start looking for specific things to handle */
236 if (op == USB_CB_SETUP_MSG) {
237 bool setup_handled = false;
238 const struct usb_setup *setup = args->setup;
239 DEBUG_ASSERT(setup);
240 LTRACEF("SETUP: req_type=%#x req=%#x value=%#x index=%#x len=%#x\n",
241 setup->request_type, setup->request, setup->value, setup->index, setup->length);
242
243 if ((setup->request_type & TYPE_MASK) == TYPE_STANDARD) {
244 switch (setup->request) {
245 case SET_ADDRESS:
246 LTRACEF("SET_ADDRESS 0x%x\n", setup->value);
247 usbc_ep0_ack();
248 usbc_set_address(setup->value);
249 setup_handled = true;
250 break;
251 case SET_FEATURE:
252 case CLEAR_FEATURE:
253 LTRACEF("SET/CLEAR_FEATURE, feature 0x%x\n", setup->value);
254 usbc_ep0_ack();
255 setup_handled = true;
256 break;
257 case SET_DESCRIPTOR:
258 LTRACEF("SET_DESCRIPTOR\n");
259 usbc_ep0_stall();
260 setup_handled = true;
261 break;
262 case GET_DESCRIPTOR: {
263 if ((setup->request_type & RECIP_MASK) == RECIP_DEVICE) {
264 /* handle device descriptor fetches */
265
266 /* Get the right descriptors based on current speed */
267 const struct usb_descriptor_speed *speed;
268 if (usbc_is_highspeed()) {
269 speed = &usb.config->highspeed;
270 } else {
271 speed = &usb.config->lowspeed;
272 }
273
274 switch (setup->value) {
275 case 0x100: /* device */
276 LTRACEF("got GET_DESCRIPTOR, device descriptor\n");
277 usbc_ep0_send(speed->device.desc, speed->device.len,
278 setup->length);
279 break;
280 case 0x200: /* CONFIGURATION */
281 LTRACEF("got GET_DESCRIPTOR, config descriptor\n");
282 usbc_ep0_send(speed->config.desc, speed->config.len,
283 setup->length);
284 break;
285 case 0x300: /* Language ID */
286 LTRACEF("got GET_DESCRIPTOR, language id\n");
287 usbc_ep0_send(usb.config->langid.desc,
288 usb.config->langid.len, setup->length);
289 break;
290 case (0x301)...(0x3ff): {
291 /* string descriptor, search our list for a match */
292 uint i;
293 bool found = false;
294 uint8_t id = setup->value & 0xff;
295 for (i = 0; i < MAX_STRINGS; i++) {
296 if (usb.strings[i].id == id) {
297 usbc_ep0_send(usb.strings[i].string.desc,
298 usb.strings[i].string.len,
299 setup->length);
300 found = true;
301 break;
302 }
303 }
304 if (!found) {
305 /* couldn't find one, stall */
306 usbc_ep0_stall();
307 }
308 break;
309 }
310 case 0x600: /* DEVICE QUALIFIER */
311 LTRACEF("got GET_DESCRIPTOR, device qualifier\n");
312 usbc_ep0_send(speed->device_qual.desc,
313 speed->device_qual.len, setup->length);
314 break;
315 case 0xa00:
316 /* we aint got one of these */
317 LTRACEF("got GET_DESCRIPTOR, debug descriptor\n");
318 usbc_ep0_stall();
319 break;
320 default:
321 LTRACEF("unhandled descriptor %#x\n", setup->value);
322 // stall
323 break;
324 }
325 setup_handled = true;
326 }
327 break;
328 }
329
330 case SET_CONFIGURATION:
331 LTRACEF("SET_CONFIGURATION %d\n", setup->value);
332 usbc_ep0_ack();
333 usb_set_active_config(setup->value);
334 break;
335
336 case GET_CONFIGURATION:
337 LTRACEF("GET_CONFIGURATION\n");
338 usbc_ep0_send(&usb.active_config, 1, setup->length);
339 break;
340
341 case SET_INTERFACE:
342 LTRACEF("SET_INTERFACE %d\n", setup->value);
343 usbc_ep0_ack();
344 break;
345
346 case GET_INTERFACE: {
347 static uint8_t i = 1;
348 LTRACEF("GET_INTERFACE\n");
349 usbc_ep0_send(&i, 1, setup->length);
350 break;
351 }
352
353 case GET_STATUS: {
354 static uint16_t i = 1; // self powered
355 LTRACEF("GET_STATUS\n");
356 usbc_ep0_send(&i, 2, setup->length);
357 break;
358 }
359 default:
360 LTRACEF("unhandled standard request 0x%x\n", setup->request);
361 }
362 }
363
364 if (!setup_handled) {
365 usb_do_callbacks(op, args);
366 }
367 } else if (op == USB_CB_RESET) {
368 usb_do_callbacks(op, args);
369
370 usb.active_config = 0;
371 usb_do_callbacks(USB_CB_OFFLINE, args);
372 } else {
373 // other non setup messages, pass them down to anyone else
374 usb_do_callbacks(op, args);
375 }
376
377 return NO_ERROR;
378 }
379
usb_setup(usb_config * config)380 status_t usb_setup(usb_config *config)
381 {
382 DEBUG_ASSERT(config);
383 DEBUG_ASSERT(usb.active == false);
384
385 usb.config = config;
386
387 return NO_ERROR;
388 }
389
usb_start(void)390 status_t usb_start(void)
391 {
392 DEBUG_ASSERT(usb.config);
393 DEBUG_ASSERT(usb.active == false);
394
395 // go online
396 usbc_set_active(true);
397 usb.active = true;
398
399 return NO_ERROR;
400 }
401
usb_stop(void)402 status_t usb_stop(void)
403 {
404 DEBUG_ASSERT(usb.active == true);
405
406 usb.active = false;
407 usbc_set_active(false);
408
409 return NO_ERROR;
410 }
411
usb_init(uint level)412 static void usb_init(uint level)
413 {
414 list_initialize(&usb.cb_list);
415 }
416
417 LK_INIT_HOOK(usb, usb_init, LK_INIT_LEVEL_THREADING);
418