usbh_ch34x.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. /*
  2. * Copyright (c) 2024, sakumisu
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include "usbh_core.h"
  7. #include "usbh_ch34x.h"
  8. #define DEV_FORMAT "/dev/ttyUSB%d"
  9. USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_ch34x_buf[64];
  10. #define CONFIG_USBHOST_MAX_CP210X_CLASS 1
  11. static struct usbh_ch34x g_ch34x_class[CONFIG_USBHOST_MAX_CP210X_CLASS];
  12. static uint32_t g_devinuse = 0;
  13. static struct usbh_ch34x *usbh_ch34x_class_alloc(void)
  14. {
  15. int devno;
  16. for (devno = 0; devno < CONFIG_USBHOST_MAX_CP210X_CLASS; devno++) {
  17. if ((g_devinuse & (1 << devno)) == 0) {
  18. g_devinuse |= (1 << devno);
  19. memset(&g_ch34x_class[devno], 0, sizeof(struct usbh_ch34x));
  20. g_ch34x_class[devno].minor = devno;
  21. return &g_ch34x_class[devno];
  22. }
  23. }
  24. return NULL;
  25. }
  26. static void usbh_ch34x_class_free(struct usbh_ch34x *ch34x_class)
  27. {
  28. int devno = ch34x_class->minor;
  29. if (devno >= 0 && devno < 32) {
  30. g_devinuse &= ~(1 << devno);
  31. }
  32. memset(ch34x_class, 0, sizeof(struct usbh_ch34x));
  33. }
  34. static int usbh_ch34x_get_baudrate_div(uint32_t baudrate, uint8_t *factor, uint8_t *divisor)
  35. {
  36. uint8_t a;
  37. uint8_t b;
  38. uint32_t c;
  39. switch (baudrate) {
  40. case 921600:
  41. a = 0xf3;
  42. b = 7;
  43. break;
  44. case 307200:
  45. a = 0xd9;
  46. b = 7;
  47. break;
  48. default:
  49. if (baudrate > 6000000 / 255) {
  50. b = 3;
  51. c = 6000000;
  52. } else if (baudrate > 750000 / 255) {
  53. b = 2;
  54. c = 750000;
  55. } else if (baudrate > 93750 / 255) {
  56. b = 1;
  57. c = 93750;
  58. } else {
  59. b = 0;
  60. c = 11719;
  61. }
  62. a = (uint8_t)(c / baudrate);
  63. if (a == 0 || a == 0xFF) {
  64. return -USB_ERR_INVAL;
  65. }
  66. if ((c / a - baudrate) > (baudrate - c / (a + 1))) {
  67. a++;
  68. }
  69. a = (uint8_t)(256 - a);
  70. break;
  71. }
  72. *factor = a;
  73. *divisor = b;
  74. return 0;
  75. }
  76. static int usbh_ch34x_get_version(struct usbh_ch34x *ch34x_class)
  77. {
  78. struct usb_setup_packet *setup;
  79. int ret;
  80. if (!ch34x_class || !ch34x_class->hport) {
  81. return -USB_ERR_INVAL;
  82. }
  83. setup = ch34x_class->hport->setup;
  84. setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
  85. setup->bRequest = CH34X_READ_VERSION;
  86. setup->wValue = 0;
  87. setup->wIndex = 0;
  88. setup->wLength = 2;
  89. ret = usbh_control_transfer(ch34x_class->hport, setup, g_ch34x_buf);
  90. if (ret < 0) {
  91. return ret;
  92. }
  93. USB_LOG_INFO("Ch34x chip version %02x:%02x\r\n", g_ch34x_buf[0], g_ch34x_buf[1]);
  94. return ret;
  95. }
  96. static int usbh_ch34x_flow_ctrl(struct usbh_ch34x *ch34x_class)
  97. {
  98. struct usb_setup_packet *setup;
  99. if (!ch34x_class || !ch34x_class->hport) {
  100. return -USB_ERR_INVAL;
  101. }
  102. setup = ch34x_class->hport->setup;
  103. setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
  104. setup->bRequest = CH34X_WRITE_REG;
  105. setup->wValue = 0x2727;
  106. setup->wIndex = 0;
  107. setup->wLength = 0;
  108. return usbh_control_transfer(ch34x_class->hport, setup, NULL);
  109. }
  110. int usbh_ch34x_set_line_coding(struct usbh_ch34x *ch34x_class, struct cdc_line_coding *line_coding)
  111. {
  112. struct usb_setup_packet *setup;
  113. uint16_t reg_value = 0;
  114. uint16_t value = 0;
  115. uint8_t factor = 0;
  116. uint8_t divisor = 0;
  117. if (!ch34x_class || !ch34x_class->hport) {
  118. return -USB_ERR_INVAL;
  119. }
  120. setup = ch34x_class->hport->setup;
  121. memcpy((uint8_t *)&ch34x_class->line_coding, line_coding, sizeof(struct cdc_line_coding));
  122. /* refer to https://github.com/WCHSoftGroup/ch341ser_linux/blob/main/driver/ch341.c */
  123. switch (line_coding->bParityType) {
  124. case 0:
  125. break;
  126. case 1:
  127. reg_value |= CH341_L_PO;
  128. break;
  129. case 2:
  130. reg_value |= CH341_L_PE;
  131. break;
  132. case 3:
  133. reg_value |= CH341_L_PM;
  134. break;
  135. case 4:
  136. reg_value |= CH341_L_PS;
  137. break;
  138. default:
  139. return -USB_ERR_INVAL;
  140. }
  141. switch (line_coding->bDataBits) {
  142. case 5:
  143. reg_value |= CH341_L_D5;
  144. break;
  145. case 6:
  146. reg_value |= CH341_L_D6;
  147. break;
  148. case 7:
  149. reg_value |= CH341_L_D7;
  150. break;
  151. case 8:
  152. reg_value |= CH341_L_D8;
  153. break;
  154. default:
  155. return -USB_ERR_INVAL;
  156. }
  157. if (line_coding->bCharFormat == 2) {
  158. reg_value |= CH341_L_SB;
  159. }
  160. reg_value |= 0xC0;
  161. value |= 0x9c;
  162. value |= reg_value << 8;
  163. usbh_ch34x_get_baudrate_div(line_coding->dwDTERate, &factor, &divisor);
  164. setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
  165. setup->bRequest = CH34X_SERIAL_INIT;
  166. setup->wValue = value;
  167. setup->wIndex = (factor << 8) | 0x80 | divisor;
  168. setup->wLength = 0;
  169. return usbh_control_transfer(ch34x_class->hport, setup, NULL);
  170. }
  171. int usbh_ch34x_get_line_coding(struct usbh_ch34x *ch34x_class, struct cdc_line_coding *line_coding)
  172. {
  173. memcpy(line_coding, (uint8_t *)&ch34x_class->line_coding, sizeof(struct cdc_line_coding));
  174. return 0;
  175. }
  176. int usbh_ch34x_set_line_state(struct usbh_ch34x *ch34x_class, bool dtr, bool rts)
  177. {
  178. struct usb_setup_packet *setup;
  179. if (!ch34x_class || !ch34x_class->hport) {
  180. return -USB_ERR_INVAL;
  181. }
  182. setup = ch34x_class->hport->setup;
  183. setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
  184. setup->bRequest = CH34X_MODEM_CTRL;
  185. setup->wValue = 0x0f | (dtr << 5) | (rts << 6);
  186. setup->wIndex = 0;
  187. setup->wLength = 0;
  188. return usbh_control_transfer(ch34x_class->hport, setup, NULL);
  189. }
  190. static int usbh_ch34x_connect(struct usbh_hubport *hport, uint8_t intf)
  191. {
  192. struct usb_endpoint_descriptor *ep_desc;
  193. int ret = 0;
  194. struct usbh_ch34x *ch34x_class = usbh_ch34x_class_alloc();
  195. if (ch34x_class == NULL) {
  196. USB_LOG_ERR("Fail to alloc ch34x_class\r\n");
  197. return -USB_ERR_NOMEM;
  198. }
  199. ch34x_class->hport = hport;
  200. ch34x_class->intf = intf;
  201. hport->config.intf[intf].priv = ch34x_class;
  202. usbh_ch34x_get_version(ch34x_class);
  203. usbh_ch34x_flow_ctrl(ch34x_class);
  204. for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
  205. ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
  206. if (USB_GET_ENDPOINT_TYPE(ep_desc->bmAttributes) == USB_ENDPOINT_TYPE_INTERRUPT) {
  207. continue;
  208. } else {
  209. if (ep_desc->bEndpointAddress & 0x80) {
  210. USBH_EP_INIT(ch34x_class->bulkin, ep_desc);
  211. } else {
  212. USBH_EP_INIT(ch34x_class->bulkout, ep_desc);
  213. }
  214. }
  215. }
  216. snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, ch34x_class->minor);
  217. USB_LOG_INFO("Register CH34X Class:%s\r\n", hport->config.intf[intf].devname);
  218. #if 0
  219. USB_LOG_INFO("Test ch34x rx and tx and rx for 5 times, baudrate is 115200\r\n");
  220. struct cdc_line_coding linecoding;
  221. uint8_t count = 5;
  222. linecoding.dwDTERate = 115200;
  223. linecoding.bDataBits = 8;
  224. linecoding.bParityType = 0;
  225. linecoding.bCharFormat = 0;
  226. usbh_ch34x_set_line_coding(ch34x_class, &linecoding);
  227. usbh_ch34x_set_line_state(ch34x_class, true, false);
  228. memset(g_ch34x_buf, 'a', sizeof(g_ch34x_buf));
  229. ret = usbh_ch34x_bulk_out_transfer(ch34x_class, g_ch34x_buf, sizeof(g_ch34x_buf), 0xfffffff);
  230. USB_LOG_RAW("out ret:%d\r\n", ret);
  231. while (count--) {
  232. ret = usbh_ch34x_bulk_in_transfer(ch34x_class, g_ch34x_buf, sizeof(g_ch34x_buf), 0xfffffff);
  233. USB_LOG_RAW("in ret:%d\r\n", ret);
  234. if (ret > 0) {
  235. for (uint32_t i = 0; i < ret; i++) {
  236. USB_LOG_RAW("%02x ", g_ch34x_buf[i]);
  237. }
  238. USB_LOG_RAW("\r\n");
  239. }
  240. }
  241. #endif
  242. usbh_ch34x_run(ch34x_class);
  243. return ret;
  244. }
  245. static int usbh_ch34x_disconnect(struct usbh_hubport *hport, uint8_t intf)
  246. {
  247. int ret = 0;
  248. struct usbh_ch34x *ch34x_class = (struct usbh_ch34x *)hport->config.intf[intf].priv;
  249. if (ch34x_class) {
  250. if (ch34x_class->bulkin) {
  251. usbh_kill_urb(&ch34x_class->bulkin_urb);
  252. }
  253. if (ch34x_class->bulkout) {
  254. usbh_kill_urb(&ch34x_class->bulkout_urb);
  255. }
  256. if (hport->config.intf[intf].devname[0] != '\0') {
  257. USB_LOG_INFO("Unregister CH34X Class:%s\r\n", hport->config.intf[intf].devname);
  258. usbh_ch34x_stop(ch34x_class);
  259. }
  260. usbh_ch34x_class_free(ch34x_class);
  261. }
  262. return ret;
  263. }
  264. int usbh_ch34x_bulk_in_transfer(struct usbh_ch34x *ch34x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
  265. {
  266. int ret;
  267. struct usbh_urb *urb = &ch34x_class->bulkin_urb;
  268. usbh_bulk_urb_fill(urb, ch34x_class->hport, ch34x_class->bulkin, buffer, buflen, timeout, NULL, NULL);
  269. ret = usbh_submit_urb(urb);
  270. if (ret == 0) {
  271. ret = urb->actual_length;
  272. }
  273. return ret;
  274. }
  275. int usbh_ch34x_bulk_out_transfer(struct usbh_ch34x *ch34x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
  276. {
  277. int ret;
  278. struct usbh_urb *urb = &ch34x_class->bulkout_urb;
  279. usbh_bulk_urb_fill(urb, ch34x_class->hport, ch34x_class->bulkout, buffer, buflen, timeout, NULL, NULL);
  280. ret = usbh_submit_urb(urb);
  281. if (ret == 0) {
  282. ret = urb->actual_length;
  283. }
  284. return ret;
  285. }
  286. __WEAK void usbh_ch34x_run(struct usbh_ch34x *ch34x_class)
  287. {
  288. (void)ch34x_class;
  289. }
  290. __WEAK void usbh_ch34x_stop(struct usbh_ch34x *ch34x_class)
  291. {
  292. (void)ch34x_class;
  293. }
  294. static const uint16_t ch34x_id_table[][2] = {
  295. { 0x1A86, 0x7523 },
  296. { 0, 0 },
  297. };
  298. const struct usbh_class_driver ch34x_class_driver = {
  299. .driver_name = "ch34x",
  300. .connect = usbh_ch34x_connect,
  301. .disconnect = usbh_ch34x_disconnect
  302. };
  303. CLASS_INFO_DEFINE const struct usbh_class_info ch34x_class_info = {
  304. .match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
  305. .class = 0xff,
  306. .subclass = 0x00,
  307. .protocol = 0x00,
  308. .id_table = ch34x_id_table,
  309. .class_driver = &ch34x_class_driver
  310. };