1 /*
2  * Copyright (c) 2008-2015 Travis Geiselbrecht
3  *
4  * Use of this source code is governed by a MIT-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/MIT
7  */
8 #include <dev/usb.h>
9 
10 #include <lk/debug.h>
11 #include <lk/trace.h>
12 #include <lk/err.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <assert.h>
16 #include <lk/list.h>
17 #include <dev/usbc.h>
18 #include <lk/init.h>
19 
20 /*
21  * USB device side support. Handles configuration and main high level host requests.
22  * USB device controller must pump the stack via usbc_callback() and implement the
23  * usbc function interface.
24  */
25 
26 /* TODO: make big endian safe */
27 
28 #define LOCAL_TRACE 0
29 
30 #define MAX_STRINGS 8
31 static struct {
32     bool active;
33     uint8_t active_config;
34 
35     usb_config *config;
36 
37     struct list_node cb_list;
38 
39     usb_string strings[MAX_STRINGS];
40 } usb;
41 
42 typedef struct {
43     struct list_node node;
44     usb_callback_t cb;
45     void *cookie;
46 } usb_callback_container_t;
47 
48 static void usb_do_callbacks(usb_callback_op_t op, const union usb_callback_args *args);
49 
append_desc_data(usb_descriptor * desc,const void * dat,size_t len)50 static status_t append_desc_data(usb_descriptor *desc, const void *dat, size_t len) {
51     uint8_t *ptr = malloc(desc->len + len);
52     if (!ptr) {
53         return ERR_NO_MEMORY;
54     }
55 
56     memcpy(ptr, desc->desc, desc->len);
57     memcpy(ptr + desc->len, dat, len);
58 
59     /* free the old buffer if it wasn't marked static */
60     if ((desc->flags & USB_DESC_FLAG_STATIC) == 0)
61         free(desc->desc);
62     desc->flags &= ~USB_DESC_FLAG_STATIC;
63 
64     desc->desc = ptr;
65     desc->len += len;
66 
67     return NO_ERROR;
68 }
69 
usb_get_current_iface_num(const usb_descriptor * desc)70 static uint8_t usb_get_current_iface_num(const usb_descriptor *desc) {
71     DEBUG_ASSERT(desc);
72 
73     return ((uint8_t *)desc->desc)[4];
74 }
75 
usb_get_current_iface_num_highspeed(void)76 uint8_t usb_get_current_iface_num_highspeed(void) {
77     return usb_get_current_iface_num(&usb.config->highspeed.config);
78 }
79 
usb_get_current_iface_num_lowspeed(void)80 uint8_t usb_get_current_iface_num_lowspeed(void) {
81     return usb_get_current_iface_num(&usb.config->lowspeed.config);
82 }
83 
84 /* returns the interface number assigned or error */
usb_append_interface(usb_descriptor * desc,const uint8_t * int_descr,size_t len)85 static int usb_append_interface(usb_descriptor *desc, const uint8_t *int_descr, size_t len) {
86     uint8_t *ptr = malloc(len);
87     if (!ptr) {
88         return ERR_NO_MEMORY;
89     }
90 
91     // create a temporary copy of the interface
92     memcpy(ptr, int_descr, len);
93 
94     // find the last interface used
95     int interface_num = usb_get_current_iface_num(desc);  // current interface
96 
97     // patch our interface descriptor with the new id
98     ptr[2] = interface_num;
99 
100     // append it to our config descriptor
101     append_desc_data(desc, ptr, len);
102     free(ptr);
103 
104     // patch the total length of the config descriptor and set the number of interfaces
105     ((uint16_t *)desc->desc)[1] += len;
106     interface_num++;
107     ((uint8_t *)desc->desc)[4] = interface_num;
108 
109     DEBUG_ASSERT(interface_num > 0);
110     return interface_num - 1;
111 }
112 
usb_append_interface_highspeed(const uint8_t * int_descr,size_t len)113 int usb_append_interface_highspeed(const uint8_t *int_descr, size_t len) {
114     return usb_append_interface(&usb.config->highspeed.config, int_descr, len);
115 }
116 
usb_append_interface_lowspeed(const uint8_t * int_descr,size_t len)117 int usb_append_interface_lowspeed(const uint8_t *int_descr, size_t len) {
118     return usb_append_interface(&usb.config->lowspeed.config, int_descr, len);
119 }
120 
set_usb_id(uint16_t vendor,uint16_t product)121 static void set_usb_id(uint16_t vendor, uint16_t product) {
122     // patch the current configuration to with the vendor/product id
123     ((uint16_t *)usb.config->lowspeed.device.desc)[4] = vendor;
124     ((uint16_t *)usb.config->lowspeed.device.desc)[5] = product;
125 
126     ((uint16_t *)usb.config->highspeed.device.desc)[4] = vendor;
127     ((uint16_t *)usb.config->highspeed.device.desc)[5] = product;
128 }
129 
usb_add_string(const char * string,uint8_t id)130 status_t usb_add_string(const char *string, uint8_t id) {
131     uint i;
132     size_t len = strlen(string);
133 
134     uint16_t *strbuf = malloc(len * 2 + 2);
135     if (!strbuf) {
136         return ERR_NO_MEMORY;
137     }
138 
139     /* build the usb string descriptor */
140     strbuf[0] = 0x300 | (len * 2 + 2);
141     for (i = 0; i < len; i++) {
142         strbuf[i + 1] = (uint16_t)string[i];
143     }
144 
145     /* find a slot to put it */
146     for (i = 0; i < MAX_STRINGS; i++) {
147         if (usb.strings[i].id == 0) {
148             usb.strings[i].string.desc = strbuf;
149             usb.strings[i].string.len = len * 2 + 2;
150             usb.strings[i].id = id;
151             return NO_ERROR;
152         }
153     }
154 
155     /* couldn't find a spot */
156     free(strbuf);
157     return ERR_NO_MEMORY;
158 }
159 
usb_set_active_config(uint8_t config)160 static void usb_set_active_config(uint8_t config) {
161     if (config != usb.active_config) {
162         usb.active_config = config;
163         if (usb.active_config != 0) {
164             printf("usb online\n");
165             usb_do_callbacks(USB_CB_ONLINE, NULL);
166         } else {
167             printf("usb offline\n");
168             usb_do_callbacks(USB_CB_OFFLINE, NULL);
169         }
170     }
171 }
172 
usb_register_callback(usb_callback_t cb,void * cookie)173 status_t usb_register_callback(usb_callback_t cb, void *cookie) {
174     DEBUG_ASSERT(cb);
175 
176     usb_callback_container_t *c = malloc(sizeof(usb_callback_container_t));
177     if (!c) {
178         return ERR_NO_MEMORY;
179     }
180 
181     c->cb = cb;
182     c->cookie = cookie;
183     list_add_tail(&usb.cb_list, &c->node);
184 
185     return NO_ERROR;
186 }
187 
usb_do_callbacks(usb_callback_op_t op,const union usb_callback_args * args)188 static void usb_do_callbacks(usb_callback_op_t op, const union usb_callback_args *args) {
189     usb_callback_container_t *c;
190     list_for_every_entry(&usb.cb_list, c, usb_callback_container_t, node) {
191         c->cb(c->cookie, op, args);
192     }
193 }
194 
usbc_callback(usb_callback_op_t op,const union usb_callback_args * args)195 status_t usbc_callback(usb_callback_op_t op, const union usb_callback_args *args) {
196     LTRACEF("op %d, args %p\n", op, args);
197 
198     /* start looking for specific things to handle */
199     if (op == USB_CB_SETUP_MSG) {
200         bool setup_handled = false;
201         const struct usb_setup *setup = args->setup;
202         DEBUG_ASSERT(setup);
203         LTRACEF("SETUP: req_type=%#x req=%#x value=%#x index=%#x len=%#x\n",
204                 setup->request_type, setup->request, setup->value, setup->index, setup->length);
205 
206         if ((setup->request_type & TYPE_MASK) == TYPE_STANDARD) {
207             switch (setup->request) {
208                 case SET_ADDRESS:
209                     LTRACEF("SET_ADDRESS 0x%x\n", setup->value);
210                     usbc_ep0_ack();
211                     usbc_set_address(setup->value);
212                     setup_handled = true;
213                     break;
214                 case SET_FEATURE:
215                 case CLEAR_FEATURE:
216                     LTRACEF("SET/CLEAR_FEATURE, feature 0x%x\n", setup->value);
217                     usbc_ep0_ack();
218                     setup_handled = true;
219                     break;
220                 case SET_DESCRIPTOR:
221                     LTRACEF("SET_DESCRIPTOR\n");
222                     usbc_ep0_stall();
223                     setup_handled = true;
224                     break;
225                 case GET_DESCRIPTOR: {
226                     if ((setup->request_type & RECIP_MASK) == RECIP_DEVICE) {
227                         /* handle device descriptor fetches */
228 
229                         /* Get the right descriptors based on current speed */
230                         const struct usb_descriptor_speed *speed;
231                         if (usbc_is_highspeed()) {
232                             speed = &usb.config->highspeed;
233                         } else {
234                             speed = &usb.config->lowspeed;
235                         }
236 
237                         switch (setup->value) {
238                             case 0x100: /* device */
239                                 LTRACEF("got GET_DESCRIPTOR, device descriptor\n");
240                                 usbc_ep0_send(speed->device.desc, speed->device.len,
241                                               setup->length);
242                                 break;
243                             case 0x200:    /* CONFIGURATION */
244                                 LTRACEF("got GET_DESCRIPTOR, config descriptor\n");
245                                 usbc_ep0_send(speed->config.desc, speed->config.len,
246                                               setup->length);
247                                 break;
248                             case 0x300:    /* Language ID */
249                                 LTRACEF("got GET_DESCRIPTOR, language id\n");
250                                 usbc_ep0_send(usb.config->langid.desc,
251                                               usb.config->langid.len, setup->length);
252                                 break;
253                             case (0x301)...(0x3ff): {
254                                 /* string descriptor, search our list for a match */
255                                 uint i;
256                                 bool found = false;
257                                 uint8_t id = setup->value & 0xff;
258                                 for (i = 0; i < MAX_STRINGS; i++) {
259                                     if (usb.strings[i].id == id) {
260                                         usbc_ep0_send(usb.strings[i].string.desc,
261                                                       usb.strings[i].string.len,
262                                                       setup->length);
263                                         found = true;
264                                         break;
265                                     }
266                                 }
267                                 if (!found) {
268                                     /* couldn't find one, stall */
269                                     usbc_ep0_stall();
270                                 }
271                                 break;
272                             }
273                             case 0x600:    /* DEVICE QUALIFIER */
274                                 LTRACEF("got GET_DESCRIPTOR, device qualifier\n");
275                                 usbc_ep0_send(speed->device_qual.desc,
276                                               speed->device_qual.len, setup->length);
277                                 break;
278                             case 0xa00:
279                                 /* we aint got one of these */
280                                 LTRACEF("got GET_DESCRIPTOR, debug descriptor\n");
281                                 usbc_ep0_stall();
282                                 break;
283                             default:
284                                 LTRACEF("unhandled descriptor %#x\n", setup->value);
285                                 // stall
286                                 break;
287                         }
288                         setup_handled = true;
289                     }
290                     break;
291                 }
292 
293                 case SET_CONFIGURATION:
294                     LTRACEF("SET_CONFIGURATION %d\n", setup->value);
295                     usbc_ep0_ack();
296                     usb_set_active_config(setup->value);
297                     break;
298 
299                 case GET_CONFIGURATION:
300                     LTRACEF("GET_CONFIGURATION\n");
301                     usbc_ep0_send(&usb.active_config, 1, setup->length);
302                     break;
303 
304                 case SET_INTERFACE:
305                     LTRACEF("SET_INTERFACE %d\n", setup->value);
306                     usbc_ep0_ack();
307                     break;
308 
309                 case GET_INTERFACE: {
310                     static uint8_t i = 1;
311                     LTRACEF("GET_INTERFACE\n");
312                     usbc_ep0_send(&i, 1, setup->length);
313                     break;
314                 }
315 
316                 case GET_STATUS: {
317                     static uint16_t i = 1; // self powered
318                     LTRACEF("GET_STATUS\n");
319                     usbc_ep0_send(&i, 2, setup->length);
320                     break;
321                 }
322                 default:
323                     LTRACEF("unhandled standard request 0x%x\n", setup->request);
324             }
325         }
326 
327         if (!setup_handled) {
328             usb_do_callbacks(op, args);
329         }
330     } else if (op == USB_CB_RESET) {
331         usb_do_callbacks(op, args);
332 
333         usb.active_config = 0;
334         usb_do_callbacks(USB_CB_OFFLINE, args);
335     } else {
336         // other non setup messages, pass them down to anyone else
337         usb_do_callbacks(op, args);
338     }
339 
340     return NO_ERROR;
341 }
342 
usb_setup(usb_config * config)343 status_t usb_setup(usb_config *config) {
344     DEBUG_ASSERT(config);
345     DEBUG_ASSERT(usb.active == false);
346 
347     usb.config = config;
348 
349     return NO_ERROR;
350 }
351 
usb_start(void)352 status_t usb_start(void) {
353     DEBUG_ASSERT(usb.config);
354     DEBUG_ASSERT(usb.active == false);
355 
356     // go online
357     usbc_set_active(true);
358     usb.active = true;
359 
360     return NO_ERROR;
361 }
362 
usb_stop(void)363 status_t usb_stop(void) {
364     DEBUG_ASSERT(usb.active == true);
365 
366     usb.active = false;
367     usbc_set_active(false);
368 
369     return NO_ERROR;
370 }
371 
usb_init(uint level)372 static void usb_init(uint level) {
373     list_initialize(&usb.cb_list);
374 }
375 
376 LK_INIT_HOOK(usb, usb_init, LK_INIT_LEVEL_THREADING);
377