1 /*
2 * Copyright (c) 2013-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 <app/cdcserialtest/cdcserialtest.h>
9 #include <lk/err.h>
10 #include <lk/debug.h>
11 #include <stdio.h>
12 #include <lk/trace.h>
13 #include <target.h>
14 #include <lk/compiler.h>
15 #include <dev/usb.h>
16 #include <dev/usbc.h>
17 #include <dev/usb/class/cdcserial.h>
18 #include <hw/usb.h>
19 #include <lk/init.h>
20
21 #define LOCAL_TRACE 0
22
23 #define W(w) (w & 0xff), (w >> 8)
24 #define W3(w) (w & 0xff), ((w >> 8) & 0xff), ((w >> 16) & 0xff)
25
26 /* top level device descriptor */
27 static const uint8_t dev_descr[] = {
28 0x12, /* descriptor length */
29 DEVICE, /* Device Descriptor type */
30 W(0x0200), /* USB Version */
31 239, /* class */
32 2, /* subclass */
33 1, /* protocol */
34 64, /* max packet size, ept0 */
35 W(0x9999), /* vendor */
36 W(0x9999), /* product */
37 W(0x9999), /* release */
38 0x2, /* manufacturer string */
39 0x1, /* product string */
40 0x0, /* serialno string */
41 0x1, /* num configs */
42 };
43
44 /* high/low speed device qualifier */
45 static const uint8_t devqual_descr[] = {
46 0x0a, /* len */
47 DEVICE_QUALIFIER, /* Device Qualifier type */
48 W(0x0200), /* USB version */
49 0x00, /* class */
50 0x00, /* subclass */
51 0x00, /* protocol */
52 64, /* max packet size, ept0 */
53 0x01, /* num configs */
54 0x00 /* reserved */
55 };
56
57 static const uint8_t cfg_descr[] = {
58 0x09, /* Length of Cfg Descr */
59 CONFIGURATION, /* Type of Cfg Descr */
60 W(0x09), /* Total Length (incl ifc, ept) */
61 0x00, /* # Interfaces */
62 0x01, /* Cfg Value */
63 0x00, /* Cfg String */
64 0xc0, /* Attributes -- self powered */
65 250, /* Power Consumption - 500mA */
66 };
67
68 static const uchar langid[] = { 0x04, 0x03, 0x09, 0x04 };
69
70 static const uint8_t if_descriptor_lowspeed[] = {
71 0x09, /* length */
72 INTERFACE, /* type */
73 0x01, /* interface num */
74 0x00, /* alternates */
75 0x02, /* endpoint count */
76 0xff, /* interface class */
77 0xff, /* interface subclass */
78 0x00, /* interface protocol */
79 0x00, /* string index */
80
81 /* endpoint 1 IN */
82 0x07, /* length */
83 ENDPOINT, /* type */
84 0x83, /* address: 1 IN */
85 0x02, /* type: bulk */
86 W(64), /* max packet size: 64 */
87 00, /* interval */
88
89 /* endpoint 1 OUT */
90 0x07, /* length */
91 ENDPOINT, /* type */
92 0x03, /* address: 1 OUT */
93 0x02, /* type: bulk */
94 W(64), /* max packet size: 64 */
95 00, /* interval */
96 };
97
98 usb_config config = {
99 .lowspeed = {
100 .device = USB_DESC_STATIC(dev_descr),
101 .device_qual = USB_DESC_STATIC(devqual_descr),
102 .config = USB_DESC_STATIC(cfg_descr),
103 },
104 .highspeed = {
105 .device = USB_DESC_STATIC(dev_descr),
106 .device_qual = USB_DESC_STATIC(devqual_descr),
107 .config = USB_DESC_STATIC(cfg_descr),
108 },
109
110 .langid = USB_DESC_STATIC(langid),
111 };
112
113 static status_t ep_cb_rx(ep_t endpoint, usbc_transfer_t *t);
114 static status_t ep_cb_tx(ep_t endpoint, usbc_transfer_t *t);
115
116 static cdcserial_channel_t cdc_channel;
117
queue_rx(void)118 static void queue_rx(void) {
119 static usbc_transfer_t transfer;
120 static uint8_t buf[512];
121
122 transfer.callback = &ep_cb_rx;
123 transfer.result = 0;
124 transfer.buf = &buf;
125 transfer.buflen = sizeof(buf);
126 transfer.bufpos = 0;
127 transfer.extra = 0;
128
129 usbc_queue_rx(3, &transfer);
130 }
131
queue_tx(void)132 static void queue_tx(void) {
133 static usbc_transfer_t transfer;
134 static uint8_t buf[512];
135
136 for (uint i = 0; i < sizeof(buf); i++) {
137 buf[i] = ~i;
138 }
139
140 transfer.callback = &ep_cb_tx;
141 transfer.result = 0;
142 transfer.buf = &buf;
143 transfer.buflen = sizeof(buf);
144 transfer.bufpos = 0;
145 transfer.extra = 0;
146
147 usbc_queue_tx(3, &transfer);
148 }
149
ep_cb_rx(ep_t endpoint,usbc_transfer_t * t)150 static status_t ep_cb_rx(ep_t endpoint, usbc_transfer_t *t) {
151 #if LOCAL_TRACE
152 LTRACEF("ep %u transfer %p\n", endpoint, t);
153 usbc_dump_transfer(t);
154
155 if (t->result >= 0) {
156 hexdump8(t->buf, t->bufpos);
157 }
158 #endif
159
160 if (t->result >= 0)
161 queue_rx();
162
163 return NO_ERROR;
164 }
165
ep_cb_tx(ep_t endpoint,usbc_transfer_t * t)166 static status_t ep_cb_tx(ep_t endpoint, usbc_transfer_t *t) {
167 #if LOCAL_TRACE
168 LTRACEF("ep %u transfer %p\n", endpoint, t);
169 usbc_dump_transfer(t);
170 #endif
171
172 if (t->result >= 0)
173 queue_tx();
174
175 return NO_ERROR;
176 }
177
usb_cb(void * cookie,usb_callback_op_t op,const union usb_callback_args * args)178 static status_t usb_cb(void *cookie, usb_callback_op_t op, const union usb_callback_args *args) {
179 LTRACEF("cookie %p, op %u, args %p\n", cookie, op, args);
180
181 if (op == USB_CB_ONLINE) {
182 usbc_setup_endpoint(3, USB_IN, 0x40, USB_BULK);
183 usbc_setup_endpoint(3, USB_OUT, 0x40, USB_BULK);
184
185 queue_rx();
186 queue_tx();
187 }
188 return NO_ERROR;
189 }
190
target_usb_setup(void)191 void target_usb_setup(void) {
192 usb_setup(&config);
193 printf("appending interfaces\n");
194 cdcserial_create_channel(&cdc_channel, 0x1, 0x2);
195 cdctest_setup(&cdc_channel);
196
197 usb_append_interface_lowspeed(if_descriptor_lowspeed, sizeof(if_descriptor_lowspeed));
198 usb_append_interface_highspeed(if_descriptor_lowspeed, sizeof(if_descriptor_lowspeed));
199 usb_register_callback(&usb_cb, NULL);
200
201 usb_add_string("LK", 1);
202 usb_add_string("LK Industries", 2);
203
204 usb_start();
205 }
206