First version
[3rdparty/ote_partner/tlk.git] / dev / usb / usb.c
1 /*
2  * Copyright (c) 2008 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 <err.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28 #include <dev/usbc.h>
29 #include <dev/usb.h>
30
31 #define LOCAL_TRACE 0
32
33 #define MAX_STRINGS 8
34 static usb_string strings[MAX_STRINGS];
35
36 static usb_config *config;
37
38 static uint8_t active_config;
39 static bool usb_active = false;
40
41 static void append_desc_data(usb_descriptor *desc, const void *dat, size_t len)
42 {
43         uint8_t *ptr = malloc(desc->len + len);
44
45         memcpy(ptr, desc->desc, desc->len);
46         memcpy(ptr + desc->len, dat, len);
47         free(desc->desc);
48         desc->desc = ptr;
49         desc->len += len;
50 }
51
52 /* returns the interface number assigned */
53 static int usb_append_interface(usb_descriptor *desc, const uint8_t *int_descr, size_t len)
54 {
55         uint8_t *ptr = malloc(len);
56         int interface_num;
57
58         // create a temporary copy of the interface
59         memcpy(ptr, int_descr, len);
60
61         // find the last interface used
62         interface_num = ((uint8_t *)desc->desc)[4]; // current interface
63
64         // patch our interface descriptor with the new id
65         ptr[2] = interface_num;
66
67         // append it to our config desriptor
68         append_desc_data(desc, ptr, len);
69         free(ptr);
70
71         // patch the total length of the config descriptor and set the number of interfaces
72         ((uint16_t *)desc->desc)[1] += len;
73         interface_num++;
74         ((uint8_t *)desc->desc)[4] = interface_num;
75
76         return interface_num - 1;
77 }
78
79 int usb_append_interface_highspeed(const uint8_t *int_descr, size_t len)
80 {
81         return usb_append_interface(&config->highspeed.config, int_descr, len);
82 }
83
84 int usb_append_interface_lowspeed(const uint8_t *int_descr, size_t len)
85 {
86         return usb_append_interface(&config->lowspeed.config, int_descr, len);
87 }
88
89 void usb_set_string_descriptor(usb_descriptor *desc, const char *string)
90 {
91         int len = strlen(string);
92         ushort *data;
93         int datalen = len * 2 + 2;
94
95         data = malloc(datalen);
96         
97         /* write length field */
98         data[0] = 0x0300 + datalen;
99
100         /* copy the string into the uint16_t based usb string */
101         int i;
102         for (i = 0; i < len; i++) {
103                 data[i + 1] = string[i];
104         }
105
106         desc->desc = (void *)data;
107         desc->len = datalen;
108 }
109
110 static void set_usb_id(uint16_t vendor, uint16_t product)
111 {
112         // patch the current configuration to with the vendor/product id
113         ((uint16_t *)config->lowspeed.device.desc)[4] = vendor;
114         ((uint16_t *)config->lowspeed.device.desc)[5] = product;
115
116         ((uint16_t *)config->highspeed.device.desc)[4] = vendor;
117         ((uint16_t *)config->highspeed.device.desc)[5] = product;
118 }
119
120 void usb_add_string(const char *string, uint8_t id) 
121 {
122         uint i;
123         size_t len = strlen(string);
124         uint16_t *strbuf = malloc(len * 2 + 2);
125
126         /* build the usb string descriptor */
127         strbuf[0] = 0x300 | (len * 2 + 2);
128         for (i = 0; i < len; i++) {
129                 strbuf[i + 1] = (uint16_t)string[i];
130         }
131
132         /* find a slot to put it */
133         for (i = 0; i < MAX_STRINGS; i++) {
134                 if (strings[i].id == 0) {
135                         strings[i].string.desc = strbuf;
136                         strings[i].string.len = len * 2 + 2;
137                         strings[i].id = id;
138                         break;
139                 }
140         }
141 }
142
143 static int default_usb_callback(usbc_callback_op_t op, const union usb_callback_args *args)
144 {
145         LTRACEF("op %d, args %p\n", op, args);
146
147         /* start looking for specific things to handle */
148         if (op == CB_SETUP_MSG) {
149                 const struct usb_setup *setup = args->setup;
150                 DEBUG_ASSERT(setup);
151                 LTRACEF("SETUP: req_type=%#x req=%#x value=%#x index=%#x len=%#x\n", setup->request_type, setup->request, setup->value, setup->index, setup->length);
152
153                 if ((setup->request_type & TYPE_MASK) == TYPE_STANDARD) {
154                         switch (setup->request) {
155                                 case SET_ADDRESS:
156                                         LTRACEF("SET_ADDRESS 0x%x\n", setup->value);
157                                         usbc_ep0_ack();
158                                         break;
159                                 case SET_FEATURE:
160                                 case CLEAR_FEATURE:
161                                         // OTAY
162                                         LTRACEF("SET/CLEAR_FEATURE, feature 0x%x\n", setup->value);
163                                         usbc_ep0_ack();
164                                         break;
165                                 case SET_DESCRIPTOR:
166                                         LTRACEF("SET_DESCRIPTOR\n");
167                                         usbc_ep0_stall();
168                                         break;
169                                 case GET_DESCRIPTOR: {
170                                         /* Get the right descriptors based on current speed */
171                                         const struct usb_descriptor_speed *speed;
172                                         if (usbc_is_highspeed()) {
173                                                 speed = &config->highspeed;
174                                         } else {
175                                                 speed = &config->lowspeed;
176                                         }
177
178                                         if ((setup->request_type & RECIP_MASK) == RECIP_DEVICE) {
179                                                 switch (setup->value) {
180                                                         case 0x100: /* device */
181                                                                 LTRACEF("got GET_DESCRIPTOR, device descriptor\n");
182                                                                 usbc_ep0_send(speed->device.desc, speed->device.len, 
183                                                                                 setup->length);
184                                                                 break;
185                                                         case 0x200:    /* CONFIGURATION */
186                                                                 LTRACEF("got GET_DESCRIPTOR, config descriptor\n");
187                                                                 usbc_ep0_send(speed->config.desc, speed->config.len,
188                                                                                 setup->length);
189                                                                 break;
190                                                         case 0x300:    /* Language ID */
191                                                                 LTRACEF("got GET_DESCRIPTOR, language id\n");
192                                                                 usbc_ep0_send(config->langid.desc,
193                                                                                 config->langid.len, setup->length);
194                                                                 break;
195                                                         case (0x301)...(0x3ff): {
196                                                                 /* string descriptor, search our list for a match */
197                                                                 uint i;
198                                                                 bool found = false;
199                                                                 uint8_t id = setup->value & 0xff;
200                                                                 for (i = 0; i < MAX_STRINGS; i++) {
201                                                                         if (strings[i].id == id) {
202                                                                                 usbc_ep0_send(strings[i].string.desc,
203                                                                                         strings[i].string.len, 
204                                                                                         setup->length);
205                                                                                 found = true;
206                                                                                 break;
207                                                                         }
208                                                                 }
209                                                                 if (!found) {
210                                                                         /* couldn't find one, stall */
211                                                                         usbc_ep0_stall();
212                                                                 }
213                                                                 break;
214                                                         }
215                                                         case 0x600:    /* DEVICE QUALIFIER */
216                                                                 LTRACEF("got GET_DESCRIPTOR, device qualifier\n");
217                                                                 usbc_ep0_send(speed->device_qual.desc, 
218                                                                                 speed->device_qual.len, setup->length);
219                                                                 break;
220                                                         case 0xa00:
221                                                                 /* we aint got one of these */
222                                                                 LTRACEF("got GET_DESCRIPTOR, debug descriptor\n");
223                                                                 usbc_ep0_stall();
224                                                                 break;
225                                                         default:
226                                                                 LTRACEF("unhandled descriptor %#x\n", setup->value);
227                                                                 // stall
228                                                                 break;
229                                                 }
230                                         } else {
231                                                 // interface/endpoint descriptors? let someone else handle it
232                                                 // STALL
233                                         }
234                                         break;
235                                 }
236
237                                 case SET_CONFIGURATION:
238                                         LTRACEF("SET_CONFIGURATION %d\n", setup->value);
239                                         active_config = setup->value;
240                                         usbc_ep0_ack();
241                                         break;
242
243                                 case GET_CONFIGURATION:
244                                         LTRACEF("GET_CONFIGURATION\n");
245                                         usbc_ep0_send(&active_config, 1, setup->length);
246                                         break;
247
248                                 case SET_INTERFACE:
249                                         LTRACEF("SET_INTERFACE %d\n", setup->value);
250                                         usbc_ep0_ack();
251                                         break;
252
253                                 case GET_INTERFACE: {
254                                         static uint8_t i = 1;
255                                         LTRACEF("GET_INTERFACE\n");
256                                         usbc_ep0_send(&i, 1, setup->length);
257                                         break;
258                                 }
259
260                                 case GET_STATUS: {
261                                         static uint16_t i = 1; // self powered
262                                         LTRACEF("GET_STATUS\n");
263                                         usbc_ep0_send(&i, 2, setup->length);
264                                         break;
265                                 }
266                                 default:
267                                         LTRACEF("unhandled standard request 0x%x\n", setup->request);
268                         }
269                 }
270         }
271
272         return 0;
273 }
274
275 void usb_setup(usb_config *_config)
276 {
277         ASSERT(_config);
278
279         config = _config;
280
281         ASSERT(usb_active == false);
282
283         // set the default usb control callback handler 
284         usbc_set_callback(&default_usb_callback);
285 }
286
287 void usb_start(void)
288 {
289         ASSERT(config);
290         ASSERT(usb_active == false);
291
292         // go online
293         usbc_set_active(true);
294         usb_active = true;
295 }
296
297 void usb_stop(void)
298 {
299         ASSERT(usb_active == true);
300
301         usb_active = false;
302         usbc_set_active(false);
303 }
304
305 void usb_init(void)
306 {
307 }
308