summaryrefslogtreecommitdiff
path: root/class/serial
diff options
context:
space:
mode:
Diffstat (limited to 'class/serial')
-rw-r--r--class/serial/usbh_cdc_acm.c2
-rw-r--r--class/serial/usbh_ch34x.c2
-rw-r--r--class/serial/usbh_cp210x.c2
-rw-r--r--class/serial/usbh_ftdi.c4
-rw-r--r--class/serial/usbh_pl2303.c8
-rw-r--r--class/serial/usbh_serial.c68
-rw-r--r--class/serial/usbh_serial.h13
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 */