usbh_ftdi.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. /*
  2. * Copyright (c) 2024 ~ 2025, sakumisu
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include "usbh_core.h"
  7. #include "usbh_serial.h"
  8. #include "usbh_ftdi.h"
  9. #undef USB_DBG_TAG
  10. #define USB_DBG_TAG "usbh_ftdi"
  11. #include "usb_log.h"
  12. enum ftdi_chip_type {
  13. SIO,
  14. FT232A,
  15. FT232B,
  16. FT2232C,
  17. FT232R,
  18. FT232H,
  19. FT2232H,
  20. FT4232H,
  21. FT4232HA,
  22. FT232HP,
  23. FT233HP,
  24. FT2232HP,
  25. FT2233HP,
  26. FT4232HP,
  27. FT4233HP,
  28. FTX,
  29. };
  30. static const char *ftdi_chip_name[] = {
  31. [SIO] = "SIO", /* the serial part of FT8U100AX */
  32. [FT232A] = "FT232A",
  33. [FT232B] = "FT232B",
  34. [FT2232C] = "FT2232C/D",
  35. [FT232R] = "FT232R",
  36. [FT232H] = "FT232H",
  37. [FT2232H] = "FT2232H",
  38. [FT4232H] = "FT4232H",
  39. [FT4232HA] = "FT4232HA",
  40. [FT232HP] = "FT232HP",
  41. [FT233HP] = "FT233HP",
  42. [FT2232HP] = "FT2232HP",
  43. [FT2233HP] = "FT2233HP",
  44. [FT4232HP] = "FT4232HP",
  45. [FT4233HP] = "FT4233HP",
  46. [FTX] = "FT-X",
  47. };
  48. struct usbh_ftdi {
  49. enum ftdi_chip_type chip_type;
  50. };
  51. static uint32_t ftdi_232bm_baud_base_to_divisor(uint32_t baud, int base)
  52. {
  53. static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 };
  54. uint32_t divisor;
  55. /* divisor shifted 3 bits to the left */
  56. int divisor3 = DIV_ROUND_CLOSEST(base, 2 * baud);
  57. divisor = divisor3 >> 3;
  58. divisor |= (uint32_t)divfrac[divisor3 & 0x7] << 14;
  59. /* Deal with special cases for highest baud rates. */
  60. if (divisor == 1) /* 1.0 */
  61. divisor = 0;
  62. else if (divisor == 0x4001) /* 1.5 */
  63. divisor = 1;
  64. return divisor;
  65. }
  66. static uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud)
  67. {
  68. return ftdi_232bm_baud_base_to_divisor(baud, 48000000);
  69. }
  70. static uint32_t ftdi_2232h_baud_base_to_divisor(uint32_t baud, int base)
  71. {
  72. static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 };
  73. uint32_t divisor;
  74. int divisor3;
  75. /* hi-speed baud rate is 10-bit sampling instead of 16-bit */
  76. divisor3 = DIV_ROUND_CLOSEST(8 * base, 10 * baud);
  77. divisor = divisor3 >> 3;
  78. divisor |= (uint32_t)divfrac[divisor3 & 0x7] << 14;
  79. /* Deal with special cases for highest baud rates. */
  80. if (divisor == 1) /* 1.0 */
  81. divisor = 0;
  82. else if (divisor == 0x4001) /* 1.5 */
  83. divisor = 1;
  84. /*
  85. * Set this bit to turn off a divide by 2.5 on baud rate generator
  86. * This enables baud rates up to 12Mbaud but cannot reach below 1200
  87. * baud with this bit set
  88. */
  89. divisor |= 0x00020000;
  90. return divisor;
  91. }
  92. static uint32_t ftdi_2232h_baud_to_divisor(uint32_t baud)
  93. {
  94. return ftdi_2232h_baud_base_to_divisor(baud, 120000000);
  95. }
  96. int usbh_ftdi_reset(struct usbh_serial *serial)
  97. {
  98. struct usb_setup_packet *setup;
  99. if (!serial || !serial->hport) {
  100. return -USB_ERR_INVAL;
  101. }
  102. setup = serial->hport->setup;
  103. setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
  104. setup->bRequest = FTDI_SIO_RESET;
  105. setup->wValue = 0;
  106. setup->wIndex = serial->intf;
  107. setup->wLength = 0;
  108. return usbh_control_transfer(serial->hport, setup, NULL);
  109. }
  110. static int usbh_ftdi_set_baudrate(struct usbh_serial *serial, uint32_t baudrate)
  111. {
  112. struct usb_setup_packet *setup;
  113. struct usbh_ftdi *ftdi_class;
  114. uint32_t div_value;
  115. uint16_t value;
  116. uint8_t baudrate_high;
  117. if (!serial || !serial->hport || !serial->priv) {
  118. return -USB_ERR_INVAL;
  119. }
  120. setup = serial->hport->setup;
  121. ftdi_class = (struct usbh_ftdi *)serial->priv;
  122. switch (ftdi_class->chip_type) {
  123. case FT232B:
  124. case FT2232C:
  125. case FT232R:
  126. if (baudrate > 3000000) {
  127. return -USB_ERR_INVAL;
  128. }
  129. div_value = ftdi_232bm_baud_to_divisor(baudrate);
  130. break;
  131. default:
  132. if ((baudrate <= 12000000) && (baudrate >= 1200)) {
  133. div_value = ftdi_2232h_baud_to_divisor(baudrate);
  134. } else if (baudrate < 1200) {
  135. div_value = ftdi_232bm_baud_to_divisor(baudrate);
  136. } else {
  137. return -USB_ERR_INVAL;
  138. }
  139. break;
  140. }
  141. value = div_value & 0xFFFF;
  142. baudrate_high = (div_value >> 16) & 0xff;
  143. setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
  144. setup->bRequest = FTDI_SIO_SET_BAUDRATE;
  145. setup->wValue = value;
  146. setup->wIndex = (baudrate_high << 8) | serial->intf;
  147. setup->wLength = 0;
  148. return usbh_control_transfer(serial->hport, setup, NULL);
  149. }
  150. static int usbh_ftdi_set_data_format(struct usbh_serial *serial, uint8_t databits, uint8_t parity, uint8_t stopbits, uint8_t isbreak)
  151. {
  152. /**
  153. * D0-D7 databits BITS_7=7, BITS_8=8
  154. * D8-D10 parity NONE=0, ODD=1, EVEN=2, MARK=3, SPACE=4
  155. * D11-D12 STOP_BIT_1=0, STOP_BIT_15=1, STOP_BIT_2=2
  156. * D14 BREAK_OFF=0, BREAK_ON=1
  157. **/
  158. struct usb_setup_packet *setup;
  159. uint16_t value;
  160. if (!serial || !serial->hport) {
  161. return -USB_ERR_INVAL;
  162. }
  163. setup = serial->hport->setup;
  164. value = ((isbreak & 0x01) << 14) | ((stopbits & 0x03) << 11) | ((parity & 0x0f) << 8) | (databits & 0x0f);
  165. setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
  166. setup->bRequest = FTDI_SIO_SET_DATA;
  167. setup->wValue = value;
  168. setup->wIndex = serial->intf;
  169. setup->wLength = 0;
  170. return usbh_control_transfer(serial->hport, setup, NULL);
  171. }
  172. static int usbh_ftdi_set_latency_timer(struct usbh_serial *serial, uint16_t value)
  173. {
  174. struct usb_setup_packet *setup;
  175. if (!serial || !serial->hport) {
  176. return -USB_ERR_INVAL;
  177. }
  178. setup = serial->hport->setup;
  179. setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
  180. setup->bRequest = FTDI_SIO_SET_LATENCY_TIMER;
  181. setup->wValue = value;
  182. setup->wIndex = serial->intf;
  183. setup->wLength = 0;
  184. return usbh_control_transfer(serial->hport, setup, NULL);
  185. }
  186. static int usbh_ftdi_attach(struct usbh_serial *serial)
  187. {
  188. uint16_t version;
  189. uint8_t chip_type;
  190. int ret;
  191. version = serial->hport->device_desc.bcdDevice;
  192. switch (version) {
  193. case 0x400:
  194. chip_type = FT232B;
  195. break;
  196. case 0x500:
  197. chip_type = FT2232C;
  198. break;
  199. case 0x600:
  200. chip_type = FT232R;
  201. break;
  202. case 0x700:
  203. chip_type = FT2232H;
  204. break;
  205. case 0x900:
  206. chip_type = FT232H;
  207. break;
  208. default:
  209. USB_LOG_ERR("Unsupported FTDI chip version: 0x%04x\r\n", version);
  210. return -USB_ERR_NOTSUPP;
  211. }
  212. USB_LOG_INFO("chip name: %s\r\n", ftdi_chip_name[chip_type]);
  213. struct usbh_ftdi *ftdi_class = usb_osal_malloc(sizeof(struct usbh_ftdi));
  214. if (!ftdi_class) {
  215. USB_LOG_ERR("No memory for ftdi_class\r\n");
  216. return -USB_ERR_NOMEM;
  217. }
  218. memset(ftdi_class, 0, sizeof(struct usbh_ftdi));
  219. serial->priv = ftdi_class;
  220. ftdi_class->chip_type = chip_type;
  221. ret = usbh_ftdi_set_latency_timer(serial, 0x10);
  222. if (ret < 0) {
  223. goto errout;
  224. }
  225. return 0;
  226. errout:
  227. serial->priv = NULL;
  228. usb_osal_free(ftdi_class);
  229. return ret;
  230. }
  231. static void usbh_ftdi_detach(struct usbh_serial *serial)
  232. {
  233. if (serial && serial->priv) {
  234. serial->priv = NULL;
  235. usb_osal_free(serial->priv);
  236. }
  237. }
  238. static int usbh_ftdi_set_flow_ctrl(struct usbh_serial *serial, bool hardctrl)
  239. {
  240. struct usb_setup_packet *setup;
  241. if (!serial || !serial->hport) {
  242. return -USB_ERR_INVAL;
  243. }
  244. setup = serial->hport->setup;
  245. setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
  246. setup->bRequest = FTDI_SIO_SET_FLOW_CTRL;
  247. setup->wValue = hardctrl ? FTDI_SIO_RTS_CTS_HS : FTDI_SIO_DISABLE_FLOW_CTRL;
  248. setup->wIndex = serial->intf;
  249. setup->wLength = 0;
  250. return usbh_control_transfer(serial->hport, setup, NULL);
  251. }
  252. static int usbh_ftdi_set_line_coding(struct usbh_serial *serial, struct cdc_line_coding *line_coding)
  253. {
  254. int ret = usbh_ftdi_set_baudrate(serial, line_coding->dwDTERate);
  255. if (ret < 0) {
  256. return ret;
  257. }
  258. return usbh_ftdi_set_data_format(serial, line_coding->bDataBits, line_coding->bParityType, line_coding->bCharFormat, 0);
  259. }
  260. static int usbh_ftdi_set_line_state(struct usbh_serial *serial, bool dtr, bool rts)
  261. {
  262. struct usb_setup_packet *setup;
  263. uint16_t value = 0;
  264. if (!serial || !serial->hport) {
  265. return -USB_ERR_INVAL;
  266. }
  267. setup = serial->hport->setup;
  268. value = ((dtr ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW) | (rts ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW));
  269. setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
  270. setup->bRequest = FTDI_SIO_SET_MODEM_CTRL;
  271. setup->wValue = value;
  272. setup->wIndex = serial->intf;
  273. setup->wLength = 0;
  274. return usbh_control_transfer(serial->hport, setup, NULL);
  275. }
  276. static int usbh_ftdi_get_modem_status(struct usbh_serial *serial)
  277. {
  278. struct usb_setup_packet *setup;
  279. uint16_t status = 0;
  280. int ret;
  281. if (!serial || !serial->hport) {
  282. return -USB_ERR_INVAL;
  283. }
  284. setup = serial->hport->setup;
  285. setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
  286. setup->bRequest = FTDI_SIO_GET_MODEM_STATUS;
  287. setup->wValue = 0x0000;
  288. setup->wIndex = serial->intf;
  289. setup->wLength = 2;
  290. ret = usbh_control_transfer(serial->hport, setup, serial->iobuffer);
  291. if (ret < 0) {
  292. return 0;
  293. }
  294. status = (serial->iobuffer[0] & FTDI_SIO_DSR_MASK ? USBH_SERIAL_TIOCM_DSR : 0) |
  295. (serial->iobuffer[0] & FTDI_SIO_CTS_MASK ? USBH_SERIAL_TIOCM_CTS : 0) |
  296. (serial->iobuffer[0] & FTDI_SIO_RI_MASK ? USBH_SERIAL_TIOCM_RI : 0) |
  297. (serial->iobuffer[0] & FTDI_SIO_RLSD_MASK ? USBH_SERIAL_TIOCM_CD : 0) |
  298. (serial->line_state & USBH_SERIAL_TIOCM_DTR ? USBH_SERIAL_TIOCM_DTR : 0) |
  299. (serial->line_state & USBH_SERIAL_TIOCM_RTS ? USBH_SERIAL_TIOCM_RTS : 0);
  300. return status;
  301. }
  302. static const struct usbh_serial_driver ftdi_driver = {
  303. .driver_name = "ftdi",
  304. .ignore_rx_header = 2,
  305. .ignore_tx_header = 0,
  306. .attach = usbh_ftdi_attach,
  307. .detach = usbh_ftdi_detach,
  308. .set_flow_control = usbh_ftdi_set_flow_ctrl,
  309. .set_line_coding = usbh_ftdi_set_line_coding,
  310. .get_line_coding = NULL,
  311. .set_line_state = usbh_ftdi_set_line_state,
  312. .get_modem_status = usbh_ftdi_get_modem_status,
  313. };
  314. static int usbh_ftdi_connect(struct usbh_hubport *hport, uint8_t intf)
  315. {
  316. return usbh_serial_probe(hport, intf, &ftdi_driver) ? 0 : -USB_ERR_NOMEM;
  317. }
  318. static int usbh_ftdi_disconnect(struct usbh_hubport *hport, uint8_t intf)
  319. {
  320. struct usbh_serial *serial = (struct usbh_serial *)hport->config.intf[intf].priv;
  321. if (serial) {
  322. usbh_serial_remove(serial);
  323. }
  324. return 0;
  325. }
  326. static const uint16_t ftdi_id_table[][2] = {
  327. { 0x0403, 0x6001 },
  328. { 0x0403, 0x6010 },
  329. { 0x0403, 0x6014 },
  330. { 0, 0 },
  331. };
  332. const struct usbh_class_driver ftdi_class_driver = {
  333. .driver_name = "ftdi",
  334. .connect = usbh_ftdi_connect,
  335. .disconnect = usbh_ftdi_disconnect
  336. };
  337. CLASS_INFO_DEFINE const struct usbh_class_info ftdi_class_info = {
  338. .match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
  339. .bInterfaceClass = 0xff,
  340. .bInterfaceSubClass = 0x00,
  341. .bInterfaceProtocol = 0x00,
  342. .id_table = ftdi_id_table,
  343. .class_driver = &ftdi_class_driver
  344. };