diff --git a/osal/usb_osal_nuttx.c b/osal/usb_osal_nuttx.c index 52b17130..1fb58ca8 100644 --- a/osal/usb_osal_nuttx.c +++ b/osal/usb_osal_nuttx.c @@ -131,6 +131,7 @@ int usb_osal_sem_give(usb_osal_sem_t sem) void usb_osal_sem_reset(usb_osal_sem_t sem) { + nxsem_reset((sem_t *)sem, 0); } usb_osal_mutex_t usb_osal_mutex_create(void) diff --git a/platform/nuttx/usbd_cdcacm.c b/platform/nuttx/usbd_cdcacm.c new file mode 100644 index 00000000..96b0f702 --- /dev/null +++ b/platform/nuttx/usbd_cdcacm.c @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2025, sakumisu + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include + +#include "usbd_core.h" +#include "usbd_cdc_acm.h" + +#include + +#ifndef CONFIG_USBDEV_CDCACM_RXBUFSIZE +#define CONFIG_USBDEV_CDCACM_RXBUFSIZE 512 +#endif + +#ifndef CONFIG_USBDEV_CDCACM_TXBUFSIZE +#define CONFIG_USBDEV_CDCACM_TXBUFSIZE 512 +#endif + +USB_NOCACHE_RAM_SECTION struct usbdev_serial_s { + char name[16]; + struct circbuf_s circ; + uint8_t inep; + uint8_t outep; + uint32_t rxlen; + int error; + sem_t txdone_sem; + sem_t rxdone_sem; + struct usbd_interface ctrl_intf; + struct usbd_interface data_intf; + __attribute__((aligned(32))) uint8_t cache_tempbuffer[512]; + __attribute__((aligned(32))) uint8_t cache_rxbuffer[CONFIG_USBDEV_CDCACM_RXBUFSIZE]; + __attribute__((aligned(32))) uint8_t cache_txbuffer[CONFIG_USBDEV_CDCACM_TXBUFSIZE]; +}; + +struct usbdev_serial_s *g_usb_cdcacm_serial[8]; + +void usbd_cdc_acm_bulk_out1(uint8_t busid, uint8_t ep, uint32_t nbytes) +{ + g_usb_cdcacm_serial[0]->error = 0; + g_usb_cdcacm_serial[0]->rxlen = nbytes; + nxsem_post(&g_usb_cdcacm_serial[0]->rxdone_sem); +} + +void usbd_cdc_acm_bulk_in1(uint8_t busid, uint8_t ep, uint32_t nbytes) +{ + if ((nbytes % usbd_get_ep_mps(busid, ep)) == 0 && nbytes) { + /* send zlp */ + usbd_ep_start_write(busid, ep, NULL, 0); + } else { + nxsem_post(&g_usb_cdcacm_serial[0]->txdone_sem); + } +} + +void usbd_cdc_acm_bulk_out2(uint8_t busid, uint8_t ep, uint32_t nbytes) +{ + g_usb_cdcacm_serial[1]->error = 0; + g_usb_cdcacm_serial[1]->rxlen = nbytes; + nxsem_post(&g_usb_cdcacm_serial[1]->rxdone_sem); +} + +void usbd_cdc_acm_bulk_in2(uint8_t busid, uint8_t ep, uint32_t nbytes) +{ + if ((nbytes % usbd_get_ep_mps(busid, ep)) == 0 && nbytes) { + /* send zlp */ + usbd_ep_start_write(busid, ep, NULL, 0); + } else { + nxsem_post(&g_usb_cdcacm_serial[1]->txdone_sem); + } +} + +void usbd_cdc_acm_bulk_out3(uint8_t busid, uint8_t ep, uint32_t nbytes) +{ + g_usb_cdcacm_serial[1]->error = 0; + g_usb_cdcacm_serial[2]->rxlen = nbytes; + nxsem_post(&g_usb_cdcacm_serial[2]->rxdone_sem); +} + +void usbd_cdc_acm_bulk_in3(uint8_t busid, uint8_t ep, uint32_t nbytes) +{ + if ((nbytes % usbd_get_ep_mps(busid, ep)) == 0 && nbytes) { + /* send zlp */ + usbd_ep_start_write(busid, ep, NULL, 0); + } else { + nxsem_post(&g_usb_cdcacm_serial[2]->txdone_sem); + } +} + +/* Character driver methods */ + +static int usbdev_open(FAR struct file *filep); +static int usbdev_close(FAR struct file *filep); +static ssize_t usbdev_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); +static ssize_t usbdev_write(FAR struct file *filep, + FAR const char *buffer, size_t buflen); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations g_usbdevops = { + usbdev_open, /* open */ + usbdev_close, /* close */ + usbdev_read, /* read */ + usbdev_write, /* write */ + NULL, /* seek */ + NULL, /* ioctl */ + NULL, /* mmap */ + NULL, /* truncate */ + NULL /* poll */ +}; + +static int usbdev_open(FAR struct file *filep) +{ + FAR struct inode *inode = filep->f_inode; + + DEBUGASSERT(inode->i_private); + + if (usb_device_is_configured(0)) { + return OK; + } else { + return -ENODEV; + } +} + +static int usbdev_close(FAR struct file *filep) +{ + FAR struct inode *inode = filep->f_inode; + + DEBUGASSERT(inode->i_private); + + if (!usb_device_is_configured(0)) { + return -ENODEV; + } + + return 0; +} + +static ssize_t usbdev_read(FAR struct file *filep, FAR char *buffer, + size_t buflen) +{ + FAR struct inode *inode = filep->f_inode; + struct usbdev_serial_s *serial; + int ret; + + DEBUGASSERT(inode->i_private); + serial = (struct usbdev_serial_s *)inode->i_private; + + if (!usb_device_is_configured(0)) { + return -ENODEV; + } + + while (circbuf_used(&serial->circ) == 0) { + nxsem_reset(&serial->rxdone_sem, 0); + usbd_ep_start_read(0, serial->outep, serial->cache_tempbuffer, usbd_get_ep_mps(0, serial->outep)); + ret = nxsem_wait(&serial->rxdone_sem); + if (ret < 0) { + return ret; + } + if (serial->error < 0) { + return serial->error; + } +#if defined(CONFIG_ARCH_DCACHE) && !defined(CONFIG_USB_DCACHE_ENABLE) + up_invalidate_dcache((uintptr_t)serial->cache_tempbuffer, (uintptr_t)(serial->cache_tempbuffer + USB_ALIGN_UP(serial->rxlen, 64))); +#endif + circbuf_overwrite(&serial->circ, serial->cache_tempbuffer, serial->rxlen); + } + return circbuf_read(&serial->circ, buffer, buflen); +} + +static ssize_t usbdev_write(FAR struct file *filep, FAR const char *buffer, + size_t buflen) +{ + FAR struct inode *inode = filep->f_inode; + struct usbdev_serial_s *serial; + int ret; + + DEBUGASSERT(inode->i_private); + serial = (struct usbdev_serial_s *)inode->i_private; + + if (!usb_device_is_configured(0)) { + return -ENODEV; + } + +#ifdef CONFIG_ARCH_DCACHE + uint32_t write_len = 0; + + while (write_len < buflen) { + uint32_t len = buflen - write_len; + if (len > CONFIG_USBDEV_CDCACM_TXBUFSIZE) { + len = CONFIG_USBDEV_CDCACM_TXBUFSIZE; + } + memcpy(serial->cache_txbuffer, buffer + write_len, len); +#ifndef CONFIG_USB_DCACHE_ENABLE + up_clean_dcache((uintptr_t)serial->cache_txbuffer, (uintptr_t)(serial->cache_txbuffer + USB_ALIGN_UP(len, 64))); +#endif + nxsem_reset(&serial->txdone_sem, 0); + usbd_ep_start_write(0, serial->inep, serial->cache_txbuffer, len); + ret = nxsem_wait(&serial->txdone_sem); + if (ret < 0) { + return ret; + } else { + if (serial->error < 0) { + return serial->error; + } + write_len += len; + } + } + return buflen; +#else + nxsem_reset(&serial->txdone_sem, 0); + usbd_ep_start_write(0, serial->inep, buffer, buflen); + ret = nxsem_wait(&serial->txdone_sem); + if (ret < 0) { + return ret; + } else { + return buflen; + } +#endif +} + +static struct usbd_endpoint cdc_out_ep[8] = { + { .ep_addr = 0, + .ep_cb = usbd_cdc_acm_bulk_out1 }, + { .ep_addr = 0, + .ep_cb = usbd_cdc_acm_bulk_out2 }, + { .ep_addr = 0, + .ep_cb = usbd_cdc_acm_bulk_out3 } +}; + +static struct usbd_endpoint cdc_in_ep[8] = { + { .ep_addr = 0, + .ep_cb = usbd_cdc_acm_bulk_in1 }, + { .ep_addr = 0, + .ep_cb = usbd_cdc_acm_bulk_in2 }, + { .ep_addr = 0, + .ep_cb = usbd_cdc_acm_bulk_in3 } +}; + +static void cdcacm_notify_handler1(uint8_t busid, uint8_t event, void *arg) +{ + switch (event) { + case USBD_EVENT_RESET: + break; + case USBD_EVENT_DISCONNECTED: + g_usb_cdcacm_serial[0]->error = -ENOTCONN; + nxsem_post(&g_usb_cdcacm_serial[0]->txdone_sem); + nxsem_post(&g_usb_cdcacm_serial[0]->rxdone_sem); + break; + + case USBD_EVENT_CONFIGURED: + nxsem_post(&g_usb_cdcacm_serial[0]->txdone_sem); + nxsem_post(&g_usb_cdcacm_serial[0]->rxdone_sem); + break; + default: + break; + } +} + +static void cdcacm_notify_handler2(uint8_t busid, uint8_t event, void *arg) +{ + switch (event) { + case USBD_EVENT_RESET: + break; + case USBD_EVENT_DISCONNECTED: + g_usb_cdcacm_serial[1]->error = -ENOTCONN; + nxsem_post(&g_usb_cdcacm_serial[1]->txdone_sem); + nxsem_post(&g_usb_cdcacm_serial[1]->rxdone_sem); + break; + + case USBD_EVENT_CONFIGURED: + nxsem_post(&g_usb_cdcacm_serial[1]->txdone_sem); + nxsem_post(&g_usb_cdcacm_serial[1]->rxdone_sem); + break; + default: + break; + } +} + +static void cdcacm_notify_handler3(uint8_t busid, uint8_t event, void *arg) +{ + switch (event) { + case USBD_EVENT_RESET: + break; + case USBD_EVENT_DISCONNECTED: + g_usb_cdcacm_serial[2]->error = -ENOTCONN; + nxsem_post(&g_usb_cdcacm_serial[2]->txdone_sem); + nxsem_post(&g_usb_cdcacm_serial[2]->rxdone_sem); + break; + + case USBD_EVENT_CONFIGURED: + nxsem_post(&g_usb_cdcacm_serial[2]->txdone_sem); + nxsem_post(&g_usb_cdcacm_serial[2]->rxdone_sem); + break; + default: + break; + } +} + +usbd_notify_handler cdcacm_notify_handler[8] = { + cdcacm_notify_handler1, + cdcacm_notify_handler2, + cdcacm_notify_handler3 +}; + +void usbd_cdcacm_init(uint8_t busid, uint8_t id, const char *path, uint8_t outep, uint8_t inep) +{ + g_usb_cdcacm_serial[id] = kmm_malloc(sizeof(struct usbdev_serial_s)); + DEBUGASSERT(g_usb_cdcacm_serial[id]); + + memset(g_usb_cdcacm_serial[id], 0, sizeof(struct usbdev_serial_s)); + strncpy(g_usb_cdcacm_serial[id]->name, path, sizeof(g_usb_cdcacm_serial[id]->name) - 1); + + circbuf_init(&g_usb_cdcacm_serial[id]->circ, g_usb_cdcacm_serial[id]->cache_rxbuffer, CONFIG_USBDEV_CDCACM_RXBUFSIZE); + + nxsem_init(&g_usb_cdcacm_serial[id]->rxdone_sem, 0, 0); + nxsem_init(&g_usb_cdcacm_serial[id]->txdone_sem, 0, 0); + + usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &g_usb_cdcacm_serial[id]->ctrl_intf)); + usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &g_usb_cdcacm_serial[id]->data_intf)); + g_usb_cdcacm_serial[id]->ctrl_intf.notify_handler = cdcacm_notify_handler[id]; + + cdc_out_ep[id].ep_addr = outep; + cdc_in_ep[id].ep_addr = inep; + g_usb_cdcacm_serial[id]->outep = outep; + g_usb_cdcacm_serial[id]->inep = inep; + usbd_add_endpoint(busid, &cdc_out_ep[id]); + usbd_add_endpoint(busid, &cdc_in_ep[id]); + + register_driver(path, &g_usbdevops, 0666, g_usb_cdcacm_serial[id]); +} + +void usbd_cdcacm_deinit(uint8_t busid, uint8_t id) +{ + unregister_driver(g_usb_cdcacm_serial[id]->name); + + kmm_free(g_usb_cdcacm_serial[id]); +} \ No newline at end of file diff --git a/platform/nuttx/usbd_fs.c b/platform/nuttx/usbd_fs.c new file mode 100644 index 00000000..3110dc6b --- /dev/null +++ b/platform/nuttx/usbd_fs.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025, sakumisu + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +#include "usbd_core.h" +#include "usbd_msc.h" + +#ifndef CONFIG_USBDEV_MSC_THREAD +#error "CONFIG_USBDEV_MSC_THREAD must be enabled" +#endif + +static FAR struct inode *inode; +static struct geometry geo; +static char devpath[32]; + +void usbd_msc_get_cap(uint8_t busid, uint8_t lun, uint32_t *block_num, uint32_t *block_size) +{ + int ret; + + /* Open the block driver */ + + ret = open_blockdriver(devpath, 0, &inode); + if (ret < 0) { + *block_num = 0; + *block_size = 0; + return; + } + + /* Get the drive geometry */ + + if (!inode || !inode->u.i_bops || !inode->u.i_bops->geometry || + inode->u.i_bops->geometry(inode, &geo) != OK || !geo.geo_available) { + *block_num = 0; + *block_size = 0; + return; + } + + *block_num = geo.geo_nsectors; + *block_size = geo.geo_sectorsize; + + USB_LOG_INFO("block_num: %ld, block_size: %ld\n", *block_num, *block_size); +} + +int usbd_msc_sector_read(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length) +{ + if (inode->u.i_bops->read) { + inode->u.i_bops->read(inode, buffer, sector, length / geo.geo_sectorsize); + } + + return 0; +} + +int usbd_msc_sector_write(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length) +{ + if (inode->u.i_bops->write) { + inode->u.i_bops->write(inode, buffer, sector, length / geo.geo_sectorsize); + } + + return 0; +} + +static struct usbd_interface intf0; + +void usbd_msc_init(uint8_t busid, char *path, uint8_t outep, uint8_t inep) +{ + memset(devpath, 0, sizeof(devpath)); + strncpy(devpath, path, sizeof(devpath) - 1); + usbd_add_interface(busid, usbd_msc_init_intf(busid, &intf0, outep, inep)); +} \ No newline at end of file diff --git a/platform/nuttx/usbh_fs.c b/platform/nuttx/usbh_fs.c index a55369f1..9f0e2b19 100644 --- a/platform/nuttx/usbh_fs.c +++ b/platform/nuttx/usbh_fs.c @@ -3,25 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include #include -#include #include "usbh_core.h" #include "usbh_msc.h" @@ -38,6 +20,57 @@ #define DEV_FORMAT "/dev/sd%c" +static int nuttx_errorcode(int error) +{ + int err = 0; + + switch (error) { + case -USB_ERR_NOMEM: + err = -EIO; + break; + case -USB_ERR_INVAL: + err = -EINVAL; + break; + case -USB_ERR_NODEV: + err = -ENODEV; + break; + case -USB_ERR_NOTCONN: + err = -ENOTCONN; + break; + case -USB_ERR_NOTSUPP: + err = -EIO; + break; + case -USB_ERR_BUSY: + err = -EBUSY; + break; + case -USB_ERR_RANGE: + err = -ERANGE; + break; + case -USB_ERR_STALL: + err = -EPERM; + break; + case -USB_ERR_NAK: + err = -EAGAIN; + break; + case -USB_ERR_DT: + err = -EIO; + break; + case -USB_ERR_IO: + err = -EIO; + break; + case -USB_ERR_SHUTDOWN: + err = -ESHUTDOWN; + break; + case -USB_ERR_TIMEOUT: + err = -ETIMEDOUT; + break; + + default: + break; + } + return err; +} + static int usbhost_open(FAR struct inode *inode); static int usbhost_close(FAR struct inode *inode); static ssize_t usbhost_read(FAR struct inode *inode, unsigned char *buffer, @@ -90,18 +123,14 @@ static ssize_t usbhost_read(FAR struct inode *inode, unsigned char *buffer, DEBUGASSERT(inode->i_private); msc_class = (struct usbh_msc *)inode->i_private; - if (msc_class->hport && msc_class->hport->connected) { - ret = usbh_msc_scsi_read10(msc_class, startsector, (uint8_t *)buffer, nsectors); - if (ret < 0) { - return ret; - } else { -#ifdef CONFIG_ARCH_DCACHE - up_invalidate_dcache((uintptr_t)buffer, (uintptr_t)(buffer + nsectors * msc_class->blocksize)); -#endif - return nsectors; - } + ret = usbh_msc_scsi_read10(msc_class, startsector, (uint8_t *)buffer, nsectors); + if (ret < 0) { + return nuttx_errorcode(ret); } else { - return -ENODEV; +#if defined(CONFIG_ARCH_DCACHE) && !defined(CONFIG_USB_DCACHE_ENABLE) + up_invalidate_dcache((uintptr_t)buffer, (uintptr_t)(buffer + nsectors * msc_class->blocksize)); +#endif + return nsectors; } } @@ -115,18 +144,14 @@ static ssize_t usbhost_write(FAR struct inode *inode, DEBUGASSERT(inode->i_private); msc_class = (struct usbh_msc *)inode->i_private; - if (msc_class->hport && msc_class->hport->connected) { -#ifdef CONFIG_ARCH_DCACHE - up_flush_dcache((uintptr_t)buffer, (uintptr_t)(buffer + nsectors * msc_class->blocksize)); +#if defined(CONFIG_ARCH_DCACHE) && !defined(CONFIG_USB_DCACHE_ENABLE) + up_clean_dcache((uintptr_t)buffer, (uintptr_t)(buffer + nsectors * msc_class->blocksize)); #endif - ret = usbh_msc_scsi_write10(msc_class, startsector, (uint8_t *)buffer, nsectors); - if (ret < 0) { - return ret; - } else { - return nsectors; - } + ret = usbh_msc_scsi_write10(msc_class, startsector, (uint8_t *)buffer, nsectors); + if (ret < 0) { + return nuttx_errorcode(ret); } else { - return -ENODEV; + return nsectors; } } @@ -147,7 +172,7 @@ static int usbhost_geometry(FAR struct inode *inode, geometry->geo_nsectors = msc_class->blocknum; geometry->geo_sectorsize = msc_class->blocksize; - uinfo("nsectors: %" PRIdOFF " sectorsize: %" PRIi16 "\n", + USB_LOG_DBG("nsectors: %ld, sectorsize: %ld\n", geometry->geo_nsectors, geometry->geo_sectorsize); return OK; } else { diff --git a/platform/nuttx/usbh_net.c b/platform/nuttx/usbh_net.c index d84165d5..c7af90f9 100644 --- a/platform/nuttx/usbh_net.c +++ b/platform/nuttx/usbh_net.c @@ -3,16 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include - -#include -#include -#include -#include -#include -#include -#include - #include #include diff --git a/platform/nuttx/usbh_serial.c b/platform/nuttx/usbh_serial.c new file mode 100644 index 00000000..1538714c --- /dev/null +++ b/platform/nuttx/usbh_serial.c @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2025, sakumisu + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include + +#include "usbh_core.h" +#include "usbh_cdc_acm.h" + +#include + +#define DEV_FORMAT "/dev/ttyACM%d" + +#ifndef CONFIG_USBHOST_CDCACM_RXBUFSIZE +#define CONFIG_USBHOST_CDCACM_RXBUFSIZE 512 +#endif + +#ifndef CONFIG_USBHOST_CDCACM_TXBUFSIZE +#define CONFIG_USBHOST_CDCACM_TXBUFSIZE 512 +#endif + +struct usbhost_serial_s { + struct circbuf_s circ; + __attribute__((aligned(32))) uint8_t cache_rxbuffer[CONFIG_USBHOST_CDCACM_RXBUFSIZE]; + __attribute__((aligned(32))) uint8_t cache_txbuffer[CONFIG_USBHOST_CDCACM_TXBUFSIZE]; +}; + +static int nuttx_errorcode(int error) +{ + int err = 0; + + switch (error) { + case -USB_ERR_NOMEM: + err = -EIO; + break; + case -USB_ERR_INVAL: + err = -EINVAL; + break; + case -USB_ERR_NODEV: + err = -ENODEV; + break; + case -USB_ERR_NOTCONN: + err = -ENOTCONN; + break; + case -USB_ERR_NOTSUPP: + err = -EIO; + break; + case -USB_ERR_BUSY: + err = -EBUSY; + break; + case -USB_ERR_RANGE: + err = -ERANGE; + break; + case -USB_ERR_STALL: + err = -EPERM; + break; + case -USB_ERR_NAK: + err = -EAGAIN; + break; + case -USB_ERR_DT: + err = -EIO; + break; + case -USB_ERR_IO: + err = -EIO; + break; + case -USB_ERR_SHUTDOWN: + err = -ESHUTDOWN; + break; + case -USB_ERR_TIMEOUT: + err = -ETIMEDOUT; + break; + + default: + break; + } + return err; +} + +/* Character driver methods */ + +static int usbhost_open(FAR struct file *filep); +static int usbhost_close(FAR struct file *filep); +static ssize_t usbhost_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); +static ssize_t usbhost_write(FAR struct file *filep, + FAR const char *buffer, size_t buflen); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations g_usbhostops = { + usbhost_open, /* open */ + usbhost_close, /* close */ + usbhost_read, /* read */ + usbhost_write, /* write */ + NULL, /* seek */ + NULL, /* ioctl */ + NULL, /* mmap */ + NULL, /* truncate */ + NULL /* poll */ +}; + +static int usbhost_open(FAR struct file *filep) +{ + struct usbh_cdc_acm *cdc_acm_class; + FAR struct inode *inode = filep->f_inode; + + DEBUGASSERT(inode->i_private); + cdc_acm_class = (struct usbh_cdc_acm *)inode->i_private; + + if (cdc_acm_class->hport && cdc_acm_class->hport->connected) { + return OK; + } else { + return -ENODEV; + } +} + +static int usbhost_close(FAR struct file *filep) +{ + FAR struct inode *inode = filep->f_inode; + + DEBUGASSERT(inode->i_private); + return 0; +} + +static ssize_t usbhost_read(FAR struct file *filep, FAR char *buffer, + size_t buflen) +{ + struct usbh_cdc_acm *cdc_acm_class; + FAR struct inode *inode = filep->f_inode; + struct usbhost_serial_s *serial; + __attribute__((aligned(32))) uint8_t cache_tempbuffer[512]; + int ret; + + DEBUGASSERT(inode->i_private || cdc_acm_class->user_data); + cdc_acm_class = (struct usbh_cdc_acm *)inode->i_private; + serial = cdc_acm_class->user_data; + + while (circbuf_used(&serial->circ) == 0) { + ret = usbh_cdc_acm_bulk_in_transfer(cdc_acm_class, cache_tempbuffer, cdc_acm_class->bulkin->wMaxPacketSize, 0xffffffff); + if (ret < 0) { + return nuttx_errorcode(ret); + } +#if defined(CONFIG_ARCH_DCACHE) && !defined(CONFIG_USB_DCACHE_ENABLE) + up_invalidate_dcache((uintptr_t)cache_tempbuffer, (uintptr_t)(cache_tempbuffer + cdc_acm_class->bulkin->wMaxPacketSize)); +#endif + circbuf_overwrite(&serial->circ, cache_tempbuffer, USB_ALIGN_UP(ret, 64)); + } + return circbuf_read(&serial->circ, buffer, buflen); +} + +static ssize_t usbhost_write(FAR struct file *filep, FAR const char *buffer, + size_t buflen) +{ + struct usbh_cdc_acm *cdc_acm_class; + FAR struct inode *inode = filep->f_inode; + struct usbhost_serial_s *serial; + int ret; + + DEBUGASSERT(inode->i_private || cdc_acm_class->user_data); + cdc_acm_class = (struct usbh_cdc_acm *)inode->i_private; + serial = cdc_acm_class->user_data; + +#ifdef CONFIG_ARCH_DCACHE + uint32_t write_len = 0; + + while (write_len < buflen) { + uint32_t len = buflen - write_len; + if (len > CONFIG_USBHOST_CDCACM_TXBUFSIZE) { + len = CONFIG_USBHOST_CDCACM_TXBUFSIZE; + } + memcpy(serial->cache_txbuffer, buffer + write_len, len); +#ifndef CONFIG_USB_DCACHE_ENABLE + up_clean_dcache((uintptr_t)serial->cache_txbuffer, (uintptr_t)(serial->cache_txbuffer + USB_ALIGN_UP(len, 64))); +#endif + ret = usbh_cdc_acm_bulk_out_transfer(cdc_acm_class, serial->cache_txbuffer, len, 0xffffffff); + if (ret < 0) { + return nuttx_errorcode(ret); + } else { + write_len += len; + } + } + return buflen; +#else + ret = usbh_cdc_acm_bulk_out_transfer(cdc_acm_class, (uint8_t *)buffer, buflen, 0xffffffff); + if (ret < 0) { + return nuttx_errorcode(ret); + } else { + return buflen; + } +#endif +} + +void usbh_cdc_acm_run(struct usbh_cdc_acm *cdc_acm_class) +{ + char devname[32]; + struct usbhost_serial_s *serial; + + snprintf(devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, cdc_acm_class->minor); + + serial = kmm_malloc(sizeof(struct usbhost_serial_s)); + DEBUGASSERT(serial); + + memset(serial, 0, sizeof(struct usbhost_serial_s)); + + circbuf_init(&serial->circ, serial->cache_rxbuffer, CONFIG_USBHOST_CDCACM_RXBUFSIZE); + + cdc_acm_class->user_data = serial; + + struct cdc_line_coding linecoding; + + 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); + + register_driver(devname, &g_usbhostops, 0666, cdc_acm_class); +} + +void usbh_cdc_acm_stop(struct usbh_cdc_acm *cdc_acm_class) +{ + char devname[32]; + struct usbhost_serial_s *serial; + + snprintf(devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, cdc_acm_class->minor); + unregister_driver(devname); + + serial = cdc_acm_class->user_data; + + kmm_free(serial); +} \ No newline at end of file