From 5897edffedce7cf96a77fba7bec0187488a1b9ad Mon Sep 17 00:00:00 2001 From: sakumisu <1203593632@qq.com> Date: Sat, 3 Feb 2024 16:53:28 +0800 Subject: [PATCH] make serial driver standard for cdc acm, ftdi, cp210x, ch34x --- class/cdc/usbh_cdc_acm.c | 68 +++---- class/cdc/usbh_cdc_acm.h | 12 +- class/vendor/usbh_ch34x.c | 352 +++++++++++++++++++++++++++++++++++++ class/vendor/usbh_ch34x.h | 74 ++++++++ class/vendor/usbh_cp210x.c | 291 ++++++++++++++++++++++++++++++ class/vendor/usbh_cp210x.h | 71 ++++++++ class/vendor/usbh_ftdi.c | 148 ++++++++++------ class/vendor/usbh_ftdi.h | 17 +- 8 files changed, 926 insertions(+), 107 deletions(-) create mode 100644 class/vendor/usbh_ch34x.c create mode 100644 class/vendor/usbh_ch34x.h create mode 100644 class/vendor/usbh_cp210x.c create mode 100644 class/vendor/usbh_cp210x.h diff --git a/class/cdc/usbh_cdc_acm.c b/class/cdc/usbh_cdc_acm.c index d11e14e2..0f472c2a 100644 --- a/class/cdc/usbh_cdc_acm.c +++ b/class/cdc/usbh_cdc_acm.c @@ -12,7 +12,7 @@ #define DEV_FORMAT "/dev/ttyACM%d" -USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX struct cdc_line_coding g_cdc_line_coding; +USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_acm_buf[64]; static struct usbh_cdc_acm g_cdc_acm_class[CONFIG_USBHOST_MAX_CDC_ACM_CLASS]; static uint32_t g_devinuse = 0; @@ -49,12 +49,12 @@ int usbh_cdc_acm_set_line_coding(struct usbh_cdc_acm *cdc_acm_class, struct cdc_ setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE; setup->bRequest = CDC_REQUEST_SET_LINE_CODING; setup->wValue = 0; - setup->wIndex = cdc_acm_class->ctrl_intf; + setup->wIndex = cdc_acm_class->intf; setup->wLength = 7; - memcpy((uint8_t *)&g_cdc_line_coding, line_coding, sizeof(struct cdc_line_coding)); + memcpy(g_cdc_acm_buf, line_coding, sizeof(struct cdc_line_coding)); - return usbh_control_transfer(cdc_acm_class->hport, setup, (uint8_t *)&g_cdc_line_coding); + return usbh_control_transfer(cdc_acm_class->hport, setup, g_cdc_acm_buf); } int usbh_cdc_acm_get_line_coding(struct usbh_cdc_acm *cdc_acm_class, struct cdc_line_coding *line_coding) @@ -65,14 +65,14 @@ int usbh_cdc_acm_get_line_coding(struct usbh_cdc_acm *cdc_acm_class, struct cdc_ setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE; setup->bRequest = CDC_REQUEST_GET_LINE_CODING; setup->wValue = 0; - setup->wIndex = cdc_acm_class->ctrl_intf; + setup->wIndex = cdc_acm_class->intf; setup->wLength = 7; - ret = usbh_control_transfer(cdc_acm_class->hport, setup, (uint8_t *)&g_cdc_line_coding); + ret = usbh_control_transfer(cdc_acm_class->hport, setup, g_cdc_acm_buf); if (ret < 0) { return ret; } - memcpy(line_coding, (uint8_t *)&g_cdc_line_coding, sizeof(struct cdc_line_coding)); + memcpy(line_coding, g_cdc_acm_buf, sizeof(struct cdc_line_coding)); return ret; } @@ -83,19 +83,16 @@ int usbh_cdc_acm_set_line_state(struct usbh_cdc_acm *cdc_acm_class, bool dtr, bo setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE; setup->bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE; setup->wValue = (dtr << 0) | (rts << 1); - setup->wIndex = cdc_acm_class->ctrl_intf; + setup->wIndex = cdc_acm_class->intf; setup->wLength = 0; - cdc_acm_class->dtr = dtr; - cdc_acm_class->rts = rts; - return usbh_control_transfer(cdc_acm_class->hport, setup, NULL); } static int usbh_cdc_acm_connect(struct usbh_hubport *hport, uint8_t intf) { struct usb_endpoint_descriptor *ep_desc; - int ret; + int ret = 0; struct usbh_cdc_acm *cdc_acm_class = usbh_cdc_acm_class_alloc(); if (cdc_acm_class == NULL) { @@ -104,28 +101,11 @@ static int usbh_cdc_acm_connect(struct usbh_hubport *hport, uint8_t intf) } cdc_acm_class->hport = hport; - cdc_acm_class->ctrl_intf = intf; - cdc_acm_class->data_intf = intf + 1; + cdc_acm_class->intf = intf; hport->config.intf[intf].priv = cdc_acm_class; hport->config.intf[intf + 1].priv = NULL; - cdc_acm_class->linecoding.dwDTERate = 115200; - cdc_acm_class->linecoding.bDataBits = 8; - cdc_acm_class->linecoding.bParityType = 0; - cdc_acm_class->linecoding.bCharFormat = 0; - ret = usbh_cdc_acm_set_line_coding(cdc_acm_class, &cdc_acm_class->linecoding); - if (ret < 0) { - USB_LOG_ERR("Fail to set linecoding\r\n"); - return ret; - } - - ret = usbh_cdc_acm_set_line_state(cdc_acm_class, true, true); - if (ret < 0) { - USB_LOG_ERR("Fail to set line state\r\n"); - return ret; - } - #ifdef CONFIG_USBHOST_CDC_ACM_NOTIFY ep_desc = &hport->config.intf[intf].altsetting[0].ep[0].ep_desc; USBH_EP_INIT(cdc_acm_class->intin, ep_desc); @@ -144,6 +124,34 @@ static int usbh_cdc_acm_connect(struct usbh_hubport *hport, uint8_t intf) USB_LOG_INFO("Register CDC ACM Class:%s\r\n", hport->config.intf[intf].devname); +#if 0 + USB_LOG_INFO("Test cdc acm rx and tx and rx for 5 times, baudrate is 115200\r\n"); + + struct cdc_line_coding linecoding; + uint8_t count = 5; + + linecoding.dwDTERate = 115200; + linecoding.bDataBits = 8; + linecoding.bParityType = 0; + linecoding.bCharFormat = 0; + usbh_cdc_acm_set_line_coding(cdc_acm_class, &linecoding); + usbh_cdc_acm_set_line_state(cdc_acm_class, true, false); + + memset(g_cdc_acm_buf, 'a', sizeof(g_cdc_acm_buf)); + ret = usbh_cdc_acm_bulk_out_transfer(cdc_acm_class, g_cdc_acm_buf, sizeof(g_cdc_acm_buf), 0xfffffff); + USB_LOG_RAW("out ret:%d\r\n", ret); + while (count--) { + ret = usbh_cdc_acm_bulk_in_transfer(cdc_acm_class, g_cdc_acm_buf, sizeof(g_cdc_acm_buf), 0xfffffff); + USB_LOG_RAW("in ret:%d\r\n", ret); + if (ret > 0) { + for (uint32_t i = 0; i < ret; i++) { + USB_LOG_RAW("%02x ", g_cdc_acm_buf[i]); + } + } + USB_LOG_RAW("\r\n"); + } +#endif + usbh_cdc_acm_run(cdc_acm_class); return ret; } diff --git a/class/cdc/usbh_cdc_acm.h b/class/cdc/usbh_cdc_acm.h index f06b0ab3..ac6f191c 100644 --- a/class/cdc/usbh_cdc_acm.h +++ b/class/cdc/usbh_cdc_acm.h @@ -12,16 +12,18 @@ struct usbh_cdc_acm { struct usbh_hubport *hport; struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */ struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */ - struct usb_endpoint_descriptor *intin; /* INTR IN endpoint (optional) */ +#ifdef CONFIG_USBHOST_CDC_ACM_NOTIFY + struct usb_endpoint_descriptor *intin; /* INTR IN endpoint (optional) */ +#endif struct usbh_urb bulkout_urb; struct usbh_urb bulkin_urb; +#ifdef CONFIG_USBHOST_CDC_ACM_NOTIFY struct usbh_urb intin_urb; +#endif struct cdc_line_coding linecoding; - uint8_t ctrl_intf; /* Control interface number */ - uint8_t data_intf; /* Data interface number */ - bool dtr; - bool rts; + + uint8_t intf; uint8_t minor; }; diff --git a/class/vendor/usbh_ch34x.c b/class/vendor/usbh_ch34x.c new file mode 100644 index 00000000..9f905270 --- /dev/null +++ b/class/vendor/usbh_ch34x.c @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2022, sakumisu + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "usbh_core.h" +#include "usbh_ch34x.h" + +#define DEV_FORMAT "/dev/ttyUSB%d" + +USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_ch34x_buf[64]; + +#define CONFIG_USBHOST_MAX_CP210X_CLASS 1 + +static struct usbh_ch34x g_ch34x_class[CONFIG_USBHOST_MAX_CP210X_CLASS]; +static uint32_t g_devinuse = 0; + +static struct usbh_ch34x *usbh_ch34x_class_alloc(void) +{ + int devno; + + for (devno = 0; devno < CONFIG_USBHOST_MAX_CP210X_CLASS; devno++) { + if ((g_devinuse & (1 << devno)) == 0) { + g_devinuse |= (1 << devno); + memset(&g_ch34x_class[devno], 0, sizeof(struct usbh_ch34x)); + g_ch34x_class[devno].minor = devno; + return &g_ch34x_class[devno]; + } + } + return NULL; +} + +static void usbh_ch34x_class_free(struct usbh_ch34x *ch34x_class) +{ + int devno = ch34x_class->minor; + + if (devno >= 0 && devno < 32) { + g_devinuse &= ~(1 << devno); + } + memset(ch34x_class, 0, sizeof(struct usbh_ch34x)); +} + +static int usbh_ch34x_get_baudrate_div(uint32_t baudrate, uint8_t *factor, uint8_t *divisor) +{ + uint8_t a; + uint8_t b; + uint32_t c; + + switch (baudrate) { + case 921600: + a = 0xf3; + b = 7; + break; + + case 307200: + a = 0xd9; + b = 7; + break; + + default: + if (baudrate > 6000000 / 255) { + b = 3; + c = 6000000; + } else if (baudrate > 750000 / 255) { + b = 2; + c = 750000; + } else if (baudrate > 93750 / 255) { + b = 1; + c = 93750; + } else { + b = 0; + c = 11719; + } + a = (uint8_t)(c / baudrate); + if (a == 0 || a == 0xFF) { + return -USB_ERR_INVAL; + } + if ((c / a - baudrate) > (baudrate - c / (a + 1))) { + a++; + } + a = (uint8_t)(256 - a); + break; + } + + *factor = a; + *divisor = b; + + return 0; +} + +static int usbh_ch34x_get_version(struct usbh_ch34x *ch34x_class) +{ + struct usb_setup_packet *setup = ch34x_class->hport->setup; + int ret; + + setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE; + setup->bRequest = CH34X_READ_VERSION; + setup->wValue = 0; + setup->wIndex = 0; + setup->wLength = 2; + + ret = usbh_control_transfer(ch34x_class->hport, setup, g_ch34x_buf); + if (ret < 0) { + return ret; + } + + USB_LOG_INFO("Ch34x chip version %02x:%02x\r\n", g_ch34x_buf[0], g_ch34x_buf[1]); + return ret; +} + +static int usbh_ch34x_flow_ctrl(struct usbh_ch34x *ch34x_class) +{ + struct usb_setup_packet *setup = ch34x_class->hport->setup; + + setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE; + setup->bRequest = CH34X_WRITE_REG; + setup->wValue = 0x2727; + setup->wIndex = 0; + setup->wLength = 0; + + return usbh_control_transfer(ch34x_class->hport, setup, NULL); +} + +int usbh_ch34x_set_line_coding(struct usbh_ch34x *ch34x_class, struct cdc_line_coding *line_coding) +{ + struct usb_setup_packet *setup = ch34x_class->hport->setup; + uint16_t reg_value = 0; + uint16_t value = 0; + uint8_t factor = 0; + uint8_t divisor = 0; + + memcpy((uint8_t *)&ch34x_class->line_coding, line_coding, sizeof(struct cdc_line_coding)); + + /* refer to https://github.com/WCHSoftGroup/ch341ser_linux/blob/main/driver/ch341.c */ + + switch (line_coding->bParityType) { + case 0: + break; + case 1: + reg_value |= CH341_L_PO; + break; + case 2: + reg_value |= CH341_L_PE; + break; + case 3: + reg_value |= CH341_L_PM; + break; + case 4: + reg_value |= CH341_L_PS; + break; + default: + return -USB_ERR_INVAL; + } + + switch (line_coding->bDataBits) { + case 5: + reg_value |= CH341_L_D5; + break; + case 6: + reg_value |= CH341_L_D6; + break; + case 7: + reg_value |= CH341_L_D7; + break; + case 8: + reg_value |= CH341_L_D8; + break; + default: + return -USB_ERR_INVAL; + } + + if (line_coding->bCharFormat == 2) { + reg_value |= CH341_L_SB; + } + + reg_value |= 0xC0; + + value |= 0x9c; + value |= reg_value << 8; + + usbh_ch34x_get_baudrate_div(line_coding->dwDTERate, &factor, &divisor); + + setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE; + setup->bRequest = CH34X_SERIAL_INIT; + setup->wValue = value; + setup->wIndex = (factor << 8) | 0x80 | divisor; + setup->wLength = 0; + + return usbh_control_transfer(ch34x_class->hport, setup, NULL); +} + +int usbh_ch34x_get_line_coding(struct usbh_ch34x *ch34x_class, struct cdc_line_coding *line_coding) +{ + memcpy(line_coding, (uint8_t *)&ch34x_class->line_coding, sizeof(struct cdc_line_coding)); + return 0; +} + +int usbh_ch34x_set_line_state(struct usbh_ch34x *ch34x_class, bool dtr, bool rts) +{ + struct usb_setup_packet *setup = ch34x_class->hport->setup; + + setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE; + setup->bRequest = CH34X_MODEM_CTRL; + setup->wValue = 0x0f | (dtr << 5) | (rts << 6); + setup->wIndex = 0; + setup->wLength = 0; + + return usbh_control_transfer(ch34x_class->hport, setup, NULL); +} + +static int usbh_ch34x_connect(struct usbh_hubport *hport, uint8_t intf) +{ + struct usb_endpoint_descriptor *ep_desc; + int ret = 0; + + struct usbh_ch34x *ch34x_class = usbh_ch34x_class_alloc(); + if (ch34x_class == NULL) { + USB_LOG_ERR("Fail to alloc ch34x_class\r\n"); + return -USB_ERR_NOMEM; + } + + ch34x_class->hport = hport; + ch34x_class->intf = intf; + + hport->config.intf[intf].priv = ch34x_class; + + usbh_ch34x_get_version(ch34x_class); + usbh_ch34x_flow_ctrl(ch34x_class); + + for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) { + ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc; + if (USB_GET_ENDPOINT_TYPE(ep_desc->bmAttributes) == USB_ENDPOINT_TYPE_INTERRUPT) { + continue; + } else { + if (ep_desc->bEndpointAddress & 0x80) { + USBH_EP_INIT(ch34x_class->bulkin, ep_desc); + } else { + USBH_EP_INIT(ch34x_class->bulkout, ep_desc); + } + } + } + + snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, ch34x_class->minor); + + USB_LOG_INFO("Register CH34X Class:%s\r\n", hport->config.intf[intf].devname); + +#if 0 + USB_LOG_INFO("Test ch34x rx and tx and rx for 5 times, baudrate is 115200\r\n"); + + struct cdc_line_coding linecoding; + uint8_t count = 5; + + linecoding.dwDTERate = 115200; + linecoding.bDataBits = 8; + linecoding.bParityType = 0; + linecoding.bCharFormat = 0; + usbh_ch34x_set_line_coding(ch34x_class, &linecoding); + usbh_ch34x_set_line_state(ch34x_class, true, false); + + memset(g_ch34x_buf, 'a', sizeof(g_ch34x_buf)); + ret = usbh_ch34x_bulk_out_transfer(ch34x_class, g_ch34x_buf, sizeof(g_ch34x_buf), 0xfffffff); + USB_LOG_RAW("out ret:%d\r\n", ret); + while (count--) { + ret = usbh_ch34x_bulk_in_transfer(ch34x_class, g_ch34x_buf, sizeof(g_ch34x_buf), 0xfffffff); + USB_LOG_RAW("in ret:%d\r\n", ret); + if (ret > 0) { + for (uint32_t i = 0; i < ret; i++) { + USB_LOG_RAW("%02x ", g_ch34x_buf[i]); + } + USB_LOG_RAW("\r\n"); + } + } +#endif + usbh_ch34x_run(ch34x_class); + return ret; +} + +static int usbh_ch34x_disconnect(struct usbh_hubport *hport, uint8_t intf) +{ + int ret = 0; + + struct usbh_ch34x *ch34x_class = (struct usbh_ch34x *)hport->config.intf[intf].priv; + + if (ch34x_class) { + if (ch34x_class->bulkin) { + usbh_kill_urb(&ch34x_class->bulkin_urb); + } + + if (ch34x_class->bulkout) { + usbh_kill_urb(&ch34x_class->bulkout_urb); + } + + if (hport->config.intf[intf].devname[0] != '\0') { + USB_LOG_INFO("Unregister CH34X Class:%s\r\n", hport->config.intf[intf].devname); + usbh_ch34x_stop(ch34x_class); + } + + usbh_ch34x_class_free(ch34x_class); + } + + return ret; +} + +int usbh_ch34x_bulk_in_transfer(struct usbh_ch34x *ch34x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout) +{ + int ret; + struct usbh_urb *urb = &ch34x_class->bulkin_urb; + + usbh_bulk_urb_fill(urb, ch34x_class->hport, ch34x_class->bulkin, buffer, buflen, timeout, NULL, NULL); + ret = usbh_submit_urb(urb); + if (ret == 0) { + ret = urb->actual_length; + } + return ret; +} + +int usbh_ch34x_bulk_out_transfer(struct usbh_ch34x *ch34x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout) +{ + int ret; + struct usbh_urb *urb = &ch34x_class->bulkout_urb; + + usbh_bulk_urb_fill(urb, ch34x_class->hport, ch34x_class->bulkout, buffer, buflen, timeout, NULL, NULL); + ret = usbh_submit_urb(urb); + if (ret == 0) { + ret = urb->actual_length; + } + return ret; +} + +__WEAK void usbh_ch34x_run(struct usbh_ch34x *ch34x_class) +{ +} + +__WEAK void usbh_ch34x_stop(struct usbh_ch34x *ch34x_class) +{ +} + +const struct usbh_class_driver ch34x_class_driver = { + .driver_name = "ch34x", + .connect = usbh_ch34x_connect, + .disconnect = usbh_ch34x_disconnect +}; + +CLASS_INFO_DEFINE const struct usbh_class_info ch34x_class_info = { + .match_flags = USB_CLASS_MATCH_VENDOR | USB_CLASS_MATCH_PRODUCT | USB_CLASS_MATCH_INTF_CLASS, + .class = 0xff, + .subclass = 0xff, + .protocol = 0xff, + .vid = 0x1A86, + .pid = 0x7523, + .class_driver = &ch34x_class_driver +}; \ No newline at end of file diff --git a/class/vendor/usbh_ch34x.h b/class/vendor/usbh_ch34x.h new file mode 100644 index 00000000..256928dd --- /dev/null +++ b/class/vendor/usbh_ch34x.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2022, sakumisu + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef USBH_CH34X_H +#define USBH_CH34X_H + +#include "usb_cdc.h" + +/* Requests */ +#define CH34X_READ_VERSION 0x5F +#define CH34X_WRITE_REG 0x9A +#define CH34X_READ_REG 0x95 +#define CH34X_SERIAL_INIT 0xA1 +#define CH34X_MODEM_CTRL 0xA4 + +// modem control bits +#define CH34X_BIT_RTS (1 << 6) +#define CH34X_BIT_DTR (1 << 5) + +#define CH341_CTO_O 0x10 +#define CH341_CTO_D 0x20 +#define CH341_CTO_R 0x40 +#define CH341_CTI_C 0x01 +#define CH341_CTI_DS 0x02 +#define CH341_CTRL_RI 0x04 +#define CH341_CTI_DC 0x08 +#define CH341_CTI_ST 0x0f + +#define CH341_L_ER 0x80 +#define CH341_L_ET 0x40 +#define CH341_L_PS 0x38 +#define CH341_L_PM 0x28 +#define CH341_L_PE 0x18 +#define CH341_L_PO 0x08 +#define CH341_L_SB 0x04 +#define CH341_L_D8 0x03 +#define CH341_L_D7 0x02 +#define CH341_L_D6 0x01 +#define CH341_L_D5 0x00 + +struct usbh_ch34x { + struct usbh_hubport *hport; + struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */ + struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */ + struct usbh_urb bulkout_urb; + struct usbh_urb bulkin_urb; + + struct cdc_line_coding line_coding; + + uint8_t intf; + uint8_t minor; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int usbh_ch34x_set_line_coding(struct usbh_ch34x *ch34x_class, struct cdc_line_coding *line_coding); +int usbh_ch34x_get_line_coding(struct usbh_ch34x *ch34x_class, struct cdc_line_coding *line_coding); +int usbh_ch34x_set_line_state(struct usbh_ch34x *ch34x_class, bool dtr, bool rts); + +int usbh_ch34x_bulk_in_transfer(struct usbh_ch34x *ch34x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout); +int usbh_ch34x_bulk_out_transfer(struct usbh_ch34x *ch34x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout); + +void usbh_ch34x_run(struct usbh_ch34x *ch34x_class); +void usbh_ch34x_stop(struct usbh_ch34x *ch34x_class); + +#ifdef __cplusplus +} +#endif + +#endif /* USBH_CH34X_H */ diff --git a/class/vendor/usbh_cp210x.c b/class/vendor/usbh_cp210x.c new file mode 100644 index 00000000..565786f3 --- /dev/null +++ b/class/vendor/usbh_cp210x.c @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2022, sakumisu + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "usbh_core.h" +#include "usbh_cp210x.h" + +#define DEV_FORMAT "/dev/ttyUSB%d" + +USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cp210x_buf[64]; + +#define CONFIG_USBHOST_MAX_CP210X_CLASS 4 + +static struct usbh_cp210x g_cp210x_class[CONFIG_USBHOST_MAX_CP210X_CLASS]; +static uint32_t g_devinuse = 0; + +static struct usbh_cp210x *usbh_cp210x_class_alloc(void) +{ + int devno; + + for (devno = 0; devno < CONFIG_USBHOST_MAX_CP210X_CLASS; devno++) { + if ((g_devinuse & (1 << devno)) == 0) { + g_devinuse |= (1 << devno); + memset(&g_cp210x_class[devno], 0, sizeof(struct usbh_cp210x)); + g_cp210x_class[devno].minor = devno; + return &g_cp210x_class[devno]; + } + } + return NULL; +} + +static void usbh_cp210x_class_free(struct usbh_cp210x *cp210x_class) +{ + int devno = cp210x_class->minor; + + if (devno >= 0 && devno < 32) { + g_devinuse &= ~(1 << devno); + } + memset(cp210x_class, 0, sizeof(struct usbh_cp210x)); +} + +static int usbh_cp210x_enable(struct usbh_cp210x *cp210x_class) +{ + struct usb_setup_packet *setup = cp210x_class->hport->setup; + + setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_INTERFACE; + setup->bRequest = CP210X_IFC_ENABLE; + setup->wValue = 1; + setup->wIndex = cp210x_class->intf; + setup->wLength = 0; + + return usbh_control_transfer(cp210x_class->hport, setup, NULL); +} + +static int usbh_cp210x_set_flow(struct usbh_cp210x *cp210x_class) +{ + struct usb_setup_packet *setup = cp210x_class->hport->setup; + + setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_INTERFACE; + setup->bRequest = CP210X_SET_FLOW; + setup->wValue = 0; + setup->wIndex = cp210x_class->intf; + setup->wLength = 16; + + memset(g_cp210x_buf, 0, 16); + g_cp210x_buf[13] = 0x20; + return usbh_control_transfer(cp210x_class->hport, setup, g_cp210x_buf); +} + +static int usbh_cp210x_set_chars(struct usbh_cp210x *cp210x_class) +{ + struct usb_setup_packet *setup = cp210x_class->hport->setup; + + setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_INTERFACE; + setup->bRequest = CP210X_SET_CHARS; + setup->wValue = 0; + setup->wIndex = cp210x_class->intf; + setup->wLength = 6; + + memset(g_cp210x_buf, 0, 6); + g_cp210x_buf[0] = 0x80; + g_cp210x_buf[4] = 0x88; + g_cp210x_buf[5] = 0x28; + return usbh_control_transfer(cp210x_class->hport, setup, g_cp210x_buf); +} + +static int usbh_cp210x_set_baudrate(struct usbh_cp210x *cp210x_class, uint32_t baudrate) +{ + struct usb_setup_packet *setup = cp210x_class->hport->setup; + + setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_INTERFACE; + setup->bRequest = CP210X_SET_BAUDRATE; + setup->wValue = 0; + setup->wIndex = cp210x_class->intf; + setup->wLength = 4; + + memcpy(g_cp210x_buf, (uint8_t *)&baudrate, 4); + return usbh_control_transfer(cp210x_class->hport, setup, g_cp210x_buf); +} + +static int usbh_cp210x_set_data_format(struct usbh_cp210x *cp210x_class, uint8_t databits, uint8_t parity, uint8_t stopbits) +{ + struct usb_setup_packet *setup = cp210x_class->hport->setup; + uint16_t value; + + value = ((databits & 0x0F) << 8) | ((parity & 0x0f) << 4) | ((stopbits & 0x03) << 0); + + setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_INTERFACE; + setup->bRequest = CP210X_SET_LINE_CTL; + setup->wValue = value; + setup->wIndex = cp210x_class->intf; + setup->wLength = 0; + + return usbh_control_transfer(cp210x_class->hport, setup, NULL); +} + +static int usbh_cp210x_set_mhs(struct usbh_cp210x *cp210x_class, uint8_t dtr, uint8_t rts, uint8_t dtr_mask, uint8_t rts_mask) +{ + struct usb_setup_packet *setup = cp210x_class->hport->setup; + uint16_t value; + + value = ((dtr & 0x01) << 0) | ((rts & 0x01) << 1) | ((dtr_mask & 0x01) << 8) | ((rts_mask & 0x01) << 9); + + setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_INTERFACE; + setup->bRequest = CP210X_SET_MHS; + setup->wValue = value; + setup->wIndex = cp210x_class->intf; + setup->wLength = 0; + + return usbh_control_transfer(cp210x_class->hport, setup, NULL); +} + +int usbh_cp210x_set_line_coding(struct usbh_cp210x *cp210x_class, struct cdc_line_coding *line_coding) +{ + memcpy((uint8_t *)&cp210x_class->line_coding, line_coding, sizeof(struct cdc_line_coding)); + usbh_cp210x_set_baudrate(cp210x_class, line_coding->dwDTERate); + return usbh_cp210x_set_data_format(cp210x_class, line_coding->bDataBits, line_coding->bParityType, line_coding->bCharFormat); +} + +int usbh_cp210x_get_line_coding(struct usbh_cp210x *cp210x_class, struct cdc_line_coding *line_coding) +{ + memcpy(line_coding, (uint8_t *)&cp210x_class->line_coding, sizeof(struct cdc_line_coding)); + return 0; +} + +int usbh_cp210x_set_line_state(struct usbh_cp210x *cp210x_class, bool dtr, bool rts) +{ + return usbh_cp210x_set_mhs(cp210x_class, dtr, rts, 1, 1); +} + +static int usbh_cp210x_connect(struct usbh_hubport *hport, uint8_t intf) +{ + struct usb_endpoint_descriptor *ep_desc; + int ret = 0; + + struct usbh_cp210x *cp210x_class = usbh_cp210x_class_alloc(); + if (cp210x_class == NULL) { + USB_LOG_ERR("Fail to alloc cp210x_class\r\n"); + return -USB_ERR_NOMEM; + } + + cp210x_class->hport = hport; + cp210x_class->intf = intf; + + hport->config.intf[intf].priv = cp210x_class; + + usbh_cp210x_enable(cp210x_class); + usbh_cp210x_set_flow(cp210x_class); + usbh_cp210x_set_chars(cp210x_class); + + for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) { + ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc; + + if (ep_desc->bEndpointAddress & 0x80) { + USBH_EP_INIT(cp210x_class->bulkin, ep_desc); + } else { + USBH_EP_INIT(cp210x_class->bulkout, ep_desc); + } + } + + snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, cp210x_class->minor); + + USB_LOG_INFO("Register CP210X Class:%s\r\n", hport->config.intf[intf].devname); + +#if 0 + USB_LOG_INFO("Test cp2102 rx and tx and rx for 5 times, baudrate is 115200\r\n"); + + struct cdc_line_coding linecoding; + uint8_t count = 5; + + linecoding.dwDTERate = 115200; + linecoding.bDataBits = 8; + linecoding.bParityType = 0; + linecoding.bCharFormat = 0; + usbh_cp210x_set_line_coding(cp210x_class, &linecoding); + usbh_cp210x_set_line_state(cp210x_class, true, false); + + memset(g_cp210x_buf, 'a', sizeof(g_cp210x_buf)); + ret = usbh_cp210x_bulk_out_transfer(cp210x_class, g_cp210x_buf, sizeof(g_cp210x_buf), 0xfffffff); + USB_LOG_RAW("out ret:%d\r\n", ret); + while (count--) { + ret = usbh_cp210x_bulk_in_transfer(cp210x_class, g_cp210x_buf, sizeof(g_cp210x_buf), 0xfffffff); + USB_LOG_RAW("in ret:%d\r\n", ret); + if (ret > 0) { + for (uint32_t i = 0; i < ret; i++) { + USB_LOG_RAW("%02x ", g_cp210x_buf[i]); + } + USB_LOG_RAW("\r\n"); + } + } +#endif + usbh_cp210x_run(cp210x_class); + return ret; +} + +static int usbh_cp210x_disconnect(struct usbh_hubport *hport, uint8_t intf) +{ + int ret = 0; + + struct usbh_cp210x *cp210x_class = (struct usbh_cp210x *)hport->config.intf[intf].priv; + + if (cp210x_class) { + if (cp210x_class->bulkin) { + usbh_kill_urb(&cp210x_class->bulkin_urb); + } + + if (cp210x_class->bulkout) { + usbh_kill_urb(&cp210x_class->bulkout_urb); + } + + if (hport->config.intf[intf].devname[0] != '\0') { + USB_LOG_INFO("Unregister CP210X Class:%s\r\n", hport->config.intf[intf].devname); + usbh_cp210x_stop(cp210x_class); + } + + usbh_cp210x_class_free(cp210x_class); + } + + return ret; +} + +int usbh_cp210x_bulk_in_transfer(struct usbh_cp210x *cp210x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout) +{ + int ret; + struct usbh_urb *urb = &cp210x_class->bulkin_urb; + + usbh_bulk_urb_fill(urb, cp210x_class->hport, cp210x_class->bulkin, buffer, buflen, timeout, NULL, NULL); + ret = usbh_submit_urb(urb); + if (ret == 0) { + ret = urb->actual_length; + } + return ret; +} + +int usbh_cp210x_bulk_out_transfer(struct usbh_cp210x *cp210x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout) +{ + int ret; + struct usbh_urb *urb = &cp210x_class->bulkout_urb; + + usbh_bulk_urb_fill(urb, cp210x_class->hport, cp210x_class->bulkout, buffer, buflen, timeout, NULL, NULL); + ret = usbh_submit_urb(urb); + if (ret == 0) { + ret = urb->actual_length; + } + return ret; +} + +__WEAK void usbh_cp210x_run(struct usbh_cp210x *cp210x_class) +{ +} + +__WEAK void usbh_cp210x_stop(struct usbh_cp210x *cp210x_class) +{ +} + +const struct usbh_class_driver cp210x_class_driver = { + .driver_name = "cp210x", + .connect = usbh_cp210x_connect, + .disconnect = usbh_cp210x_disconnect +}; + +CLASS_INFO_DEFINE const struct usbh_class_info cp210x_class_info = { + .match_flags = USB_CLASS_MATCH_VENDOR | USB_CLASS_MATCH_PRODUCT | USB_CLASS_MATCH_INTF_CLASS, + .class = 0xff, + .subclass = 0xff, + .protocol = 0xff, + .vid = 0x10C4, + .pid = 0xEA60, + .class_driver = &cp210x_class_driver +}; \ No newline at end of file diff --git a/class/vendor/usbh_cp210x.h b/class/vendor/usbh_cp210x.h new file mode 100644 index 00000000..8cfb184d --- /dev/null +++ b/class/vendor/usbh_cp210x.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2022, sakumisu + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef USBH_CP210X_H +#define USBH_CP210X_H + +#include "usb_cdc.h" + +/* Requests */ +#define CP210X_IFC_ENABLE 0x00 +#define CP210X_SET_BAUDDIV 0x01 +#define CP210X_GET_BAUDDIV 0x02 +#define CP210X_SET_LINE_CTL 0x03 // Set parity, data bits, stop bits +#define CP210X_GET_LINE_CTL 0x04 +#define CP210X_SET_BREAK 0x05 +#define CP210X_IMM_CHAR 0x06 +#define CP210X_SET_MHS 0x07 // Set DTR, RTS +#define CP210X_GET_MDMSTS 0x08 +#define CP210X_SET_XON 0x09 +#define CP210X_SET_XOFF 0x0A +#define CP210X_SET_EVENTMASK 0x0B +#define CP210X_GET_EVENTMASK 0x0C +#define CP210X_SET_CHAR 0x0D +#define CP210X_GET_CHARS 0x0E +#define CP210X_GET_PROPS 0x0F +#define CP210X_GET_COMM_STATUS 0x10 +#define CP210X_RESET 0x11 +#define CP210X_PURGE 0x12 +#define CP210X_SET_FLOW 0x13 +#define CP210X_GET_FLOW 0x14 +#define CP210X_EMBED_EVENTS 0x15 +#define CP210X_GET_EVENTSTATE 0x16 +#define CP210X_SET_CHARS 0x19 +#define CP210X_GET_BAUDRATE 0x1D +#define CP210X_SET_BAUDRATE 0x1E // Set baudrate +#define CP210X_VENDOR_SPECIFIC 0xFF + +struct usbh_cp210x { + struct usbh_hubport *hport; + struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */ + struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */ + struct usbh_urb bulkout_urb; + struct usbh_urb bulkin_urb; + + struct cdc_line_coding line_coding; + + uint8_t intf; + uint8_t minor; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int usbh_cp210x_set_line_coding(struct usbh_cp210x *ftdi_class, struct cdc_line_coding *line_coding); +int usbh_cp210x_get_line_coding(struct usbh_cp210x *ftdi_class, struct cdc_line_coding *line_coding); +int usbh_cp210x_set_line_state(struct usbh_cp210x *ftdi_class, bool dtr, bool rts); + +int usbh_cp210x_bulk_in_transfer(struct usbh_cp210x *cp210x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout); +int usbh_cp210x_bulk_out_transfer(struct usbh_cp210x *cp210x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout); + +void usbh_cp210x_run(struct usbh_cp210x *cp210x_class); +void usbh_cp210x_stop(struct usbh_cp210x *cp210x_class); + +#ifdef __cplusplus +} +#endif + +#endif /* USBH_CP210X_H */ diff --git a/class/vendor/usbh_ftdi.c b/class/vendor/usbh_ftdi.c index d8312eb1..dcc79cdd 100644 --- a/class/vendor/usbh_ftdi.c +++ b/class/vendor/usbh_ftdi.c @@ -8,7 +8,7 @@ #define DEV_FORMAT "/dev/ttyUSB%d" -USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_ftdi_buf[32]; +USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_ftdi_buf[64]; #define CONFIG_USBHOST_MAX_FTDI_CLASS 4 @@ -115,7 +115,7 @@ static int usbh_ftdi_set_baudrate(struct usbh_ftdi *ftdi_class, uint32_t baudrat return usbh_control_transfer(ftdi_class->hport, setup, NULL); } -static int usbh_ftdi_set_data_format(struct usbh_ftdi *ftdi_class, uint8_t databits, uint8_t parity, uint8_t stopbits) +static int usbh_ftdi_set_data_format(struct usbh_ftdi *ftdi_class, uint8_t databits, uint8_t parity, uint8_t stopbits, uint8_t isbreak) { /** * D0-D7 databits BITS_7=7, BITS_8=8 @@ -124,8 +124,7 @@ static int usbh_ftdi_set_data_format(struct usbh_ftdi *ftdi_class, uint8_t datab * D14 BREAK_OFF=0, BREAK_ON=1 **/ - uint8_t isbreak = 0; - uint16_t value = (databits & 0x0F) | ((parity & 0x03) << 8) | ((stopbits & 0x03) << 11) | ((isbreak & 0x01) << 14); + uint16_t value = ((isbreak & 0x01) << 14) | ((stopbits & 0x03) << 11) | ((parity & 0x0f) << 8) | (databits & 0x0f); struct usb_setup_packet *setup = ftdi_class->hport->setup; @@ -138,6 +137,64 @@ static int usbh_ftdi_set_data_format(struct usbh_ftdi *ftdi_class, uint8_t datab return usbh_control_transfer(ftdi_class->hport, setup, NULL); } +static int usbh_ftdi_set_latency_timer(struct usbh_ftdi *ftdi_class, uint16_t value) +{ + struct usb_setup_packet *setup = ftdi_class->hport->setup; + + setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE; + setup->bRequest = SIO_SET_LATENCY_TIMER_REQUEST; + setup->wValue = value; + setup->wIndex = ftdi_class->intf; + setup->wLength = 0; + + return usbh_control_transfer(ftdi_class->hport, setup, NULL); +} + +static int usbh_ftdi_set_flow_ctrl(struct usbh_ftdi *ftdi_class, uint16_t value) +{ + struct usb_setup_packet *setup = ftdi_class->hport->setup; + + setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE; + setup->bRequest = SIO_SET_FLOW_CTRL_REQUEST; + setup->wValue = value; + setup->wIndex = ftdi_class->intf; + setup->wLength = 0; + + return usbh_control_transfer(ftdi_class->hport, setup, NULL); +} + +static int usbh_ftdi_read_modem_status(struct usbh_ftdi *ftdi_class) +{ + struct usb_setup_packet *setup = ftdi_class->hport->setup; + int ret; + + setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE; + setup->bRequest = SIO_POLL_MODEM_STATUS_REQUEST; + setup->wValue = 0x0000; + setup->wIndex = ftdi_class->intf; + setup->wLength = 2; + + ret = usbh_control_transfer(ftdi_class->hport, setup, g_ftdi_buf); + if (ret < 0) { + return ret; + } + memcpy(ftdi_class->modem_status, g_ftdi_buf, 2); + return ret; +} + +int usbh_ftdi_set_line_coding(struct usbh_ftdi *ftdi_class, struct cdc_line_coding *line_coding) +{ + memcpy((uint8_t *)&ftdi_class->line_coding, line_coding, sizeof(struct cdc_line_coding)); + usbh_ftdi_set_baudrate(ftdi_class, line_coding->dwDTERate); + return usbh_ftdi_set_data_format(ftdi_class, line_coding->bDataBits, line_coding->bParityType, line_coding->bCharFormat, 0); +} + +int usbh_ftdi_get_line_coding(struct usbh_ftdi *ftdi_class, struct cdc_line_coding *line_coding) +{ + memcpy(line_coding, (uint8_t *)&ftdi_class->line_coding, sizeof(struct cdc_line_coding)); + return 0; +} + int usbh_ftdi_set_line_state(struct usbh_ftdi *ftdi_class, bool dtr, bool rts) { int ret; @@ -157,61 +214,10 @@ int usbh_ftdi_set_line_state(struct usbh_ftdi *ftdi_class, bool dtr, bool rts) return ret; } -int usbh_ftdi_set_line_coding(struct usbh_ftdi *ftdi_class, struct cdc_line_coding *line_coding) -{ - usbh_ftdi_set_baudrate(ftdi_class, line_coding->dwDTERate); - return usbh_ftdi_set_data_format(ftdi_class, line_coding->bDataBits, line_coding->bParityType, line_coding->bCharFormat); -} - -int usbh_ftdi_set_latency_timer(struct usbh_ftdi *ftdi_class, uint16_t value) -{ - struct usb_setup_packet *setup = ftdi_class->hport->setup; - - setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE; - setup->bRequest = SIO_SET_LATENCY_TIMER_REQUEST; - setup->wValue = value; - setup->wIndex = ftdi_class->intf; - setup->wLength = 0; - - return usbh_control_transfer(ftdi_class->hport, setup, NULL); -} - -int usbh_ftdi_set_flow_ctrl(struct usbh_ftdi *ftdi_class, uint16_t value) -{ - struct usb_setup_packet *setup = ftdi_class->hport->setup; - - setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE; - setup->bRequest = SIO_SET_FLOW_CTRL_REQUEST; - setup->wValue = value; - setup->wIndex = ftdi_class->intf; - setup->wLength = 0; - - return usbh_control_transfer(ftdi_class->hport, setup, NULL); -} - -int usbh_ftdi_read_modem_status(struct usbh_ftdi *ftdi_class) -{ - struct usb_setup_packet *setup = ftdi_class->hport->setup; - int ret; - - setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE; - setup->bRequest = SIO_POLL_MODEM_STATUS_REQUEST; - setup->wValue = 0x0000; - setup->wIndex = ftdi_class->intf; - setup->wLength = 2; - - ret = usbh_control_transfer(ftdi_class->hport, setup, g_ftdi_buf); - if (ret < 0) { - return ret; - } - memcpy(ftdi_class->modem_status, g_ftdi_buf, 2); - return ret; -} - static int usbh_ftdi_connect(struct usbh_hubport *hport, uint8_t intf) { struct usb_endpoint_descriptor *ep_desc; - int ret; + int ret = 0; struct usbh_ftdi *ftdi_class = usbh_ftdi_class_alloc(); if (ftdi_class == NULL) { @@ -227,9 +233,8 @@ static int usbh_ftdi_connect(struct usbh_hubport *hport, uint8_t intf) usbh_ftdi_reset(ftdi_class); usbh_ftdi_set_flow_ctrl(ftdi_class, SIO_DISABLE_FLOW_CTRL); usbh_ftdi_set_latency_timer(ftdi_class, 0x10); - usbh_ftdi_set_line_state(ftdi_class, true, false); usbh_ftdi_read_modem_status(ftdi_class); - printf("modem status:%02x:%02x\r\n", ftdi_class->modem_status[0], ftdi_class->modem_status[1]); + USB_LOG_INFO("modem status:%02x:%02x\r\n", ftdi_class->modem_status[0], ftdi_class->modem_status[1]); for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) { ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc; @@ -245,6 +250,33 @@ static int usbh_ftdi_connect(struct usbh_hubport *hport, uint8_t intf) USB_LOG_INFO("Register FTDI Class:%s\r\n", hport->config.intf[intf].devname); +#if 0 + USB_LOG_INFO("Test ftdi rx and tx and rx for 5 times, baudrate is 115200\r\n"); + + struct cdc_line_coding linecoding; + uint8_t count = 5; + + linecoding.dwDTERate = 115200; + linecoding.bDataBits = 8; + linecoding.bParityType = 0; + linecoding.bCharFormat = 0; + usbh_ftdi_set_line_coding(ftdi_class, &linecoding); + usbh_ftdi_set_line_state(ftdi_class, true, false); + + memset(g_ftdi_buf, 'a', sizeof(g_ftdi_buf)); + ret = usbh_ftdi_bulk_out_transfer(ftdi_class, g_ftdi_buf, sizeof(g_ftdi_buf), 0xfffffff); + USB_LOG_RAW("out ret:%d\r\n", ret); + while (count--) { + ret = usbh_ftdi_bulk_in_transfer(ftdi_class, g_ftdi_buf, sizeof(g_ftdi_buf), 0xfffffff); + USB_LOG_RAW("in ret:%d\r\n", ret); + if (ret > 0) { + for (uint32_t i = 0; i < ret; i++) { + USB_LOG_RAW("%02x ", g_ftdi_buf[i]); + } + } + USB_LOG_RAW("\r\n"); + } +#endif usbh_ftdi_run(ftdi_class); return ret; } diff --git a/class/vendor/usbh_ftdi.h b/class/vendor/usbh_ftdi.h index 7e7ecd18..70387d76 100644 --- a/class/vendor/usbh_ftdi.h +++ b/class/vendor/usbh_ftdi.h @@ -46,6 +46,8 @@ struct usbh_ftdi { struct usbh_urb bulkout_urb; struct usbh_urb bulkin_urb; + struct cdc_line_coding line_coding; + uint8_t intf; uint8_t minor; uint8_t modem_status[2]; @@ -55,24 +57,11 @@ struct usbh_ftdi { extern "C" { #endif -int usbh_ftdi_reset(struct usbh_ftdi *ftdi_class); -int usbh_ftdi_set_flow_ctrl(struct usbh_ftdi *ftdi_class, uint16_t value); int usbh_ftdi_set_line_coding(struct usbh_ftdi *ftdi_class, struct cdc_line_coding *line_coding); +int usbh_ftdi_get_line_coding(struct usbh_ftdi *ftdi_class, struct cdc_line_coding *line_coding); int usbh_ftdi_set_line_state(struct usbh_ftdi *ftdi_class, bool dtr, bool rts); -/** - * @brief start a bulk in transfer - * - * @param [in] buffer buffer[0] and buffer[1] is modem status - * @param [in] buflen should be 64 or 512 - */ int usbh_ftdi_bulk_in_transfer(struct usbh_ftdi *ftdi_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout); -/** - * @brief start a bulk out transfer - * - * @param [in] buffer - * @param [in] buflen - */ int usbh_ftdi_bulk_out_transfer(struct usbh_ftdi *ftdi_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout); void usbh_ftdi_run(struct usbh_ftdi *ftdi_class);