blob: a22106cbd1d68a8bbe5834bf7c1d96144ecfc875 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * Copyright (c) 2015 Brian Swetland
3 * Copyright (c) 2008 Google, Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files
7 * (the "Software"), to deal in the Software without restriction,
8 * including without limitation the rights to use, copy, modify, merge,
9 * publish, distribute, sublicense, and/or sell copies of the Software,
10 * and to permit persons to whom the Software is furnished to do so,
11 * subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25#include <malloc.h>
26#include <printf.h>
27#include <string.h>
28#include <dev/udc.h>
29
30#include "udc-common.h"
31
32static udc_descriptor_t *udc_descriptor_alloc(unsigned type, unsigned num, unsigned len)
33{
34 struct udc_descriptor *desc;
35 if ((len > 255) || (len < 2) || (num > 255) || (type > 255))
36 return 0;
37
38 if(!(desc = malloc(sizeof(struct udc_descriptor) + len)))
39 return 0;
40
41 desc->next = 0;
42 desc->tag = (type << 8) | num;
43 desc->len = len;
44 desc->data[0] = len;
45 desc->data[1] = type;
46
47 return desc;
48}
49
50static udc_descriptor_t langid_list = {
51 .tag = 0x0300,
52 .len = 4,
53 .data = { 0x04, TYPE_STRING, 0x09, 0x04 }, // EN_US
54};
55
56static struct udc_descriptor *desc_list = &langid_list;
57static unsigned next_string_id = 1;
58
59udc_descriptor_t *udc_descriptor_find(unsigned tag)
60{
61 udc_descriptor_t *desc = desc_list;
62 while (desc != NULL) {
63 if (desc->tag == tag) {
64 return desc;
65 }
66 desc = desc->next;
67 }
68 printf("cant find %08x\n", tag);
69 return NULL;
70}
71
72static void udc_descriptor_register(struct udc_descriptor *desc)
73{
74 desc->next = desc_list;
75 desc_list = desc;
76}
77
78static unsigned udc_string_desc_alloc(const char *str)
79{
80 unsigned len;
81 struct udc_descriptor *desc;
82 unsigned char *data;
83
84 if (next_string_id > 255)
85 return 0;
86
87 if (!str)
88 return 0;
89
90 len = strlen(str);
91 desc = udc_descriptor_alloc(TYPE_STRING, next_string_id, len * 2 + 2);
92 if (!desc)
93 return 0;
94 next_string_id++;
95
96 /* expand ascii string to utf16 */
97 data = desc->data + 2;
98 while (len-- > 0) {
99 *data++ = *str++;
100 *data++ = 0;
101 }
102
103 udc_descriptor_register(desc);
104 return desc->tag & 0xff;
105}
106
107
108static unsigned udc_ifc_desc_size(udc_gadget_t *g)
109{
110 return 9 + g->ifc_endpoints * 7;
111}
112
113static void udc_ifc_desc_fill(udc_gadget_t *g, unsigned ifcn, unsigned char *data)
114{
115 unsigned n;
116
117 data[0] = 0x09;
118 data[1] = TYPE_INTERFACE;
119 data[2] = ifcn; // ifc number
120 data[3] = 0x00; // alt number
121 data[4] = g->ifc_endpoints;
122 data[5] = g->ifc_class;
123 data[6] = g->ifc_subclass;
124 data[7] = g->ifc_protocol;
125 data[8] = udc_string_desc_alloc(g->ifc_string);
126
127 data += 9;
128 for (n = 0; n < g->ifc_endpoints; n++) {
129 udc_ept_desc_fill(g->ept[n], data);
130 data += 7;
131 }
132}
133
134void udc_create_descriptors(udc_device_t *device, udc_gadget_t *gadgetlist)
135{
136 udc_descriptor_t *desc;
137 udc_gadget_t *gadget;
138 unsigned size;
139 uint8_t *data, *p;
140 uint8_t n;
141
142 // create our device descriptor
143 desc = udc_descriptor_alloc(TYPE_DEVICE, 0, 18);
144 data = desc->data;
145 data[2] = 0x00; // usb spec rev 2.00
146 data[3] = 0x02;
147 data[4] = 0x00; // class
148 data[5] = 0x00; // subclass
149 data[6] = 0x00; // protocol
150 data[7] = 0x40; // max packet size on ept 0
151 data[8] = device->vendor_id;
152 data[9] = device->vendor_id >> 8;
153 data[10] = device->product_id;
154 data[11] = device->product_id >> 8;
155 data[12] = device->version_id;
156 data[13] = device->version_id >> 8;
157 data[14] = udc_string_desc_alloc(device->manufacturer);
158 data[15] = udc_string_desc_alloc(device->product);
159 data[16] = udc_string_desc_alloc(device->serialno);
160 data[17] = 1; // number of configurations
161 udc_descriptor_register(desc);
162
163 // create our configuration descriptor
164 size = 9;
165 n = 0;
166 for (gadget = gadgetlist; gadget; gadget = gadget->next) {
167 size += udc_ifc_desc_size(gadget);
168 n++;
169 }
170 desc = udc_descriptor_alloc(TYPE_CONFIGURATION, 0, size);
171 data = desc->data;
172 data[0] = 0x09;
173 data[2] = size;
174 data[3] = size >> 8;
175 data[4] = n; // number of interfaces
176 data[5] = 0x01; // configuration value
177 data[6] = 0x00; // configuration string
178 data[7] = 0x80; // attributes
179 data[8] = 0x80; // max power (250ma) -- todo fix this
180
181 n = 0;
182 p = data + 9;
183 for (gadget = gadgetlist; gadget; gadget = gadget->next) {
184 udc_ifc_desc_fill(gadget, n++, p);
185 p += udc_ifc_desc_size(gadget);
186 }
187 udc_descriptor_register(desc);
188}