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