usb_msg.c 7.1 KB

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