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