usbh_serial.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  1. /*
  2. * Copyright (c) 2025, sakumisu
  3. * Copyright (c) 2025, MDLZCOOL
  4. *
  5. * SPDX-License-Identifier: Apache-2.0
  6. */
  7. #include "usbh_core.h"
  8. #include "usbh_serial.h"
  9. #undef USB_DBG_TAG
  10. #define USB_DBG_TAG "usbh_serial"
  11. #include "usb_log.h"
  12. #define DEV_FORMAT_VENDOR "/dev/ttyUSB%d"
  13. #define DEV_FORMAT_CDC_ACM "/dev/ttyACM%d"
  14. #define CONFIG_USBHOST_MAX_SERIAL_CLASS 4
  15. static struct usbh_serial g_serial_class[CONFIG_USBHOST_MAX_SERIAL_CLASS];
  16. static uint32_t g_devinuse = 0;
  17. static uint32_t g_cdcacm_devinuse = 0;
  18. USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_serial_iobuffer[CONFIG_USBHOST_MAX_SERIAL_CLASS][USB_ALIGN_UP((USBH_SERIAL_RX2_NOCACHE_OFFSET + USBH_SERIAL_RX2_NOCACHE_SIZE), CONFIG_USB_ALIGN_SIZE)];
  19. static struct usbh_serial *usbh_serial_alloc(bool is_cdcacm)
  20. {
  21. uint8_t devno;
  22. uint8_t devno2;
  23. for (devno = 0; devno < CONFIG_USBHOST_MAX_SERIAL_CLASS; devno++) {
  24. if ((g_devinuse & (1U << devno)) == 0) {
  25. g_devinuse |= (1U << devno);
  26. memset(&g_serial_class[devno], 0, sizeof(struct usbh_serial));
  27. g_serial_class[devno].minor = devno;
  28. g_serial_class[devno].cdc_minor = -1;
  29. g_serial_class[devno].iobuffer = g_serial_iobuffer[devno];
  30. g_serial_class[devno].rx_complete_sem = usb_osal_sem_create(0);
  31. if (is_cdcacm) {
  32. for (devno2 = 0; devno2 < CONFIG_USBHOST_MAX_SERIAL_CLASS; devno2++) {
  33. if ((g_cdcacm_devinuse & (1U << devno2)) == 0) {
  34. g_cdcacm_devinuse |= (1U << devno2);
  35. g_serial_class[devno].cdc_minor = devno2;
  36. return &g_serial_class[devno];
  37. }
  38. }
  39. g_devinuse &= ~(1U << devno);
  40. return NULL;
  41. } else {
  42. return &g_serial_class[devno];
  43. }
  44. }
  45. }
  46. return NULL;
  47. }
  48. static void usbh_serial_free(struct usbh_serial *serial)
  49. {
  50. uint8_t devno = serial->minor;
  51. if (devno < 32) {
  52. g_devinuse &= ~(1U << devno);
  53. }
  54. if (serial->cdc_minor >= 0) {
  55. g_cdcacm_devinuse &= ~(1U << serial->cdc_minor);
  56. }
  57. if (g_serial_class[devno].rx_complete_sem) {
  58. usb_osal_sem_delete(g_serial_class[devno].rx_complete_sem);
  59. }
  60. }
  61. static void usbh_serial_callback(void *arg, int nbytes)
  62. {
  63. struct usbh_serial *serial = (struct usbh_serial *)arg;
  64. int ret;
  65. if (nbytes < 0) {
  66. if (nbytes != -USB_ERR_SHUTDOWN) {
  67. USB_LOG_ERR("serial transfer error: %d\n", nbytes);
  68. }
  69. serial->rx_errorcode = nbytes;
  70. usb_osal_sem_give(serial->rx_complete_sem);
  71. return;
  72. }
  73. if (nbytes < serial->driver->ignore_rx_header) {
  74. USB_LOG_ERR("serial rx short packet: %d\n", nbytes);
  75. serial->rx_errorcode = -USB_ERR_IO;
  76. usb_osal_sem_give(serial->rx_complete_sem);
  77. return;
  78. }
  79. if (nbytes >= serial->driver->ignore_rx_header) {
  80. /* resubmit the read urb */
  81. usbh_bulk_urb_fill(&serial->bulkin_urb, serial->hport, serial->bulkin, &serial->iobuffer[serial->rx_buf_index ? USBH_SERIAL_RX_NOCACHE_OFFSET : USBH_SERIAL_RX2_NOCACHE_OFFSET], serial->bulkin->wMaxPacketSize,
  82. 0, usbh_serial_callback, serial);
  83. ret = usbh_submit_urb(&serial->bulkin_urb);
  84. if (ret < 0) {
  85. USB_LOG_ERR("serial submit failed: %d\n", ret);
  86. serial->rx_errorcode = ret;
  87. usb_osal_sem_give(serial->rx_complete_sem);
  88. return;
  89. }
  90. usb_ringbuffer_write(&serial->rx_rb,
  91. &serial->iobuffer[(serial->rx_buf_index ? USBH_SERIAL_RX2_NOCACHE_OFFSET : USBH_SERIAL_RX_NOCACHE_OFFSET) + serial->driver->ignore_rx_header],
  92. (nbytes - serial->driver->ignore_rx_header));
  93. if (serial->rx_complete_callback) {
  94. serial->rx_complete_callback(serial, nbytes - serial->driver->ignore_rx_header);
  95. }
  96. serial->rx_buf_index ^= 1;
  97. serial->rx_errorcode = 0;
  98. usb_osal_sem_give(serial->rx_complete_sem);
  99. }
  100. }
  101. struct usbh_serial *usbh_serial_probe(struct usbh_hubport *hport, uint8_t intf,
  102. const struct usbh_serial_driver *driver)
  103. {
  104. struct usb_endpoint_descriptor *ep_desc;
  105. struct usbh_serial *serial;
  106. bool is_cdcacm = false;
  107. int ret;
  108. if (strcmp(driver->driver_name, "cdc_acm") == 0) {
  109. is_cdcacm = true;
  110. }
  111. serial = usbh_serial_alloc(is_cdcacm);
  112. if (serial == NULL) {
  113. USB_LOG_ERR("Fail to alloc serial class\r\n");
  114. return NULL;
  115. }
  116. serial->hport = hport;
  117. serial->intf = intf;
  118. serial->driver = driver;
  119. if (driver->attach) {
  120. ret = driver->attach(serial);
  121. if (ret < 0) {
  122. USB_LOG_ERR("Serial attach failed: %d\r\n", ret);
  123. usbh_serial_free(serial);
  124. return NULL;
  125. }
  126. }
  127. if (is_cdcacm) {
  128. intf = intf + 1; /* data interface */
  129. }
  130. for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
  131. ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
  132. if (USB_GET_ENDPOINT_TYPE(ep_desc->bmAttributes) == USB_ENDPOINT_TYPE_BULK) {
  133. if (ep_desc->bEndpointAddress & 0x80) {
  134. USBH_EP_INIT(serial->bulkin, ep_desc);
  135. } else {
  136. USBH_EP_INIT(serial->bulkout, ep_desc);
  137. }
  138. }
  139. }
  140. if (is_cdcacm) {
  141. intf = intf - 1; /* data interface */
  142. }
  143. if (!serial->bulkin || !serial->bulkout) {
  144. USB_LOG_ERR("Serial bulk in/out endpoint not found\r\n");
  145. usbh_serial_free(serial);
  146. return NULL;
  147. }
  148. if (is_cdcacm) {
  149. snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT_CDC_ACM, serial->cdc_minor);
  150. } else {
  151. snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT_VENDOR, serial->minor);
  152. }
  153. hport->config.intf[intf].priv = serial;
  154. USB_LOG_INFO("Register Serial Class: %s (%s)\r\n", hport->config.intf[intf].devname, driver->driver_name);
  155. usbh_serial_run(serial);
  156. return serial;
  157. }
  158. void usbh_serial_remove(struct usbh_serial *serial)
  159. {
  160. if (!serial || !serial->hport)
  161. return;
  162. usbh_serial_close(serial);
  163. if (serial->driver && serial->driver->detach) {
  164. serial->driver->detach(serial);
  165. }
  166. if (serial->hport->config.intf[serial->intf].priv) {
  167. usb_osal_thread_schedule_other();
  168. USB_LOG_INFO("Unregister Serial Class: %s (%s)\r\n", serial->hport->config.intf[serial->intf].devname, serial->driver->driver_name);
  169. usbh_serial_stop(serial);
  170. }
  171. usbh_serial_free(serial);
  172. }
  173. struct usbh_serial *usbh_serial_open(const char *devname, uint32_t open_flags)
  174. {
  175. struct usbh_serial *serial;
  176. int ret;
  177. serial = usbh_find_class_instance(devname);
  178. if (!serial) {
  179. return NULL;
  180. }
  181. if (serial->ref_count != 0) {
  182. USB_LOG_ERR("Device busy: %s\r\n", devname);
  183. return NULL;
  184. }
  185. if (serial && serial->driver && serial->driver->open) {
  186. ret = serial->driver->open(serial);
  187. if (ret < 0) {
  188. return NULL;
  189. }
  190. }
  191. usb_ringbuffer_init(&serial->rx_rb, serial->rx_rb_pool, CONFIG_USBHOST_SERIAL_RX_SIZE);
  192. serial->ref_count++;
  193. serial->open_flags = open_flags;
  194. return serial;
  195. }
  196. int usbh_serial_close(struct usbh_serial *serial)
  197. {
  198. if (!serial || !serial->hport) {
  199. return -USB_ERR_INVAL;
  200. }
  201. if (serial->ref_count == 0) {
  202. return 0;
  203. }
  204. if (serial->bulkin) {
  205. usbh_kill_urb(&serial->bulkin_urb);
  206. }
  207. if (serial->bulkout) {
  208. usbh_kill_urb(&serial->bulkout_urb);
  209. }
  210. if (serial && serial->driver && serial->driver->set_flow_control && serial->rtscts) {
  211. serial->driver->set_flow_control(serial, false);
  212. }
  213. if (serial && serial->driver && serial->driver->close) {
  214. serial->driver->close(serial);
  215. }
  216. serial->ref_count--;
  217. serial->rtscts = false;
  218. return 0;
  219. }
  220. static int usbh_serial_tiocmset(struct usbh_serial *serial, uint32_t set, uint32_t clear)
  221. {
  222. int ret;
  223. uint16_t line_state;
  224. bool dtr;
  225. bool rts;
  226. if (!serial || !serial->hport || !serial->hport->connected) {
  227. return -USB_ERR_INVAL;
  228. }
  229. if (serial->ref_count == 0) {
  230. return -USB_ERR_NODEV;
  231. }
  232. line_state = serial->line_state;
  233. clear &= ~set; /* 'set' takes precedence over 'clear' */
  234. if (set & USBH_SERIAL_TIOCM_DTR) {
  235. line_state |= USBH_SERIAL_TIOCM_DTR;
  236. }
  237. if (set & USBH_SERIAL_TIOCM_RTS) {
  238. line_state |= USBH_SERIAL_TIOCM_RTS;
  239. }
  240. if (clear & USBH_SERIAL_TIOCM_DTR) {
  241. line_state &= ~USBH_SERIAL_TIOCM_DTR;
  242. }
  243. if (clear & USBH_SERIAL_TIOCM_RTS) {
  244. line_state &= ~USBH_SERIAL_TIOCM_RTS;
  245. }
  246. dtr = (line_state & USBH_SERIAL_TIOCM_DTR) ? true : false;
  247. rts = (line_state & USBH_SERIAL_TIOCM_RTS) ? true : false;
  248. if (serial && serial->driver && serial->driver->set_line_state) {
  249. ret = serial->driver->set_line_state(serial, dtr, rts);
  250. } else {
  251. return -USB_ERR_NOTSUPP;
  252. }
  253. serial->line_state = line_state;
  254. return ret;
  255. }
  256. int usbh_serial_control(struct usbh_serial *serial, int cmd, void *arg)
  257. {
  258. int ret;
  259. if (!serial || !serial->hport || !serial->hport->connected) {
  260. return -USB_ERR_INVAL;
  261. }
  262. if (serial->ref_count == 0) {
  263. return -USB_ERR_NODEV;
  264. }
  265. switch (cmd) {
  266. case USBH_SERIAL_CMD_SET_ATTR: {
  267. struct usbh_serial_termios *termios = (struct usbh_serial_termios *)arg;
  268. struct cdc_line_coding line_coding;
  269. line_coding.dwDTERate = termios->baudrate;
  270. line_coding.bCharFormat = termios->stopbits;
  271. line_coding.bParityType = termios->parity;
  272. line_coding.bDataBits = termios->databits;
  273. if (serial->bulkin) {
  274. usbh_kill_urb(&serial->bulkin_urb);
  275. }
  276. if (serial->bulkout) {
  277. usbh_kill_urb(&serial->bulkout_urb);
  278. }
  279. if (serial && serial->driver && serial->driver->set_line_coding) {
  280. ret = serial->driver->set_line_coding(serial, &line_coding);
  281. if (ret < 0) {
  282. return ret;
  283. }
  284. } else {
  285. return -USB_ERR_NOTSUPP;
  286. }
  287. memcpy(&serial->line_coding, &line_coding, sizeof(struct cdc_line_coding));
  288. if (serial && serial->driver && serial->driver->set_flow_control) {
  289. ret = serial->driver->set_flow_control(serial, termios->rtscts);
  290. }
  291. serial->rtscts = termios->rtscts;
  292. serial->rx_timeout_ms = termios->rx_timeout;
  293. ret = usbh_serial_tiocmset(serial, USBH_SERIAL_TIOCM_DTR | USBH_SERIAL_TIOCM_RTS, 0);
  294. if (ret < 0) {
  295. return ret;
  296. }
  297. usb_ringbuffer_reset(&serial->rx_rb);
  298. usb_osal_sem_reset(serial->rx_complete_sem);
  299. serial->rx_buf_index = 0;
  300. usbh_bulk_urb_fill(&serial->bulkin_urb, serial->hport, serial->bulkin, &serial->iobuffer[serial->rx_buf_index ? USBH_SERIAL_RX2_NOCACHE_OFFSET : USBH_SERIAL_RX_NOCACHE_OFFSET], serial->bulkin->wMaxPacketSize,
  301. 0, usbh_serial_callback, serial);
  302. ret = usbh_submit_urb(&serial->bulkin_urb);
  303. return ret;
  304. } break;
  305. case USBH_SERIAL_CMD_GET_ATTR: {
  306. struct usbh_serial_termios *termios = (struct usbh_serial_termios *)arg;
  307. struct cdc_line_coding line_coding;
  308. if (serial && serial->driver && serial->driver->get_line_coding) {
  309. return serial->driver->get_line_coding(serial, &line_coding);
  310. } else {
  311. memcpy(&line_coding, &serial->line_coding, sizeof(struct cdc_line_coding));
  312. }
  313. termios->baudrate = line_coding.dwDTERate;
  314. termios->stopbits = line_coding.bCharFormat;
  315. termios->parity = line_coding.bParityType;
  316. termios->databits = line_coding.bDataBits;
  317. termios->rtscts = serial->rtscts;
  318. termios->rx_timeout = serial->rx_timeout_ms;
  319. return 0;
  320. } break;
  321. case USBH_SERIAL_CMD_IOCMBIS: {
  322. uint32_t flags = *(uint32_t *)arg;
  323. return usbh_serial_tiocmset(serial, flags, 0);
  324. } break;
  325. case USBH_SERIAL_CMD_IOCMBIC: {
  326. uint32_t flags = *(uint32_t *)arg;
  327. return usbh_serial_tiocmset(serial, 0, flags);
  328. } break;
  329. case USBH_SERIAL_CMD_TIOCMSET: {
  330. uint32_t flags = *(uint32_t *)arg;
  331. uint32_t set = 0;
  332. uint32_t clear = 0;
  333. set |= (flags & USBH_SERIAL_TIOCM_DTR) ? USBH_SERIAL_TIOCM_DTR : 0;
  334. set |= (flags & USBH_SERIAL_TIOCM_RTS) ? USBH_SERIAL_TIOCM_RTS : 0;
  335. clear |= !(flags & USBH_SERIAL_TIOCM_DTR) ? USBH_SERIAL_TIOCM_DTR : 0;
  336. clear |= !(flags & USBH_SERIAL_TIOCM_RTS) ? USBH_SERIAL_TIOCM_RTS : 0;
  337. return usbh_serial_tiocmset(serial, set, clear);
  338. } break;
  339. case USBH_SERIAL_CMD_TIOCMGET: {
  340. uint32_t *flags = (uint32_t *)arg;
  341. int status;
  342. if (serial && serial->driver && serial->driver->get_modem_status) {
  343. status = serial->driver->get_modem_status(serial);
  344. if (status < 0) {
  345. return status;
  346. }
  347. } else {
  348. return -USB_ERR_NOTSUPP;
  349. }
  350. *flags = status;
  351. } break;
  352. default:
  353. break;
  354. }
  355. return -USB_ERR_NOTSUPP;
  356. }
  357. int usbh_serial_write(struct usbh_serial *serial, const void *buffer, uint32_t buflen)
  358. {
  359. int ret;
  360. struct usbh_urb *urb;
  361. if (!serial || !serial->hport || !serial->hport->connected || !serial->bulkout) {
  362. return -USB_ERR_INVAL;
  363. }
  364. if (serial->ref_count == 0) {
  365. return -USB_ERR_NODEV;
  366. }
  367. urb = &serial->bulkout_urb;
  368. usbh_bulk_urb_fill(urb, serial->hport, serial->bulkout, (uint8_t *)buffer, buflen, 0xffffffff, NULL, NULL);
  369. ret = usbh_submit_urb(urb);
  370. if (ret == 0) {
  371. ret = urb->actual_length;
  372. }
  373. return ret;
  374. }
  375. int usbh_serial_read(struct usbh_serial *serial, void *buffer, uint32_t buflen)
  376. {
  377. int ret;
  378. if (!serial || !serial->hport || !serial->hport->connected || !serial->bulkin || !serial->line_coding.dwDTERate) {
  379. return -USB_ERR_INVAL;
  380. }
  381. if (serial->ref_count == 0) {
  382. return -USB_ERR_NODEV;
  383. }
  384. if (serial->open_flags & USBH_SERIAL_O_NONBLOCK) {
  385. return usb_ringbuffer_read(&serial->rx_rb, buffer, buflen);
  386. } else {
  387. if (usb_ringbuffer_get_used(&serial->rx_rb) == 0) {
  388. ret = usb_osal_sem_take(serial->rx_complete_sem, serial->rx_timeout_ms == 0 ? USB_OSAL_WAITING_FOREVER : serial->rx_timeout_ms);
  389. if (ret < 0) {
  390. return ret;
  391. }
  392. if (serial->rx_errorcode < 0) {
  393. return serial->rx_errorcode;
  394. }
  395. }
  396. return usb_ringbuffer_read(&serial->rx_rb, buffer, buflen);
  397. }
  398. }
  399. int usbh_serial_cdc_write_async(struct usbh_serial *serial, uint8_t *buffer, uint32_t buflen, usbh_complete_callback_t complete, void *arg)
  400. {
  401. struct usbh_urb *urb;
  402. if (!serial || !serial->hport || !serial->hport->connected || !serial->bulkout || !complete || serial->line_coding.dwDTERate) {
  403. return -USB_ERR_INVAL;
  404. }
  405. if (serial->ref_count == 0) {
  406. return -USB_ERR_NODEV;
  407. }
  408. urb = &serial->bulkout_urb;
  409. usbh_bulk_urb_fill(urb, serial->hport, serial->bulkout, buffer, buflen,
  410. 0, complete, serial);
  411. return usbh_submit_urb(urb);
  412. }
  413. int usbh_serial_cdc_read_async(struct usbh_serial *serial, uint8_t *buffer, uint32_t buflen, usbh_complete_callback_t complete, void *arg)
  414. {
  415. struct usbh_urb *urb;
  416. if (!serial || !serial->hport || !serial->hport->connected || !serial->bulkin || !complete || serial->line_coding.dwDTERate) {
  417. return -USB_ERR_INVAL;
  418. }
  419. if (serial->ref_count == 0) {
  420. return -USB_ERR_NODEV;
  421. }
  422. if (buflen % serial->bulkin->wMaxPacketSize) {
  423. return -USB_ERR_INVAL;
  424. }
  425. urb = &serial->bulkin_urb;
  426. usbh_bulk_urb_fill(urb, serial->hport, serial->bulkin, buffer, MIN(buflen, serial->bulkin->wMaxPacketSize),
  427. 0, complete, serial);
  428. return usbh_submit_urb(urb);
  429. }
  430. void usbh_serial_help(void)
  431. {
  432. USB_LOG_RAW("USB host serial test\r\n"
  433. "Usage: usbh_serial <ttypath> [options]...\r\n"
  434. "\r\n"
  435. "-b <baud> set serial baudrate\r\n"
  436. "-t <dtr> <rts> set rts and dtr\r\n"
  437. "-w string write string\r\n"
  438. "-r read data and dump\r\n"
  439. "-x close serial device\r\n"
  440. "\r\n");
  441. }
  442. static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_serial_testbuffer[512];
  443. int usbh_serial(int argc, char **argv)
  444. {
  445. static struct usbh_serial *serial;
  446. int ret;
  447. if (argc < 3) {
  448. usbh_serial_help();
  449. return 0;
  450. }
  451. if (serial) {
  452. if (!serial->hport || !serial->hport->connected) {
  453. serial = NULL;
  454. }
  455. }
  456. if (!serial) {
  457. serial = usbh_serial_open(argv[1], USBH_SERIAL_O_RDWR | USBH_SERIAL_O_NONBLOCK);
  458. if (!serial) {
  459. USB_LOG_ERR("Fail to open serial device: %s\r\n", argv[1]);
  460. return -USB_ERR_INVAL;
  461. }
  462. }
  463. if (strncmp(argv[2], "-b", 2) == 0 && argc >= 4) {
  464. struct usbh_serial_termios termios;
  465. memset(&termios, 0, sizeof(termios));
  466. termios.baudrate = atoi(argv[3]);
  467. termios.stopbits = 0;
  468. termios.parity = 0;
  469. termios.databits = 8;
  470. termios.rtscts = false;
  471. termios.rx_timeout = 0;
  472. usbh_serial_control(serial, USBH_SERIAL_CMD_SET_ATTR, &termios);
  473. } else if (strncmp(argv[2], "-t", 2) == 0 && argc >= 5) {
  474. uint32_t flags;
  475. flags = atoi(argv[3]) ? USBH_SERIAL_TIOCM_DTR : 0;
  476. flags |= atoi(argv[4]) ? USBH_SERIAL_TIOCM_RTS : 0;
  477. usbh_serial_control(serial, USBH_SERIAL_CMD_TIOCMSET, &flags);
  478. USB_LOG_INFO("Set DTR: %d, RTS: %d\r\n", atoi(argv[3]), atoi(argv[4]));
  479. } else if (strncmp(argv[2], "-w", 2) == 0 && argc >= 4) {
  480. memcpy(g_serial_testbuffer, argv[3], MIN(strlen(argv[3]), sizeof(g_serial_testbuffer)));
  481. uint32_t len = snprintf((char *)g_serial_testbuffer, sizeof(g_serial_testbuffer), "%s\r\n", argv[3]);
  482. ret = usbh_serial_write(serial, g_serial_testbuffer, len);
  483. if (ret >= 0) {
  484. USB_LOG_INFO("Write %d bytes\r\n", ret);
  485. } else {
  486. USB_LOG_ERR("Write failed: %d\r\n", ret);
  487. }
  488. } else if (strncmp(argv[2], "-r", 2) == 0) {
  489. ret = usbh_serial_read(serial, g_serial_testbuffer, sizeof(g_serial_testbuffer));
  490. if (ret >= 0) {
  491. usb_hexdump(g_serial_testbuffer, ret);
  492. USB_LOG_INFO("Read %d bytes\r\n", ret);
  493. } else {
  494. USB_LOG_ERR("Read failed: %d\r\n", ret);
  495. }
  496. } else if (strncmp(argv[2], "-x", 2) == 0) {
  497. usbh_serial_close(serial);
  498. serial = NULL;
  499. } else {
  500. usbh_serial_help();
  501. }
  502. return 0;
  503. }
  504. __WEAK void usbh_serial_run(struct usbh_serial *serial)
  505. {
  506. (void)serial;
  507. }
  508. __WEAK void usbh_serial_stop(struct usbh_serial *serial)
  509. {
  510. (void)serial;
  511. }
  512. static int usbh_cdc_data_connect(struct usbh_hubport *hport, uint8_t intf)
  513. {
  514. (void)hport;
  515. (void)intf;
  516. return 0;
  517. }
  518. static int usbh_cdc_data_disconnect(struct usbh_hubport *hport, uint8_t intf)
  519. {
  520. (void)hport;
  521. (void)intf;
  522. return 0;
  523. }
  524. const struct usbh_class_driver cdc_data_class_driver = {
  525. .driver_name = "cdc_data",
  526. .connect = usbh_cdc_data_connect,
  527. .disconnect = usbh_cdc_data_disconnect
  528. };
  529. CLASS_INFO_DEFINE const struct usbh_class_info cdc_data_class_info = {
  530. .match_flags = USB_CLASS_MATCH_INTF_CLASS,
  531. .bInterfaceClass = USB_DEVICE_CLASS_CDC_DATA,
  532. .bInterfaceSubClass = 0x00,
  533. .bInterfaceProtocol = 0x00,
  534. .id_table = NULL,
  535. .class_driver = &cdc_data_class_driver
  536. };