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