usbh_serial.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /*
  2. * Copyright (c) 2025, sakumisu
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <nuttx/kmalloc.h>
  7. #include <nuttx/mutex.h>
  8. #include <nuttx/semaphore.h>
  9. #include "usbh_core.h"
  10. #include "usbh_cdc_acm.h"
  11. #include <nuttx/mm/circbuf.h>
  12. #define DEV_FORMAT "/dev/ttyACM%d"
  13. #ifndef CONFIG_USBHOST_CDCACM_RXBUFSIZE
  14. #define CONFIG_USBHOST_CDCACM_RXBUFSIZE 512
  15. #endif
  16. #ifndef CONFIG_USBHOST_CDCACM_TXBUFSIZE
  17. #define CONFIG_USBHOST_CDCACM_TXBUFSIZE 512
  18. #endif
  19. struct usbhost_serial_s {
  20. struct circbuf_s circ;
  21. __attribute__((aligned(32))) uint8_t cache_rxbuffer[CONFIG_USBHOST_CDCACM_RXBUFSIZE];
  22. __attribute__((aligned(32))) uint8_t cache_txbuffer[CONFIG_USBHOST_CDCACM_TXBUFSIZE];
  23. };
  24. static int nuttx_errorcode(int error)
  25. {
  26. int err = 0;
  27. switch (error) {
  28. case -USB_ERR_NOMEM:
  29. err = -EIO;
  30. break;
  31. case -USB_ERR_INVAL:
  32. err = -EINVAL;
  33. break;
  34. case -USB_ERR_NODEV:
  35. err = -ENODEV;
  36. break;
  37. case -USB_ERR_NOTCONN:
  38. err = -ENOTCONN;
  39. break;
  40. case -USB_ERR_NOTSUPP:
  41. err = -EIO;
  42. break;
  43. case -USB_ERR_BUSY:
  44. err = -EBUSY;
  45. break;
  46. case -USB_ERR_RANGE:
  47. err = -ERANGE;
  48. break;
  49. case -USB_ERR_STALL:
  50. err = -EPERM;
  51. break;
  52. case -USB_ERR_NAK:
  53. err = -EAGAIN;
  54. break;
  55. case -USB_ERR_DT:
  56. err = -EIO;
  57. break;
  58. case -USB_ERR_IO:
  59. err = -EIO;
  60. break;
  61. case -USB_ERR_SHUTDOWN:
  62. err = -ESHUTDOWN;
  63. break;
  64. case -USB_ERR_TIMEOUT:
  65. err = -ETIMEDOUT;
  66. break;
  67. default:
  68. break;
  69. }
  70. return err;
  71. }
  72. /* Character driver methods */
  73. static int usbhost_open(FAR struct file *filep);
  74. static int usbhost_close(FAR struct file *filep);
  75. static ssize_t usbhost_read(FAR struct file *filep, FAR char *buffer,
  76. size_t buflen);
  77. static ssize_t usbhost_write(FAR struct file *filep,
  78. FAR const char *buffer, size_t buflen);
  79. /****************************************************************************
  80. * Private Data
  81. ****************************************************************************/
  82. static const struct file_operations g_usbhostops = {
  83. usbhost_open, /* open */
  84. usbhost_close, /* close */
  85. usbhost_read, /* read */
  86. usbhost_write, /* write */
  87. NULL, /* seek */
  88. NULL, /* ioctl */
  89. NULL, /* mmap */
  90. NULL, /* truncate */
  91. NULL /* poll */
  92. };
  93. static int usbhost_open(FAR struct file *filep)
  94. {
  95. struct usbh_cdc_acm *cdc_acm_class;
  96. FAR struct inode *inode = filep->f_inode;
  97. DEBUGASSERT(inode->i_private);
  98. cdc_acm_class = (struct usbh_cdc_acm *)inode->i_private;
  99. if (cdc_acm_class->hport && cdc_acm_class->hport->connected) {
  100. return OK;
  101. } else {
  102. return -ENODEV;
  103. }
  104. }
  105. static int usbhost_close(FAR struct file *filep)
  106. {
  107. FAR struct inode *inode = filep->f_inode;
  108. DEBUGASSERT(inode->i_private);
  109. return 0;
  110. }
  111. static ssize_t usbhost_read(FAR struct file *filep, FAR char *buffer,
  112. size_t buflen)
  113. {
  114. struct usbh_cdc_acm *cdc_acm_class;
  115. FAR struct inode *inode = filep->f_inode;
  116. struct usbhost_serial_s *serial;
  117. __attribute__((aligned(32))) uint8_t cache_tempbuffer[512];
  118. int ret;
  119. DEBUGASSERT(inode->i_private || cdc_acm_class->user_data);
  120. cdc_acm_class = (struct usbh_cdc_acm *)inode->i_private;
  121. serial = cdc_acm_class->user_data;
  122. while (circbuf_used(&serial->circ) == 0) {
  123. ret = usbh_cdc_acm_bulk_in_transfer(cdc_acm_class, cache_tempbuffer, cdc_acm_class->bulkin->wMaxPacketSize, 0xffffffff);
  124. if (ret < 0) {
  125. return nuttx_errorcode(ret);
  126. }
  127. #if defined(CONFIG_ARCH_DCACHE) && !defined(CONFIG_USB_DCACHE_ENABLE)
  128. up_invalidate_dcache((uintptr_t)cache_tempbuffer, (uintptr_t)(cache_tempbuffer + cdc_acm_class->bulkin->wMaxPacketSize));
  129. #endif
  130. circbuf_overwrite(&serial->circ, cache_tempbuffer, USB_ALIGN_UP(ret, 64));
  131. }
  132. return circbuf_read(&serial->circ, buffer, buflen);
  133. }
  134. static ssize_t usbhost_write(FAR struct file *filep, FAR const char *buffer,
  135. size_t buflen)
  136. {
  137. struct usbh_cdc_acm *cdc_acm_class;
  138. FAR struct inode *inode = filep->f_inode;
  139. struct usbhost_serial_s *serial;
  140. int ret;
  141. DEBUGASSERT(inode->i_private || cdc_acm_class->user_data);
  142. cdc_acm_class = (struct usbh_cdc_acm *)inode->i_private;
  143. serial = cdc_acm_class->user_data;
  144. #ifdef CONFIG_ARCH_DCACHE
  145. uint32_t write_len = 0;
  146. while (write_len < buflen) {
  147. uint32_t len = buflen - write_len;
  148. if (len > CONFIG_USBHOST_CDCACM_TXBUFSIZE) {
  149. len = CONFIG_USBHOST_CDCACM_TXBUFSIZE;
  150. }
  151. memcpy(serial->cache_txbuffer, buffer + write_len, len);
  152. #ifndef CONFIG_USB_DCACHE_ENABLE
  153. up_clean_dcache((uintptr_t)serial->cache_txbuffer, (uintptr_t)(serial->cache_txbuffer + USB_ALIGN_UP(len, 64)));
  154. #endif
  155. ret = usbh_cdc_acm_bulk_out_transfer(cdc_acm_class, serial->cache_txbuffer, len, 0xffffffff);
  156. if (ret < 0) {
  157. return nuttx_errorcode(ret);
  158. } else {
  159. write_len += len;
  160. }
  161. }
  162. return buflen;
  163. #else
  164. ret = usbh_cdc_acm_bulk_out_transfer(cdc_acm_class, (uint8_t *)buffer, buflen, 0xffffffff);
  165. if (ret < 0) {
  166. return nuttx_errorcode(ret);
  167. } else {
  168. return buflen;
  169. }
  170. #endif
  171. }
  172. void usbh_cdc_acm_run(struct usbh_cdc_acm *cdc_acm_class)
  173. {
  174. char devname[32];
  175. struct usbhost_serial_s *serial;
  176. snprintf(devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, cdc_acm_class->minor);
  177. serial = kmm_malloc(sizeof(struct usbhost_serial_s));
  178. DEBUGASSERT(serial);
  179. memset(serial, 0, sizeof(struct usbhost_serial_s));
  180. circbuf_init(&serial->circ, serial->cache_rxbuffer, CONFIG_USBHOST_CDCACM_RXBUFSIZE);
  181. cdc_acm_class->user_data = serial;
  182. struct cdc_line_coding linecoding;
  183. linecoding.dwDTERate = 115200;
  184. linecoding.bDataBits = 8;
  185. linecoding.bParityType = 0;
  186. linecoding.bCharFormat = 0;
  187. usbh_cdc_acm_set_line_coding(cdc_acm_class, &linecoding);
  188. usbh_cdc_acm_set_line_state(cdc_acm_class, true, false);
  189. register_driver(devname, &g_usbhostops, 0666, cdc_acm_class);
  190. }
  191. void usbh_cdc_acm_stop(struct usbh_cdc_acm *cdc_acm_class)
  192. {
  193. char devname[32];
  194. struct usbhost_serial_s *serial;
  195. snprintf(devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, cdc_acm_class->minor);
  196. unregister_driver(devname);
  197. serial = cdc_acm_class->user_data;
  198. kmm_free(serial);
  199. }