Skip to content

Commit 8f44b8b

Browse files
committed
feat(platform/nuttx): update fs & net & cdcacm support
Signed-off-by: sakumisu <1203593632@qq.com>
1 parent c399be3 commit 8f44b8b

File tree

6 files changed

+650
-50
lines changed

6 files changed

+650
-50
lines changed

osal/usb_osal_nuttx.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ int usb_osal_sem_give(usb_osal_sem_t sem)
131131

132132
void usb_osal_sem_reset(usb_osal_sem_t sem)
133133
{
134+
nxsem_reset((sem_t *)sem, 0);
134135
}
135136

136137
usb_osal_mutex_t usb_osal_mutex_create(void)

platform/nuttx/usbd_cdcacm.c

Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
/*
2+
* Copyright (c) 2025, sakumisu
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#include <nuttx/kmalloc.h>
7+
#include <nuttx/mutex.h>
8+
#include <nuttx/semaphore.h>
9+
#include <fcntl.h>
10+
11+
#include "usbd_core.h"
12+
#include "usbd_cdc_acm.h"
13+
14+
#include <nuttx/mm/circbuf.h>
15+
16+
#ifndef CONFIG_USBDEV_CDCACM_RXBUFSIZE
17+
#define CONFIG_USBDEV_CDCACM_RXBUFSIZE 512
18+
#endif
19+
20+
#ifndef CONFIG_USBDEV_CDCACM_TXBUFSIZE
21+
#define CONFIG_USBDEV_CDCACM_TXBUFSIZE 512
22+
#endif
23+
24+
USB_NOCACHE_RAM_SECTION struct usbdev_serial_s {
25+
char name[16];
26+
struct circbuf_s circ;
27+
uint8_t inep;
28+
uint8_t outep;
29+
struct usbd_interface ctrl_intf;
30+
struct usbd_interface data_intf;
31+
__attribute__((aligned(32))) uint8_t cache_tempbuffer[512];
32+
__attribute__((aligned(32))) uint8_t cache_rxbuffer[CONFIG_USBDEV_CDCACM_RXBUFSIZE];
33+
__attribute__((aligned(32))) uint8_t cache_txbuffer[CONFIG_USBDEV_CDCACM_TXBUFSIZE];
34+
};
35+
36+
struct usbdev_serial_ep_s {
37+
uint32_t rxlen;
38+
int error;
39+
sem_t txdone_sem;
40+
sem_t rxdone_sem;
41+
bool used;
42+
};
43+
44+
struct usbdev_serial_s *g_usb_cdcacm_serial[8] = { 0 };
45+
struct usbdev_serial_ep_s g_usb_cdcacm_serial_ep[2][8] = { 0 };
46+
47+
void usbd_cdc_acm_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
48+
{
49+
g_usb_cdcacm_serial_ep[0][ep & 0x0f].error = 0;
50+
g_usb_cdcacm_serial_ep[0][ep & 0x0f].rxlen = nbytes;
51+
nxsem_post(&g_usb_cdcacm_serial_ep[0][ep & 0x0f].rxdone_sem);
52+
}
53+
54+
void usbd_cdc_acm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
55+
{
56+
if ((nbytes % usbd_get_ep_mps(busid, ep)) == 0 && nbytes) {
57+
/* send zlp */
58+
usbd_ep_start_write(busid, ep, NULL, 0);
59+
} else {
60+
nxsem_post(&g_usb_cdcacm_serial_ep[1][ep & 0x0f].txdone_sem);
61+
}
62+
}
63+
64+
/* Character driver methods */
65+
66+
static int usbdev_open(FAR struct file *filep);
67+
static int usbdev_close(FAR struct file *filep);
68+
static ssize_t usbdev_read(FAR struct file *filep, FAR char *buffer,
69+
size_t buflen);
70+
static ssize_t usbdev_write(FAR struct file *filep,
71+
FAR const char *buffer, size_t buflen);
72+
73+
/****************************************************************************
74+
* Private Data
75+
****************************************************************************/
76+
77+
static const struct file_operations g_usbdevops = {
78+
usbdev_open, /* open */
79+
usbdev_close, /* close */
80+
usbdev_read, /* read */
81+
usbdev_write, /* write */
82+
NULL, /* seek */
83+
NULL, /* ioctl */
84+
NULL, /* mmap */
85+
NULL, /* truncate */
86+
NULL /* poll */
87+
};
88+
89+
static int usbdev_open(FAR struct file *filep)
90+
{
91+
FAR struct inode *inode = filep->f_inode;
92+
93+
DEBUGASSERT(inode->i_private);
94+
95+
if (usb_device_is_configured(0)) {
96+
return OK;
97+
} else {
98+
return -ENODEV;
99+
}
100+
}
101+
102+
static int usbdev_close(FAR struct file *filep)
103+
{
104+
FAR struct inode *inode = filep->f_inode;
105+
106+
DEBUGASSERT(inode->i_private);
107+
108+
if (!usb_device_is_configured(0)) {
109+
return -ENODEV;
110+
}
111+
112+
return 0;
113+
}
114+
115+
static ssize_t usbdev_read(FAR struct file *filep, FAR char *buffer,
116+
size_t buflen)
117+
{
118+
FAR struct inode *inode = filep->f_inode;
119+
struct usbdev_serial_s *serial;
120+
int ret;
121+
122+
DEBUGASSERT(inode->i_private);
123+
serial = (struct usbdev_serial_s *)inode->i_private;
124+
125+
if (!usb_device_is_configured(0)) {
126+
return -ENODEV;
127+
}
128+
129+
while (circbuf_used(&serial->circ) == 0) {
130+
nxsem_reset(&g_usb_cdcacm_serial_ep[0][serial->outep & 0x0f].rxdone_sem, 0);
131+
usbd_ep_start_read(0, serial->outep, serial->cache_tempbuffer, usbd_get_ep_mps(0, serial->outep));
132+
ret = nxsem_wait(&g_usb_cdcacm_serial_ep[0][serial->outep & 0x0f].rxdone_sem);
133+
if (ret < 0) {
134+
return ret;
135+
}
136+
if (g_usb_cdcacm_serial_ep[0][serial->outep & 0x0f].error < 0) {
137+
return g_usb_cdcacm_serial_ep[0][serial->outep & 0x0f].error;
138+
}
139+
#if defined(CONFIG_ARCH_DCACHE) && !defined(CONFIG_USB_DCACHE_ENABLE)
140+
up_invalidate_dcache((uintptr_t)serial->cache_tempbuffer, (uintptr_t)(serial->cache_tempbuffer + USB_ALIGN_UP(g_usb_cdcacm_serial_ep[0][serial->outep & 0x0f].rxlen, 64)));
141+
#endif
142+
circbuf_overwrite(&serial->circ, serial->cache_tempbuffer, g_usb_cdcacm_serial_ep[0][serial->outep & 0x0f].rxlen);
143+
}
144+
return circbuf_read(&serial->circ, buffer, buflen);
145+
}
146+
147+
static ssize_t usbdev_write(FAR struct file *filep, FAR const char *buffer,
148+
size_t buflen)
149+
{
150+
FAR struct inode *inode = filep->f_inode;
151+
struct usbdev_serial_s *serial;
152+
int ret;
153+
154+
DEBUGASSERT(inode->i_private);
155+
serial = (struct usbdev_serial_s *)inode->i_private;
156+
157+
if (!usb_device_is_configured(0)) {
158+
return -ENODEV;
159+
}
160+
161+
#ifdef CONFIG_ARCH_DCACHE
162+
uint32_t write_len = 0;
163+
164+
while (write_len < buflen) {
165+
uint32_t len = buflen - write_len;
166+
if (len > CONFIG_USBDEV_CDCACM_TXBUFSIZE) {
167+
len = CONFIG_USBDEV_CDCACM_TXBUFSIZE;
168+
}
169+
memcpy(serial->cache_txbuffer, buffer + write_len, len);
170+
#ifndef CONFIG_USB_DCACHE_ENABLE
171+
up_clean_dcache((uintptr_t)serial->cache_txbuffer, (uintptr_t)(serial->cache_txbuffer + USB_ALIGN_UP(len, 64)));
172+
#endif
173+
nxsem_reset(&g_usb_cdcacm_serial_ep[0][serial->inep & 0x0f].txdone_sem, 0);
174+
usbd_ep_start_write(0, serial->inep, serial->cache_txbuffer, len);
175+
ret = nxsem_wait(&g_usb_cdcacm_serial_ep[0][serial->inep & 0x0f].txdone_sem);
176+
if (ret < 0) {
177+
return ret;
178+
} else {
179+
if (g_usb_cdcacm_serial_ep[1][serial->inep & 0x0f].error < 0) {
180+
return g_usb_cdcacm_serial_ep[1][serial->inep & 0x0f].error;
181+
}
182+
write_len += len;
183+
}
184+
}
185+
return buflen;
186+
#else
187+
nxsem_reset(&g_usb_cdcacm_serial_ep[0][outep & 0x0f].txdone_sem, 0);
188+
usbd_ep_start_write(0, serial->inep, buffer, buflen);
189+
ret = nxsem_wait(&g_usb_cdcacm_serial_ep[0][outep & 0x0f].txdone_sem);
190+
if (ret < 0) {
191+
return ret;
192+
} else {
193+
if (g_usb_cdcacm_serial_ep[1][serial->inep & 0x0f].error < 0) {
194+
return g_usb_cdcacm_serial_ep[1][serial->inep & 0x0f].error;
195+
}
196+
return buflen;
197+
}
198+
#endif
199+
}
200+
201+
static struct usbd_endpoint cdc_out_ep[8] = { 0 };
202+
static struct usbd_endpoint cdc_in_ep[8] = { 0 };
203+
204+
static void cdcacm_notify_handler(uint8_t busid, uint8_t event, void *arg)
205+
{
206+
switch (event) {
207+
case USBD_EVENT_RESET:
208+
break;
209+
case USBD_EVENT_DISCONNECTED:
210+
for (size_t i = 0; i < 8; i++) {
211+
if (g_usb_cdcacm_serial_ep[0][i & 0x0f].used) {
212+
g_usb_cdcacm_serial_ep[0][i & 0x0f].error = -ESHUTDOWN;
213+
nxsem_post(&g_usb_cdcacm_serial_ep[0][i & 0x0f].rxdone_sem);
214+
}
215+
if (g_usb_cdcacm_serial_ep[1][i & 0x0f].used) {
216+
g_usb_cdcacm_serial_ep[1][i & 0x0f].error = -ESHUTDOWN;
217+
nxsem_post(&g_usb_cdcacm_serial_ep[1][i & 0x0f].txdone_sem);
218+
}
219+
}
220+
break;
221+
case USBD_EVENT_CONFIGURED:
222+
for (size_t i = 0; i < 8; i++) {
223+
if (g_usb_cdcacm_serial_ep[0][i & 0x0f].used) {
224+
g_usb_cdcacm_serial_ep[0][i & 0x0f].error = 0;
225+
nxsem_post(&g_usb_cdcacm_serial_ep[0][i & 0x0f].rxdone_sem);
226+
}
227+
if (g_usb_cdcacm_serial_ep[1][i & 0x0f].used) {
228+
g_usb_cdcacm_serial_ep[1][i & 0x0f].error = 0;
229+
nxsem_post(&g_usb_cdcacm_serial_ep[1][i & 0x0f].txdone_sem);
230+
}
231+
}
232+
break;
233+
default:
234+
break;
235+
}
236+
}
237+
238+
void usbd_cdcacm_init(uint8_t busid, uint8_t id, const char *path, uint8_t outep, uint8_t inep)
239+
{
240+
g_usb_cdcacm_serial[id] = kmm_malloc(sizeof(struct usbdev_serial_s));
241+
DEBUGASSERT(g_usb_cdcacm_serial[id]);
242+
243+
memset(g_usb_cdcacm_serial[id], 0, sizeof(struct usbdev_serial_s));
244+
strncpy(g_usb_cdcacm_serial[id]->name, path, sizeof(g_usb_cdcacm_serial[id]->name) - 1);
245+
246+
circbuf_init(&g_usb_cdcacm_serial[id]->circ, g_usb_cdcacm_serial[id]->cache_rxbuffer, CONFIG_USBDEV_CDCACM_RXBUFSIZE);
247+
248+
nxsem_init(&g_usb_cdcacm_serial_ep[0][outep & 0x0f].rxdone_sem, 0, 0);
249+
nxsem_init(&g_usb_cdcacm_serial_ep[1][inep & 0x0f].txdone_sem, 0, 0);
250+
g_usb_cdcacm_serial_ep[0][outep & 0x0f].used = true;
251+
g_usb_cdcacm_serial_ep[1][inep & 0x0f].used = true;
252+
253+
usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &g_usb_cdcacm_serial[id]->ctrl_intf));
254+
usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &g_usb_cdcacm_serial[id]->data_intf));
255+
g_usb_cdcacm_serial[id]->ctrl_intf.notify_handler = cdcacm_notify_handler;
256+
g_usb_cdcacm_serial[id]->outep = outep;
257+
g_usb_cdcacm_serial[id]->inep = inep;
258+
259+
cdc_out_ep[id].ep_addr = outep;
260+
cdc_out_ep[id].ep_cb = usbd_cdc_acm_bulk_out;
261+
cdc_in_ep[id].ep_addr = inep;
262+
cdc_in_ep[id].ep_cb = usbd_cdc_acm_bulk_in;
263+
264+
usbd_add_endpoint(busid, &cdc_out_ep[id]);
265+
usbd_add_endpoint(busid, &cdc_in_ep[id]);
266+
267+
register_driver(path, &g_usbdevops, 0666, g_usb_cdcacm_serial[id]);
268+
}
269+
270+
void usbd_cdcacm_deinit(uint8_t busid, uint8_t id)
271+
{
272+
unregister_driver(g_usb_cdcacm_serial[id]->name);
273+
274+
kmm_free(g_usb_cdcacm_serial[id]);
275+
}

