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