usbcdc.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. #include <stdlib.h>
  2. #include <libopencm3/cm3/nvic.h>
  3. #include <libopencm3/usb/usbd.h>
  4. #include <libopencm3/usb/cdc.h>
  5. #include <libopencm3/stm32/desig.h>
  6. #define UID_LEN (12 * 2 + 1) /* 12-byte, each byte turnned into 2-byte hex, then '\0'. */
  7. #define DEV_VID 0x0483 /* ST Microelectronics */
  8. #define DEV_PID 0x5740 /* STM32 */
  9. #define DEV_VER 0x0009 /* 0.9 */
  10. #define EP_INT 0x83
  11. #define EP_OUT 0x82
  12. #define EP_IN 0x01
  13. #define STR_MAN 0x01
  14. #define STR_PROD 0x02
  15. #define STR_SER 0x03
  16. #define STR_IFACE 0x04
  17. #include "usbcdc.h"
  18. static const struct usb_device_descriptor dev = {
  19. .bLength = USB_DT_DEVICE_SIZE,
  20. .bDescriptorType = USB_DT_DEVICE,
  21. .bcdUSB = 0x0200,
  22. .bDeviceClass = USB_CLASS_CDC,
  23. .bDeviceSubClass = 0,
  24. .bDeviceProtocol = 0,
  25. .bMaxPacketSize0 = USBCDC_PKT_SIZE_DAT,
  26. .idVendor = DEV_VID,
  27. .idProduct = DEV_PID,
  28. .bcdDevice = DEV_VER,
  29. .iManufacturer = STR_MAN,
  30. .iProduct = STR_PROD,
  31. .iSerialNumber = STR_SER,
  32. .bNumConfigurations = 1,
  33. };
  34. /*
  35. * This notification endpoint isn't implemented. According to CDC spec its
  36. * optional, but its absence causes a NULL pointer dereference in Linux
  37. * cdc_acm driver.
  38. */
  39. static const struct usb_endpoint_descriptor comm_endp[] = {{
  40. .bLength = USB_DT_ENDPOINT_SIZE,
  41. .bDescriptorType = USB_DT_ENDPOINT,
  42. .bEndpointAddress = EP_INT,
  43. .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
  44. .wMaxPacketSize = USBCDC_PKT_SIZE_INT,
  45. .bInterval = 255,
  46. }};
  47. static const struct usb_endpoint_descriptor data_endp[] = {{
  48. .bLength = USB_DT_ENDPOINT_SIZE,
  49. .bDescriptorType = USB_DT_ENDPOINT,
  50. .bEndpointAddress = EP_IN,
  51. .bmAttributes = USB_ENDPOINT_ATTR_BULK,
  52. .wMaxPacketSize = USBCDC_PKT_SIZE_DAT,
  53. .bInterval = 1,
  54. }, {
  55. .bLength = USB_DT_ENDPOINT_SIZE,
  56. .bDescriptorType = USB_DT_ENDPOINT,
  57. .bEndpointAddress = EP_OUT,
  58. .bmAttributes = USB_ENDPOINT_ATTR_BULK,
  59. .wMaxPacketSize = USBCDC_PKT_SIZE_DAT,
  60. .bInterval = 1,
  61. }};
  62. static const struct {
  63. struct usb_cdc_header_descriptor header;
  64. struct usb_cdc_call_management_descriptor call_mgmt;
  65. struct usb_cdc_acm_descriptor acm;
  66. struct usb_cdc_union_descriptor cdc_union;
  67. } __attribute__((packed)) cdcacm_functional_descriptors = {
  68. .header = {
  69. .bFunctionLength = sizeof(struct usb_cdc_header_descriptor),
  70. .bDescriptorType = CS_INTERFACE,
  71. .bDescriptorSubtype = USB_CDC_TYPE_HEADER,
  72. .bcdCDC = 0x0110,
  73. },
  74. .call_mgmt = {
  75. .bFunctionLength = sizeof(struct usb_cdc_call_management_descriptor),
  76. .bDescriptorType = CS_INTERFACE,
  77. .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT,
  78. .bmCapabilities = 0,
  79. .bDataInterface = 1,
  80. },
  81. .acm = {
  82. .bFunctionLength = sizeof(struct usb_cdc_acm_descriptor),
  83. .bDescriptorType = CS_INTERFACE,
  84. .bDescriptorSubtype = USB_CDC_TYPE_ACM,
  85. .bmCapabilities = 0,
  86. },
  87. .cdc_union = {
  88. .bFunctionLength = sizeof(struct usb_cdc_union_descriptor),
  89. .bDescriptorType = CS_INTERFACE,
  90. .bDescriptorSubtype = USB_CDC_TYPE_UNION,
  91. .bControlInterface = 0,
  92. .bSubordinateInterface0 = 1,
  93. },
  94. };
  95. static const struct usb_interface_descriptor comm_iface[] = {{
  96. .bLength = USB_DT_INTERFACE_SIZE,
  97. .bDescriptorType = USB_DT_INTERFACE,
  98. .bInterfaceNumber = 0,
  99. .bAlternateSetting = 0,
  100. .bNumEndpoints = 1,
  101. .bInterfaceClass = USB_CLASS_CDC,
  102. .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
  103. .bInterfaceProtocol = USB_CDC_PROTOCOL_AT,
  104. .iInterface = STR_IFACE,
  105. .endpoint = comm_endp,
  106. .extra = &cdcacm_functional_descriptors,
  107. .extralen = sizeof(cdcacm_functional_descriptors),
  108. }};
  109. static const struct usb_interface_descriptor data_iface[] = {{
  110. .bLength = USB_DT_INTERFACE_SIZE,
  111. .bDescriptorType = USB_DT_INTERFACE,
  112. .bInterfaceNumber = 1,
  113. .bAlternateSetting = 0,
  114. .bNumEndpoints = 2,
  115. .bInterfaceClass = USB_CLASS_DATA,
  116. .bInterfaceSubClass = 0,
  117. .bInterfaceProtocol = 0,
  118. .iInterface = STR_IFACE,
  119. .endpoint = data_endp,
  120. }};
  121. static const struct usb_interface ifaces[] = {{
  122. .num_altsetting = 1,
  123. .altsetting = comm_iface,
  124. }, {
  125. .num_altsetting = 1,
  126. .altsetting = data_iface,
  127. }};
  128. static const struct usb_config_descriptor config = {
  129. .bLength = USB_DT_CONFIGURATION_SIZE,
  130. .bDescriptorType = USB_DT_CONFIGURATION,
  131. .wTotalLength = 0,
  132. .bNumInterfaces = 2,
  133. .bConfigurationValue = 1,
  134. .iConfiguration = 0,
  135. .bmAttributes = 0x80,
  136. .bMaxPower = 0x32,
  137. .interface = ifaces,
  138. };
  139. /* Buffer to be used for control requests. */
  140. static uint8_t usbd_control_buffer[128];
  141. static enum usbd_request_return_codes cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
  142. uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req)) {
  143. switch (req->bRequest) {
  144. case USB_CDC_REQ_SET_CONTROL_LINE_STATE: {
  145. /*
  146. * This Linux cdc_acm driver requires this to be implemented
  147. * even though it's optional in the CDC spec, and we don't
  148. * advertise it in the ACM functional descriptor.
  149. */
  150. char local_buf[10];
  151. struct usb_cdc_notification *notif = (void *)local_buf;
  152. /* We echo signals back to host as notification. */
  153. notif->bmRequestType = 0xa1;
  154. notif->bNotification = USB_CDC_NOTIFY_SERIAL_STATE;
  155. notif->wValue = 0;
  156. notif->wIndex = 0;
  157. notif->wLength = 2;
  158. local_buf[8] = req->wValue & 3;
  159. local_buf[9] = 0;
  160. return USBD_REQ_HANDLED;
  161. }
  162. case USB_CDC_REQ_SET_LINE_CODING:
  163. if (*len < sizeof(struct usb_cdc_line_coding))
  164. return USBD_REQ_NOTSUPP;
  165. return USBD_REQ_HANDLED;
  166. }
  167. return USBD_REQ_NOTSUPP;
  168. }
  169. volatile bool usb_ready = false;
  170. static void cdcacm_reset(void) {
  171. usb_ready = false;
  172. }
  173. static void cdcacm_set_config(usbd_device *usbd_dev, uint16_t wValue) {
  174. usbd_ep_setup(usbd_dev, EP_IN , USB_ENDPOINT_ATTR_BULK, 64, NULL);
  175. usbd_ep_setup(usbd_dev, EP_OUT, USB_ENDPOINT_ATTR_BULK, 64, NULL);
  176. usbd_ep_setup(usbd_dev, EP_INT, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
  177. usbd_register_control_callback(
  178. usbd_dev,
  179. USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
  180. USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
  181. cdcacm_control_request);
  182. if (wValue > 0) {
  183. usb_ready = true;
  184. }
  185. }
  186. static usbd_device *usbd_dev; /* Just a pointer, need not to be volatile. */
  187. static char serial[UID_LEN];
  188. /* Vendor, device, version. */
  189. static const char *usb_strings[] = {
  190. "dword1511.info",
  191. "STM32 virtual serprog for flashrom",
  192. serial,
  193. "serprog",
  194. };
  195. #define N_USB_STRS sizeof(usb_strings)/sizeof(usb_strings[0])
  196. void usbcdc_init(void) {
  197. desig_get_unique_id_as_string(serial, UID_LEN);
  198. #ifdef STM32F0
  199. usbd_dev = usbd_init(&st_usbfs_v2_usb_driver, &dev, &config, usb_strings, N_USB_STRS, usbd_control_buffer, sizeof(usbd_control_buffer));
  200. #else
  201. usbd_dev = usbd_init(&st_usbfs_v1_usb_driver, &dev, &config, usb_strings, N_USB_STRS, usbd_control_buffer, sizeof(usbd_control_buffer));
  202. #endif /* STM32F0 */
  203. usbd_register_set_config_callback(usbd_dev, cdcacm_set_config);
  204. usbd_register_reset_callback(usbd_dev, cdcacm_reset);
  205. /* NOTE: Must be called after USB setup since this enables calling usbd_poll(). */
  206. #ifdef STM32F0
  207. nvic_enable_irq(NVIC_USB_IRQ);
  208. #else
  209. /* NVIC_USB_HP_CAN_TX_IRQ */
  210. nvic_enable_irq(NVIC_USB_LP_CAN_RX0_IRQ);
  211. nvic_enable_irq(NVIC_USB_WAKEUP_IRQ);
  212. #endif /* STM32F0 */
  213. }
  214. /* Application-level functions */
  215. uint16_t usbcdc_write(void *buf, size_t len) {
  216. uint16_t ret;
  217. /* Blocking write */
  218. while (0 == (ret = usbd_ep_write_packet(usbd_dev, EP_OUT, buf, len)));
  219. return ret;
  220. }
  221. uint16_t usbcdc_putc(char c) {
  222. return usbcdc_write(&c, sizeof(c));
  223. }
  224. uint16_t usbcdc_putu32(uint32_t word) {
  225. //uint32_t l = __builtin_bswap32(word);
  226. //return usbcdc_write(&l, sizeof(word));
  227. /* We are using little endian, so no bit swap. */
  228. return usbcdc_write(&word, sizeof(word));
  229. }
  230. /* We need to maintain a RX user buffer since libopencm3 will throw rest of the packet away. */
  231. char usbcdc_rxbuf[USBCDC_PKT_SIZE_DAT]; /* DMA needs access */
  232. static uint8_t usbcdc_rxbuf_head = 0;
  233. static uint8_t usbcdc_rxbuf_tail = 0; /* Indicates empty buffer */
  234. uint16_t usbcdc_fetch_packet(void) {
  235. uint16_t ret;
  236. /* Blocking read. Assume RX user buffer is empty. TODO: consider setting a timeout */
  237. while (0 == (ret = usbd_ep_read_packet(usbd_dev, EP_IN, usbcdc_rxbuf, USBCDC_PKT_SIZE_DAT)));
  238. usbcdc_rxbuf_head = 0;
  239. usbcdc_rxbuf_tail = ret;
  240. return ret;
  241. }
  242. char usbcdc_getc(void) {
  243. char c;
  244. if (usbcdc_rxbuf_head >= usbcdc_rxbuf_tail) {
  245. usbcdc_fetch_packet();
  246. }
  247. c = usbcdc_rxbuf[usbcdc_rxbuf_head];
  248. usbcdc_rxbuf_head ++;
  249. return c;
  250. }
  251. uint32_t usbcdc_getu24(void) {
  252. uint32_t val = 0;
  253. val = (uint32_t)usbcdc_getc() << 0;
  254. val |= (uint32_t)usbcdc_getc() << 8;
  255. val |= (uint32_t)usbcdc_getc() << 16;
  256. return val;
  257. }
  258. uint32_t usbcdc_getu32(void) {
  259. uint32_t val = 0;
  260. val = (uint32_t)usbcdc_getc() << 0;
  261. val |= (uint32_t)usbcdc_getc() << 8;
  262. val |= (uint32_t)usbcdc_getc() << 16;
  263. val |= (uint32_t)usbcdc_getc() << 24;
  264. return val;
  265. }
  266. uint8_t usbcdc_get_remainder(char **bufpp) {
  267. uint8_t len = usbcdc_rxbuf_tail - usbcdc_rxbuf_head;
  268. *bufpp = &(usbcdc_rxbuf[usbcdc_rxbuf_head]);
  269. usbcdc_rxbuf_head = usbcdc_rxbuf_tail; /* Mark as used. */
  270. return len;
  271. }
  272. /* Interrupts */
  273. static void usb_int_relay(void) {
  274. /* Need to pass a parameter... otherwise just alias it directly. */
  275. usbd_poll(usbd_dev);
  276. }
  277. #ifdef STM32F0
  278. void usb_isr(void)
  279. __attribute__ ((alias ("usb_int_relay")));
  280. #else
  281. void usb_wakeup_isr(void)
  282. __attribute__ ((alias ("usb_int_relay")));
  283. void usb_hp_can_tx_isr(void)
  284. __attribute__ ((alias ("usb_int_relay")));
  285. void usb_lp_can_rx0_isr(void)
  286. __attribute__ ((alias ("usb_int_relay")));
  287. #endif /* STM32F0 */