1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <inttypes.h>
5
6 #include <usb/sunxi_hal_udc.h>
7 #include <usb/ch9.h>
8 #include <usb/storage.h>
9
10 #include <hal_log.h>
11
12 #include "usb_msg.h"
13
14 static struct usb_device_descriptor demo_device_desc = {
15 .bLength = USB_DT_DEVICE_SIZE,
16 .bDescriptorType = USB_DT_DEVICE,
17 .bcdUSB = 0x0200,
18 .bDeviceClass = 0,
19 .bDeviceSubClass = 0,
20 .bDeviceProtocol = 0,
21 .bMaxPacketSize0 = 64,
22 .idVendor = 0x18d1,
23 .idProduct = 0x0001,
24 .bcdDevice = 0x0001,
25 .iManufacturer = 0x01,
26 .iProduct = 0x02,
27 .iSerialNumber = 0x03,
28 .bNumConfigurations = 1
29 };
30
31 static struct usb_config_descriptor demo_config_desc = {
32 .bLength = USB_DT_CONFIG_SIZE,
33 .bDescriptorType = USB_DT_CONFIG,
34 .wTotalLength = 32, /* FIXME */
35 .bNumInterfaces = 1,
36 .bConfigurationValue = 1,
37 .iConfiguration = 0,
38 .bmAttributes = 0x80,
39 .bMaxPower = 0x64 /* 200mA */
40 };
41
42 static struct usb_interface_descriptor demo_intf_desc = {
43 .bLength = USB_DT_INTERFACE_SIZE,
44 .bDescriptorType = USB_DT_INTERFACE,
45 .bInterfaceNumber = 0x0,
46 .bAlternateSetting = 0x0,
47 .bNumEndpoints = 2,
48 .bInterfaceClass = 0x08, /* Mass Storage class */
49 .bInterfaceSubClass = 0x06, /* SCSI Transparent Subclass */
50 .bInterfaceProtocol = 0x50, /* Bulk-Only Protocol */
51 .iInterface = 0
52 };
53
54 static struct usb_endpoint_descriptor demo_ep_bulk_out = {
55 .bLength = USB_DT_ENDPOINT_SIZE,
56 .bDescriptorType = USB_DT_ENDPOINT,
57 .bEndpointAddress = 0x1 | USB_DIR_OUT,
58 .bmAttributes = USB_ENDPOINT_XFER_BULK,
59 .wMaxPacketSize = 0x0200, /* 512 Bytes */
60 .bInterval = 0
61 };
62
63 static struct usb_endpoint_descriptor demo_ep_bulk_in = {
64 .bLength = USB_DT_ENDPOINT_SIZE,
65 .bDescriptorType = USB_DT_ENDPOINT,
66 .bEndpointAddress = 0x1 | USB_DIR_IN,
67 .bmAttributes = USB_ENDPOINT_XFER_BULK,
68 .wMaxPacketSize = 0x0200, /* 512 Bytes */
69 .bInterval = 0
70 };
71
72 /*
73 * String descriptors
74 */
75 static const uint16_t g_str_lang_id[] = {
76 0x0304, 0x0409
77 };
78
79 static const uint16_t g_str_manufacturer[] = {
80 0x030e, 'G', 'o', 'o', 'g', 'l', 'e'
81 };
82
83 static const uint16_t g_str_product[] = {
84 0x0308, 'M', 's', 'g'
85 };
86
87 static const uint16_t g_str_serialnumber[] = {
88 0x0314, '2', '0', '0', '8', '0', '4', '1', '1'
89 };
90
91 struct usb_msg_dev g_msg_dev = {
92 .max_lun = 0,
93 };
94
95 static void *g_config_desc = NULL;
96
usb_msg_desc_init(void)97 void usb_msg_desc_init(void)
98 {
99 uint32_t config_desc_len;
100 void *buf;
101
102 config_desc_len = demo_config_desc.bLength + demo_intf_desc.bLength
103 + demo_ep_bulk_out.bLength + demo_ep_bulk_in.bLength;
104
105 g_config_desc = malloc(config_desc_len);
106
107 /* compose configuation, interface and endpoint descriptors */
108 buf = g_config_desc;
109 memcpy(buf, &demo_config_desc, demo_config_desc.bLength);
110 buf += demo_config_desc.bLength;
111 memcpy(buf, &demo_intf_desc, demo_intf_desc.bLength);
112 buf += demo_intf_desc.bLength;
113 memcpy(buf, &demo_ep_bulk_out, demo_ep_bulk_out.bLength);
114 buf += demo_ep_bulk_out.bLength;
115 memcpy(buf, &demo_ep_bulk_in, demo_ep_bulk_in.bLength);
116
117 hal_udc_device_desc_init(&demo_device_desc);
118 hal_udc_config_desc_init(g_config_desc, config_desc_len);
119 /* FIXME: string descriptors must be initialized in the following order now */
120 hal_udc_string_desc_init(g_str_lang_id);
121 hal_udc_string_desc_init(g_str_manufacturer);
122 hal_udc_string_desc_init(g_str_product);
123 hal_udc_string_desc_init(g_str_serialnumber);
124 }
125
usb_msg_ep_init(void)126 static void usb_msg_ep_init(void)
127 {
128 hal_log_info("usb demo ep init...\n");
129
130 /* init bulk-in ep */
131 hal_udc_ep_enable(demo_ep_bulk_in.bEndpointAddress,
132 demo_ep_bulk_in.wMaxPacketSize,
133 demo_ep_bulk_in.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
134
135 /* initialise bulk-out ep buf in order to get the first CBW */
136 hal_udc_ep_set_buf(demo_ep_bulk_out.bEndpointAddress,
137 g_msg_dev.cbw,
138 sizeof(g_msg_dev.cbw));
139
140 /* init bulk-out ep */
141 hal_udc_ep_enable(demo_ep_bulk_out.bEndpointAddress,
142 demo_ep_bulk_out.wMaxPacketSize,
143 demo_ep_bulk_out.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
144 }
145
usb_msg_class_request_handler(struct usb_ctrlrequest * crq)146 static udc_errno_t usb_msg_class_request_handler(struct usb_ctrlrequest *crq)
147 {
148 udc_errno_t ret = UDC_ERRNO_SUCCESS;
149
150 switch(crq->bRequest) {
151 case US_BULK_RESET_REQUEST:
152 /* TODO */
153 break;
154 case US_BULK_GET_MAX_LUN:
155 hal_log_info("get MAX_LUN\r\n");
156
157 if (crq->bRequestType !=
158 (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) {
159 ret = UDC_ERRNO_CMD_INVALID;
160 break;
161 }
162 /* FIXME: a fake response for demo */
163 hal_udc_ep_write(0, &g_msg_dev.max_lun, sizeof(g_msg_dev.max_lun));
164 break;
165 default:
166 ret = UDC_ERRNO_CMD_INVALID;
167 break;
168 }
169
170 return ret;
171 }
172
usb_msg_standard_request_handler(struct usb_ctrlrequest * crq)173 static udc_errno_t usb_msg_standard_request_handler(struct usb_ctrlrequest *crq)
174 {
175 udc_errno_t ret = UDC_ERRNO_SUCCESS;
176
177 switch (crq->bRequest) {
178 case USB_REQ_SET_CONFIGURATION:
179 /* FIXME: usb msg driver should be independent of demo code */
180 usb_msg_ep_init();
181 break;
182 default:
183 ret = UDC_ERRNO_CMD_INVALID;
184 break;
185 }
186
187 return ret;
188 }
189
usb_msg_scsi_cmd_handler(struct bulk_cb_wrap * cbw)190 static udc_errno_t usb_msg_scsi_cmd_handler(struct bulk_cb_wrap *cbw)
191 {
192 udc_errno_t ret = UDC_ERRNO_SUCCESS;
193 uint8_t opcode = cbw->CDB[0];
194 uint8_t fake_rsp[36] = {0x00, 0x80, 0x02, 0x02, 0x1F, 0x00, 0x00,
195 0x00, 0x54, 0x69, 0x6e, 0x61, 0x20, 0x20, 0x20,
196 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
197 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
198 0x20, 0x20, 0x20, 0x20, 0x20};
199
200 hal_log_info("scsi cmd opcode: 0x%x\n", opcode);
201
202 switch (opcode) {
203 case 0x12: /* INQUIRY */
204 /* FIXME: a fake response for demo */
205 hal_udc_ep_write(demo_ep_bulk_in.bEndpointAddress, fake_rsp, sizeof(fake_rsp));
206 break;
207 default:
208 ret = UDC_ERRNO_CMD_INVALID;
209 break;
210 }
211
212 return ret;
213 }
214
usb_msg_callback(uint8_t ep_addr,udc_callback_event_t event,void * data,uint32_t len)215 udc_errno_t usb_msg_callback(uint8_t ep_addr, udc_callback_event_t event, void *data, uint32_t len)
216 {
217 uint8_t ep_idx;
218 uint8_t is_in;
219 udc_errno_t ret = UDC_ERRNO_SUCCESS;
220 struct usb_ctrlrequest *crq;
221 struct bulk_cb_wrap *cbw;
222
223 hal_log_info("usb_msg_callback event: %"PRIu32", len: %"PRIu32"\n", event, len);
224
225 ep_idx = ep_addr & 0x7f;
226 is_in = ep_addr & USB_DIR_IN;
227
228 if (ep_idx == 0) { /* handle ep0 */
229 crq = (struct usb_ctrlrequest *)data;
230
231 switch (event) {
232 case UDC_EVENT_RX_STANDARD_REQUEST:
233 ret = usb_msg_standard_request_handler(crq);
234 break;
235 case UDC_EVENT_RX_CLASS_REQUEST:
236 ret = usb_msg_class_request_handler(crq);
237 break;
238 default:
239 ret = UDC_ERRNO_CMD_NOT_SUPPORTED;
240 break;
241 }
242 } else { /* handle ep1~4 */
243 if (is_in) {
244 /* TODO: maybe useless? */
245 } else {
246 cbw = (struct bulk_cb_wrap *)data;
247
248 switch (event) {
249 case UDC_EVENT_RX_DATA:
250 usb_msg_scsi_cmd_handler(cbw);
251 break;
252 default:
253 ret = UDC_ERRNO_CMD_NOT_SUPPORTED;
254 break;
255 }
256 }
257 }
258
259 return ret;
260 }
261