platform/nuttx/usbd_fs.c

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright (c) 2025, sakumisu
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#include <nuttx/fs/fs.h>
7+
8+
#include "usbd_core.h"
9+
#include "usbd_msc.h"
10+
11+
#ifndef CONFIG_USBDEV_MSC_THREAD
12+
#error "CONFIG_USBDEV_MSC_THREAD must be enabled"
13+
#endif
14+
15+
static FAR struct inode *inode;
16+
static struct geometry geo;
17+
static char devpath[32];
18+
19+
void usbd_msc_get_cap(uint8_t busid, uint8_t lun, uint32_t *block_num, uint32_t *block_size)
20+
{
21+
int ret;
22+
23+
/* Open the block driver */
24+
25+
ret = open_blockdriver(devpath, 0, &inode);
26+
if (ret < 0) {
27+
*block_num = 0;
28+
*block_size = 0;
29+
return;
30+
}
31+
32+
/* Get the drive geometry */
33+
34+
if (!inode || !inode->u.i_bops || !inode->u.i_bops->geometry ||
35+
inode->u.i_bops->geometry(inode, &geo) != OK || !geo.geo_available) {
36+
*block_num = 0;
37+
*block_size = 0;
38+
return;
39+
}
40+
41+
*block_num = geo.geo_nsectors;
42+
*block_size = geo.geo_sectorsize;
43+
44+
USB_LOG_INFO("block_num: %ld, block_size: %ld\n", *block_num, *block_size);
45+
}
46+
47+
int usbd_msc_sector_read(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length)
48+
{
49+
if (inode->u.i_bops->read) {
50+
inode->u.i_bops->read(inode, buffer, sector, length / geo.geo_sectorsize);
51+
}
52+
53+
return 0;
54+
}
55+
56+
int usbd_msc_sector_write(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length)
57+
{
58+
if (inode->u.i_bops->write) {
59+
inode->u.i_bops->write(inode, buffer, sector, length / geo.geo_sectorsize);
60+
}
61+
62+
return 0;
63+
}
64+
65+
static struct usbd_interface intf0;
66+
67+
void usbd_msc_init(uint8_t busid, char *path, uint8_t outep, uint8_t inep)
68+
{
69+
memset(devpath, 0, sizeof(devpath));
70+
strncpy(devpath, path, sizeof(devpath) - 1);
71+
usbd_add_interface(busid, usbd_msc_init_intf(busid, &intf0, outep, inep));
72+
}

0 commit comments

Comments
 (0)