diff options
Diffstat (limited to 'class/serial')
| -rw-r--r-- | class/serial/usbh_cdc_acm.c | 2 | ||||
| -rw-r--r-- | class/serial/usbh_ch34x.c | 2 | ||||
| -rw-r--r-- | class/serial/usbh_cp210x.c | 2 | ||||
| -rw-r--r-- | class/serial/usbh_ftdi.c | 4 | ||||
| -rw-r--r-- | class/serial/usbh_pl2303.c | 8 | ||||
| -rw-r--r-- | class/serial/usbh_serial.c | 68 | ||||
| -rw-r--r-- | class/serial/usbh_serial.h | 13 |
7 files changed, 65 insertions, 34 deletions
diff --git a/class/serial/usbh_cdc_acm.c b/class/serial/usbh_cdc_acm.c index cf5363ef..48643cb3 100644 --- a/class/serial/usbh_cdc_acm.c +++ b/class/serial/usbh_cdc_acm.c @@ -108,7 +108,7 @@ static int usbh_cdc_acm_get_line_coding(struct usbh_serial *serial, struct cdc_l setup->wLength = 7; ret = usbh_control_transfer(serial->hport, setup, serial->iobuffer); - if (ret < 0) { + if (ret < sizeof(struct cdc_line_coding)) { return ret; } memcpy(line_coding, serial->iobuffer, sizeof(struct cdc_line_coding)); diff --git a/class/serial/usbh_ch34x.c b/class/serial/usbh_ch34x.c index 4595bcae..a5fcd334 100644 --- a/class/serial/usbh_ch34x.c +++ b/class/serial/usbh_ch34x.c @@ -103,7 +103,7 @@ static int usbh_ch34x_control_in(struct usbh_serial *serial, uint8_t bRequest, u setup->wLength = size; ret = usbh_control_transfer(serial->hport, setup, serial->iobuffer); - if (ret < 0) { + if (ret < size) { return ret; } memcpy(data, serial->iobuffer, size); diff --git a/class/serial/usbh_cp210x.c b/class/serial/usbh_cp210x.c index 7b240e2c..0f645a17 100644 --- a/class/serial/usbh_cp210x.c +++ b/class/serial/usbh_cp210x.c @@ -181,7 +181,7 @@ static int usbh_cp210x_control_in(struct usbh_serial *serial, uint8_t bRequest, setup->wLength = size; ret = usbh_control_transfer(serial->hport, setup, serial->iobuffer); - if (ret < 0) { + if (ret < size) { return ret; } memcpy(data, serial->iobuffer, size); diff --git a/class/serial/usbh_ftdi.c b/class/serial/usbh_ftdi.c index c2d3a77b..19f00110 100644 --- a/class/serial/usbh_ftdi.c +++ b/class/serial/usbh_ftdi.c @@ -340,8 +340,8 @@ static int usbh_ftdi_get_modem_status(struct usbh_serial *serial) setup->wLength = 2; ret = usbh_control_transfer(serial->hport, setup, serial->iobuffer); - if (ret < 0) { - return 0; + if (ret < 2) { + return ret; } status = (serial->iobuffer[0] & FTDI_SIO_DSR_MASK ? USBH_SERIAL_TIOCM_DSR : 0) | diff --git a/class/serial/usbh_pl2303.c b/class/serial/usbh_pl2303.c index 062f8128..e3b6a307 100644 --- a/class/serial/usbh_pl2303.c +++ b/class/serial/usbh_pl2303.c @@ -242,10 +242,10 @@ static int pl2303_vendor_read(struct usbh_serial *serial, uint16_t wValue, uint8 setup->wLength = 1; ret = usbh_control_transfer(serial->hport, setup, serial->iobuffer); - if (ret < 0) { + if (ret < 1) { return ret; } - memcpy(data, serial->iobuffer, 1); + *data = serial->iobuffer[0]; return ret; } @@ -280,7 +280,7 @@ static bool pl2303_is_hxd_clone(struct usbh_serial *serial) setup->wLength = 7; ret = usbh_control_transfer(serial->hport, setup, serial->iobuffer); - if (ret < 0) { + if (ret < 7) { return false; } return true; @@ -566,7 +566,7 @@ static int usbh_pl2303_get_line_coding(struct usbh_serial *serial, struct cdc_li setup->wLength = 7; ret = usbh_control_transfer(serial->hport, setup, serial->iobuffer); - if (ret < 0) { + if (ret < sizeof(struct cdc_line_coding)) { return ret; } memcpy(line_coding, serial->iobuffer, sizeof(struct cdc_line_coding)); diff --git a/class/serial/usbh_serial.c b/class/serial/usbh_serial.c index 66aa51fc..5cc96fd1 100644 --- a/class/serial/usbh_serial.c +++ b/class/serial/usbh_serial.c @@ -19,7 +19,9 @@ static struct usbh_serial g_serial_class[CONFIG_USBHOST_MAX_SERIAL_CLASS]; static uint32_t g_devinuse = 0; static uint32_t g_cdcacm_devinuse = 0; -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)]; +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 + CONFIG_USBHOST_SERIAL_BULKIN_SIZE), CONFIG_USB_ALIGN_SIZE)]; + +static void usbh_serial_callback(void *arg, int nbytes); static struct usbh_serial *usbh_serial_alloc(bool is_cdcacm) { @@ -35,6 +37,11 @@ static struct usbh_serial *usbh_serial_alloc(bool is_cdcacm) g_serial_class[devno].iobuffer = g_serial_iobuffer[devno]; g_serial_class[devno].rx_complete_sem = usb_osal_sem_create(0); + if (g_serial_class[devno].rx_complete_sem == NULL) { + g_devinuse &= ~(1U << devno); + return NULL; + } + if (is_cdcacm) { for (devno2 = 0; devno2 < CONFIG_USBHOST_MAX_SERIAL_CLASS; devno2++) { if ((g_cdcacm_devinuse & (1U << devno2)) == 0) { @@ -67,15 +74,28 @@ static void usbh_serial_free(struct usbh_serial *serial) if (g_serial_class[devno].rx_complete_sem) { usb_osal_sem_delete(g_serial_class[devno].rx_complete_sem); + g_serial_class[devno].rx_complete_sem = NULL; } } +static int usbh_serial_rx_restart(struct usbh_serial *serial) +{ + /* resubmit the read urb */ + serial->rx_errorcode = 0; + 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], CONFIG_USBHOST_SERIAL_BULKIN_SIZE, + 0, usbh_serial_callback, serial); + return usbh_submit_urb(&serial->bulkin_urb); +} + static void usbh_serial_callback(void *arg, int nbytes) { struct usbh_serial *serial = (struct usbh_serial *)arg; - uint32_t free_space; + uint8_t prev_buf_index; int ret; + if (!serial) + return; + if (nbytes < 0) { if (nbytes != -USB_ERR_SHUTDOWN) { USB_LOG_ERR("serial transfer error: %d\n", nbytes); @@ -93,30 +113,29 @@ static void usbh_serial_callback(void *arg, int nbytes) } if (nbytes >= serial->driver->ignore_rx_header) { - /* resubmit the read urb */ - 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, - 0, usbh_serial_callback, serial); - ret = usbh_submit_urb(&serial->bulkin_urb); - if (ret < 0) { - USB_LOG_ERR("serial submit failed: %d\n", ret); - serial->rx_errorcode = ret; - usb_osal_sem_give(serial->rx_complete_sem); - return; - } - - free_space = usb_ringbuffer_get_free(&serial->rx_rb); - if (free_space < (nbytes - serial->driver->ignore_rx_header)) { - USB_LOG_ERR("serial rx ringbuffer overflow, free space: %u, rx size: %u\n", free_space, (nbytes - serial->driver->ignore_rx_header)); + prev_buf_index = serial->rx_buf_index; + serial->rx_buf_index ^= 1; + // next ringbuffer write will cause overflow, so don't resubmit the read urb + if (((nbytes - serial->driver->ignore_rx_header) + CONFIG_USBHOST_SERIAL_BULKIN_SIZE) > usb_ringbuffer_get_free(&serial->rx_rb)) { + serial->rx_pending = true; + } else { + serial->rx_pending = false; + ret = usbh_serial_rx_restart(serial); + if (ret < 0) { + USB_LOG_ERR("serial submit failed: %d\n", ret); + serial->rx_errorcode = ret; + usb_osal_sem_give(serial->rx_complete_sem); + return; + } } usb_ringbuffer_write(&serial->rx_rb, - &serial->iobuffer[(serial->rx_buf_index ? USBH_SERIAL_RX2_NOCACHE_OFFSET : USBH_SERIAL_RX_NOCACHE_OFFSET) + serial->driver->ignore_rx_header], + &serial->iobuffer[(prev_buf_index ? USBH_SERIAL_RX2_NOCACHE_OFFSET : USBH_SERIAL_RX_NOCACHE_OFFSET) + serial->driver->ignore_rx_header], (nbytes - serial->driver->ignore_rx_header)); if (serial->rx_complete_callback) { serial->rx_complete_callback(serial, nbytes - serial->driver->ignore_rx_header); } - serial->rx_buf_index ^= 1; serial->rx_errorcode = 0; usb_osal_sem_give(serial->rx_complete_sem); } @@ -375,10 +394,7 @@ int usbh_serial_control(struct usbh_serial *serial, int cmd, void *arg) usb_ringbuffer_reset(&serial->rx_rb); usb_osal_sem_reset(serial->rx_complete_sem); serial->rx_buf_index = 0; - 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, - 0, usbh_serial_callback, serial); - ret = usbh_submit_urb(&serial->bulkin_urb); - + ret = usbh_serial_rx_restart(serial); return ret; } break; case USBH_SERIAL_CMD_GET_ATTR: { @@ -480,6 +496,14 @@ int usbh_serial_read(struct usbh_serial *serial, void *buffer, uint32_t buflen) return -USB_ERR_NODEV; } + if (usb_ringbuffer_get_free(&serial->rx_rb) >= CONFIG_USBHOST_SERIAL_BULKIN_SIZE && serial->rx_pending) { + serial->rx_pending = false; + ret = usbh_serial_rx_restart(serial); + if (ret < 0) { + return ret; + } + } + if (serial->open_flags & USBH_SERIAL_O_NONBLOCK) { return usb_ringbuffer_read(&serial->rx_rb, buffer, buflen); } else { diff --git a/class/serial/usbh_serial.h b/class/serial/usbh_serial.h index 06a31709..17d0bd43 100644 --- a/class/serial/usbh_serial.h +++ b/class/serial/usbh_serial.h @@ -9,14 +9,20 @@ #include "usb_cdc.h" +#ifndef CONFIG_USBHOST_SERIAL_BULKIN_SIZE +#define CONFIG_USBHOST_SERIAL_BULKIN_SIZE 512 +#endif + #define USBH_SERIAL_CTRL_NOCACHE_OFFSET 0 #define USBH_SERIAL_CTRL_NOCACHE_SIZE 32 #define USBH_SERIAL_INT_NOCACHE_OFFSET USB_ALIGN_UP(USBH_SERIAL_CTRL_NOCACHE_SIZE, CONFIG_USB_ALIGN_SIZE) #define USBH_SERIAL_INT_NOCACHE_SIZE 32 #define USBH_SERIAL_RX_NOCACHE_OFFSET USB_ALIGN_UP((USBH_SERIAL_INT_NOCACHE_OFFSET + USBH_SERIAL_INT_NOCACHE_SIZE), CONFIG_USB_ALIGN_SIZE) -#define USBH_SERIAL_RX_NOCACHE_SIZE 512 -#define USBH_SERIAL_RX2_NOCACHE_OFFSET USB_ALIGN_UP((USBH_SERIAL_RX_NOCACHE_OFFSET + USBH_SERIAL_RX_NOCACHE_SIZE), CONFIG_USB_ALIGN_SIZE) -#define USBH_SERIAL_RX2_NOCACHE_SIZE 512 +#define USBH_SERIAL_RX2_NOCACHE_OFFSET USB_ALIGN_UP((USBH_SERIAL_RX_NOCACHE_OFFSET + CONFIG_USBHOST_SERIAL_BULKIN_SIZE), CONFIG_USB_ALIGN_SIZE) + +#if CONFIG_USBHOST_SERIAL_RX_SIZE < CONFIG_USBHOST_SERIAL_BULKIN_SIZE +#error "CONFIG_USBHOST_SERIAL_RX_SIZE must be greater than or equal to CONFIG_USBHOST_SERIAL_BULKIN_SIZE" +#endif #define USBH_SERIAL_DATABITS_5 5 #define USBH_SERIAL_DATABITS_6 6 @@ -142,6 +148,7 @@ struct usbh_serial { uint8_t rx_buf_index; int rx_errorcode; usbh_serial_rx_complete_callback_t rx_complete_callback; + bool rx_pending; void *priv; /* Private Data */ void *user_data; /* User Data */ |
