1 /*
2  * Copyright (c) 2015 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 <dev/usb/class/bulktest.h>
24 
25 #include <debug.h>
26 #include <trace.h>
27 #include <err.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <assert.h>
31 #include <list.h>
32 #include <dev/usbc.h>
33 #include <dev/usb.h>
34 #include <lk/init.h>
35 
36 /* a simple demo usb class device that reflects data written to
37  * one endpoint to the other.
38  */
39 
40 #define LOCAL_TRACE 0
41 
42 #define W(w) (w & 0xff), (w >> 8)
43 #define W3(w) (w & 0xff), ((w >> 8) & 0xff), ((w >> 16) & 0xff)
44 
45 static status_t ep_cb_rx(ep_t endpoint, usbc_transfer_t *t);
46 static status_t ep_cb_tx(ep_t endpoint, usbc_transfer_t *t);
47 
48 #define TRANSFER_SIZE 512
49 
queue_rx(void)50 static void queue_rx(void)
51 {
52     static usbc_transfer_t transfer;
53     static uint8_t buf[TRANSFER_SIZE];
54 
55     transfer.callback = &ep_cb_rx;
56     transfer.result = 0;
57     transfer.buf = &buf;
58     transfer.buflen = sizeof(buf);
59     transfer.bufpos = 0;
60     transfer.extra = 0;
61 
62     usbc_queue_rx(1, &transfer);
63 }
64 
queue_tx(void)65 static void queue_tx(void)
66 {
67     static usbc_transfer_t transfer;
68     static uint8_t buf[TRANSFER_SIZE];
69 
70     for (uint i = 0; i < sizeof(buf); i++) {
71         buf[i] = ~i;
72     }
73 
74     transfer.callback = &ep_cb_tx;
75     transfer.result = 0;
76     transfer.buf = &buf;
77     transfer.buflen = sizeof(buf);
78     transfer.bufpos = 0;
79     transfer.extra = 0;
80 
81     usbc_queue_tx(1, &transfer);
82 }
83 
84 
ep_cb_rx(ep_t endpoint,usbc_transfer_t * t)85 static status_t ep_cb_rx(ep_t endpoint, usbc_transfer_t *t)
86 {
87 #if LOCAL_TRACE
88     LTRACEF("ep %u transfer %p\n", endpoint, t);
89     usbc_dump_transfer(t);
90 
91     if (t->result >= 0) {
92         hexdump8(t->buf, t->bufpos);
93     }
94 #endif
95 
96     if (t->result >= 0)
97         queue_rx();
98 
99     return NO_ERROR;
100 }
101 
ep_cb_tx(ep_t endpoint,usbc_transfer_t * t)102 static status_t ep_cb_tx(ep_t endpoint, usbc_transfer_t *t)
103 {
104 #if LOCAL_TRACE
105     LTRACEF("ep %u transfer %p\n", endpoint, t);
106     usbc_dump_transfer(t);
107 #endif
108 
109     if (t->result >= 0)
110         queue_tx();
111 
112     return NO_ERROR;
113 }
114 
bulktest_usb_cb(void * cookie,usb_callback_op_t op,const union usb_callback_args * args)115 static status_t bulktest_usb_cb(void *cookie, usb_callback_op_t op, const union usb_callback_args *args)
116 {
117     LTRACEF("cookie %p, op %u, args %p\n", cookie, op, args);
118 
119     if (op == USB_CB_ONLINE) {
120         usbc_setup_endpoint(1, USB_IN, 0x40, USB_BULK);
121         usbc_setup_endpoint(1, USB_OUT, 0x40, USB_BULK);
122 
123         queue_rx();
124         queue_tx();
125     }
126     return NO_ERROR;
127 }
128 
usb_class_bulktest_init(uint interface_num,ep_t epin,ep_t epout)129 status_t usb_class_bulktest_init(uint interface_num, ep_t epin, ep_t epout)
130 {
131     LTRACEF("epin %u, epout %u\n", epin, epout);
132 
133     /* build a descriptor for it */
134     uint8_t if_descriptor[] = {
135         0x09,           /* length */
136         INTERFACE,      /* type */
137         interface_num,  /* interface num */
138         0x00,           /* alternates */
139         0x02,           /* endpoint count */
140         0xff,           /* interface class */
141         0xff,           /* interface subclass */
142         0x00,           /* interface protocol */
143         0x00,           /* string index */
144 
145         /* endpoint 1 IN */
146         0x07,           /* length */
147         ENDPOINT,       /* type */
148         epin | 0x80,    /* address: 1 IN */
149         0x02,           /* type: bulk */
150         W(64),          /* max packet size: 64 */
151         00,             /* interval */
152 
153         /* endpoint 1 OUT */
154         0x07,           /* length */
155         ENDPOINT,       /* type */
156         epout,          /* address: 1 OUT */
157         0x02,           /* type: bulk */
158         W(64),          /* max packet size: 64 */
159         00,             /* interval */
160     };
161 
162     usb_append_interface_lowspeed(if_descriptor, sizeof(if_descriptor));
163     usb_append_interface_highspeed(if_descriptor, sizeof(if_descriptor));
164 
165     usb_register_callback(&bulktest_usb_cb, NULL);
166 
167     return NO_ERROR;
168 }
169 
170