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