summaryrefslogtreecommitdiff
path: root/components/legacy
diff options
context:
space:
mode:
Diffstat (limited to 'components/legacy')
-rw-r--r--components/legacy/Kconfig200
-rw-r--r--components/legacy/usb/SConscript13
-rw-r--r--components/legacy/usb/usbdevice/SConscript38
-rw-r--r--components/legacy/usb/usbdevice/class/audio_mic.c581
-rw-r--r--components/legacy/usb/usbdevice/class/audio_speaker.c582
-rw-r--r--components/legacy/usb/usbdevice/class/cdc.h229
-rw-r--r--components/legacy/usb/usbdevice/class/cdc_vcom.c1008
-rw-r--r--components/legacy/usb/usbdevice/class/ecm.c682
-rw-r--r--components/legacy/usb/usbdevice/class/hid.c756
-rw-r--r--components/legacy/usb/usbdevice/class/hid.h258
-rw-r--r--components/legacy/usb/usbdevice/class/mstorage.c1167
-rw-r--r--components/legacy/usb/usbdevice/class/mstorage.h53
-rw-r--r--components/legacy/usb/usbdevice/class/ndis.h237
-rw-r--r--components/legacy/usb/usbdevice/class/rndis.c1476
-rw-r--r--components/legacy/usb/usbdevice/class/rndis.h227
-rw-r--r--components/legacy/usb/usbdevice/class/uaudioreg.h419
-rw-r--r--components/legacy/usb/usbdevice/class/winusb.c375
-rw-r--r--components/legacy/usb/usbdevice/class/winusb.h24
-rw-r--r--components/legacy/usb/usbdevice/core/usbdevice.c164
-rw-r--r--components/legacy/usb/usbdevice/core/usbdevice_core.c2269
-rw-r--r--components/legacy/usb/usbhost/SConscript34
-rw-r--r--components/legacy/usb/usbhost/class/adk.c426
-rw-r--r--components/legacy/usb/usbhost/class/adk.h43
-rw-r--r--components/legacy/usb/usbhost/class/hid.c410
-rw-r--r--components/legacy/usb/usbhost/class/hid.h41
-rw-r--r--components/legacy/usb/usbhost/class/mass.c647
-rw-r--r--components/legacy/usb/usbhost/class/mass.h50
-rw-r--r--components/legacy/usb/usbhost/class/udisk.c456
-rw-r--r--components/legacy/usb/usbhost/class/ukbd.c93
-rw-r--r--components/legacy/usb/usbhost/class/umouse.c190
-rw-r--r--components/legacy/usb/usbhost/core/driver.c147
-rw-r--r--components/legacy/usb/usbhost/core/hub.c727
-rw-r--r--components/legacy/usb/usbhost/core/usbhost.c76
-rw-r--r--components/legacy/usb/usbhost/core/usbhost_core.c586
34 files changed, 14684 insertions, 0 deletions
diff --git a/components/legacy/Kconfig b/components/legacy/Kconfig
new file mode 100644
index 0000000000..d20c0f92f9
--- /dev/null
+++ b/components/legacy/Kconfig
@@ -0,0 +1,200 @@
+menu "Using USB legacy version"
+ config RT_USING_USB
+ bool
+ default n
+
+ config RT_USING_USB_HOST
+ bool "Using USB host"
+ default n
+ select RT_USING_USB
+
+ if RT_USING_USB_HOST
+ config RT_USBH_MSTORAGE
+ bool "Enable Udisk Drivers"
+ default n
+ if RT_USBH_MSTORAGE
+ config UDISK_MOUNTPOINT
+ string "Udisk mount dir"
+ default "/"
+ endif
+ config RT_USBH_HID
+ bool "Enable HID Drivers"
+ default n
+ if RT_USBH_HID
+ config RT_USBH_HID_MOUSE
+ bool "Enable HID mouse protocol"
+ default n
+ config RT_USBH_HID_KEYBOARD
+ bool "Enable HID keyboard protocol"
+ default n
+ endif
+ endif
+ config RT_USING_USB_DEVICE
+ bool "Using USB device"
+ default n
+ select RT_USING_USB
+
+ if RT_USING_USB_DEVICE || RT_USING_USB_HOST
+ config RT_USBD_THREAD_STACK_SZ
+ int "usb thread stack size"
+ default 4096
+ endif
+ if RT_USING_USB_DEVICE
+ config USB_VENDOR_ID
+ hex "USB Vendor ID"
+ default 0x0FFE
+ config USB_PRODUCT_ID
+ hex "USB Product ID"
+ default 0x0001
+
+ config RT_USB_DEVICE_COMPOSITE
+ bool "Enable composite device"
+ default n
+ choice
+ prompt "Device type"
+ default _RT_USB_DEVICE_NONE
+ depends on !RT_USB_DEVICE_COMPOSITE
+ config _RT_USB_DEVICE_NONE
+ bool "Using custom class by register interface"
+ select RT_USB_DEVICE_NONE
+ config _RT_USB_DEVICE_CDC
+ bool "Enable to use device as CDC device"
+ select RT_USB_DEVICE_CDC
+ config _RT_USB_DEVICE_MSTORAGE
+ bool "Enable to use device as Mass Storage device"
+ select RT_USB_DEVICE_MSTORAGE
+ config _RT_USB_DEVICE_HID
+ bool "Enable to use device as HID device"
+ select RT_USB_DEVICE_HID
+ config _RT_USB_DEVICE_RNDIS
+ bool "Enable to use device as rndis device"
+ select RT_USB_DEVICE_RNDIS
+ depends on RT_USING_LWIP
+ config _RT_USB_DEVICE_ECM
+ bool "Enable to use device as ecm device"
+ select RT_USB_DEVICE_ECM
+ depends on RT_USING_LWIP
+ config _RT_USB_DEVICE_WINUSB
+ bool "Enable to use device as winusb device"
+ select RT_USB_DEVICE_WINUSB
+ config _RT_USB_DEVICE_AUDIO
+ bool "Enable to use device as audio device"
+ select RT_USB_DEVICE_AUDIO
+ endchoice
+ if RT_USB_DEVICE_COMPOSITE
+ config RT_USB_DEVICE_CDC
+ bool "Enable to use device as CDC device"
+ default n
+ config RT_USB_DEVICE_NONE
+ bool
+ default y
+ config RT_USB_DEVICE_MSTORAGE
+ bool "Enable to use device as Mass Storage device"
+ default n
+ config RT_USB_DEVICE_HID
+ bool "Enable to use device as HID device"
+ default n
+ config RT_USB_DEVICE_RNDIS
+ bool "Enable to use device as rndis device"
+ default n
+ depends on RT_USING_LWIP
+ config RT_USB_DEVICE_ECM
+ bool "Enable to use device as ecm device"
+ default n
+ depends on RT_USING_LWIP
+ config RT_USB_DEVICE_WINUSB
+ bool "Enable to use device as winusb device"
+ default n
+ config RT_USB_DEVICE_AUDIO
+ bool "Enable to use device as audio device"
+ default n
+ endif
+ if RT_USB_DEVICE_CDC
+ config RT_VCOM_TASK_STK_SIZE
+ int "virtual com thread stack size"
+ default 512
+ config RT_CDC_RX_BUFSIZE
+ int "virtual com rx buffer size"
+ default 128
+ config RT_VCOM_TX_USE_DMA
+ bool "Enable to use dma for vcom tx"
+ default n
+ config RT_VCOM_SERNO
+ string "serial number of virtual com"
+ default "32021919830108"
+ config RT_VCOM_SER_LEN
+ int "serial number length of virtual com"
+ default 14
+ config RT_VCOM_TX_TIMEOUT
+ int "tx timeout(ticks) of virtual com"
+ default 1000
+ endif
+ if RT_USB_DEVICE_WINUSB
+ config RT_WINUSB_GUID
+ string "Guid for winusb"
+ default "{6860DC3C-C05F-4807-8807-1CA861CC1D66}"
+ endif
+ if RT_USB_DEVICE_MSTORAGE
+ config RT_USB_MSTORAGE_DISK_NAME
+ string "msc class disk name"
+ default "flash0"
+ endif
+
+ if RT_USB_DEVICE_RNDIS
+ config RNDIS_DELAY_LINK_UP
+ bool "Delay linkup media connection"
+ select RT_USING_TIMER_SOFT
+ default n
+ endif
+
+ if RT_USB_DEVICE_HID
+ config RT_USB_DEVICE_HID_KEYBOARD
+ bool "Use to HID device as Keyboard"
+ default n
+ if RT_USB_DEVICE_HID_KEYBOARD
+ config RT_USB_DEVICE_HID_KEYBOARD_NUMBER
+ int "Number of Keyboard(max 3)"
+ default 1
+ range 1 3
+ endif
+ config RT_USB_DEVICE_HID_MOUSE
+ bool "Use to HID device as Mouse"
+ default n
+ config RT_USB_DEVICE_HID_GENERAL
+ bool "Use to HID device as General HID device"
+ default y
+ if RT_USB_DEVICE_HID_GENERAL
+ config RT_USB_DEVICE_HID_GENERAL_OUT_REPORT_LENGTH
+ int "General HID device out report length"
+ default 63
+ range 0 63
+
+ config RT_USB_DEVICE_HID_GENERAL_IN_REPORT_LENGTH
+ int "General HID device in report length"
+ default 63
+ range 0 63
+ endif
+ config RT_USB_DEVICE_HID_MEDIA
+ bool "Use to HID device as media keyboard"
+ default y
+ endif
+ if RT_USB_DEVICE_AUDIO
+ config RT_USB_DEVICE_AUDIO_MIC
+ bool "Use usb mic device as audio device"
+ default n
+ if RT_USB_DEVICE_AUDIO_MIC
+ config RT_USBD_MIC_DEVICE_NAME
+ string "audio mic device name"
+ default "mic0"
+ endif
+ config RT_USB_DEVICE_AUDIO_SPEAKER
+ bool "Use usb speaker device as audio device"
+ default n
+ if RT_USB_DEVICE_AUDIO_SPEAKER
+ config RT_USBD_SPEAKER_DEVICE_NAME
+ string "audio speaker device name"
+ default "sound0"
+ endif
+ endif
+ endif
+endmenu
diff --git a/components/legacy/usb/SConscript b/components/legacy/usb/SConscript
new file mode 100644
index 0000000000..3e148cefe2
--- /dev/null
+++ b/components/legacy/usb/SConscript
@@ -0,0 +1,13 @@
+# for module compiling
+import os
+from building import *
+
+cwd = GetCurrentDir()
+objs = []
+list = os.listdir(cwd)
+
+for d in list:
+ path = os.path.join(cwd, d)
+ if os.path.isfile(os.path.join(path, 'SConscript')):
+ objs = objs + SConscript(os.path.join(d, 'SConscript'))
+Return('objs')
diff --git a/components/legacy/usb/usbdevice/SConscript b/components/legacy/usb/usbdevice/SConscript
new file mode 100644
index 0000000000..3cc5bf6d43
--- /dev/null
+++ b/components/legacy/usb/usbdevice/SConscript
@@ -0,0 +1,38 @@
+Import('RTT_ROOT')
+from building import *
+
+cwd = GetCurrentDir()
+src = Split("""
+core/usbdevice_core.c
+core/usbdevice.c
+""")
+
+if GetDepend('RT_USB_DEVICE_CDC'):
+ src += Glob('class/cdc_vcom.c')
+
+if GetDepend('RT_USB_DEVICE_HID'):
+ src += Glob('class/hid.c')
+
+if GetDepend('RT_USB_DEVICE_MSTORAGE'):
+ src += Glob('class/mstorage.c')
+
+if GetDepend('RT_USB_DEVICE_ECM'):
+ src += Glob('class/ecm.c')
+
+if GetDepend('RT_USB_DEVICE_RNDIS'):
+ src += Glob('class/rndis.c')
+
+if GetDepend('RT_USB_DEVICE_WINUSB'):
+ src += Glob('class/winusb.c')
+
+if GetDepend('RT_USB_DEVICE_AUDIO_MIC'):
+ src += Glob('class/audio_mic.c')
+
+if GetDepend('RT_USB_DEVICE_AUDIO_SPEAKER'):
+ src += Glob('class/audio_speaker.c')
+
+CPPPATH = [cwd]
+
+group = DefineGroup('rt_usbd', src, depend = ['RT_USING_USB_DEVICE'], CPPPATH = CPPPATH)
+
+Return('group')
diff --git a/components/legacy/usb/usbdevice/class/audio_mic.c b/components/legacy/usb/usbdevice/class/audio_mic.c
new file mode 100644
index 0000000000..9612e6b93f
--- /dev/null
+++ b/components/legacy/usb/usbdevice/class/audio_mic.c
@@ -0,0 +1,581 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2019-09-07 flybreak the first version
+ */
+
+#include <rthw.h>
+#include <rtdevice.h>
+#include "drivers/usb_device.h"
+
+#include "uaudioreg.h"
+
+#define DBG_TAG "usbd.audio.mic"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#define RECORD_SAMPLERATE 16000
+#define RECORD_CHANNEL 1
+#define RESOLUTION_BITS 16
+
+#define RESOLUTION_BYTE (RESOLUTION_BITS / 8)
+#define RECORD_PER_MS_SZ ((RECORD_SAMPLERATE * RECORD_CHANNEL * RESOLUTION_BYTE) / 1000)
+#define RECORD_BUFFER_SZ (RECORD_PER_MS_SZ * 20) /* 20ms */
+
+#if defined(RT_USBD_MIC_DEVICE_NAME)
+ #define MIC_DEVICE_NAME RT_USBD_MIC_DEVICE_NAME
+#else
+ #define MIC_DEVICE_NAME "mic0"
+#endif
+
+#define EVENT_RECORD_START (1 << 0)
+#define EVENT_RECORD_STOP (1 << 1)
+#define EVENT_RECORD_DATA (1 << 2)
+
+#define MIC_INTF_STR_INDEX 8
+/*
+ * uac mic descriptor define
+ */
+
+#define UAC_CS_INTERFACE 0x24
+#define UAC_CS_ENDPOINT 0x25
+
+#define UAC_MAX_PACKET_SIZE 64
+#define UAC_EP_MAX_PACKET_SIZE 32
+#define UAC_CHANNEL_NUM RECORD_CHANNEL
+
+struct uac_ac_descriptor
+{
+#ifdef RT_USB_DEVICE_COMPOSITE
+ struct uiad_descriptor iad_desc;
+#endif
+ struct uinterface_descriptor intf_desc;
+ struct usb_audio_control_descriptor hdr_desc;
+ struct usb_audio_input_terminal it_desc;
+ struct usb_audio_output_terminal ot_desc;
+#if UAC_USE_FEATURE_UNIT
+ struct usb_audio_feature_unit feature_unit_desc;
+#endif
+};
+
+struct uac_as_descriptor
+{
+ struct uinterface_descriptor intf_desc;
+ struct usb_audio_streaming_interface_descriptor hdr_desc;
+ struct usb_audio_streaming_type1_descriptor format_type_desc;
+ struct uendpoint_descriptor ep_desc;
+ struct usb_audio_streaming_endpoint_descriptor as_ep_desc;
+};
+
+/*
+ * uac mic device type
+ */
+
+struct uac_audio_mic
+{
+ rt_device_t dev;
+ rt_event_t event;
+ rt_uint8_t open_count;
+
+ rt_uint8_t *buffer;
+ rt_uint32_t buffer_index;
+
+ uep_t ep;
+};
+static struct uac_audio_mic mic;
+
+rt_align(4)
+static struct udevice_descriptor dev_desc =
+{
+ USB_DESC_LENGTH_DEVICE, //bLength;
+ USB_DESC_TYPE_DEVICE, //type;
+ USB_BCD_VERSION, //bcdUSB;
+ USB_CLASS_DEVICE, //bDeviceClass;
+ 0x00, //bDeviceSubClass;
+ 0x00, //bDeviceProtocol;
+ UAC_MAX_PACKET_SIZE, //bMaxPacketSize0;
+ _VENDOR_ID, //idVendor;
+ _PRODUCT_ID, //idProduct;
+ USB_BCD_DEVICE, //bcdDevice;
+ USB_STRING_MANU_INDEX, //iManufacturer;
+ USB_STRING_PRODUCT_INDEX, //iProduct;
+ USB_STRING_SERIAL_INDEX, //iSerialNumber;Unused.
+ USB_DYNAMIC, //bNumConfigurations;
+};
+
+//FS and HS needed
+rt_align(4)
+static struct usb_qualifier_descriptor dev_qualifier =
+{
+ sizeof(dev_qualifier), //bLength
+ USB_DESC_TYPE_DEVICEQUALIFIER, //bDescriptorType
+ 0x0200, //bcdUSB
+ USB_CLASS_AUDIO, //bDeviceClass
+ 0x00, //bDeviceSubClass
+ 0x00, //bDeviceProtocol
+ 64, //bMaxPacketSize0
+ 0x01, //bNumConfigurations
+ 0,
+};
+
+rt_align(4)
+const static char *_ustring[] =
+{
+ "Language",
+ "RT-Thread Team.",
+ "RT-Thread Audio Microphone",
+ "32021919830108",
+ "Configuration",
+ "Interface",
+};
+
+rt_align(4)
+static struct uac_ac_descriptor ac_desc =
+{
+#ifdef RT_USB_DEVICE_COMPOSITE
+ /* Interface Association Descriptor */
+ {
+ USB_DESC_LENGTH_IAD,
+ USB_DESC_TYPE_IAD,
+ USB_DYNAMIC,
+ 0x02,
+ USB_CLASS_AUDIO,
+ USB_SUBCLASS_AUDIOSTREAMING,
+ 0x00,
+ 0x00,
+ },
+#endif
+ /* Interface Descriptor */
+ {
+ USB_DESC_LENGTH_INTERFACE,
+ USB_DESC_TYPE_INTERFACE,
+ USB_DYNAMIC,
+ 0x00,
+ 0x00,
+ USB_CLASS_AUDIO,
+ USB_SUBCLASS_AUDIOCONTROL,
+ 0x00,
+#ifdef RT_USB_DEVICE_COMPOSITE
+ MIC_INTF_STR_INDEX,
+#else
+ 0x00,
+#endif
+ },
+ /* Header Descriptor */
+ {
+ sizeof(struct usb_audio_control_descriptor),
+ UAC_CS_INTERFACE,
+ UDESCSUB_AC_HEADER,
+ 0x0100, /* Version: 1.00 */
+ 0x001E, /* Total length: 30 */
+ 0x01, /* Total number of interfaces: 1 */
+ {0x01}, /* Interface number: 1 */
+ },
+ /* Input Terminal Descriptor */
+ {
+ sizeof(struct usb_audio_input_terminal),
+ UAC_CS_INTERFACE,
+ UDESCSUB_AC_INPUT,
+ 0x01, /* Terminal ID: 1 */
+ 0x0201, /* Terminal Type: Microphone (0x0201) */
+ 0x00, /* Assoc Terminal: 0 */
+ 0x01, /* Number Channels: 1 */
+ 0x0000, /* Channel Config: 0x0000 */
+ 0x00, /* Channel Names: 0 */
+ 0x00, /* Terminal: 0 */
+ },
+ /* Output Terminal Descriptor */
+ {
+ sizeof(struct usb_audio_output_terminal),
+ UAC_CS_INTERFACE,
+ UDESCSUB_AC_OUTPUT,
+ 0x02, /* Terminal ID: 2 */
+ 0x0101, /* Terminal Type: USB Streaming (0x0101) */
+ 0x00, /* Assoc Terminal: 0 */
+ 0x01, /* Source ID: 1 */
+ 0x00, /* Terminal: 0 */
+ },
+#if UAC_USE_FEATURE_UNIT
+ /* Feature unit Descriptor */
+ {
+ sizeof(struct usb_audio_feature_unit),
+ UAC_CS_INTERFACE,
+ UDESCSUB_AC_FEATURE,
+ 0x02,
+ 0x01,
+ 0x01,
+ 0x00,
+ 0x01,
+ },
+#endif
+};
+
+rt_align(4)
+static struct uinterface_descriptor as_desc0 =
+{
+ USB_DESC_LENGTH_INTERFACE,
+ USB_DESC_TYPE_INTERFACE,
+ USB_DYNAMIC,
+ 0x00,
+ 0x00,
+ USB_CLASS_AUDIO,
+ USB_SUBCLASS_AUDIOSTREAMING,
+ 0x00,
+ 0x00,
+};
+
+rt_align(4)
+static struct uac_as_descriptor as_desc =
+{
+ /* Interface Descriptor */
+ {
+ USB_DESC_LENGTH_INTERFACE,
+ USB_DESC_TYPE_INTERFACE,
+ USB_DYNAMIC,
+ 0x01,
+ 0x01,
+ USB_CLASS_AUDIO,
+ USB_SUBCLASS_AUDIOSTREAMING,
+ 0x00,
+ 0x00,
+ },
+ /* General AS Descriptor */
+ {
+ sizeof(struct usb_audio_streaming_interface_descriptor),
+ UAC_CS_INTERFACE,
+ AS_GENERAL,
+ 0x02, /* Terminal ID: 2 */
+ 0x01, /* Interface delay in frames: 1 */
+ UA_FMT_PCM,
+ },
+ /* Format type i Descriptor */
+ {
+ sizeof(struct usb_audio_streaming_type1_descriptor),
+ UAC_CS_INTERFACE,
+ FORMAT_TYPE,
+ FORMAT_TYPE_I,
+ UAC_CHANNEL_NUM,
+ 2, /* Subframe Size: 2 */
+ RESOLUTION_BITS,
+ 0x01, /* Samples Frequence Type: 1 */
+ {0}, /* Samples Frequence */
+ },
+ /* Endpoint Descriptor */
+ {
+ USB_DESC_LENGTH_ENDPOINT,
+ USB_DESC_TYPE_ENDPOINT,
+ USB_DYNAMIC | USB_DIR_IN,
+ USB_EP_ATTR_ISOC,
+ UAC_EP_MAX_PACKET_SIZE,
+ 0x01,
+ },
+ /* AS Endpoint Descriptor */
+ {
+ sizeof(struct usb_audio_streaming_endpoint_descriptor),
+ UAC_CS_ENDPOINT,
+ AS_GENERAL,
+ },
+};
+
+void mic_entry(void *parameter)
+{
+ struct rt_audio_caps caps = {0};
+ rt_uint32_t e, index;
+
+ mic.buffer = rt_malloc(RECORD_BUFFER_SZ);
+ if (mic.buffer == RT_NULL)
+ {
+ LOG_E("malloc failed");
+ goto __exit;
+ }
+
+ mic.dev = rt_device_find(MIC_DEVICE_NAME);
+ if (mic.dev == RT_NULL)
+ {
+ LOG_E("can't find device:%s", MIC_DEVICE_NAME);
+ goto __exit;
+ }
+
+ while (1)
+ {
+ if (rt_event_recv(mic.event, EVENT_RECORD_START | EVENT_RECORD_STOP,
+ RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
+ 1000, &e) != RT_EOK)
+ {
+ continue;
+ }
+ if (mic.open_count == 0)
+ {
+ continue;
+ }
+ LOG_D("record start");
+
+ rt_device_open(mic.dev, RT_DEVICE_OFLAG_RDONLY);
+
+ caps.main_type = AUDIO_TYPE_INPUT;
+ caps.sub_type = AUDIO_DSP_PARAM;
+ caps.udata.config.samplerate = RECORD_SAMPLERATE;
+ caps.udata.config.channels = RECORD_CHANNEL;
+ caps.udata.config.samplebits = RESOLUTION_BITS;
+ rt_device_control(mic.dev, AUDIO_CTL_CONFIGURE, &caps);
+
+ while (1)
+ {
+ if (rt_event_recv(mic.event, EVENT_RECORD_DATA | EVENT_RECORD_STOP,
+ RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
+ 1000, &e) != RT_EOK)
+ {
+ if (mic.open_count > 0)
+ continue;
+ else
+ break;
+ }
+ if (e & EVENT_RECORD_DATA)
+ {
+ index = (mic.buffer_index >= RECORD_BUFFER_SZ / 2) ? 0 : (RECORD_BUFFER_SZ / 2);
+ rt_device_read(mic.dev, 0, mic.buffer + index, RECORD_BUFFER_SZ / 2);
+ }
+ else if (e & EVENT_RECORD_STOP)
+ {
+ break;
+ }
+ }
+ LOG_D("record stop");
+ rt_device_close(mic.dev);
+ }
+
+__exit:
+ if (mic.buffer)
+ rt_free(mic.buffer);
+}
+
+static rt_err_t _record_start(ufunction_t func)
+{
+ mic.ep->request.buffer = RT_NULL;
+ mic.ep->request.size = UAC_EP_MAX_PACKET_SIZE;
+ mic.ep->request.req_type = UIO_REQUEST_WRITE;
+ rt_usbd_io_request(func->device, mic.ep, &mic.ep->request);
+
+ mic.open_count ++;
+ rt_event_send(mic.event, EVENT_RECORD_START);
+ return 0;
+}
+
+static rt_err_t _record_stop(ufunction_t func)
+{
+ mic.open_count --;
+ rt_event_send(mic.event, EVENT_RECORD_STOP);
+ return 0;
+}
+
+static rt_err_t _ep_data_in_handler(ufunction_t func, rt_size_t size)
+{
+ RT_ASSERT(func != RT_NULL);
+ LOG_D("_ep_data_in_handler");
+
+ mic.ep->request.buffer = mic.buffer + mic.buffer_index;
+ mic.ep->request.size = UAC_EP_MAX_PACKET_SIZE;
+ mic.ep->request.req_type = UIO_REQUEST_WRITE;
+ rt_usbd_io_request(func->device, mic.ep, &mic.ep->request);
+
+ mic.buffer_index += UAC_EP_MAX_PACKET_SIZE;
+ if (mic.buffer_index >= RECORD_BUFFER_SZ)
+ {
+ mic.buffer_index = 0;
+ rt_event_send(mic.event, EVENT_RECORD_DATA);
+ }
+ else if (mic.buffer_index == RECORD_BUFFER_SZ / 2)
+ {
+ rt_event_send(mic.event, EVENT_RECORD_DATA);
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t _interface_as_handler(ufunction_t func, ureq_t setup)
+{
+ RT_ASSERT(func != RT_NULL);
+ RT_ASSERT(func->device != RT_NULL);
+ RT_ASSERT(setup != RT_NULL);
+
+ LOG_D("_interface_as_handler");
+
+ if ((setup->request_type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD)
+ {
+ switch (setup->bRequest)
+ {
+ case USB_REQ_GET_INTERFACE:
+ break;
+ case USB_REQ_SET_INTERFACE:
+ LOG_D("set interface handler");
+ if (setup->wValue == 1)
+ {
+ _record_start(func);
+ }
+ else if (setup->wValue == 0)
+ {
+ _record_stop(func);
+ }
+ break;
+ default:
+ LOG_D("unknown uac request 0x%x", setup->bRequest);
+ return -RT_ERROR;
+ }
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t _function_enable(ufunction_t func)
+{
+ RT_ASSERT(func != RT_NULL);
+
+ LOG_D("uac function enable");
+
+ return RT_EOK;
+}
+
+static rt_err_t _function_disable(ufunction_t func)
+{
+ RT_ASSERT(func != RT_NULL);
+
+ LOG_D("uac function disable");
+ _record_stop(func);
+ return RT_EOK;
+}
+
+static struct ufunction_ops ops =
+{
+ _function_enable,
+ _function_disable,
+ RT_NULL,
+};
+/**
+ * This function will configure uac descriptor.
+ *
+ * @param comm the communication interface number.
+ * @param data the data interface number.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _uac_descriptor_config(struct uac_ac_descriptor *ac,
+ rt_uint8_t cintf_nr, struct uac_as_descriptor *as, rt_uint8_t sintf_nr)
+{
+ ac->hdr_desc.baInterfaceNr[0] = sintf_nr;
+#ifdef RT_USB_DEVICE_COMPOSITE
+ ac->iad_desc.bFirstInterface = cintf_nr;
+#endif
+
+ return RT_EOK;
+}
+
+static rt_err_t _uac_samplerate_config(struct uac_as_descriptor *as, rt_uint32_t samplerate)
+{
+ as->format_type_desc.tSamFreq[0 * 3 + 2] = samplerate >> 16 & 0xff;
+ as->format_type_desc.tSamFreq[0 * 3 + 1] = samplerate >> 8 & 0xff;
+ as->format_type_desc.tSamFreq[0 * 3 + 0] = samplerate & 0xff;
+ return RT_EOK;
+}
+
+/**
+ * This function will create a uac function instance.
+ *
+ * @param device the usb device object.
+ *
+ * @return RT_EOK on successful.
+ */
+ufunction_t rt_usbd_function_uac_mic_create(udevice_t device)
+{
+ ufunction_t func;
+ uintf_t intf_ac, intf_as;
+ ualtsetting_t setting_as0;
+ ualtsetting_t setting_ac, setting_as;
+ struct uac_as_descriptor *as_desc_t;
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+
+#ifdef RT_USB_DEVICE_COMPOSITE
+ rt_usbd_device_set_interface_string(device, MIC_INTF_STR_INDEX, _ustring[2]);
+#else
+ /* set usb device string description */
+ rt_usbd_device_set_string(device, _ustring);
+#endif
+ /* create a uac function */
+ func = rt_usbd_function_new(device, &dev_desc, &ops);
+ //not support HS
+ //rt_usbd_device_set_qualifier(device, &dev_qualifier);
+
+ /* create interface */
+ intf_ac = rt_usbd_interface_new(device, RT_NULL);
+ intf_as = rt_usbd_interface_new(device, _interface_as_handler);
+
+ /* create alternate setting */
+ setting_ac = rt_usbd_altsetting_new(sizeof(struct uac_ac_descriptor));
+ setting_as0 = rt_usbd_altsetting_new(sizeof(struct uinterface_descriptor));
+ setting_as = rt_usbd_altsetting_new(sizeof(struct uac_as_descriptor));
+ /* config desc in alternate setting */
+ rt_usbd_altsetting_config_descriptor(setting_ac, &ac_desc,
+ (rt_off_t) & ((struct uac_ac_descriptor *)0)->intf_desc);
+ rt_usbd_altsetting_config_descriptor(setting_as0, &as_desc0, 0);
+ rt_usbd_altsetting_config_descriptor(setting_as, &as_desc,
+ (rt_off_t) & ((struct uac_as_descriptor *)0)->intf_desc);
+ /* configure the uac interface descriptor */
+ _uac_descriptor_config(setting_ac->desc, intf_ac->intf_num, setting_as->desc, intf_as->intf_num);
+ _uac_samplerate_config(setting_as->desc, RECORD_SAMPLERATE);
+
+ /* create endpoint */
+ as_desc_t = (struct uac_as_descriptor *)setting_as->desc;
+ mic.ep = rt_usbd_endpoint_new(&as_desc_t->ep_desc, _ep_data_in_handler);
+
+ /* add the endpoint to the alternate setting */
+ rt_usbd_altsetting_add_endpoint(setting_as, mic.ep);
+
+ /* add the alternate setting to the interface, then set default setting of the interface */
+ rt_usbd_interface_add_altsetting(intf_ac, setting_ac);
+ rt_usbd_set_altsetting(intf_ac, 0);
+ rt_usbd_interface_add_altsetting(intf_as, setting_as0);
+ rt_usbd_interface_add_altsetting(intf_as, setting_as);
+ rt_usbd_set_altsetting(intf_as, 0);
+
+ /* add the interface to the uac function */
+ rt_usbd_function_add_interface(func, intf_ac);
+ rt_usbd_function_add_interface(func, intf_as);
+
+ return func;
+}
+
+int audio_mic_init(void)
+{
+ rt_thread_t mic_tid;
+ mic.event = rt_event_create("mic_event", RT_IPC_FLAG_FIFO);
+
+ mic_tid = rt_thread_create("mic_thread",
+ mic_entry, RT_NULL,
+ 1024,
+ 5, 10);
+
+ if (mic_tid != RT_NULL)
+ rt_thread_startup(mic_tid);
+ return RT_EOK;
+}
+INIT_COMPONENT_EXPORT(audio_mic_init);
+
+/*
+ * register uac class
+ */
+struct udclass uac_class =
+{
+ .rt_usbd_function_create = rt_usbd_function_uac_mic_create
+};
+
+int rt_usbd_uac_mic_class_register(void)
+{
+ rt_usbd_class_register(&uac_class);
+ return 0;
+}
+INIT_PREV_EXPORT(rt_usbd_uac_mic_class_register);
diff --git a/components/legacy/usb/usbdevice/class/audio_speaker.c b/components/legacy/usb/usbdevice/class/audio_speaker.c
new file mode 100644
index 0000000000..6560990c8e
--- /dev/null
+++ b/components/legacy/usb/usbdevice/class/audio_speaker.c
@@ -0,0 +1,582 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2019-09-19 flybreak the first version
+ */
+
+#include <rthw.h>
+#include <rtdevice.h>
+#include "drivers/usb_device.h"
+
+#define AUFMT_MAX_FREQUENCIES 1
+#include "uaudioreg.h"
+
+#define DBG_TAG "usbd.audio.speaker"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#define AUDIO_SAMPLERATE 16000
+#define AUDIO_CHANNEL 1
+#define RESOLUTION_BITS 16
+
+#define RESOLUTION_BYTE (RESOLUTION_BITS / 8)
+#define AUDIO_PER_MS_SZ ((AUDIO_SAMPLERATE * AUDIO_CHANNEL * RESOLUTION_BYTE) / 1000)
+#define AUDIO_BUFFER_SZ (AUDIO_PER_MS_SZ * 20) /* 20ms */
+
+#if defined(RT_USBD_SPEAKER_DEVICE_NAME)
+ #define SPEAKER_DEVICE_NAME RT_USBD_SPEAKER_DEVICE_NAME
+#else
+ #define SPEAKER_DEVICE_NAME "sound0"
+#endif
+
+#define EVENT_AUDIO_START (1 << 0)
+#define EVENT_AUDIO_STOP (1 << 1)
+#define EVENT_AUDIO_DATA (1 << 2)
+
+#define SPK_INTF_STR_INDEX 9
+/*
+ * uac speaker descriptor define
+ */
+
+#define UAC_CS_INTERFACE 0x24
+#define UAC_CS_ENDPOINT 0x25
+
+#define UAC_MAX_PACKET_SIZE 64
+#define UAC_EP_MAX_PACKET_SIZE 32
+#define UAC_CHANNEL_NUM AUDIO_CHANNEL
+
+struct uac_ac_descriptor
+{
+#ifdef RT_USB_DEVICE_COMPOSITE
+ struct uiad_descriptor iad_desc;
+#endif
+ struct uinterface_descriptor intf_desc;
+ struct usb_audio_control_descriptor hdr_desc;
+ struct usb_audio_input_terminal it_desc;
+ struct usb_audio_output_terminal ot_desc;
+#if UAC_USE_FEATURE_UNIT
+ struct usb_audio_feature_unit feature_unit_desc;
+#endif
+};
+
+struct uac_as_descriptor
+{
+ struct uinterface_descriptor intf_desc;
+ struct usb_audio_streaming_interface_descriptor hdr_desc;
+ struct usb_audio_streaming_type1_descriptor format_type_desc;
+ struct uendpoint_descriptor ep_desc;
+ struct usb_audio_streaming_endpoint_descriptor as_ep_desc;
+};
+
+/*
+ * uac speaker device type
+ */
+
+struct uac_audio_speaker
+{
+ rt_device_t dev;
+ rt_event_t event;
+ rt_uint8_t open_count;
+
+ rt_uint8_t *buffer;
+ rt_uint32_t buffer_index;
+
+ uep_t ep;
+};
+static struct uac_audio_speaker speaker;
+
+rt_align(4)
+static struct udevice_descriptor dev_desc =
+{
+ USB_DESC_LENGTH_DEVICE, //bLength;
+ USB_DESC_TYPE_DEVICE, //type;
+ USB_BCD_VERSION, //bcdUSB;
+ USB_CLASS_DEVICE, //bDeviceClass;
+ 0x00, //bDeviceSubClass;
+ 0x00, //bDeviceProtocol;
+ UAC_MAX_PACKET_SIZE, //bMaxPacketSize0;
+ _VENDOR_ID, //idVendor;
+ _PRODUCT_ID, //idProduct;
+ USB_BCD_DEVICE, //bcdDevice;
+ USB_STRING_MANU_INDEX, //iManufacturer;
+ USB_STRING_PRODUCT_INDEX, //iProduct;
+ USB_STRING_SERIAL_INDEX, //iSerialNumber;Unused.
+ USB_DYNAMIC, //bNumConfigurations;
+};
+
+//FS and HS needed
+rt_align(4)
+static struct usb_qualifier_descriptor dev_qualifier =
+{
+ sizeof(dev_qualifier), //bLength
+ USB_DESC_TYPE_DEVICEQUALIFIER, //bDescriptorType
+ 0x0200, //bcdUSB
+ USB_CLASS_AUDIO, //bDeviceClass
+ 0x00, //bDeviceSubClass
+ 0x00, //bDeviceProtocol
+ 64, //bMaxPacketSize0
+ 0x01, //bNumConfigurations
+ 0,
+};
+
+rt_align(4)
+const static char *_ustring[] =
+{
+ "Language",
+ "RT-Thread Team.",
+ "RT-Thread Audio Speaker",
+ "32021919830108",
+ "Configuration",
+ "Interface",
+};
+
+rt_align(4)
+static struct uac_ac_descriptor ac_desc =
+{
+#ifdef RT_USB_DEVICE_COMPOSITE
+ /* Interface Association Descriptor */
+ {
+ USB_DESC_LENGTH_IAD,
+ USB_DESC_TYPE_IAD,
+ USB_DYNAMIC,
+ 0x02,
+ USB_CLASS_AUDIO,
+ USB_SUBCLASS_AUDIOSTREAMING,
+ 0x00,
+ 0x00,
+ },
+#endif
+ /* Interface Descriptor */
+ {
+ USB_DESC_LENGTH_INTERFACE,
+ USB_DESC_TYPE_INTERFACE,
+ USB_DYNAMIC,
+ 0x00,
+ 0x00,
+ USB_CLASS_AUDIO,
+ USB_SUBCLASS_AUDIOCONTROL,
+ 0x00,
+#ifdef RT_USB_DEVICE_COMPOSITE
+ SPK_INTF_STR_INDEX,
+#else
+ 0x00,
+#endif
+ },
+ /* Header Descriptor */
+ {
+ sizeof(struct usb_audio_control_descriptor),
+ UAC_CS_INTERFACE,
+ UDESCSUB_AC_HEADER,
+ 0x0100, /* Version: 1.00 */
+ 0x0027, /* Total length: 39 */
+ 0x01, /* Total number of interfaces: 1 */
+ {0x01}, /* Interface number: 1 */
+ },
+ /* Input Terminal Descriptor */
+ {
+ sizeof(struct usb_audio_input_terminal),
+ UAC_CS_INTERFACE,
+ UDESCSUB_AC_INPUT,
+ 0x01, /* Terminal ID: 1 */
+ 0x0101, /* Terminal Type: USB Streaming (0x0101) */
+ 0x00, /* Assoc Terminal: 0 */
+ 0x01, /* Number Channels: 1 */
+ 0x0000, /* Channel Config: 0x0000 */
+ 0x00, /* Channel Names: 0 */
+ 0x00, /* Terminal: 0 */
+ },
+ /* Output Terminal Descriptor */
+ {
+ sizeof(struct usb_audio_output_terminal),
+ UAC_CS_INTERFACE,
+ UDESCSUB_AC_OUTPUT,
+ 0x02, /* Terminal ID: 2 */
+ 0x0302, /* Terminal Type: Headphones (0x0302) */
+ 0x00, /* Assoc Terminal: 0 */
+ 0x01, /* Source ID: 1 */
+ 0x00, /* Terminal: 0 */
+ },
+#if UAC_USE_FEATURE_UNIT
+ /* Feature unit Descriptor */
+ {
+ UAC_DT_FEATURE_UNIT_SIZE(UAC_CH_NUM),
+ UAC_CS_INTERFACE,
+ UAC_FEATURE_UNIT,
+ 0x02,
+ 0x0101,
+ 0x00,
+ 0x01,
+ },
+#endif
+};
+
+rt_align(4)
+static struct uinterface_descriptor as_desc0 =
+{
+ USB_DESC_LENGTH_INTERFACE,
+ USB_DESC_TYPE_INTERFACE,
+ USB_DYNAMIC,
+ 0x00,
+ 0x00,
+ USB_CLASS_AUDIO,
+ USB_SUBCLASS_AUDIOSTREAMING,
+ 0x00,
+ 0x00,
+};
+
+rt_align(4)
+static struct uac_as_descriptor as_desc =
+{
+ /* Interface Descriptor */
+ {
+ USB_DESC_LENGTH_INTERFACE,
+ USB_DESC_TYPE_INTERFACE,
+ USB_DYNAMIC,
+ 0x01,
+ 0x01,
+ USB_CLASS_AUDIO,
+ USB_SUBCLASS_AUDIOSTREAMING,
+ 0x00,
+ 0x00,
+ },
+ /* General AS Descriptor */
+ {
+ sizeof(struct usb_audio_streaming_interface_descriptor),
+ UAC_CS_INTERFACE,
+ AS_GENERAL,
+ 0x01, /* Terminal ID: 1 */
+ 0x01, /* Interface delay in frames: 1 */
+ UA_FMT_PCM,
+ },
+ /* Format type i Descriptor */
+ {
+ sizeof(struct usb_audio_streaming_type1_descriptor),
+ UAC_CS_INTERFACE,
+ FORMAT_TYPE,
+ FORMAT_TYPE_I,
+ UAC_CHANNEL_NUM,
+ 2, /* Subframe Size: 2 */
+ RESOLUTION_BITS,
+ 0x01, /* Samples Frequence Type: 1 */
+ {0}, /* Samples Frequence */
+ },
+ /* Endpoint Descriptor */
+ {
+ USB_DESC_LENGTH_ENDPOINT,
+ USB_DESC_TYPE_ENDPOINT,
+ USB_DYNAMIC | USB_DIR_OUT,
+ USB_EP_ATTR_ISOC,
+ UAC_EP_MAX_PACKET_SIZE,
+ 0x01,
+ },
+ /* AS Endpoint Descriptor */
+ {
+ sizeof(struct usb_audio_streaming_endpoint_descriptor),
+ UAC_CS_ENDPOINT,
+ AS_GENERAL,
+ },
+};
+
+void speaker_entry(void *parameter)
+{
+ struct rt_audio_caps caps = {0};
+ rt_uint32_t e, index;
+
+ speaker.buffer = rt_malloc(AUDIO_BUFFER_SZ);
+ if (speaker.buffer == RT_NULL)
+ {
+ LOG_E("malloc failed");
+ goto __exit;
+ }
+
+ speaker.dev = rt_device_find(SPEAKER_DEVICE_NAME);
+ if (speaker.dev == RT_NULL)
+ {
+ LOG_E("can't find device:%s", SPEAKER_DEVICE_NAME);
+ goto __exit;
+ }
+
+ while (1)
+ {
+ if (rt_event_recv(speaker.event, EVENT_AUDIO_START | EVENT_AUDIO_STOP,
+ RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
+ 1000, &e) != RT_EOK)
+ {
+ continue;
+ }
+ if (speaker.open_count == 0)
+ {
+ continue;
+ }
+ LOG_D("play start");
+
+ rt_device_open(speaker.dev, RT_DEVICE_OFLAG_WRONLY);
+
+ caps.main_type = AUDIO_TYPE_OUTPUT;
+ caps.sub_type = AUDIO_DSP_PARAM;
+ caps.udata.config.samplerate = AUDIO_SAMPLERATE;
+ caps.udata.config.channels = AUDIO_CHANNEL;
+ caps.udata.config.samplebits = RESOLUTION_BITS;
+ rt_device_control(speaker.dev, AUDIO_CTL_CONFIGURE, &caps);
+
+ while (1)
+ {
+ if (rt_event_recv(speaker.event, EVENT_AUDIO_DATA | EVENT_AUDIO_STOP,
+ RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
+ 1000, &e) != RT_EOK)
+ {
+ if (speaker.open_count > 0)
+ continue;
+ else
+ break;
+ }
+ if (e & EVENT_AUDIO_DATA)
+ {
+ index = (speaker.buffer_index >= AUDIO_BUFFER_SZ / 2) ? 0 : (AUDIO_BUFFER_SZ / 2);
+ rt_device_write(speaker.dev, 0, speaker.buffer + index, AUDIO_BUFFER_SZ / 2);
+ }
+ else if (e & EVENT_AUDIO_STOP)
+ {
+ break;
+ }
+ }
+ LOG_D("play stop");
+ rt_device_close(speaker.dev);
+ }
+
+__exit:
+ if (speaker.buffer)
+ rt_free(speaker.buffer);
+}
+
+static rt_err_t _audio_start(ufunction_t func)
+{
+ speaker.ep->request.buffer = speaker.buffer;
+ speaker.ep->request.size = UAC_EP_MAX_PACKET_SIZE;
+ speaker.ep->request.req_type = UIO_REQUEST_READ_FULL;
+ rt_usbd_io_request(func->device, speaker.ep, &speaker.ep->request);
+
+ speaker.open_count ++;
+ rt_event_send(speaker.event, EVENT_AUDIO_START);
+
+ return 0;
+}
+
+static rt_err_t _audio_stop(ufunction_t func)
+{
+ speaker.open_count --;
+ rt_event_send(speaker.event, EVENT_AUDIO_STOP);
+ return 0;
+}
+
+static rt_err_t _ep_data_handler(ufunction_t func, rt_size_t size)
+{
+ RT_ASSERT(func != RT_NULL);
+ LOG_D("_ep_data_handler");
+
+ speaker.ep->request.buffer = speaker.buffer + speaker.buffer_index;
+ speaker.ep->request.size = UAC_EP_MAX_PACKET_SIZE;
+ speaker.ep->request.req_type = UIO_REQUEST_READ_FULL;
+ rt_usbd_io_request(func->device, speaker.ep, &speaker.ep->request);
+
+ speaker.buffer_index += UAC_EP_MAX_PACKET_SIZE;
+ if (speaker.buffer_index >= AUDIO_BUFFER_SZ)
+ {
+ speaker.buffer_index = 0;
+ rt_event_send(speaker.event, EVENT_AUDIO_DATA);
+ }
+ else if (speaker.buffer_index == AUDIO_BUFFER_SZ / 2)
+ {
+ rt_event_send(speaker.event, EVENT_AUDIO_DATA);
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t _interface_as_handler(ufunction_t func, ureq_t setup)
+{
+ RT_ASSERT(func != RT_NULL);
+ RT_ASSERT(func->device != RT_NULL);
+ RT_ASSERT(setup != RT_NULL);
+
+ LOG_D("_interface_as_handler");
+
+ if ((setup->request_type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD)
+ {
+ switch (setup->bRequest)
+ {
+ case USB_REQ_GET_INTERFACE:
+ break;
+ case USB_REQ_SET_INTERFACE:
+ LOG_D("set interface handler");
+ if (setup->wValue == 1)
+ {
+ _audio_start(func);
+ }
+ else if (setup->wValue == 0)
+ {
+ _audio_stop(func);
+ }
+ break;
+ default:
+ LOG_D("unknown uac request 0x%x", setup->bRequest);
+ return -RT_ERROR;
+ }
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t _function_enable(ufunction_t func)
+{
+ RT_ASSERT(func != RT_NULL);
+
+ LOG_D("uac function enable");
+
+ return RT_EOK;
+}
+
+static rt_err_t _function_disable(ufunction_t func)
+{
+ RT_ASSERT(func != RT_NULL);
+
+ LOG_D("uac function disable");
+ _audio_stop(func);
+ return RT_EOK;
+}
+
+static struct ufunction_ops ops =
+{
+ _function_enable,
+ _function_disable,
+ RT_NULL,
+};
+/**
+ * This function will configure uac descriptor.
+ *
+ * @param comm the communication interface number.
+ * @param data the data interface number.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _uac_descriptor_config(struct uac_ac_descriptor *ac,
+ rt_uint8_t cintf_nr, struct uac_as_descriptor *as, rt_uint8_t sintf_nr)
+{
+ ac->hdr_desc.baInterfaceNr[0] = sintf_nr;
+#ifdef RT_USB_DEVICE_COMPOSITE
+ ac->iad_desc.bFirstInterface = cintf_nr;
+#endif
+
+ return RT_EOK;
+}
+
+static rt_err_t _uac_samplerate_config(struct uac_as_descriptor *as, rt_uint32_t samplerate)
+{
+ as->format_type_desc.tSamFreq[0 * 3 + 2] = samplerate >> 16 & 0xff;
+ as->format_type_desc.tSamFreq[0 * 3 + 1] = samplerate >> 8 & 0xff;
+ as->format_type_desc.tSamFreq[0 * 3 + 0] = samplerate & 0xff;
+ return RT_EOK;
+}
+
+/**
+ * This function will create a uac function instance.
+ *
+ * @param device the usb device object.
+ *
+ * @return RT_EOK on successful.
+ */
+ufunction_t rt_usbd_function_uac_speaker_create(udevice_t device)
+{
+ ufunction_t func;
+ uintf_t intf_ac, intf_as;
+ ualtsetting_t setting_as0;
+ ualtsetting_t setting_ac, setting_as;
+ struct uac_as_descriptor *as_desc_t;
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+
+#ifdef RT_USB_DEVICE_COMPOSITE
+ rt_usbd_device_set_interface_string(device, SPK_INTF_STR_INDEX, _ustring[2]);
+#else
+ /* set usb device string description */
+ rt_usbd_device_set_string(device, _ustring);
+#endif
+ /* create a uac function */
+ func = rt_usbd_function_new(device, &dev_desc, &ops);
+ //not support HS
+ //rt_usbd_device_set_qualifier(device, &dev_qualifier);
+
+ /* create interface */
+ intf_ac = rt_usbd_interface_new(device, RT_NULL);
+ intf_as = rt_usbd_interface_new(device, _interface_as_handler);
+
+ /* create alternate setting */
+ setting_ac = rt_usbd_altsetting_new(sizeof(struct uac_ac_descriptor));
+ setting_as0 = rt_usbd_altsetting_new(sizeof(struct uinterface_descriptor));
+ setting_as = rt_usbd_altsetting_new(sizeof(struct uac_as_descriptor));
+ /* config desc in alternate setting */
+ rt_usbd_altsetting_config_descriptor(setting_ac, &ac_desc,
+ (rt_off_t) & ((struct uac_ac_descriptor *)0)->intf_desc);
+ rt_usbd_altsetting_config_descriptor(setting_as0, &as_desc0, 0);
+ rt_usbd_altsetting_config_descriptor(setting_as, &as_desc,
+ (rt_off_t) & ((struct uac_as_descriptor *)0)->intf_desc);
+ /* configure the uac interface descriptor */
+ _uac_descriptor_config(setting_ac->desc, intf_ac->intf_num, setting_as->desc, intf_as->intf_num);
+ _uac_samplerate_config(setting_as->desc, AUDIO_SAMPLERATE);
+
+ /* create endpoint */
+ as_desc_t = (struct uac_as_descriptor *)setting_as->desc;
+ speaker.ep = rt_usbd_endpoint_new(&as_desc_t->ep_desc, _ep_data_handler);
+
+ /* add the endpoint to the alternate setting */
+ rt_usbd_altsetting_add_endpoint(setting_as, speaker.ep);
+
+ /* add the alternate setting to the interface, then set default setting of the interface */
+ rt_usbd_interface_add_altsetting(intf_ac, setting_ac);
+ rt_usbd_set_altsetting(intf_ac, 0);
+ rt_usbd_interface_add_altsetting(intf_as, setting_as0);
+ rt_usbd_interface_add_altsetting(intf_as, setting_as);
+ rt_usbd_set_altsetting(intf_as, 0);
+
+ /* add the interface to the uac function */
+ rt_usbd_function_add_interface(func, intf_ac);
+ rt_usbd_function_add_interface(func, intf_as);
+
+ return func;
+}
+
+int audio_speaker_init(void)
+{
+ rt_thread_t speaker_tid;
+ speaker.event = rt_event_create("speaker_event", RT_IPC_FLAG_FIFO);
+
+ speaker_tid = rt_thread_create("speaker_thread",
+ speaker_entry, RT_NULL,
+ 1024,
+ 5, 10);
+
+ if (speaker_tid != RT_NULL)
+ rt_thread_startup(speaker_tid);
+ return RT_EOK;
+}
+INIT_COMPONENT_EXPORT(audio_speaker_init);
+
+/*
+ * register uac class
+ */
+static struct udclass uac_speaker_class =
+{
+ .rt_usbd_function_create = rt_usbd_function_uac_speaker_create
+};
+
+int rt_usbd_uac_speaker_class_register(void)
+{
+ rt_usbd_class_register(&uac_speaker_class);
+ return 0;
+}
+INIT_PREV_EXPORT(rt_usbd_uac_speaker_class_register);
diff --git a/components/legacy/usb/usbdevice/class/cdc.h b/components/legacy/usb/usbdevice/class/cdc.h
new file mode 100644
index 0000000000..6b79876734
--- /dev/null
+++ b/components/legacy/usb/usbdevice/class/cdc.h
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2012-10-03 Yi Qiu first version
+ * 2012-12-12 heyuanjie87 add CDC endpoints collection
+ */
+
+#ifndef __CDC_H__
+#define __CDC_H__
+
+#define USB_CDC_BUFSIZE 0x40
+
+#define USB_CDC_CLASS_COMM 0x02
+#define USB_CDC_CLASS_DATA 0x0A
+
+#define USB_CDC_SUBCLASS_NONE 0x00
+#define USB_CDC_SUBCLASS_DLCM 0x01
+#define USB_CDC_SUBCLASS_ACM 0x02
+#define USB_CDC_SUBCLASS_TCM 0x03
+#define USB_CDC_SUBCLASS_MCCM 0x04
+#define USB_CDC_SUBCLASS_CCM 0x05
+#define USB_CDC_SUBCLASS_ETH 0x06
+#define USB_CDC_SUBCLASS_ATM 0x07
+#define USB_CDC_SUBCLASS_EEM 0x0C
+
+#define USB_CDC_PROTOCOL_NONE 0x00
+#define USB_CDC_PROTOCOL_V25TER 0x01
+#define USB_CDC_PROTOCOL_I430 0x30
+#define USB_CDC_PROTOCOL_HDLC 0x31
+#define USB_CDC_PROTOCOL_TRANS 0x32
+#define USB_CDC_PROTOCOL_Q921M 0x50
+#define USB_CDC_PROTOCOL_Q921 0x51
+#define USB_CDC_PROTOCOL_Q921TM 0x52
+#define USB_CDC_PROTOCOL_V42BIS 0x90
+#define USB_CDC_PROTOCOL_Q931 0x91
+#define USB_CDC_PROTOCOL_V120 0x92
+#define USB_CDC_PROTOCOL_CAPI20 0x93
+#define USB_CDC_PROTOCOL_HOST 0xFD
+#define USB_CDC_PROTOCOL_PUFD 0xFE
+#define USB_CDC_PROTOCOL_VENDOR 0xFF
+#define USB_CDC_PROTOCOL_EEM 0x07
+
+#define USB_CDC_CS_INTERFACE 0x24
+#define USB_CDC_CS_ENDPOINT 0x25
+
+#define USB_CDC_SCS_HEADER 0x00
+#define USB_CDC_SCS_CALL_MGMT 0x01
+#define USB_CDC_SCS_ACM 0x02
+#define USB_CDC_SCS_UNION 0x06
+#define USB_CDC_SCS_ETH 0x0F
+
+#define CDC_SEND_ENCAPSULATED_COMMAND 0x00
+#define CDC_GET_ENCAPSULATED_RESPONSE 0x01
+#define CDC_SET_COMM_FEATURE 0x02
+#define CDC_GET_COMM_FEATURE 0x03
+#define CDC_CLEAR_COMM_FEATURE 0x04
+#define CDC_SET_AUX_LINE_STATE 0x10
+#define CDC_SET_HOOK_STATE 0x11
+#define CDC_PULSE_SETUP 0x12
+#define CDC_SEND_PULSE 0x13
+#define CDC_SET_PULSE_TIME 0x14
+#define CDC_RING_AUX_JACK 0x15
+#define CDC_SET_LINE_CODING 0x20
+#define CDC_GET_LINE_CODING 0x21
+#define CDC_SET_CONTROL_LINE_STATE 0x22
+#define CDC_SEND_BREAK 0x23
+#define CDC_SET_RINGER_PARMS 0x30
+#define CDC_GET_RINGER_PARMS 0x31
+#define CDC_SET_OPERATION_PARMS 0x32
+#define CDC_GET_OPERATION_PARMS 0x33
+#define CDC_SET_LINE_PARMS 0x34
+#define CDC_GET_LINE_PARMS 0x35
+#define CDC_DIAL_DIGITS 0x36
+#define CDC_SET_UNIT_PARAMETER 0x37
+#define CDC_GET_UNIT_PARAMETER 0x38
+#define CDC_CLEAR_UNIT_PARAMETER 0x39
+#define CDC_GET_PROFILE 0x3A
+#define CDC_SET_ETH_MULTICAST_FILTERS 0x40
+#define CDC_SET_ETH_POWER_MGMT_FILT 0x41
+#define CDC_GET_ETH_POWER_MGMT_FILT 0x42
+#define CDC_SET_ETH_PACKET_FILTER 0x43
+#define CDC_GET_ETH_STATISTIC 0x44
+#define CDC_SET_ATM_DATA_FORMAT 0x50
+#define CDC_GET_ATM_DEVICE_STATISTICS 0x51
+#define CDC_SET_ATM_DEFAULT_VC 0x52
+#define CDC_GET_ATM_VC_STATISTICS 0x53
+
+#pragma pack(1)
+
+struct ucdc_header_descriptor
+{
+ rt_uint8_t length;
+ rt_uint8_t type;
+ rt_uint8_t subtype;
+ rt_uint16_t bcd;
+};
+typedef struct ucdc_header_descriptor* ucdc_hdr_desc_t;
+
+struct ucdc_acm_descriptor
+{
+ rt_uint8_t length;
+ rt_uint8_t type;
+ rt_uint8_t subtype;
+ rt_uint8_t capabilties;
+};
+typedef struct ucdc_acm_descriptor* ucdc_acm_desc_t;
+
+struct ucdc_call_mgmt_descriptor
+{
+ rt_uint8_t length;
+ rt_uint8_t type;
+ rt_uint8_t subtype;
+ rt_uint8_t capabilties;
+ rt_uint8_t data_interface;
+};
+typedef struct ucdc_call_mgmt_descriptor* ucdc_call_mgmt_desc_t;
+
+struct ucdc_union_descriptor
+{
+ rt_uint8_t length;
+ rt_uint8_t type;
+ rt_uint8_t subtype;
+ rt_uint8_t master_interface;
+ rt_uint8_t slave_interface0;
+};
+typedef struct ucdc_union_descriptor* ucdc_union_desc_t;
+
+struct ucdc_comm_descriptor
+{
+#ifdef RT_USB_DEVICE_COMPOSITE
+ struct uiad_descriptor iad_desc;
+#endif
+ struct uinterface_descriptor intf_desc;
+ struct ucdc_header_descriptor hdr_desc;
+ struct ucdc_call_mgmt_descriptor call_mgmt_desc;
+ struct ucdc_acm_descriptor acm_desc;
+ struct ucdc_union_descriptor union_desc;
+ struct uendpoint_descriptor ep_desc;
+};
+typedef struct ucdc_comm_descriptor* ucdc_comm_desc_t;
+
+struct ucdc_enet_descriptor
+{
+ rt_uint8_t bFunctionLength;
+ rt_uint8_t bDescriptorType;
+ rt_uint8_t bDescriptorSubtype;
+ rt_uint8_t iMACAddress;
+ rt_uint8_t bmEthernetStatistics[4];
+ rt_uint16_t wMaxSegmentSize;
+ rt_uint16_t wMCFilters;
+ rt_uint8_t bNumberPowerFilters;
+};
+struct ucdc_eth_descriptor
+{
+#ifdef RT_USB_DEVICE_COMPOSITE
+ struct uiad_descriptor iad_desc;
+#endif
+ struct uinterface_descriptor intf_desc;
+ struct ucdc_header_descriptor hdr_desc;
+ struct ucdc_union_descriptor union_desc;
+ struct ucdc_enet_descriptor enet_desc;
+ struct uendpoint_descriptor ep_desc;
+};
+typedef struct ucdc_eth_descriptor* ucdc_eth_desc_t;
+
+struct ucdc_data_descriptor
+{
+ struct uinterface_descriptor intf_desc;
+ struct uendpoint_descriptor ep_out_desc;
+ struct uendpoint_descriptor ep_in_desc;
+};
+typedef struct ucdc_data_descriptor* ucdc_data_desc_t;
+
+struct ucdc_line_coding
+{
+ rt_uint32_t dwDTERate;
+ rt_uint8_t bCharFormat;
+ rt_uint8_t bParityType;
+ rt_uint8_t bDataBits;
+};
+typedef struct ucdc_line_coding* ucdc_line_coding_t;
+
+struct cdc_eps
+{
+ uep_t ep_out;
+ uep_t ep_in;
+ uep_t ep_cmd;
+};
+typedef struct cdc_eps* cdc_eps_t;
+
+
+
+struct ucdc_management_element_notifications
+{
+ rt_uint8_t bmRequestType;
+ rt_uint8_t bNotificatinCode;
+ rt_uint16_t wValue;
+ rt_uint16_t wIndex;
+ rt_uint16_t wLength;
+};
+typedef struct ucdc_management_element_notifications * ucdc_mg_notifications_t;
+
+struct ucdc_connection_speed_change_data
+{
+ rt_uint32_t down_bit_rate;
+ rt_uint32_t up_bit_rate;
+};
+typedef struct connection_speed_change_data * connect_speed_data_t;
+
+enum ucdc_notification_code
+{
+ UCDC_NOTIFI_NETWORK_CONNECTION = 0x00,
+ UCDC_NOTIFI_RESPONSE_AVAILABLE = 0x01,
+ UCDC_NOTIFI_AUX_JACK_HOOK_STATE = 0x08,
+ UCDC_NOTIFI_RING_DETECT = 0x09,
+ UCDC_NOTIFI_SERIAL_STATE = 0x20,
+ UCDC_NOTIFI_CALL_STATE_CHANGE = 0x28,
+ UCDC_NOTIFI_LINE_STATE_CHANGE = 0x29,
+ UCDC_NOTIFI_CONNECTION_SPEED_CHANGE = 0x2A,
+};
+typedef enum ucdc_notification_code ucdc_notification_code_t;
+
+#pragma pack()
+
+#endif
diff --git a/components/legacy/usb/usbdevice/class/cdc_vcom.c b/components/legacy/usb/usbdevice/class/cdc_vcom.c
new file mode 100644
index 0000000000..dec102b135
--- /dev/null
+++ b/components/legacy/usb/usbdevice/class/cdc_vcom.c
@@ -0,0 +1,1008 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2012-10-02 Yi Qiu first version
+ * 2012-12-12 heyuanjie87 change endpoints and function handler
+ * 2013-06-25 heyuanjie87 remove SOF mechinism
+ * 2013-07-20 Yi Qiu do more test
+ * 2016-02-01 Urey Fix some error
+ * 2021-10-14 mazhiyuan Fix some error
+ */
+
+#include <rthw.h>
+#include <rtdevice.h>
+#include "drivers/usb_device.h"
+#include "cdc.h"
+
+#ifdef RT_USB_DEVICE_CDC
+
+#define DBG_TAG "usbdevice_cdc"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#define VCOM_INTF_STR_INDEX 5
+#ifdef RT_VCOM_TX_TIMEOUT
+#define VCOM_TX_TIMEOUT RT_VCOM_TX_TIMEOUT
+#else /*!RT_VCOM_TX_TIMEOUT*/
+#define VCOM_TX_TIMEOUT 1000
+#endif /*RT_VCOM_TX_TIMEOUT*/
+
+#ifdef RT_CDC_RX_BUFSIZE
+#define CDC_RX_BUFSIZE RT_CDC_RX_BUFSIZE
+#else
+#define CDC_RX_BUFSIZE 128
+#endif
+#define CDC_MAX_PACKET_SIZE 64
+#define VCOM_DEVICE "vcom"
+
+#ifdef RT_VCOM_TASK_STK_SIZE
+#define VCOM_TASK_STK_SIZE RT_VCOM_TASK_STK_SIZE
+#else /*!RT_VCOM_TASK_STK_SIZE*/
+#define VCOM_TASK_STK_SIZE 512
+#endif /*RT_VCOM_TASK_STK_SIZE*/
+
+#ifdef RT_VCOM_TX_USE_DMA
+#define VCOM_TX_USE_DMA
+#endif /*RT_VCOM_TX_USE_DMA*/
+
+#ifdef RT_VCOM_SERNO
+#define _SER_NO RT_VCOM_SERNO
+#else /*!RT_VCOM_SERNO*/
+#define _SER_NO "32021919830108"
+#endif /*RT_VCOM_SERNO*/
+
+#ifdef RT_VCOM_SER_LEN
+#define _SER_NO_LEN RT_VCOM_SER_LEN
+#else /*!RT_VCOM_SER_LEN*/
+#define _SER_NO_LEN 14 /*rt_strlen("32021919830108")*/
+#endif /*RT_VCOM_SER_LEN*/
+
+rt_align(RT_ALIGN_SIZE)
+static rt_uint8_t vcom_thread_stack[VCOM_TASK_STK_SIZE];
+static struct rt_thread vcom_thread;
+static struct ucdc_line_coding line_coding;
+
+#define CDC_TX_BUFSIZE 1024
+#define CDC_BULKIN_MAXSIZE (CDC_TX_BUFSIZE / 8)
+
+#define CDC_TX_HAS_DATE 0x01
+#define CDC_TX_HAS_SPACE 0x02
+
+struct vcom
+{
+ struct rt_serial_device serial;
+ uep_t ep_out;
+ uep_t ep_in;
+ uep_t ep_cmd;
+ rt_bool_t connected;
+ rt_bool_t in_sending;
+ struct rt_completion wait;
+ rt_uint8_t rx_rbp[CDC_RX_BUFSIZE];
+ struct rt_ringbuffer rx_ringbuffer;
+ rt_uint8_t tx_rbp[CDC_TX_BUFSIZE];
+ struct rt_ringbuffer tx_ringbuffer;
+ struct rt_event tx_event;
+};
+
+struct vcom_tx_msg
+{
+ struct rt_serial_device * serial;
+ const char *buf;
+ rt_size_t size;
+};
+
+rt_align(4)
+static struct udevice_descriptor dev_desc =
+{
+ USB_DESC_LENGTH_DEVICE, //bLength;
+ USB_DESC_TYPE_DEVICE, //type;
+ USB_BCD_VERSION, //bcdUSB;
+ USB_CLASS_CDC, //bDeviceClass;
+ 0x02, //bDeviceSubClass;
+ 0x00, //bDeviceProtocol;
+ CDC_MAX_PACKET_SIZE, //bMaxPacketSize0;
+ _VENDOR_ID, //idVendor;
+ _PRODUCT_ID, //idProduct;
+ USB_BCD_DEVICE, //bcdDevice;
+ USB_STRING_MANU_INDEX, //iManufacturer;
+ USB_STRING_PRODUCT_INDEX, //iProduct;
+ USB_STRING_SERIAL_INDEX, //iSerialNumber;
+ USB_DYNAMIC, //bNumConfigurations;
+};
+
+//FS and HS needed
+rt_align(4)
+static struct usb_qualifier_descriptor dev_qualifier =
+{
+ sizeof(dev_qualifier), //bLength
+ USB_DESC_TYPE_DEVICEQUALIFIER, //bDescriptorType
+ 0x0200, //bcdUSB
+ USB_CLASS_CDC, //bDeviceClass
+ 0x02, //bDeviceSubClass
+ 0x00, //bDeviceProtocol
+ 64, //bMaxPacketSize0
+ 0x01, //bNumConfigurations
+ 0,
+};
+
+/* communcation interface descriptor */
+rt_align(4)
+const static struct ucdc_comm_descriptor _comm_desc =
+{
+#ifdef RT_USB_DEVICE_COMPOSITE
+ /* Interface Association Descriptor */
+ {
+ USB_DESC_LENGTH_IAD,
+ USB_DESC_TYPE_IAD,
+ USB_DYNAMIC,
+ 0x02,
+ USB_CDC_CLASS_COMM,
+ USB_CDC_SUBCLASS_ACM,
+ USB_CDC_PROTOCOL_V25TER,
+ 0x00,
+ },
+#endif
+ /* Interface Descriptor */
+ {
+ USB_DESC_LENGTH_INTERFACE,
+ USB_DESC_TYPE_INTERFACE,
+ USB_DYNAMIC,
+ 0x00,
+ 0x01,
+ USB_CDC_CLASS_COMM,
+ USB_CDC_SUBCLASS_ACM,
+ USB_CDC_PROTOCOL_V25TER,
+#ifdef RT_USB_DEVICE_COMPOSITE
+ VCOM_INTF_STR_INDEX,
+#else
+ 0,
+#endif
+ },
+ /* Header Functional Descriptor */
+ {
+ 0x05,
+ USB_CDC_CS_INTERFACE,
+ USB_CDC_SCS_HEADER,
+ 0x0110,
+ },
+ /* Call Management Functional Descriptor */
+ {
+ 0x05,
+ USB_CDC_CS_INTERFACE,
+ USB_CDC_SCS_CALL_MGMT,
+ 0x00,
+ USB_DYNAMIC,
+ },
+ /* Abstract Control Management Functional Descriptor */
+ {
+ 0x04,
+ USB_CDC_CS_INTERFACE,
+ USB_CDC_SCS_ACM,
+ 0x02,
+ },
+ /* Union Functional Descriptor */
+ {
+ 0x05,
+ USB_CDC_CS_INTERFACE,
+ USB_CDC_SCS_UNION,
+ USB_DYNAMIC,
+ USB_DYNAMIC,
+ },
+ /* Endpoint Descriptor */
+ {
+ USB_DESC_LENGTH_ENDPOINT,
+ USB_DESC_TYPE_ENDPOINT,
+ USB_DYNAMIC | USB_DIR_IN,
+ USB_EP_ATTR_INT,
+ 0x08,
+ 0xFF,
+ },
+};
+
+/* data interface descriptor */
+rt_align(4)
+const static struct ucdc_data_descriptor _data_desc =
+{
+ /* interface descriptor */
+ {
+ USB_DESC_LENGTH_INTERFACE,
+ USB_DESC_TYPE_INTERFACE,
+ USB_DYNAMIC,
+ 0x00,
+ 0x02,
+ USB_CDC_CLASS_DATA,
+ 0x00,
+ 0x00,
+ 0x00,
+ },
+ /* endpoint, bulk out */
+ {
+ USB_DESC_LENGTH_ENDPOINT,
+ USB_DESC_TYPE_ENDPOINT,
+ USB_DYNAMIC | USB_DIR_OUT,
+ USB_EP_ATTR_BULK,
+ USB_CDC_BUFSIZE,
+ 0x00,
+ },
+ /* endpoint, bulk in */
+ {
+ USB_DESC_LENGTH_ENDPOINT,
+ USB_DESC_TYPE_ENDPOINT,
+ USB_DYNAMIC | USB_DIR_IN,
+ USB_EP_ATTR_BULK,
+ USB_CDC_BUFSIZE,
+ 0x00,
+ },
+};
+rt_align(4)
+static char serno[_SER_NO_LEN + 1] = {'\0'};
+rt_weak rt_err_t vcom_get_stored_serno(char *serno, int size);
+
+rt_err_t vcom_get_stored_serno(char *serno, int size)
+{
+ return -RT_ERROR;
+}
+rt_align(4)
+const static char* _ustring[] =
+{
+ "Language",
+ "RT-Thread Team.",
+ "RTT Virtual Serial",
+ serno,
+ "Configuration",
+ "Interface",
+};
+static void rt_usb_vcom_init(struct ufunction *func);
+
+static void _vcom_reset_state(ufunction_t func)
+{
+ struct vcom* data;
+ rt_base_t level;
+
+ RT_ASSERT(func != RT_NULL)
+
+ data = (struct vcom*)func->user_data;
+
+ level = rt_hw_interrupt_disable();
+ data->connected = RT_FALSE;
+ data->in_sending = RT_FALSE;
+ /*rt_kprintf("reset USB serial\n", cnt);*/
+ rt_hw_interrupt_enable(level);
+}
+
+/**
+ * This function will handle cdc bulk in endpoint request.
+ *
+ * @param func the usb function object.
+ * @param size request size.
+ *
+ * @return RT_EOK.
+ */
+static rt_err_t _ep_in_handler(ufunction_t func, rt_size_t size)
+{
+ struct vcom *data;
+ rt_size_t request_size;
+
+ RT_ASSERT(func != RT_NULL);
+
+ data = (struct vcom*)func->user_data;
+ request_size = data->ep_in->request.size;
+ LOG_D("_ep_in_handler %d", request_size);
+ if ((request_size != 0) && ((request_size % EP_MAXPACKET(data->ep_in)) == 0))
+ {
+ /* don't have data right now. Send a zero-length-packet to
+ * terminate the transaction.
+ *
+ * FIXME: actually, this might not be the right place to send zlp.
+ * Only the rt_device_write could know how much data is sending. */
+ data->in_sending = RT_TRUE;
+
+ data->ep_in->request.buffer = RT_NULL;
+ data->ep_in->request.size = 0;
+ data->ep_in->request.req_type = UIO_REQUEST_WRITE;
+ rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request);
+
+ return RT_EOK;
+ }
+
+ rt_completion_done(&data->wait);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will handle cdc bulk out endpoint request.
+ *
+ * @param func the usb function object.
+ * @param size request size.
+ *
+ * @return RT_EOK.
+ */
+static rt_err_t _ep_out_handler(ufunction_t func, rt_size_t size)
+{
+ rt_base_t level;
+ struct vcom *data;
+
+ RT_ASSERT(func != RT_NULL);
+
+ LOG_D("_ep_out_handler %d", size);
+
+ data = (struct vcom*)func->user_data;
+ /* ensure serial is active */
+ if((data->serial.parent.flag & RT_DEVICE_FLAG_ACTIVATED)
+ && (data->serial.parent.open_flag & RT_DEVICE_OFLAG_OPEN))
+ {
+ /* receive data from USB VCOM */
+ level = rt_hw_interrupt_disable();
+
+ rt_ringbuffer_put(&data->rx_ringbuffer, data->ep_out->buffer, size);
+ rt_hw_interrupt_enable(level);
+
+ /* notify receive data */
+ rt_hw_serial_isr(&data->serial,RT_SERIAL_EVENT_RX_IND);
+ }
+
+ data->ep_out->request.buffer = data->ep_out->buffer;
+ data->ep_out->request.size = EP_MAXPACKET(data->ep_out);
+ data->ep_out->request.req_type = UIO_REQUEST_READ_BEST;
+ rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will handle cdc interrupt in endpoint request.
+ *
+ * @param device the usb device object.
+ * @param size request size.
+ *
+ * @return RT_EOK.
+ */
+static rt_err_t _ep_cmd_handler(ufunction_t func, rt_size_t size)
+{
+ RT_ASSERT(func != RT_NULL);
+
+ LOG_D("_ep_cmd_handler");
+
+ return RT_EOK;
+}
+
+/**
+ * This function will handle cdc_get_line_coding request.
+ *
+ * @param device the usb device object.
+ * @param setup the setup request.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _cdc_get_line_coding(udevice_t device, ureq_t setup)
+{
+ struct ucdc_line_coding data;
+ rt_uint16_t size;
+
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(setup != RT_NULL);
+
+ LOG_D("_cdc_get_line_coding");
+
+ data.dwDTERate = 115200;
+ data.bCharFormat = 0;
+ data.bDataBits = 8;
+ data.bParityType = 0;
+ size = setup->wLength > 7 ? 7 : setup->wLength;
+
+ rt_usbd_ep0_write(device, (void*)&data, size);
+
+ return RT_EOK;
+}
+
+static rt_err_t _cdc_set_line_coding_callback(udevice_t device, rt_size_t size)
+{
+ LOG_D("_cdc_set_line_coding_callback");
+
+ dcd_ep0_send_status(device->dcd);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will handle cdc_set_line_coding request.
+ *
+ * @param device the usb device object.
+ * @param setup the setup request.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _cdc_set_line_coding(udevice_t device, ureq_t setup)
+{
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(setup != RT_NULL);
+
+ LOG_D("_cdc_set_line_coding");
+
+ rt_usbd_ep0_read(device, (void*)&line_coding, sizeof(struct ucdc_line_coding),
+ _cdc_set_line_coding_callback);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will handle cdc interface request.
+ *
+ * @param device the usb device object.
+ * @param setup the setup request.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _interface_handler(ufunction_t func, ureq_t setup)
+{
+ struct vcom *data;
+
+ RT_ASSERT(func != RT_NULL);
+ RT_ASSERT(func->device != RT_NULL);
+ RT_ASSERT(setup != RT_NULL);
+
+ data = (struct vcom*)func->user_data;
+
+ switch(setup->bRequest)
+ {
+ case CDC_SEND_ENCAPSULATED_COMMAND:
+ break;
+ case CDC_GET_ENCAPSULATED_RESPONSE:
+ break;
+ case CDC_SET_COMM_FEATURE:
+ break;
+ case CDC_GET_COMM_FEATURE:
+ break;
+ case CDC_CLEAR_COMM_FEATURE:
+ break;
+ case CDC_SET_LINE_CODING:
+ _cdc_set_line_coding(func->device, setup);
+ break;
+ case CDC_GET_LINE_CODING:
+ _cdc_get_line_coding(func->device, setup);
+ break;
+ case CDC_SET_CONTROL_LINE_STATE:
+ data->connected = (setup->wValue & 0x01) > 0?RT_TRUE:RT_FALSE;
+ LOG_D("vcom state:%d ", data->connected);
+ dcd_ep0_send_status(func->device->dcd);
+ break;
+ case CDC_SEND_BREAK:
+ break;
+ default:
+ rt_kprintf("unknown cdc request\n",setup->request_type);
+ return -RT_ERROR;
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * This function will run cdc function, it will be called on handle set configuration request.
+ *
+ * @param func the usb function object.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _function_enable(ufunction_t func)
+{
+ struct vcom *data;
+
+ RT_ASSERT(func != RT_NULL);
+
+ LOG_D("cdc function enable");
+
+ _vcom_reset_state(func);
+
+ data = (struct vcom*)func->user_data;
+ data->ep_out->buffer = rt_malloc(CDC_RX_BUFSIZE);
+ RT_ASSERT(data->ep_out->buffer != RT_NULL);
+
+#ifdef RT_USING_SERIAL_V2
+ data->serial.serial_rx = &data->rx_ringbuffer;
+#endif
+
+ data->ep_out->request.buffer = data->ep_out->buffer;
+ data->ep_out->request.size = EP_MAXPACKET(data->ep_out);
+
+ data->ep_out->request.req_type = UIO_REQUEST_READ_BEST;
+ rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will stop cdc function, it will be called on handle set configuration request.
+ *
+ * @param func the usb function object.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _function_disable(ufunction_t func)
+{
+ struct vcom *data;
+
+ RT_ASSERT(func != RT_NULL);
+
+ LOG_D("cdc function disable");
+
+ _vcom_reset_state(func);
+
+ data = (struct vcom*)func->user_data;
+ if(data->ep_out->buffer != RT_NULL)
+ {
+ rt_free(data->ep_out->buffer);
+ data->ep_out->buffer = RT_NULL;
+ }
+
+ return RT_EOK;
+}
+
+static struct ufunction_ops ops =
+{
+ _function_enable,
+ _function_disable,
+ RT_NULL,
+};
+
+/**
+ * This function will configure cdc descriptor.
+ *
+ * @param comm the communication interface number.
+ * @param data the data interface number.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _cdc_descriptor_config(ucdc_comm_desc_t comm,
+ rt_uint8_t cintf_nr, ucdc_data_desc_t data, rt_uint8_t dintf_nr)
+{
+ comm->call_mgmt_desc.data_interface = dintf_nr;
+ comm->union_desc.master_interface = cintf_nr;
+ comm->union_desc.slave_interface0 = dintf_nr;
+#ifdef RT_USB_DEVICE_COMPOSITE
+ comm->iad_desc.bFirstInterface = cintf_nr;
+#endif
+
+ return RT_EOK;
+}
+
+/**
+ * This function will create a cdc function instance.
+ *
+ * @param device the usb device object.
+ *
+ * @return RT_EOK on successful.
+ */
+ufunction_t rt_usbd_function_cdc_create(udevice_t device)
+{
+ ufunction_t func;
+ struct vcom* data;
+ uintf_t intf_comm, intf_data;
+ ualtsetting_t comm_setting, data_setting;
+ ucdc_data_desc_t data_desc;
+ ucdc_comm_desc_t comm_desc;
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+
+ rt_memset(serno, 0, _SER_NO_LEN + 1);
+ if(vcom_get_stored_serno(serno, _SER_NO_LEN) != RT_EOK)
+ {
+ rt_memset(serno, 0, _SER_NO_LEN + 1);
+ rt_memcpy(serno, _SER_NO, rt_strlen(_SER_NO));
+ }
+#ifdef RT_USB_DEVICE_COMPOSITE
+ rt_usbd_device_set_interface_string(device, VCOM_INTF_STR_INDEX, _ustring[2]);
+#else
+ /* set usb device string description */
+ rt_usbd_device_set_string(device, _ustring);
+#endif
+ /* create a cdc function */
+ func = rt_usbd_function_new(device, &dev_desc, &ops);
+
+ /* support HS */
+ rt_usbd_device_set_qualifier(device, &dev_qualifier);
+
+ /* allocate memory for cdc vcom data */
+ data = (struct vcom*)rt_malloc(sizeof(struct vcom));
+ RT_ASSERT(data != RT_NULL);
+ rt_memset(data, 0, sizeof(struct vcom));
+ func->user_data = (void*)data;
+
+ /* initilize vcom */
+ rt_usb_vcom_init(func);
+
+ /* create a cdc communication interface and a cdc data interface */
+ intf_comm = rt_usbd_interface_new(device, _interface_handler);
+ intf_data = rt_usbd_interface_new(device, _interface_handler);
+
+ /* create a communication alternate setting and a data alternate setting */
+ comm_setting = rt_usbd_altsetting_new(sizeof(struct ucdc_comm_descriptor));
+ data_setting = rt_usbd_altsetting_new(sizeof(struct ucdc_data_descriptor));
+
+ /* config desc in alternate setting */
+ rt_usbd_altsetting_config_descriptor(comm_setting, &_comm_desc,
+ (rt_off_t)&((ucdc_comm_desc_t)0)->intf_desc);
+ rt_usbd_altsetting_config_descriptor(data_setting, &_data_desc, 0);
+ /* configure the cdc interface descriptor */
+ _cdc_descriptor_config(comm_setting->desc, intf_comm->intf_num, data_setting->desc, intf_data->intf_num);
+
+ /* create a command endpoint */
+ comm_desc = (ucdc_comm_desc_t)comm_setting->desc;
+ data->ep_cmd = rt_usbd_endpoint_new(&comm_desc->ep_desc, _ep_cmd_handler);
+
+ /* add the command endpoint to the cdc communication interface */
+ rt_usbd_altsetting_add_endpoint(comm_setting, data->ep_cmd);
+
+ /* add the communication alternate setting to the communication interface,
+ then set default setting of the interface */
+ rt_usbd_interface_add_altsetting(intf_comm, comm_setting);
+ rt_usbd_set_altsetting(intf_comm, 0);
+
+ /* add the communication interface to the cdc function */
+ rt_usbd_function_add_interface(func, intf_comm);
+
+ /* create a bulk in and a bulk endpoint */
+ data_desc = (ucdc_data_desc_t)data_setting->desc;
+ data->ep_out = rt_usbd_endpoint_new(&data_desc->ep_out_desc, _ep_out_handler);
+ data->ep_in = rt_usbd_endpoint_new(&data_desc->ep_in_desc, _ep_in_handler);
+
+ /* add the bulk out and bulk in endpoints to the data alternate setting */
+ rt_usbd_altsetting_add_endpoint(data_setting, data->ep_in);
+ rt_usbd_altsetting_add_endpoint(data_setting, data->ep_out);
+
+ /* add the data alternate setting to the data interface
+ then set default setting of the interface */
+ rt_usbd_interface_add_altsetting(intf_data, data_setting);
+ rt_usbd_set_altsetting(intf_data, 0);
+
+ /* add the cdc data interface to cdc function */
+ rt_usbd_function_add_interface(func, intf_data);
+
+ return func;
+}
+
+/**
+* UART device in RT-Thread
+*/
+static rt_err_t _vcom_configure(struct rt_serial_device *serial,
+ struct serial_configure *cfg)
+{
+ return RT_EOK;
+}
+
+static rt_err_t _vcom_control(struct rt_serial_device *serial,
+ int cmd, void *arg)
+{
+ struct ufunction *func;
+ struct vcom *data;
+
+ func = (struct ufunction*)serial->parent.user_data;
+ data = (struct vcom*)func->user_data;
+
+ switch (cmd)
+ {
+ case RT_DEVICE_CTRL_CLR_INT:
+ /* disable rx irq */
+ break;
+ case RT_DEVICE_CTRL_SET_INT:
+ /* enable rx irq */
+ break;
+ case RT_USBD_CLASS_CTRL_CONNECTED:
+ (*(rt_bool_t*)arg) = data->connected;
+ break;
+ }
+
+ return RT_EOK;
+}
+
+static int _vcom_getc(struct rt_serial_device *serial)
+{
+ int result;
+ rt_uint8_t ch;
+ rt_base_t level;
+ struct ufunction *func;
+ struct vcom *data;
+
+ func = (struct ufunction*)serial->parent.user_data;
+ data = (struct vcom*)func->user_data;
+
+ result = -1;
+
+ level = rt_hw_interrupt_disable();
+
+ if(rt_ringbuffer_getchar(&data->rx_ringbuffer, &ch) != 0)
+ {
+ result = ch;
+ }
+
+ rt_hw_interrupt_enable(level);
+
+ return result;
+}
+
+static rt_ssize_t _vcom_rb_block_put(struct vcom *data, const rt_uint8_t *buf, rt_size_t size)
+{
+ rt_base_t level;
+ rt_size_t put_len = 0;
+ rt_size_t w_ptr = 0;
+ rt_uint32_t res;
+ rt_size_t remain_size = size;
+
+ while (remain_size)
+ {
+ level = rt_hw_interrupt_disable();
+ put_len = rt_ringbuffer_put(&data->tx_ringbuffer, (const rt_uint8_t *)&buf[w_ptr], remain_size);
+ rt_hw_interrupt_enable(level);
+ w_ptr += put_len;
+ remain_size -= put_len;
+ if (put_len == 0)
+ {
+ rt_event_recv(&data->tx_event, CDC_TX_HAS_SPACE,
+ RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
+ VCOM_TX_TIMEOUT, &res);
+ }
+ else
+ {
+ rt_event_send(&data->tx_event, CDC_TX_HAS_DATE);
+ }
+ }
+
+ return size;
+}
+
+#ifdef RT_USING_SERIAL_V1
+static rt_ssize_t _vcom_tx(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction)
+#else
+static rt_ssize_t _vcom_tx(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, rt_uint32_t tx_flag)
+#endif
+{
+ struct ufunction *func;
+ struct vcom *data;
+ rt_uint32_t send_size = 0;
+ rt_size_t ptr = 0;
+ rt_uint8_t crlf[2] = {'\r', '\n',};
+
+ func = (struct ufunction*)serial->parent.user_data;
+ data = (struct vcom*)func->user_data;
+
+ RT_ASSERT(serial != RT_NULL);
+ RT_ASSERT(buf != RT_NULL);
+
+ LOG_D("%s",__func__);
+
+ if (data->connected)
+ {
+ if((serial->parent.open_flag & RT_DEVICE_FLAG_STREAM))
+ {
+ while(send_size < size)
+ {
+ while(ptr < size && buf[ptr] != '\n')
+ {
+ ptr++;
+ }
+ if(ptr < size)
+ {
+ send_size += _vcom_rb_block_put(data, (const rt_uint8_t *)&buf[send_size], ptr - send_size);
+ _vcom_rb_block_put(data, crlf, 2);
+ send_size++;
+ ptr++;
+ }
+ else if (ptr == size)
+ {
+ send_size += _vcom_rb_block_put(data, (const rt_uint8_t *)&buf[send_size], ptr - send_size);
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ while (send_size < size)
+ {
+ send_size += _vcom_rb_block_put(data, (rt_uint8_t *)&buf[send_size], size - send_size);
+ }
+ }
+ }
+ else
+ {
+ /* recover dataqueue resources */
+ rt_hw_serial_isr(&data->serial,RT_SERIAL_EVENT_TX_DMADONE);
+ }
+
+ return size;
+}
+static int _vcom_putc(struct rt_serial_device *serial, char c)
+{
+ rt_base_t level;
+ struct ufunction *func;
+ struct vcom *data;
+
+ func = (struct ufunction*)serial->parent.user_data;
+ data = (struct vcom*)func->user_data;
+
+ RT_ASSERT(serial != RT_NULL);
+
+ if (data->connected)
+ {
+ if(c == '\n' && (serial->parent.open_flag & RT_DEVICE_FLAG_STREAM))
+ {
+ level = rt_hw_interrupt_disable();
+ rt_ringbuffer_putchar_force(&data->tx_ringbuffer, '\r');
+ rt_hw_interrupt_enable(level);
+ rt_event_send(&data->tx_event, CDC_TX_HAS_DATE);
+ }
+ level = rt_hw_interrupt_disable();
+ rt_ringbuffer_putchar_force(&data->tx_ringbuffer, c);
+ rt_hw_interrupt_enable(level);
+ rt_event_send(&data->tx_event, CDC_TX_HAS_DATE);
+ }
+
+ return 1;
+}
+
+static const struct rt_uart_ops usb_vcom_ops =
+{
+ _vcom_configure,
+ _vcom_control,
+ _vcom_putc,
+ _vcom_getc,
+ _vcom_tx
+};
+
+/* Vcom Tx Thread */
+static void vcom_tx_thread_entry(void* parameter)
+{
+ rt_base_t level;
+ rt_uint32_t res;
+ struct ufunction *func = (struct ufunction *)parameter;
+ struct vcom *data = (struct vcom*)func->user_data;
+ rt_uint8_t ch[CDC_BULKIN_MAXSIZE];
+
+ while (1)
+ {
+ if
+ (
+ (rt_event_recv(&data->tx_event, CDC_TX_HAS_DATE,
+ RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
+ RT_WAITING_FOREVER, &res) != RT_EOK) ||
+ (!(res & CDC_TX_HAS_DATE))
+ )
+ {
+ continue;
+ }
+ if(!(res & CDC_TX_HAS_DATE))
+ {
+ continue;
+ }
+ while(rt_ringbuffer_data_len(&data->tx_ringbuffer))
+ {
+ level = rt_hw_interrupt_disable();
+ res = rt_ringbuffer_get(&data->tx_ringbuffer, ch, CDC_BULKIN_MAXSIZE);
+ rt_hw_interrupt_enable(level);
+
+ if(!res)
+ {
+ continue;
+ }
+ if (!data->connected)
+ {
+#ifdef RT_USING_SERIAL_V1
+#ifndef VCOM_TX_USE_DMA
+ if(data->serial.parent.open_flag & RT_DEVICE_FLAG_INT_TX)
+#else
+ if(data->serial.parent.open_flag & RT_DEVICE_FLAG_DMA_TX)
+#endif
+#endif
+#ifdef RT_USING_SERIAL_V2
+ if(data->serial.parent.open_flag & RT_DEVICE_FLAG_TX_BLOCKING)
+#endif
+ {
+ /* drop msg */
+#ifndef VCOM_TX_USE_DMA
+ rt_hw_serial_isr(&data->serial,RT_SERIAL_EVENT_TX_DONE);
+#else
+ rt_hw_serial_isr(&data->serial,RT_SERIAL_EVENT_TX_DMADONE);
+#endif
+ }
+ continue;
+ }
+ rt_completion_init(&data->wait);
+ data->ep_in->request.buffer = ch;
+ data->ep_in->request.size = res;
+
+ data->ep_in->request.req_type = UIO_REQUEST_WRITE;
+
+ rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request);
+
+ if (rt_completion_wait(&data->wait, VCOM_TX_TIMEOUT) != RT_EOK)
+ {
+ LOG_D("vcom tx timeout");
+ }
+#ifdef RT_USING_SERIAL_V1
+#ifndef VCOM_TX_USE_DMA
+ if(data->serial.parent.open_flag & RT_DEVICE_FLAG_INT_TX)
+#else
+ if(data->serial.parent.open_flag & RT_DEVICE_FLAG_DMA_TX)
+#endif
+#endif
+#ifdef RT_USING_SERIAL_V2
+ if(data->serial.parent.open_flag & RT_DEVICE_FLAG_TX_BLOCKING)
+#endif
+ {
+#ifndef VCOM_TX_USE_DMA
+ rt_hw_serial_isr(&data->serial,RT_SERIAL_EVENT_TX_DONE);
+#else
+ rt_hw_serial_isr(&data->serial,RT_SERIAL_EVENT_TX_DMADONE);
+#endif
+ rt_event_send(&data->tx_event, CDC_TX_HAS_SPACE);
+ }
+ }
+
+ }
+}
+
+static void rt_usb_vcom_init(struct ufunction *func)
+{
+ rt_err_t result = RT_EOK;
+ struct serial_configure config;
+ struct vcom *data = (struct vcom*)func->user_data;
+
+ /* initialize ring buffer */
+ rt_ringbuffer_init(&data->rx_ringbuffer, data->rx_rbp, CDC_RX_BUFSIZE);
+ rt_ringbuffer_init(&data->tx_ringbuffer, data->tx_rbp, CDC_TX_BUFSIZE);
+
+ rt_event_init(&data->tx_event, "vcom", RT_IPC_FLAG_FIFO);
+
+ config.baud_rate = BAUD_RATE_115200;
+ config.data_bits = DATA_BITS_8;
+ config.stop_bits = STOP_BITS_1;
+ config.parity = PARITY_NONE;
+ config.bit_order = BIT_ORDER_LSB;
+ config.invert = NRZ_NORMAL;
+#if defined(RT_USING_SERIAL_V1)
+ config.bufsz = CDC_RX_BUFSIZE;
+#elif defined(RT_USING_SERIAL_V2)
+ config.rx_bufsz = CDC_RX_BUFSIZE;
+ config.tx_bufsz = CDC_TX_BUFSIZE;
+#endif
+ data->serial.ops = &usb_vcom_ops;
+ data->serial.serial_rx = RT_NULL;
+ data->serial.config = config;
+
+ /* register vcom device */
+ rt_hw_serial_register(&data->serial, VCOM_DEVICE,
+#ifndef VCOM_TX_USE_DMA
+ RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX,
+#else
+ RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_DMA_TX,
+#endif
+ func);
+
+ /* init usb device thread */
+ rt_thread_init(&vcom_thread, "vcom",
+ vcom_tx_thread_entry, func,
+ vcom_thread_stack, VCOM_TASK_STK_SIZE,
+ 16, 20);
+ result = rt_thread_startup(&vcom_thread);
+ RT_ASSERT(result == RT_EOK);
+}
+struct udclass vcom_class =
+{
+ .rt_usbd_function_create = rt_usbd_function_cdc_create
+};
+
+int rt_usbd_vcom_class_register(void)
+{
+ rt_usbd_class_register(&vcom_class);
+ return 0;
+}
+INIT_PREV_EXPORT(rt_usbd_vcom_class_register);
+
+#endif
diff --git a/components/legacy/usb/usbdevice/class/ecm.c b/components/legacy/usb/usbdevice/class/ecm.c
new file mode 100644
index 0000000000..d856a1e332
--- /dev/null
+++ b/components/legacy/usb/usbdevice/class/ecm.c
@@ -0,0 +1,682 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2017-11-19 ZYH first version
+ * 2019-06-10 ZYH fix hotplug
+ */
+
+#include <rtdevice.h>
+#ifdef RT_USB_DEVICE_ECM
+#include "cdc.h"
+
+#define DBG_LEVEL DBG_WARNING
+#define DBG_SECTION_NAME "ECM"
+#include <rtdbg.h>
+
+/* RT-Thread LWIP ethernet interface */
+#include <netif/ethernetif.h>
+
+#ifndef USB_ETH_MTU
+#define USB_ETH_MTU 1514
+#endif
+#define MAX_ADDR_LEN 6
+#define ECM_INTF_STR_INDEX 10
+
+struct rt_ecm_eth
+{
+ /* inherit from ethernet device */
+ struct eth_device parent;
+ struct ufunction * func;
+ struct cdc_eps eps;
+ /* interface address info */
+ rt_uint8_t host_addr[MAX_ADDR_LEN];
+ rt_uint8_t dev_addr[MAX_ADDR_LEN];
+
+ rt_align(4)
+ rt_uint8_t rx_pool[512];
+ rt_align(4)
+ rt_size_t rx_size;
+ rt_align(4)
+ rt_size_t rx_offset;
+ rt_align(4)
+ char rx_buffer[USB_ETH_MTU];
+ char tx_buffer[USB_ETH_MTU];
+
+ struct rt_semaphore tx_buffer_free;
+
+};
+typedef struct rt_ecm_eth * rt_ecm_eth_t;
+
+rt_align(4)
+static struct udevice_descriptor _dev_desc =
+{
+ USB_DESC_LENGTH_DEVICE, /* bLength */
+ USB_DESC_TYPE_DEVICE, /* type */
+ USB_BCD_VERSION, /* bcdUSB */
+ USB_CLASS_CDC, /* bDeviceClass */
+ USB_CDC_SUBCLASS_ETH, /* bDeviceSubClass */
+ USB_CDC_PROTOCOL_NONE, /* bDeviceProtocol */
+ 0x40, /* bMaxPacketSize0 */
+ _VENDOR_ID, /* idVendor */
+ _PRODUCT_ID, /* idProduct */
+ USB_BCD_DEVICE, /* bcdDevice */
+ USB_STRING_MANU_INDEX, /* iManufacturer */
+ USB_STRING_PRODUCT_INDEX, /* iProduct */
+ USB_STRING_SERIAL_INDEX, /* iSerialNumber */
+ USB_DYNAMIC /* bNumConfigurations */
+};
+
+/* communcation interface descriptor */
+rt_align(4)
+const static struct ucdc_eth_descriptor _comm_desc =
+{
+#ifdef RT_USB_DEVICE_COMPOSITE
+ /* Interface Association Descriptor */
+ {
+ USB_DESC_LENGTH_IAD,
+ USB_DESC_TYPE_IAD,
+ USB_DYNAMIC,
+ 0x02,
+ USB_CDC_CLASS_COMM,
+ USB_CDC_SUBCLASS_ETH,
+ USB_CDC_PROTOCOL_NONE,
+ 0x00,
+ },
+#endif
+ /* Interface Descriptor */
+ {
+ USB_DESC_LENGTH_INTERFACE,
+ USB_DESC_TYPE_INTERFACE,
+ USB_DYNAMIC,
+ 0x00,
+ 0x01,
+ USB_CDC_CLASS_COMM,
+ USB_CDC_SUBCLASS_ETH,
+ USB_CDC_PROTOCOL_NONE,
+#ifdef RT_USB_DEVICE_COMPOSITE
+ ECM_INTF_STR_INDEX,
+#else
+ 0x00,
+#endif
+ },
+ /* Header Functional Descriptor */
+ {
+ sizeof(struct ucdc_header_descriptor),
+ USB_CDC_CS_INTERFACE,
+ USB_CDC_SCS_HEADER,
+ 0x0110,
+ },
+ /* Union Functional Descriptor */
+ {
+ sizeof(struct ucdc_union_descriptor),
+ USB_CDC_CS_INTERFACE,
+ USB_CDC_SCS_UNION,
+ USB_DYNAMIC,
+ USB_DYNAMIC,
+ },
+ /* Abstract Control Management Functional Descriptor */
+ {
+ sizeof(struct ucdc_enet_descriptor),
+ USB_CDC_CS_INTERFACE,
+ USB_CDC_SCS_ETH,
+ USB_STRING_SERIAL_INDEX,
+ {0,0,0,0},
+ USB_ETH_MTU,
+ 0x00,
+ 0x00,
+ },
+ /* Endpoint Descriptor */
+ {
+ USB_DESC_LENGTH_ENDPOINT,
+ USB_DESC_TYPE_ENDPOINT,
+ USB_DIR_IN | USB_DYNAMIC,
+ USB_EP_ATTR_INT,
+ 0x08,
+ 0xFF,
+ },
+};
+
+/* data interface descriptor */
+rt_align(4)
+const static struct ucdc_data_descriptor _data_desc =
+{
+ /* interface descriptor */
+ {
+ USB_DESC_LENGTH_INTERFACE,
+ USB_DESC_TYPE_INTERFACE,
+ USB_DYNAMIC,
+ 0x00,
+ 0x02,
+ USB_CDC_CLASS_DATA,
+ USB_CDC_SUBCLASS_ETH,
+ 0x00,
+ 0x00,
+ },
+ /* endpoint, bulk out */
+ {
+ USB_DESC_LENGTH_ENDPOINT,
+ USB_DESC_TYPE_ENDPOINT,
+ USB_DIR_OUT | USB_DYNAMIC,
+ USB_EP_ATTR_BULK,
+ USB_DYNAMIC,
+ 0x00,
+ },
+ /* endpoint, bulk in */
+ {
+ USB_DESC_LENGTH_ENDPOINT,
+ USB_DESC_TYPE_ENDPOINT,
+ USB_DYNAMIC | USB_DIR_IN,
+ USB_EP_ATTR_BULK,
+ USB_DYNAMIC,
+ 0x00,
+ },
+};
+
+rt_align(4)
+const static char* _ustring[] =
+{
+ "Language", /* LANGID */
+ "RT-Thread Team.", /* MANU */
+ "RT-Thread ECM device", /* PRODUCT */
+ "3497F694ECAB", /* SERIAL (MAC)*/
+ "Configuration", /* CONFIG */
+ "Interface", /* INTERFACE */
+};
+
+rt_align(4)
+//FS and HS needed
+static struct usb_qualifier_descriptor dev_qualifier =
+{
+ sizeof(dev_qualifier), //bLength
+ USB_DESC_TYPE_DEVICEQUALIFIER, //bDescriptorType
+ 0x0200, //bcdUSB
+ USB_CLASS_CDC, //bDeviceClass
+ USB_CDC_SUBCLASS_ETH, //bDeviceSubClass
+ USB_CDC_PROTOCOL_NONE, //bDeviceProtocol
+ 64, //bMaxPacketSize0
+ 0x01, //bNumConfigurations
+ 0,
+};
+
+static rt_err_t _cdc_send_notifi(ufunction_t func,ucdc_notification_code_t notifi,rt_uint16_t wValue,rt_uint16_t wLength)
+{
+ static struct ucdc_management_element_notifications _notifi;
+ cdc_eps_t eps;
+ RT_ASSERT(func!=RT_NULL)
+ eps = &((rt_ecm_eth_t)func->user_data)->eps;
+ _notifi.bmRequestType = 0xA1;
+ _notifi.bNotificatinCode = notifi;
+ _notifi.wValue = wValue;
+ _notifi.wLength = wLength;
+
+ eps->ep_cmd->request.buffer = (void *)&_notifi;
+ eps->ep_cmd->request.size = 8;
+ eps->ep_cmd->request.req_type = UIO_REQUEST_WRITE;
+ rt_usbd_io_request(func->device, eps->ep_cmd, &eps->ep_cmd->request);
+ return RT_EOK;
+}
+
+
+static rt_err_t _ecm_set_eth_packet_filter(ufunction_t func, ureq_t setup)
+{
+ rt_ecm_eth_t _ecm_eth = (rt_ecm_eth_t)func->user_data;
+ dcd_ep0_send_status(func->device->dcd);
+
+ /* send link up. */
+ eth_device_linkchange(&_ecm_eth->parent, RT_TRUE);
+ _cdc_send_notifi(func, UCDC_NOTIFI_NETWORK_CONNECTION, 1, 0);
+
+#ifdef LWIP_USING_DHCPD
+ extern void dhcpd_start(const char *netif_name);
+ dhcpd_start("u0");
+#endif
+
+ return RT_EOK;
+}
+/**
+ * This function will handle rndis interface request.
+ *
+ * @param device the usb device object.
+ * @param setup the setup request.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _interface_handler(ufunction_t func, ureq_t setup)
+{
+ RT_ASSERT(func != RT_NULL);
+ RT_ASSERT(setup != RT_NULL);
+
+ switch(setup->bRequest)
+ {
+ case CDC_SET_ETH_PACKET_FILTER:
+ LOG_D("CDC_SET_ETH_PACKET_FILTER");
+ _ecm_set_eth_packet_filter(func, setup);
+ break;
+ default:
+ LOG_E("Unknow setup->bRequest: 0x%02X", setup->bRequest);
+ break;
+ }
+ return RT_EOK;
+}
+
+/**
+ * This function will handle rndis bulk in endpoint request.
+ *
+ * @param device the usb device object.
+ * @param size request size.
+ *
+ * @return RT_EOK.
+ */
+
+static rt_err_t _ep_in_handler(ufunction_t func, rt_size_t size)
+{
+ rt_ecm_eth_t ecm_device = (rt_ecm_eth_t)func->user_data;
+ rt_sem_release(&ecm_device->tx_buffer_free);
+ return RT_EOK;
+}
+
+/**
+ * This function will handle RNDIS bulk out endpoint request.
+ *
+ * @param device the usb device object.
+ * @param size request size.
+ *
+ * @return RT_EOK.
+ */
+static rt_err_t _ep_out_handler(ufunction_t func, rt_size_t size)
+{
+ rt_ecm_eth_t ecm_device = (rt_ecm_eth_t)func->user_data;
+ rt_memcpy((void *)(ecm_device->rx_buffer + ecm_device->rx_offset),ecm_device->rx_pool,size);
+ ecm_device->rx_offset += size;
+ if(size < EP_MAXPACKET(ecm_device->eps.ep_out))
+ {
+ ecm_device->rx_size = ecm_device->rx_offset;
+ ecm_device->rx_offset = 0;
+ eth_device_ready(&ecm_device->parent);
+
+ }else
+ {
+ ecm_device->eps.ep_out->request.buffer = ecm_device->eps.ep_out->buffer;
+ ecm_device->eps.ep_out->request.size = EP_MAXPACKET(ecm_device->eps.ep_out);
+ ecm_device->eps.ep_out->request.req_type = UIO_REQUEST_READ_BEST;
+ rt_usbd_io_request(ecm_device->func->device, ecm_device->eps.ep_out, &ecm_device->eps.ep_out->request);
+ }
+
+
+ return RT_EOK;
+}
+static rt_err_t rt_ecm_eth_init(rt_device_t dev)
+{
+ return RT_EOK;
+}
+
+static rt_err_t rt_ecm_eth_open(rt_device_t dev, rt_uint16_t oflag)
+{
+ return RT_EOK;
+}
+
+static rt_err_t rt_ecm_eth_close(rt_device_t dev)
+{
+ return RT_EOK;
+}
+
+static rt_ssize_t rt_ecm_eth_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
+{
+ rt_set_errno(-RT_ENOSYS);
+ return 0;
+}
+
+static rt_ssize_t rt_ecm_eth_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
+{
+ rt_set_errno(-RT_ENOSYS);
+ return 0;
+}
+static rt_err_t rt_ecm_eth_control(rt_device_t dev, int cmd, void *args)
+{
+ rt_ecm_eth_t ecm_eth_dev = (rt_ecm_eth_t)dev;
+ switch(cmd)
+ {
+ case NIOCTL_GADDR:
+ /* get mac address */
+ if(args) rt_memcpy(args, ecm_eth_dev->dev_addr, MAX_ADDR_LEN);
+ else return -RT_ERROR;
+ break;
+
+ default :
+ break;
+ }
+
+ return RT_EOK;
+}
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops ecm_device_ops =
+{
+ rt_ecm_eth_init,
+ rt_ecm_eth_open,
+ rt_ecm_eth_close,
+ rt_ecm_eth_read,
+ rt_ecm_eth_write,
+ rt_ecm_eth_control
+};
+#endif
+
+struct pbuf *rt_ecm_eth_rx(rt_device_t dev)
+{
+ struct pbuf* p = RT_NULL;
+ rt_uint32_t offset = 0;
+ rt_ecm_eth_t ecm_eth_dev = (rt_ecm_eth_t)dev;
+ if(ecm_eth_dev->rx_size != 0)
+ {
+ /* allocate buffer */
+ p = pbuf_alloc(PBUF_RAW, ecm_eth_dev->rx_size, PBUF_RAM);
+ if (p != RT_NULL)
+ {
+ struct pbuf* q;
+
+ for (q = p; q != RT_NULL; q= q->next)
+ {
+ /* Copy the received frame into buffer from memory pointed by the current ETHERNET DMA Rx descriptor */
+ rt_memcpy(q->payload,
+ (rt_uint8_t *)((ecm_eth_dev->rx_buffer) + offset),
+ q->len);
+ offset += q->len;
+ }
+ }
+ }
+
+ {
+ if(ecm_eth_dev->func->device->state == USB_STATE_CONFIGURED)
+ {
+ ecm_eth_dev->rx_size = 0;
+ ecm_eth_dev->rx_offset = 0;
+ ecm_eth_dev->eps.ep_out->request.buffer = ecm_eth_dev->eps.ep_out->buffer;
+ ecm_eth_dev->eps.ep_out->request.size = EP_MAXPACKET(ecm_eth_dev->eps.ep_out);
+ ecm_eth_dev->eps.ep_out->request.req_type = UIO_REQUEST_READ_BEST;
+ rt_usbd_io_request(ecm_eth_dev->func->device, ecm_eth_dev->eps.ep_out, &ecm_eth_dev->eps.ep_out->request);
+ }
+ }
+
+ return p;
+}
+
+rt_err_t rt_ecm_eth_tx(rt_device_t dev, struct pbuf* p)
+{
+ struct pbuf* q;
+ char * pbuffer;
+ rt_err_t result = RT_EOK;
+ rt_ecm_eth_t ecm_eth_dev = (rt_ecm_eth_t)dev;
+
+ if(!ecm_eth_dev->parent.link_status)
+ {
+ LOG_D("linkdown, drop pkg");
+ return RT_EOK;
+ }
+
+ if(p->tot_len > USB_ETH_MTU)
+ {
+ LOG_W("ECM MTU is:%d, but the send packet size is %d",
+ USB_ETH_MTU, p->tot_len);
+ p->tot_len = USB_ETH_MTU;
+ }
+
+ result = rt_sem_take(&ecm_eth_dev->tx_buffer_free, rt_tick_from_millisecond(1000));
+ if(result != RT_EOK)
+ {
+ LOG_W("wait for buffer free timeout");
+ /* if cost 1s to wait send done it said that connection is close . drop it */
+ rt_sem_release(&ecm_eth_dev->tx_buffer_free);
+ return result;
+ }
+
+ pbuffer = (char *)&ecm_eth_dev->tx_buffer;
+ for (q = p; q != NULL; q = q->next)
+ {
+ rt_memcpy(pbuffer, q->payload, q->len);
+ pbuffer += q->len;
+ }
+
+ {
+ if(ecm_eth_dev->func->device->state == USB_STATE_CONFIGURED)
+ {
+ ecm_eth_dev->eps.ep_in->request.buffer = (void *)&ecm_eth_dev->tx_buffer;
+ ecm_eth_dev->eps.ep_in->request.size = p->tot_len;
+ ecm_eth_dev->eps.ep_in->request.req_type = UIO_REQUEST_WRITE;
+ rt_usbd_io_request(ecm_eth_dev->func->device, ecm_eth_dev->eps.ep_in, &ecm_eth_dev->eps.ep_in->request);
+ }
+ }
+
+ return result;
+}
+/**
+ * This function will handle RNDIS interrupt in endpoint request.
+ *
+ * @param device the usb device object.
+ * @param size request size.
+ *
+ * @return RT_EOK.
+ */
+static rt_err_t _ep_cmd_handler(ufunction_t func, rt_size_t size)
+{
+ return RT_EOK;
+}
+
+/**
+ * This function will run cdc class, it will be called on handle set configuration request.
+ *
+ * @param device the usb device object.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _function_enable(ufunction_t func)
+{
+ cdc_eps_t eps;
+ rt_ecm_eth_t ecm_device = (rt_ecm_eth_t)func->user_data;
+
+ LOG_D("plugged in");
+
+ eps = (cdc_eps_t)&ecm_device->eps;
+ eps->ep_out->buffer = ecm_device->rx_pool;
+
+ /* reset eth rx tx */
+ ecm_device->rx_size = 0;
+ ecm_device->rx_offset = 0;
+
+ eps->ep_out->request.buffer = (void *)eps->ep_out->buffer;
+ eps->ep_out->request.size = EP_MAXPACKET(eps->ep_out);
+ eps->ep_out->request.req_type = UIO_REQUEST_READ_BEST;
+ rt_usbd_io_request(func->device, eps->ep_out, &eps->ep_out->request);
+ return RT_EOK;
+}
+
+/**
+ * This function will stop cdc class, it will be called on handle set configuration request.
+ *
+ * @param device the usb device object.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _function_disable(ufunction_t func)
+{
+ LOG_D("plugged out");
+
+ eth_device_linkchange(&((rt_ecm_eth_t)func->user_data)->parent, RT_FALSE);
+
+ /* reset eth rx tx */
+ ((rt_ecm_eth_t)func->user_data)->rx_size = 0;
+ ((rt_ecm_eth_t)func->user_data)->rx_offset = 0;
+
+ return RT_EOK;
+}
+
+
+static struct ufunction_ops ops =
+{
+ _function_enable,
+ _function_disable,
+ RT_NULL,
+};
+
+/**
+ * This function will configure cdc descriptor.
+ *
+ * @param comm the communication interface number.
+ * @param data the data interface number.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _cdc_descriptor_config(ucdc_comm_desc_t comm, rt_uint8_t cintf_nr, ucdc_data_desc_t data, rt_uint8_t dintf_nr, rt_uint8_t device_is_hs)
+{
+ comm->call_mgmt_desc.data_interface = dintf_nr;
+ comm->union_desc.master_interface = cintf_nr;
+ comm->union_desc.slave_interface0 = dintf_nr;
+#ifdef RT_USB_DEVICE_COMPOSITE
+ comm->iad_desc.bFirstInterface = cintf_nr;
+#endif
+ data->ep_out_desc.wMaxPacketSize = device_is_hs ? 512 : 64;
+ data->ep_in_desc.wMaxPacketSize = device_is_hs ? 512 : 64;
+ return RT_EOK;
+}
+
+
+
+/**
+ * This function will create a cdc ecm class instance.
+ *
+ * @param device the usb device object.
+ *
+ * @return RT_EOK on successful.
+ */
+ufunction_t rt_usbd_function_ecm_create(udevice_t device)
+{
+ ufunction_t cdc;
+ rt_ecm_eth_t _ecm_eth;
+ cdc_eps_t eps;
+ uintf_t intf_comm, intf_data;
+ ualtsetting_t comm_setting, data_setting;
+ ucdc_data_desc_t data_desc;
+ ucdc_eth_desc_t comm_desc;
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+
+ /* set usb device string description */
+#ifdef RT_USB_DEVICE_COMPOSITE
+ rt_usbd_device_set_interface_string(device, ECM_INTF_STR_INDEX, _ustring[2]);
+#else
+ rt_usbd_device_set_string(device, _ustring);
+#endif
+ /* create a cdc class */
+ cdc = rt_usbd_function_new(device, &_dev_desc, &ops);
+ rt_usbd_device_set_qualifier(device, &dev_qualifier);
+ _ecm_eth= rt_malloc(sizeof(struct rt_ecm_eth));
+ RT_ASSERT(_ecm_eth != RT_NULL);
+ rt_memset(_ecm_eth, 0, sizeof(struct rt_ecm_eth));
+ cdc->user_data = _ecm_eth;
+
+ _ecm_eth->func = cdc;
+ /* create a cdc class endpoints collection */
+ eps = &_ecm_eth->eps;
+ /* create a cdc communication interface and a cdc data interface */
+ intf_comm = rt_usbd_interface_new(device, _interface_handler);
+ intf_data = rt_usbd_interface_new(device, _interface_handler);
+
+ /* create a communication alternate setting and a data alternate setting */
+ comm_setting = rt_usbd_altsetting_new(sizeof(struct ucdc_eth_descriptor));
+ data_setting = rt_usbd_altsetting_new(sizeof(struct ucdc_data_descriptor));
+
+ /* config desc in alternate setting */
+ rt_usbd_altsetting_config_descriptor(comm_setting, &_comm_desc,
+ (rt_off_t)&((ucdc_eth_desc_t)0)->intf_desc);
+ rt_usbd_altsetting_config_descriptor(data_setting, &_data_desc, 0);
+ /* configure the cdc interface descriptor */
+ _cdc_descriptor_config(comm_setting->desc, intf_comm->intf_num, data_setting->desc, intf_data->intf_num, device->dcd->device_is_hs);
+
+ /* create a command endpoint */
+ comm_desc = (ucdc_eth_desc_t)comm_setting->desc;
+ eps->ep_cmd = rt_usbd_endpoint_new(&comm_desc->ep_desc, _ep_cmd_handler);
+ /* add the command endpoint to the cdc communication interface */
+ rt_usbd_altsetting_add_endpoint(comm_setting, eps->ep_cmd);
+
+ /* add the communication alternate setting to the communication interface,
+ then set default setting of the interface */
+ rt_usbd_interface_add_altsetting(intf_comm, comm_setting);
+ rt_usbd_set_altsetting(intf_comm, 0);
+ /* add the communication interface to the cdc class */
+ rt_usbd_function_add_interface(cdc, intf_comm);
+
+ /* create a bulk in and a bulk out endpoint */
+ data_desc = (ucdc_data_desc_t)data_setting->desc;
+ eps->ep_out = rt_usbd_endpoint_new(&data_desc->ep_out_desc, _ep_out_handler);
+ eps->ep_in = rt_usbd_endpoint_new(&data_desc->ep_in_desc, _ep_in_handler);
+
+ /* add the bulk out and bulk in endpoints to the data alternate setting */
+ rt_usbd_altsetting_add_endpoint(data_setting, eps->ep_in);
+ rt_usbd_altsetting_add_endpoint(data_setting, eps->ep_out);
+
+ /* add the data alternate setting to the data interface
+ then set default setting of the interface */
+ rt_usbd_interface_add_altsetting(intf_data, data_setting);
+ rt_usbd_set_altsetting(intf_data, 0);
+
+ /* add the cdc data interface to cdc class */
+ rt_usbd_function_add_interface(cdc, intf_data);
+
+ rt_sem_init(&_ecm_eth->tx_buffer_free, "ue_tx", 1, RT_IPC_FLAG_FIFO);
+ /* OUI 00-00-00, only for test. */
+ _ecm_eth->dev_addr[0] = 0x34;
+ _ecm_eth->dev_addr[1] = 0x97;
+ _ecm_eth->dev_addr[2] = 0xF6;
+ /* generate random MAC. */
+ _ecm_eth->dev_addr[3] = 0x94;//*(const rt_uint8_t *)(0x1fff7a10);
+ _ecm_eth->dev_addr[4] = 0xEC;//*(const rt_uint8_t *)(0x1fff7a14);
+ _ecm_eth->dev_addr[5] = 0xAC;//(const rt_uint8_t *)(0x1fff7a18);
+ /* OUI 00-00-00, only for test. */
+ _ecm_eth->host_addr[0] = 0x34;
+ _ecm_eth->host_addr[1] = 0x97;
+ _ecm_eth->host_addr[2] = 0xF6;
+ /* generate random MAC. */
+ _ecm_eth->host_addr[3] = 0x94;//*(const rt_uint8_t *)(0x1fff7a10);
+ _ecm_eth->host_addr[4] = 0xEC;//*(const rt_uint8_t *)(0x1fff7a14);
+ _ecm_eth->host_addr[5] = 0xAB;//*(const rt_uint8_t *)(0x1fff7a18);
+
+#ifdef RT_USING_DEVICE_OPS
+ _ecm_eth->parent.parent.ops = &ecm_device_ops;
+#else
+ _ecm_eth->parent.parent.init = rt_ecm_eth_init;
+ _ecm_eth->parent.parent.open = rt_ecm_eth_open;
+ _ecm_eth->parent.parent.close = rt_ecm_eth_close;
+ _ecm_eth->parent.parent.read = rt_ecm_eth_read;
+ _ecm_eth->parent.parent.write = rt_ecm_eth_write;
+ _ecm_eth->parent.parent.control = rt_ecm_eth_control;
+#endif
+ _ecm_eth->parent.parent.user_data = device;
+
+ _ecm_eth->parent.eth_rx = rt_ecm_eth_rx;
+ _ecm_eth->parent.eth_tx = rt_ecm_eth_tx;
+ /* register eth device */
+ eth_device_init(&_ecm_eth->parent, "u0");
+
+ /* send link up. */
+ eth_device_linkchange(&_ecm_eth->parent, RT_FALSE);
+
+ return cdc;
+}
+
+struct udclass ecm_class =
+{
+ .rt_usbd_function_create = rt_usbd_function_ecm_create
+};
+
+int rt_usbd_ecm_class_register(void)
+{
+ rt_usbd_class_register(&ecm_class);
+ return 0;
+}
+INIT_PREV_EXPORT(rt_usbd_ecm_class_register);
+
+#endif /* RT_USB_DEVICE_ECM */
diff --git a/components/legacy/usb/usbdevice/class/hid.c b/components/legacy/usb/usbdevice/class/hid.c
new file mode 100644
index 0000000000..b0c7e63e00
--- /dev/null
+++ b/components/legacy/usb/usbdevice/class/hid.c
@@ -0,0 +1,756 @@
+/*
+ * File : hid.c
+ * COPYRIGHT (C) 2006 - 2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2017-03-13 Urey the first version
+ * 2017-11-16 ZYH Update to common hid
+ */
+
+#include <rthw.h>
+#include <rtdevice.h>
+#include "drivers/usb_common.h"
+#include "drivers/usb_device.h"
+#include "hid.h"
+
+#ifdef RT_USB_DEVICE_HID
+
+#define DBG_TAG "usbdevice.hid"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#define HID_INTF_STR_INDEX 7
+struct hid_s
+{
+ struct rt_device parent;
+ struct ufunction *func;
+ uep_t ep_in;
+ uep_t ep_out;
+ int status;
+ rt_uint8_t protocol;
+ rt_uint8_t report_buf[MAX_REPORT_SIZE];
+ struct rt_messagequeue hid_mq;
+};
+
+/* CustomHID_ConfigDescriptor */
+rt_align(4)
+const rt_uint8_t _report_desc[]=
+{
+#ifdef RT_USB_DEVICE_HID_KEYBOARD
+ USAGE_PAGE(1), 0x01,
+ USAGE(1), 0x06,
+ COLLECTION(1), 0x01,
+ REPORT_ID(1), HID_REPORT_ID_KEYBOARD1,
+
+ USAGE_PAGE(1), 0x07,
+ USAGE_MINIMUM(1), 0xE0,
+ USAGE_MAXIMUM(1), 0xE7,
+ LOGICAL_MINIMUM(1), 0x00,
+ LOGICAL_MAXIMUM(1), 0x01,
+ REPORT_SIZE(1), 0x01,
+ REPORT_COUNT(1), 0x08,
+ INPUT(1), 0x02,
+ REPORT_COUNT(1), 0x01,
+ REPORT_SIZE(1), 0x08,
+ INPUT(1), 0x01,
+
+
+ REPORT_COUNT(1), 0x05,
+ REPORT_SIZE(1), 0x01,
+ USAGE_PAGE(1), 0x08,
+ USAGE_MINIMUM(1), 0x01,
+ USAGE_MAXIMUM(1), 0x05,
+ OUTPUT(1), 0x02,
+ REPORT_COUNT(1), 0x01,
+ REPORT_SIZE(1), 0x03,
+ OUTPUT(1), 0x01,
+
+
+ REPORT_COUNT(1), 0x06,
+ REPORT_SIZE(1), 0x08,
+ LOGICAL_MINIMUM(1), 0x00,
+ LOGICAL_MAXIMUM(1), 0x65,
+ USAGE_PAGE(1), 0x07,
+ USAGE_MINIMUM(1), 0x00,
+ USAGE_MAXIMUM(1), 0x65,
+ INPUT(1), 0x00,
+ END_COLLECTION(0),
+#if RT_USB_DEVICE_HID_KEYBOARD_NUMBER>1
+ /****keyboard2*****/
+ USAGE_PAGE(1), 0x01,
+ USAGE(1), 0x06,
+ COLLECTION(1), 0x01,
+ REPORT_ID(1), HID_REPORT_ID_KEYBOARD2,
+
+ USAGE_PAGE(1), 0x07,
+ USAGE_MINIMUM(1), 0xE0,
+ USAGE_MAXIMUM(1), 0xE7,
+ LOGICAL_MINIMUM(1), 0x00,
+ LOGICAL_MAXIMUM(1), 0x01,
+ REPORT_SIZE(1), 0x01,
+ REPORT_COUNT(1), 0x08,
+ INPUT(1), 0x02,
+ REPORT_COUNT(1), 0x01,
+ REPORT_SIZE(1), 0x08,
+ INPUT(1), 0x01,
+
+ REPORT_COUNT(1), 0x06,
+ REPORT_SIZE(1), 0x08,
+ LOGICAL_MINIMUM(1), 0x00,
+ LOGICAL_MAXIMUM(1), 0x65,
+ USAGE_PAGE(1), 0x07,
+ USAGE_MINIMUM(1), 0x00,
+ USAGE_MAXIMUM(1), 0x65,
+ INPUT(1), 0x00,
+ END_COLLECTION(0),
+#if RT_USB_DEVICE_HID_KEYBOARD_NUMBER>2
+ USAGE_PAGE(1), 0x01,
+ USAGE(1), 0x06,
+ COLLECTION(1), 0x01,
+ REPORT_ID(1), HID_REPORT_ID_KEYBOARD3,
+
+ USAGE_PAGE(1), 0x07,
+ USAGE_MINIMUM(1), 0xE0,
+ USAGE_MAXIMUM(1), 0xE7,
+ LOGICAL_MINIMUM(1), 0x00,
+ LOGICAL_MAXIMUM(1), 0x01,
+ REPORT_SIZE(1), 0x01,
+ REPORT_COUNT(1), 0x08,
+ INPUT(1), 0x02,
+ REPORT_COUNT(1), 0x01,
+ REPORT_SIZE(1), 0x08,
+ INPUT(1), 0x01,
+
+ REPORT_COUNT(1), 0x06,
+ REPORT_SIZE(1), 0x08,
+ LOGICAL_MINIMUM(1), 0x00,
+ LOGICAL_MAXIMUM(1), 0x65,
+ USAGE_PAGE(1), 0x07,
+ USAGE_MINIMUM(1), 0x00,
+ USAGE_MAXIMUM(1), 0x65,
+ INPUT(1), 0x00,
+ END_COLLECTION(0),
+#if RT_USB_DEVICE_HID_KEYBOARD_NUMBER>3
+ USAGE_PAGE(1), 0x01,
+ USAGE(1), 0x06,
+ COLLECTION(1), 0x01,
+ REPORT_ID(1), HID_REPORT_ID_KEYBOARD4,
+
+ USAGE_PAGE(1), 0x07,
+ USAGE_MINIMUM(1), 0xE0,
+ USAGE_MAXIMUM(1), 0xE7,
+ LOGICAL_MINIMUM(1), 0x00,
+ LOGICAL_MAXIMUM(1), 0x01,
+ REPORT_SIZE(1), 0x01,
+ REPORT_COUNT(1), 0x08,
+ INPUT(1), 0x02,
+ REPORT_COUNT(1), 0x01,
+ REPORT_SIZE(1), 0x08,
+ INPUT(1), 0x01,
+
+ REPORT_COUNT(1), 0x06,
+ REPORT_SIZE(1), 0x08,
+ LOGICAL_MINIMUM(1), 0x00,
+ LOGICAL_MAXIMUM(1), 0x65,
+ USAGE_PAGE(1), 0x07,
+ USAGE_MINIMUM(1), 0x00,
+ USAGE_MAXIMUM(1), 0x65,
+ INPUT(1), 0x00,
+ END_COLLECTION(0),
+#endif
+#endif
+#endif
+#endif
+ // Media Control
+#ifdef RT_USB_DEVICE_HID_MEDIA
+ USAGE_PAGE(1), 0x0C,
+ USAGE(1), 0x01,
+ COLLECTION(1), 0x01,
+ REPORT_ID(1), HID_REPORT_ID_MEDIA,
+ USAGE_PAGE(1), 0x0C,
+ LOGICAL_MINIMUM(1), 0x00,
+ LOGICAL_MAXIMUM(1), 0x01,
+ REPORT_SIZE(1), 0x01,
+ REPORT_COUNT(1), 0x07,
+ USAGE(1), 0xB5, // Next Track
+ USAGE(1), 0xB6, // Previous Track
+ USAGE(1), 0xB7, // Stop
+ USAGE(1), 0xCD, // Play / Pause
+ USAGE(1), 0xE2, // Mute
+ USAGE(1), 0xE9, // Volume Up
+ USAGE(1), 0xEA, // Volume Down
+ INPUT(1), 0x02, // Input (Data, Variable, Absolute)
+ REPORT_COUNT(1), 0x01,
+ INPUT(1), 0x01,
+ END_COLLECTION(0),
+#endif
+
+#ifdef RT_USB_DEVICE_HID_GENERAL
+ USAGE_PAGE(1), 0x8c,
+ USAGE(1), 0x01,
+ COLLECTION(1), 0x01,
+ REPORT_ID(1), HID_REPORT_ID_GENERAL,
+
+ REPORT_COUNT(1), RT_USB_DEVICE_HID_GENERAL_IN_REPORT_LENGTH,
+ USAGE(1), 0x03,
+ REPORT_SIZE(1), 0x08,
+ LOGICAL_MINIMUM(1), 0x00,
+ LOGICAL_MAXIMUM(1), 0xFF,
+ INPUT(1), 0x02,
+
+ REPORT_COUNT(1), RT_USB_DEVICE_HID_GENERAL_OUT_REPORT_LENGTH,
+ USAGE(1), 0x04,
+ REPORT_SIZE(1), 0x08,
+ LOGICAL_MINIMUM(1), 0x00,
+ LOGICAL_MAXIMUM(1), 0xFF,
+ OUTPUT(1), 0x02,
+ END_COLLECTION(0),
+#endif
+#ifdef RT_USB_DEVICE_HID_MOUSE
+ USAGE_PAGE(1), 0x01, // Generic Desktop
+ USAGE(1), 0x02, // Mouse
+ COLLECTION(1), 0x01, // Application
+ USAGE(1), 0x01, // Pointer
+ COLLECTION(1), 0x00, // Physical
+ REPORT_ID(1), HID_REPORT_ID_MOUSE,
+ REPORT_COUNT(1), 0x03,
+ REPORT_SIZE(1), 0x01,
+ USAGE_PAGE(1), 0x09, // Buttons
+ USAGE_MINIMUM(1), 0x1,
+ USAGE_MAXIMUM(1), 0x3,
+ LOGICAL_MINIMUM(1), 0x00,
+ LOGICAL_MAXIMUM(1), 0x01,
+ INPUT(1), 0x02,
+ REPORT_COUNT(1), 0x01,
+ REPORT_SIZE(1), 0x05,
+ INPUT(1), 0x01,
+ REPORT_COUNT(1), 0x03,
+ REPORT_SIZE(1), 0x08,
+ USAGE_PAGE(1), 0x01,
+ USAGE(1), 0x30, // X
+ USAGE(1), 0x31, // Y
+ USAGE(1), 0x38, // scroll
+ LOGICAL_MINIMUM(1), 0x81,
+ LOGICAL_MAXIMUM(1), 0x7f,
+ INPUT(1), 0x06,
+ END_COLLECTION(0),
+ END_COLLECTION(0),
+#endif
+}; /* CustomHID_ReportDescriptor */
+
+rt_align(4)
+static struct udevice_descriptor _dev_desc =
+{
+ USB_DESC_LENGTH_DEVICE, //bLength;
+ USB_DESC_TYPE_DEVICE, //type;
+ USB_BCD_VERSION, //bcdUSB;
+ 0x0, //bDeviceClass;
+ 0x00, //bDeviceSubClass;
+ 0x00, //bDeviceProtocol;
+ 64, //bMaxPacketSize0;
+ _VENDOR_ID, //idVendor;
+ _PRODUCT_ID, //idProduct;
+ USB_BCD_DEVICE, //bcdDevice;
+ USB_STRING_MANU_INDEX, //iManufacturer;
+ USB_STRING_PRODUCT_INDEX, //iProduct;
+ USB_STRING_SERIAL_INDEX, //iSerialNumber;
+ USB_DYNAMIC, //bNumConfigurations;
+};
+
+//FS and HS needed
+rt_align(4)
+static struct usb_qualifier_descriptor dev_qualifier =
+{
+ sizeof(dev_qualifier), //bLength
+ USB_DESC_TYPE_DEVICEQUALIFIER, //bDescriptorType
+ 0x0200, //bcdUSB
+ 0x0, //bDeviceClass
+ 0x0, //bDeviceSubClass
+ 0x50, //bDeviceProtocol
+ 64, //bMaxPacketSize0
+ 0x01, //bNumConfigurations
+ 0,
+};
+
+
+/* hid interface descriptor */
+rt_align(4)
+const static struct uhid_comm_descriptor _hid_comm_desc =
+{
+#ifdef RT_USB_DEVICE_COMPOSITE
+ /* Interface Association Descriptor */
+ {
+ USB_DESC_LENGTH_IAD,
+ USB_DESC_TYPE_IAD,
+ USB_DYNAMIC,
+ 0x01,
+ 0x03, /* bInterfaceClass: HID */
+#if defined(RT_USB_DEVICE_HID_KEYBOARD)||defined(RT_USB_DEVICE_HID_MOUSE)
+ USB_HID_SUBCLASS_BOOT, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
+#else
+ USB_HID_SUBCLASS_NOBOOT, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
+#endif
+#if !defined(RT_USB_DEVICE_HID_KEYBOARD)||!defined(RT_USB_DEVICE_HID_MOUSE)||!defined(RT_USB_DEVICE_HID_MEDIA)
+ USB_HID_PROTOCOL_NONE, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
+#elif !defined(RT_USB_DEVICE_HID_MOUSE)
+ USB_HID_PROTOCOL_KEYBOARD, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
+#else
+ USB_HID_PROTOCOL_MOUSE, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
+#endif
+ 0x00,
+ },
+#endif
+ /* Interface Descriptor */
+ {
+ USB_DESC_LENGTH_INTERFACE,
+ USB_DESC_TYPE_INTERFACE,
+ USB_DYNAMIC, /* bInterfaceNumber: Number of Interface */
+ 0x00, /* bAlternateSetting: Alternate setting */
+ 0x02, /* bNumEndpoints */
+ 0x03, /* bInterfaceClass: HID */
+#if defined(RT_USB_DEVICE_HID_KEYBOARD)||defined(RT_USB_DEVICE_HID_MOUSE)
+ USB_HID_SUBCLASS_BOOT, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
+#else
+ USB_HID_SUBCLASS_NOBOOT, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
+#endif
+#if !defined(RT_USB_DEVICE_HID_KEYBOARD)||!defined(RT_USB_DEVICE_HID_MOUSE)||!defined(RT_USB_DEVICE_HID_MEDIA)
+ USB_HID_PROTOCOL_NONE, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
+#elif !defined(RT_USB_DEVICE_HID_MOUSE)
+ USB_HID_PROTOCOL_KEYBOARD, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
+#else
+ USB_HID_PROTOCOL_MOUSE, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
+#endif
+#ifdef RT_USB_DEVICE_COMPOSITE
+ HID_INTF_STR_INDEX, /* iInterface: Index of string descriptor */
+#else
+ 0,
+#endif
+ },
+
+ /* HID Descriptor */
+ {
+ HID_DESCRIPTOR_SIZE, /* bLength: HID Descriptor size */
+ HID_DESCRIPTOR_TYPE, /* bDescriptorType: HID */
+ 0x0110, /* bcdHID: HID Class Spec release number */
+ 0x00, /* bCountryCode: Hardware target country */
+ 0x01, /* bNumDescriptors: Number of HID class descriptors to follow */
+ {
+ {
+ 0x22, /* bDescriptorType */
+ sizeof(_report_desc), /* wItemLength: Total length of Report descriptor */
+ },
+ },
+ },
+
+ /* Endpoint Descriptor IN */
+ {
+ USB_DESC_LENGTH_ENDPOINT,
+ USB_DESC_TYPE_ENDPOINT,
+ USB_DYNAMIC | USB_DIR_IN,
+ USB_EP_ATTR_INT,
+ 0x40,
+ 0x0A,
+ },
+
+ /* Endpoint Descriptor OUT */
+ {
+ USB_DESC_LENGTH_ENDPOINT,
+ USB_DESC_TYPE_ENDPOINT,
+ USB_DYNAMIC | USB_DIR_OUT,
+ USB_EP_ATTR_INT,
+ 0x40,
+ 0x01,
+ },
+};
+
+rt_align(4)
+const static char* _ustring[] =
+{
+ "Language",
+ "RT-Thread Team.",
+ "RTT HID-Device",
+ "32021919830108",
+ "Configuration",
+ "Interface",
+};
+
+static void dump_data(rt_uint8_t *data, rt_size_t size)
+{
+ rt_size_t i;
+ for (i = 0; i < size; i++)
+ {
+ rt_kprintf("%02x ", *data++);
+ if ((i + 1) % 8 == 0)
+ {
+ rt_kprintf("\n");
+ }else if ((i + 1) % 4 == 0){
+ rt_kprintf(" ");
+ }
+ }
+}
+static void dump_report(struct hid_report * report)
+{
+ rt_kprintf("\nHID Recived:");
+ rt_kprintf("\nReport ID %02x \n", report->report_id);
+ dump_data(report->report,report->size);
+}
+
+static rt_err_t _ep_out_handler(ufunction_t func, rt_size_t size)
+{
+ struct hid_s *data;
+ struct hid_report report;
+ RT_ASSERT(func != RT_NULL);
+ RT_ASSERT(func->device != RT_NULL);
+ data = (struct hid_s *) func->user_data;
+
+ if(size != 0)
+ {
+ rt_memcpy((void *)&report,(void*)data->ep_out->buffer,size);
+ report.size = size-1;
+ rt_mq_send(&data->hid_mq,(void *)&report,sizeof(report));
+ }
+
+ data->ep_out->request.buffer = data->ep_out->buffer;
+ data->ep_out->request.size = EP_MAXPACKET(data->ep_out);
+ data->ep_out->request.req_type = UIO_REQUEST_READ_BEST;
+ rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request);
+ return RT_EOK;
+}
+
+static rt_err_t _ep_in_handler(ufunction_t func, rt_size_t size)
+{
+ struct hid_s *data;
+ RT_ASSERT(func != RT_NULL);
+ RT_ASSERT(func->device != RT_NULL);
+
+ data = (struct hid_s *) func->user_data;
+ if(data->parent.tx_complete != RT_NULL)
+ {
+ data->parent.tx_complete(&data->parent,RT_NULL);
+ }
+ return RT_EOK;
+}
+
+static rt_err_t _hid_set_report_callback(udevice_t device, rt_size_t size)
+{
+ LOG_D("_hid_set_report_callback");
+
+ if(size != 0)
+ {
+ }
+
+ dcd_ep0_send_status(device->dcd);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will handle hid interface bRequest.
+ *
+ * @param device the usb device object.
+ * @param setup the setup bRequest.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _interface_handler(ufunction_t func, ureq_t setup)
+{
+ RT_ASSERT(func != RT_NULL);
+ RT_ASSERT(func->device != RT_NULL);
+ RT_ASSERT(setup != RT_NULL);
+
+ struct hid_s *data = (struct hid_s *) func->user_data;
+
+
+ switch (setup->bRequest)
+ {
+ case USB_REQ_GET_DESCRIPTOR:
+ if((setup->wValue >> 8) == USB_DESC_TYPE_REPORT)
+ {
+ rt_usbd_ep0_write(func->device, (void *)(&_report_desc[0]), sizeof(_report_desc));
+ }
+ else if((setup->wValue >> 8) == USB_DESC_TYPE_HID)
+ {
+
+ rt_usbd_ep0_write(func->device, (void *)(&_hid_comm_desc.hid_desc), sizeof(struct uhid_descriptor));
+ }
+ break;
+ case USB_HID_REQ_GET_REPORT:
+ if(setup->wLength == 0)
+ {
+ rt_usbd_ep0_set_stall(func->device);
+ break;
+ }
+ if((setup->wLength == 0) || (setup->wLength > MAX_REPORT_SIZE))
+ setup->wLength = MAX_REPORT_SIZE;
+ rt_usbd_ep0_write(func->device, data->report_buf,setup->wLength);
+ break;
+ case USB_HID_REQ_GET_IDLE:
+
+ dcd_ep0_send_status(func->device->dcd);
+ break;
+ case USB_HID_REQ_GET_PROTOCOL:
+ rt_usbd_ep0_write(func->device, &data->protocol,1);
+ break;
+ case USB_HID_REQ_SET_REPORT:
+
+ if((setup->wLength == 0) || (setup->wLength > MAX_REPORT_SIZE))
+ rt_usbd_ep0_set_stall(func->device);
+
+ rt_usbd_ep0_read(func->device, data->report_buf, setup->wLength, _hid_set_report_callback);
+ break;
+ case USB_HID_REQ_SET_IDLE:
+ dcd_ep0_send_status(func->device->dcd);
+ break;
+ case USB_HID_REQ_SET_PROTOCOL:
+ data->protocol = setup->wValue;
+
+ dcd_ep0_send_status(func->device->dcd);
+ break;
+ }
+
+ return RT_EOK;
+}
+
+
+/**
+ * This function will run cdc function, it will be called on handle set configuration bRequest.
+ *
+ * @param func the usb function object.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _function_enable(ufunction_t func)
+{
+ struct hid_s *data;
+
+ RT_ASSERT(func != RT_NULL);
+ RT_ASSERT(func->device != RT_NULL);
+ data = (struct hid_s *) func->user_data;
+
+ LOG_D("hid function enable");
+//
+// _vcom_reset_state(func);
+//
+ if(data->ep_out->buffer == RT_NULL)
+ {
+ data->ep_out->buffer = rt_malloc(HID_RX_BUFSIZE);
+ }
+ data->ep_out->request.buffer = data->ep_out->buffer;
+ data->ep_out->request.size = EP_MAXPACKET(data->ep_out);
+ data->ep_out->request.req_type = UIO_REQUEST_READ_BEST;
+
+ rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will stop cdc function, it will be called on handle set configuration bRequest.
+ *
+ * @param func the usb function object.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _function_disable(ufunction_t func)
+{
+ struct hid_s *data;
+
+ RT_ASSERT(func != RT_NULL);
+ RT_ASSERT(func->device != RT_NULL);
+ data = (struct hid_s *) func->user_data;
+
+ LOG_D("hid function disable");
+
+ if(data->ep_out->buffer != RT_NULL)
+ {
+ rt_free(data->ep_out->buffer);
+ data->ep_out->buffer = RT_NULL;
+ }
+
+ return RT_EOK;
+}
+
+static struct ufunction_ops ops =
+{
+ _function_enable,
+ _function_disable,
+ RT_NULL,
+};
+
+
+
+
+/**
+ * This function will configure hid descriptor.
+ *
+ * @param comm the communication interface number.
+ * @param data the data interface number.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _hid_descriptor_config(uhid_comm_desc_t hid, rt_uint8_t cintf_nr)
+{
+#ifdef RT_USB_DEVICE_COMPOSITE
+ hid->iad_desc.bFirstInterface = cintf_nr;
+#endif
+
+ return RT_EOK;
+}
+static rt_ssize_t _hid_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
+{
+ struct hid_s *hiddev = (struct hid_s *)dev;
+ struct hid_report report;
+ if (hiddev->func->device->state == USB_STATE_CONFIGURED)
+ {
+ report.report_id = pos;
+ rt_memcpy((void *)report.report,(void *)buffer,size);
+ report.size = size;
+ hiddev->ep_in->request.buffer = (void *)&report;
+ hiddev->ep_in->request.size = (size+1) > 64 ? 64 : size+1;
+ hiddev->ep_in->request.req_type = UIO_REQUEST_WRITE;
+ rt_usbd_io_request(hiddev->func->device, hiddev->ep_in, &hiddev->ep_in->request);
+ return size;
+ }
+
+ return 0;
+}
+rt_weak void HID_Report_Received(hid_report_t report)
+{
+ dump_report(report);
+}
+rt_align(RT_ALIGN_SIZE)
+static rt_uint8_t hid_thread_stack[512];
+static struct rt_thread hid_thread;
+
+static void hid_thread_entry(void* parameter)
+{
+ struct hid_report report;
+ struct hid_s *hiddev;
+ hiddev = (struct hid_s *)parameter;
+ while(1)
+ {
+ if(rt_mq_recv(&hiddev->hid_mq, &report, sizeof(report),RT_WAITING_FOREVER) < 0)
+ continue;
+ HID_Report_Received(&report);
+ }
+}
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops hid_device_ops =
+{
+ RT_NULL,
+ RT_NULL,
+ RT_NULL,
+ RT_NULL,
+ _hid_write,
+ RT_NULL,
+};
+#endif
+
+static rt_uint8_t hid_mq_pool[(sizeof(struct hid_report)+sizeof(void*))*8];
+static void rt_usb_hid_init(struct ufunction *func)
+{
+ struct hid_s *hiddev;
+ hiddev = (struct hid_s *)func->user_data;
+ rt_memset(&hiddev->parent, 0, sizeof(hiddev->parent));
+
+#ifdef RT_USING_DEVICE_OPS
+ hiddev->parent.ops = &hid_device_ops;
+#else
+ hiddev->parent.write = _hid_write;
+#endif
+ hiddev->func = func;
+
+ rt_device_register(&hiddev->parent, "hidd", RT_DEVICE_FLAG_RDWR);
+ rt_mq_init(&hiddev->hid_mq, "hiddmq", hid_mq_pool, sizeof(struct hid_report),
+ sizeof(hid_mq_pool), RT_IPC_FLAG_FIFO);
+
+ rt_thread_init(&hid_thread, "hidd", hid_thread_entry, hiddev,
+ hid_thread_stack, sizeof(hid_thread_stack), RT_USBD_THREAD_PRIO, 20);
+ rt_thread_startup(&hid_thread);
+}
+
+
+/**
+ * This function will create a hid function instance.
+ *
+ * @param device the usb device object.
+ *
+ * @return RT_EOK on successful.
+ */
+ufunction_t rt_usbd_function_hid_create(udevice_t device)
+{
+ ufunction_t func;
+ struct hid_s *data;
+
+ uintf_t hid_intf;
+ ualtsetting_t hid_setting;
+ uhid_comm_desc_t hid_desc;
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+
+ /* set usb device string description */
+#ifdef RT_USB_DEVICE_COMPOSITE
+ rt_usbd_device_set_interface_string(device, HID_INTF_STR_INDEX, _ustring[2]);
+#else
+ rt_usbd_device_set_string(device, _ustring);
+#endif
+ /* create a cdc function */
+ func = rt_usbd_function_new(device, &_dev_desc, &ops);
+
+ /* For high speed mode supporting */
+ rt_usbd_device_set_qualifier(device, &dev_qualifier);
+
+ /* allocate memory for cdc vcom data */
+ data = (struct hid_s*)rt_malloc(sizeof(struct hid_s));
+ rt_memset(data, 0, sizeof(struct hid_s));
+ func->user_data = (void*)data;
+
+ /* create an interface object */
+ hid_intf = rt_usbd_interface_new(device, _interface_handler);
+
+ /* create an alternate setting object */
+ hid_setting = rt_usbd_altsetting_new(sizeof(struct uhid_comm_descriptor));
+
+ /* config desc in alternate setting */
+ rt_usbd_altsetting_config_descriptor(hid_setting, &_hid_comm_desc, (rt_off_t)&((uhid_comm_desc_t)0)->intf_desc);
+
+ /* configure the hid interface descriptor */
+ _hid_descriptor_config(hid_setting->desc, hid_intf->intf_num);
+
+ /* create endpoint */
+ hid_desc = (uhid_comm_desc_t)hid_setting->desc;
+ data->ep_out = rt_usbd_endpoint_new(&hid_desc->ep_out_desc, _ep_out_handler);
+ data->ep_in = rt_usbd_endpoint_new(&hid_desc->ep_in_desc, _ep_in_handler);
+
+ /* add the int out and int in endpoint to the alternate setting */
+ rt_usbd_altsetting_add_endpoint(hid_setting, data->ep_out);
+ rt_usbd_altsetting_add_endpoint(hid_setting, data->ep_in);
+
+ /* add the alternate setting to the interface, then set default setting */
+ rt_usbd_interface_add_altsetting(hid_intf, hid_setting);
+ rt_usbd_set_altsetting(hid_intf, 0);
+
+ /* add the interface to the mass storage function */
+ rt_usbd_function_add_interface(func, hid_intf);
+
+ /* initilize hid */
+ rt_usb_hid_init(func);
+ return func;
+}
+struct udclass hid_class =
+{
+ .rt_usbd_function_create = rt_usbd_function_hid_create
+};
+
+int rt_usbd_hid_class_register(void)
+{
+ rt_usbd_class_register(&hid_class);
+ return 0;
+}
+INIT_PREV_EXPORT(rt_usbd_hid_class_register);
+#endif /* RT_USB_DEVICE_HID */
diff --git a/components/legacy/usb/usbdevice/class/hid.h b/components/legacy/usb/usbdevice/class/hid.h
new file mode 100644
index 0000000000..99da810ce8
--- /dev/null
+++ b/components/legacy/usb/usbdevice/class/hid.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2017-03-13 Urey the first version
+ * 2017-11-16 ZYH Update to common hid
+ */
+#ifndef _USBDEVICE_CLASS_HID_H_
+#define _USBDEVICE_CLASS_HID_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define HID_DESCRIPTOR_TYPE 0x21
+#define HID_DESCRIPTOR_SIZE 0x09
+#define HID_OFF_HID_DESC 0x12
+
+#define USB_HID_SUBCLASS_BOOT 0x01
+#define USB_HID_SUBCLASS_NOBOOT 0x00
+
+#define USB_HID_PROTOCOL_NONE 0x00
+#define USB_HID_PROTOCOL_KEYBOARD 0x01
+#define USB_HID_PROTOCOL_MOUSE 0x02
+
+
+#define USB_HID_REQ_GET_REPORT 0x01
+#define USB_HID_REQ_GET_IDLE 0x02
+#define USB_HID_REQ_GET_PROTOCOL 0x03
+#define USB_HID_REQ_SET_REPORT 0x09
+#define USB_HID_REQ_SET_IDLE 0x0a
+#define USB_HID_REQ_SET_PROTOCOL 0x0b
+
+#define MAX_REPORT_SIZE 64
+#define HID_RX_BUFSIZE 64
+
+/* HID Report Types */
+#define HID_REPORT_INPUT 0x01
+#define HID_REPORT_OUTPUT 0x02
+#define HID_REPORT_FEATURE 0x03
+
+/* Usage Pages */
+#define USAGEPAGE_UNDEFINED 0x00
+#define USAGEPAGE_GENERIC 0x01
+#define USAGEPAGE_SIMULATION 0x02
+#define USAGEPAGE_VR 0x03
+#define USAGEPAGE_SPORT 0x04
+#define USAGEPAGE_GAME 0x05
+#define USAGEPAGE_DEV_CONTROLS 0x06
+#define USAGEPAGE_KEYBOARD 0x07
+#define USAGEPAGE_LED 0x08
+#define USAGEPAGE_BUTTON 0x09
+#define USAGEPAGE_ORDINAL 0x0A
+#define USAGEPAGE_TELEPHONY 0x0B
+#define USAGEPAGE_CONSUMER 0x0C
+#define USAGEPAGE_DIGITIZER 0x0D
+#define USAGEPAGE_PIDPAGE 0x0F
+#define USAGEPAGE_UNICODE 0x10
+#define USAGEPAGE_ALPHANUMERIC 0x14
+#define USAGEPAGE_BARCODESCANNER 0x8C
+
+/* Generic Desktop Page (0x01) */
+#define USAGE_GENERIC_POINTER 0x01
+#define USAGE_GENERIC_MOUSE 0x02
+#define USAGE_GENERIC_JOYSTICK 0x04
+#define USAGE_GENERIC_GAMEPAD 0x05
+#define USAGE_GENERIC_KEYBOARD 0x06
+#define USAGE_GENERIC_KEYPAD 0x07
+#define USAGE_GENERIC_X 0x30
+#define USAGE_GENERIC_Y 0x31
+#define USAGE_GENERIC_Z 0x32
+#define USAGE_GENERIC_RX 0x33
+#define USAGE_GENERIC_RY 0x34
+#define USAGE_GENERIC_RZ 0x35
+#define USAGE_GENERIC_SLIDER 0x36
+#define USAGE_GENERIC_DIAL 0x37
+#define USAGE_GENERIC_WHEEL 0x38
+#define USAGE_GENERIC_HATSWITCH 0x39
+#define USAGE_GENERIC_COUNTED_BUFFER 0x3A
+#define USAGE_GENERIC_BYTE_COUNT 0x3B
+#define USAGE_GENERIC_MOTION_WAKEUP 0x3C
+#define USAGE_GENERIC_VX 0x40
+#define USAGE_GENERIC_VY 0x41
+#define USAGE_GENERIC_VZ 0x42
+#define USAGE_GENERIC_VBRX 0x43
+#define USAGE_GENERIC_VBRY 0x44
+#define USAGE_GENERIC_VBRZ 0x45
+#define USAGE_GENERIC_VNO 0x46
+#define USAGE_GENERIC_SYSTEM_CTL 0x80
+#define USAGE_GENERIC_SYSCTL_POWER 0x81
+#define USAGE_GENERIC_SYSCTL_SLEEP 0x82
+#define USAGE_GENERIC_SYSCTL_WAKE 0x83
+#define USAGE_GENERIC_SYSCTL_CONTEXT_MENU 0x84
+#define USAGE_GENERIC_SYSCTL_MAIN_MENU 0x85
+#define USAGE_GENERIC_SYSCTL_APP_MENU 0x86
+#define USAGE_GENERIC_SYSCTL_HELP_MENU 0x87
+#define USAGE_GENERIC_SYSCTL_MENU_EXIT 0x88
+#define USAGE_GENERIC_SYSCTL_MENU_SELECT 0x89
+#define USAGE_GENERIC_SYSCTL_MENU_RIGHT 0x8A
+#define USAGE_GENERIC_SYSCTL_MENU_LEFT 0x8B
+#define USAGE_GENERIC_SYSCTL_MENU_UP 0x8C
+#define USAGE_GENERIC_SYSCTL_MENU_DOWN 0x8D
+
+/* Simulation Controls Page(0x02) */
+#define USAGE_SIMCTRL_THROTTLE 0xBB
+
+/* HID Report Items */
+
+/* Main Items */
+#define HID_Input(x) 0x81,x
+#define HID_Output(x) 0x91,x
+#define HID_Feature(x) 0xB1,x
+#define HID_Collection(x) 0xA1,x
+#define HID_EndCollection() 0xC0
+
+/* Local Items */
+#define HID_Usage(x) 0x09,x
+#define HID_UsageMin(x) 0x19,x
+#define HID_UsageMax(x) 0x29,x
+
+/* Global Items */
+#define HID_UsagePage(x) 0x05,x
+#define HID_UsagePageVendor(x) 0x06,x,0xFF
+#define HID_LogicalMin(x) 0x15,x
+#define HID_LogicalMinS(x) 0x16,(x&0xFF),((x>>8)&0xFF)
+#define HID_LogicalMinL(x) 0x17,(x&0xFF),((x>>8)&0xFF),((x>>16)&0xFF),((x>>24)&0xFF)
+#define HID_LogicalMax(x) 0x25,x
+#define HID_LogicalMaxS(x) 0x26,(x&0xFF),((x>>8)&0xFF)
+#define HID_LogicalMaxL(x) 0x27,(x&0xFF),((x>>8)&0xFF),((x>>16)&0xFF),((x>>24)&0xFF)
+#define HID_PhysicalMin(x) 0x35,x
+#define HID_PhysicalMinS(x) 0x36,(x&0xFF),((x>>8)&0xFF)
+#define HID_PhysicalMinL(x) 0x37,(x&0xFF),((x>>8)&0xFF),((x>>16)&0xFF),((x>>24)&0xFF)
+#define HID_PhysicalMax(x) 0x45,x
+#define HID_PhysicalMaxS(x) 0x46,(x&0xFF),((x>>8)&0xFF)
+#define HID_PhysicalMaxL(x) 0x47,(x&0xFF),((x>>8)&0xFF),((x>>16)&0xFF),((x>>24)&0xFF)
+#define HID_UnitExponent(x) 0x55,x
+#define HID_Unit(x) 0x65,x
+#define HID_UnitS(x) 0x66,(x&0xFF),((x>>8)&0xFF)
+#define HID_UnitL(x) 0x67,(x&0xFF),((x>>8)&0xFF),((x>>16)&0xFF),((x>>24)&0xFF)
+#define HID_ReportSize(x) 0x75,x
+#define HID_ReportSizeS(x) 0x76,(x&0xFF),((x>>8)&0xFF))
+#define HID_ReportSizeL(x) 0x77,(x&0xFF),((x>>8)&0xFF),((x>>16)&0xFF),((x>>24)&0xFF)
+#define HID_ReportID(x) 0x85,x
+#define HID_ReportCount(x) 0x95,x
+#define HID_ReportCountS(x) 0x96,(x&0xFF),((x>>8)&0xFF)
+#define HID_ReportCountL(x) 0x97,(x&0xFF),((x>>8)&0xFF),((x>>16)&0xFF),((x>>24)&0xFF)
+#define HID_Push() 0xA4
+#define HID_Pop() 0xB4
+
+/* Input, Output, Feature Data */
+#define HID_DATA (0<<0)
+#define HID_CONST (1<<0)
+#define HID_ARRAY (0<<1)
+#define HID_VAR (1<<1)
+#define HID_ABS (0<<2)
+#define HID_REL (1<<2)
+#define HID_NOWRAP (0<<3)
+#define HID_WRAP (1<<3)
+#define HID_LINEAR (0<<4)
+#define HID_NONLINEAR (1<<4)
+#define HID_PREFERREDSTATE (0<<5)
+#define HID_NOPREFERRED (1<<5)
+#define HID_NONULLPOSITION (0<<6)
+#define HID_NULLSTATE (1<<6)
+#define HID_NONVOLATILE (0<<7)
+#define HID_VOLATILE (1<<7)
+
+/* Collection Data */
+#define HID_PHYSICAL 0x00
+#define HID_APPLICATION 0x01
+#define HID_LOGICAL 0x02
+#define HID_REPORT 0x03
+#define HID_NAMEDARRAY 0x04
+#define HID_USAGESWITCH 0x05
+#define HID_USAGEMODIFIER 0x06
+
+//HID_MBED_DEFINE
+#define HID_VERSION_1_11 (0x0111)
+
+/* HID Class */
+#define HID_CLASS (3)
+#define HID_SUBCLASS_NONE (0)
+#define HID_SUBCLASS_BOOT (1)
+#define HID_PROTOCOL_NONE (0)
+#define HID_PROTOCOL_KEYBOARD (1)
+#define HID_PROTOCOL_MOUSE (2)
+
+/* Descriptors */
+#define HID_DESCRIPTOR (33)
+#define HID_DESCRIPTOR_LENGTH (0x09)
+#define REPORT_DESCRIPTOR (34)
+
+/* Class requests */
+#define GET_REPORT (0x1)
+#define GET_IDLE (0x2)
+#define SET_REPORT (0x9)
+#define SET_IDLE (0xa)
+
+/* HID Class Report Descriptor */
+/* Short items: size is 0, 1, 2 or 3 specifying 0, 1, 2 or 4 (four) bytes */
+/* of data as per HID Class standard */
+
+/* Main items */
+#define INPUT(size) (0x80 | size)
+#define OUTPUT(size) (0x90 | size)
+#define FEATURE(size) (0xb0 | size)
+#define COLLECTION(size) (0xa0 | size)
+#define END_COLLECTION(size) (0xc0 | size)
+
+/* Global items */
+#define USAGE_PAGE(size) (0x04 | size)
+#define LOGICAL_MINIMUM(size) (0x14 | size)
+#define LOGICAL_MAXIMUM(size) (0x24 | size)
+#define PHYSICAL_MINIMUM(size) (0x34 | size)
+#define PHYSICAL_MAXIMUM(size) (0x44 | size)
+#define UNIT_EXPONENT(size) (0x54 | size)
+#define UNIT(size) (0x64 | size)
+#define REPORT_SIZE(size) (0x74 | size)
+#define REPORT_ID(size) (0x84 | size)
+#define REPORT_COUNT(size) (0x94 | size)
+#define PUSH(size) (0xa4 | size)
+#define POP(size) (0xb4 | size)
+
+/* Local items */
+#define USAGE(size) (0x08 | size)
+#define USAGE_MINIMUM(size) (0x18 | size)
+#define USAGE_MAXIMUM(size) (0x28 | size)
+#define DESIGNATOR_INDEX(size) (0x38 | size)
+#define DESIGNATOR_MINIMUM(size) (0x48 | size)
+#define DESIGNATOR_MAXIMUM(size) (0x58 | size)
+#define STRING_INDEX(size) (0x78 | size)
+#define STRING_MINIMUM(size) (0x88 | size)
+#define STRING_MAXIMUM(size) (0x98 | size)
+#define DELIMITER(size) (0xa8 | size)
+
+#define LSB(n) ((n)&0xff)
+#define MSB(n) (((n)&0xff00)>>8)
+struct uhid_comm_descriptor
+{
+#ifdef RT_USB_DEVICE_COMPOSITE
+ struct uiad_descriptor iad_desc;
+#endif
+ struct uinterface_descriptor intf_desc;
+ struct uhid_descriptor hid_desc;
+ struct uendpoint_descriptor ep_in_desc;
+ struct uendpoint_descriptor ep_out_desc;
+};
+typedef struct uhid_comm_descriptor* uhid_comm_desc_t;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _USBDEVICE_CLASS_HID_H_ */
diff --git a/components/legacy/usb/usbdevice/class/mstorage.c b/components/legacy/usb/usbdevice/class/mstorage.c
new file mode 100644
index 0000000000..a077988102
--- /dev/null
+++ b/components/legacy/usb/usbdevice/class/mstorage.c
@@ -0,0 +1,1167 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2012-10-01 Yi Qiu first version
+ * 2012-11-25 Heyuanjie87 reduce the memory consumption
+ * 2012-12-09 Heyuanjie87 change function and endpoint handler
+ * 2013-07-25 Yi Qiu update for USB CV test
+ */
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#include "drivers/usb_device.h"
+#include "mstorage.h"
+
+#ifdef RT_USING_DFS_MNTTABLE
+#include "dfs_fs.h"
+#endif
+#ifdef RT_USB_DEVICE_MSTORAGE
+#define MSTRORAGE_INTF_STR_INDEX 11
+
+#define DBG_TAG "usbdevice.mstorage"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+enum STAT
+{
+ STAT_CBW,
+ STAT_CMD,
+ STAT_CSW,
+ STAT_RECEIVE,
+ STAT_SEND,
+};
+
+typedef enum
+{
+ FIXED,
+ COUNT,
+ BLOCK_COUNT,
+}CB_SIZE_TYPE;
+
+typedef enum
+{
+ DIR_IN,
+ DIR_OUT,
+ DIR_NONE,
+}CB_DIR;
+
+typedef rt_ssize_t (*cbw_handler)(ufunction_t func, ustorage_cbw_t cbw);
+
+struct scsi_cmd
+{
+ rt_uint16_t cmd;
+ cbw_handler handler;
+ rt_size_t cmd_len;
+ CB_SIZE_TYPE type;
+ rt_size_t data_size;
+ CB_DIR dir;
+};
+
+struct mstorage
+{
+ struct ustorage_csw csw_response;
+ uep_t ep_in;
+ uep_t ep_out;
+ int status;
+ rt_uint32_t cb_data_size;
+ rt_device_t disk;
+ rt_uint32_t block;
+ rt_int32_t count;
+ rt_int32_t size;
+ struct scsi_cmd* processing;
+ struct rt_device_blk_geometry geometry;
+};
+
+rt_align(4)
+static struct udevice_descriptor dev_desc =
+{
+ USB_DESC_LENGTH_DEVICE, //bLength;
+ USB_DESC_TYPE_DEVICE, //type;
+ USB_BCD_VERSION, //bcdUSB;
+ USB_CLASS_MASS_STORAGE, //bDeviceClass;
+ 0x06, //bDeviceSubClass;
+ 0x50, //bDeviceProtocol;
+ 0x40, //bMaxPacketSize0;
+ _VENDOR_ID, //idVendor;
+ _PRODUCT_ID, //idProduct;
+ USB_BCD_DEVICE, //bcdDevice;
+ USB_STRING_MANU_INDEX, //iManufacturer;
+ USB_STRING_PRODUCT_INDEX, //iProduct;
+ USB_STRING_SERIAL_INDEX, //iSerialNumber;
+ USB_DYNAMIC, //bNumConfigurations;
+};
+
+//FS and HS needed
+rt_align(4)
+static struct usb_qualifier_descriptor dev_qualifier =
+{
+ sizeof(dev_qualifier), //bLength
+ USB_DESC_TYPE_DEVICEQUALIFIER, //bDescriptorType
+ 0x0200, //bcdUSB
+ USB_CLASS_MASS_STORAGE, //bDeviceClass
+ 0x06, //bDeviceSubClass
+ 0x50, //bDeviceProtocol
+ 64, //bMaxPacketSize0
+ 0x01, //bNumConfigurations
+ 0,
+};
+
+
+rt_align(4)
+const static struct umass_descriptor _mass_desc =
+{
+#ifdef RT_USB_DEVICE_COMPOSITE
+ /* Interface Association Descriptor */
+ {
+ USB_DESC_LENGTH_IAD,
+ USB_DESC_TYPE_IAD,
+ USB_DYNAMIC,
+ 0x01,
+ USB_CLASS_MASS_STORAGE,
+ 0x06,
+ 0x50,
+ 0x00,
+ },
+#endif
+ {
+ USB_DESC_LENGTH_INTERFACE, //bLength;
+ USB_DESC_TYPE_INTERFACE, //type;
+ USB_DYNAMIC, //bInterfaceNumber;
+ 0x00, //bAlternateSetting;
+ 0x02, //bNumEndpoints
+ USB_CLASS_MASS_STORAGE, //bInterfaceClass;
+ 0x06, //bInterfaceSubClass;
+ 0x50, //bInterfaceProtocol;
+#ifdef RT_USB_DEVICE_COMPOSITE
+ MSTRORAGE_INTF_STR_INDEX,
+#else
+ 0x00, //iInterface;
+#endif
+ },
+
+ {
+ USB_DESC_LENGTH_ENDPOINT, //bLength;
+ USB_DESC_TYPE_ENDPOINT, //type;
+ USB_DYNAMIC | USB_DIR_OUT, //bEndpointAddress;
+ USB_EP_ATTR_BULK, //bmAttributes;
+ USB_DYNAMIC, //wMaxPacketSize;
+ 0x00, //bInterval;
+ },
+
+ {
+ USB_DESC_LENGTH_ENDPOINT, //bLength;
+ USB_DESC_TYPE_ENDPOINT, //type;
+ USB_DYNAMIC | USB_DIR_IN, //bEndpointAddress;
+ USB_EP_ATTR_BULK, //bmAttributes;
+ USB_DYNAMIC, //wMaxPacketSize;
+ 0x00, //bInterval;
+ },
+};
+
+rt_align(4)
+const static char* _ustring[] =
+{
+ "Language",
+ "RT-Thread Team.",
+ "RTT Mass Storage",
+ "320219198301",
+ "Configuration",
+ "Interface",
+};
+
+static rt_ssize_t _test_unit_ready(ufunction_t func, ustorage_cbw_t cbw);
+static rt_ssize_t _request_sense(ufunction_t func, ustorage_cbw_t cbw);
+static rt_ssize_t _inquiry_cmd(ufunction_t func, ustorage_cbw_t cbw);
+static rt_ssize_t _allow_removal(ufunction_t func, ustorage_cbw_t cbw);
+static rt_ssize_t _start_stop(ufunction_t func, ustorage_cbw_t cbw);
+static rt_ssize_t _mode_sense_6(ufunction_t func, ustorage_cbw_t cbw);
+static rt_ssize_t _read_capacities(ufunction_t func, ustorage_cbw_t cbw);
+static rt_ssize_t _read_capacity(ufunction_t func, ustorage_cbw_t cbw);
+static rt_ssize_t _read_10(ufunction_t func, ustorage_cbw_t cbw);
+static rt_ssize_t _write_10(ufunction_t func, ustorage_cbw_t cbw);
+static rt_ssize_t _verify_10(ufunction_t func, ustorage_cbw_t cbw);
+
+rt_align(4)
+static struct scsi_cmd cmd_data[] =
+{
+ {SCSI_TEST_UNIT_READY, _test_unit_ready, 6, FIXED, 0, DIR_NONE},
+ {SCSI_REQUEST_SENSE, _request_sense, 6, COUNT, 0, DIR_IN},
+ {SCSI_INQUIRY_CMD, _inquiry_cmd, 6, COUNT, 0, DIR_IN},
+ {SCSI_ALLOW_REMOVAL, _allow_removal, 6, FIXED, 0, DIR_NONE},
+ {SCSI_MODE_SENSE_6, _mode_sense_6, 6, COUNT, 0, DIR_IN},
+ {SCSI_START_STOP, _start_stop, 6, FIXED, 0, DIR_NONE},
+ {SCSI_READ_CAPACITIES, _read_capacities, 10, COUNT, 0, DIR_NONE},
+ {SCSI_READ_CAPACITY, _read_capacity, 10, FIXED, 8, DIR_IN},
+ {SCSI_READ_10, _read_10, 10, BLOCK_COUNT, 0, DIR_IN},
+ {SCSI_WRITE_10, _write_10, 10, BLOCK_COUNT, 0, DIR_OUT},
+ {SCSI_VERIFY_10, _verify_10, 10, FIXED, 0, DIR_NONE},
+};
+
+static void _send_status(ufunction_t func)
+{
+ struct mstorage *data;
+
+ RT_ASSERT(func != RT_NULL);
+
+ LOG_D("_send_status");
+
+ data = (struct mstorage*)func->user_data;
+ data->ep_in->request.buffer = (rt_uint8_t*)&data->csw_response;
+ data->ep_in->request.size = SIZEOF_CSW;
+ data->ep_in->request.req_type = UIO_REQUEST_WRITE;
+ rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request);
+ data->status = STAT_CSW;
+}
+
+static rt_ssize_t _test_unit_ready(ufunction_t func, ustorage_cbw_t cbw)
+{
+ struct mstorage *data;
+
+ RT_ASSERT(func != RT_NULL);
+ RT_ASSERT(func->device != RT_NULL);
+
+ LOG_D("_test_unit_ready");
+
+ data = (struct mstorage*)func->user_data;
+ data->csw_response.status = 0;
+
+ return 0;
+}
+
+static rt_ssize_t _allow_removal(ufunction_t func, ustorage_cbw_t cbw)
+{
+ struct mstorage *data;
+
+ RT_ASSERT(func != RT_NULL);
+ RT_ASSERT(func->device != RT_NULL);
+
+ LOG_D("_allow_removal");
+
+ data = (struct mstorage*)func->user_data;
+ data->csw_response.status = 0;
+
+ return 0;
+}
+
+/**
+ * This function will handle inquiry command request.
+ *
+ * @param func the usb function object.
+ * @param cbw the command block wrapper.
+ *
+ * @return RT_EOK on successful.
+ */
+
+static rt_ssize_t _inquiry_cmd(ufunction_t func, ustorage_cbw_t cbw)
+{
+ struct mstorage *data;
+ rt_uint8_t *buf;
+
+ RT_ASSERT(func != RT_NULL);
+ RT_ASSERT(func->device != RT_NULL);
+ RT_ASSERT(cbw != RT_NULL);
+
+ LOG_D("_inquiry_cmd");
+
+ data = (struct mstorage*)func->user_data;
+ buf = data->ep_in->buffer;
+
+ *(rt_uint32_t*)&buf[0] = 0x0 | (0x80 << 8);
+ *(rt_uint32_t*)&buf[4] = 31;
+
+ rt_memset(&buf[8], 0x20, 28);
+ rt_memcpy(&buf[8], "RTT", 3);
+ rt_memcpy(&buf[16], "USB Disk", 8);
+
+ data->cb_data_size = MIN(data->cb_data_size, SIZEOF_INQUIRY_CMD);
+ data->ep_in->request.buffer = buf;
+ data->ep_in->request.size = data->cb_data_size;
+ data->ep_in->request.req_type = UIO_REQUEST_WRITE;
+ rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request);
+ data->status = STAT_CMD;
+
+ return data->cb_data_size;
+}
+
+/**
+ * This function will handle sense request.
+ *
+ * @param func the usb function object.
+ * @param cbw the command block wrapper.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_ssize_t _request_sense(ufunction_t func, ustorage_cbw_t cbw)
+{
+ struct mstorage *data;
+ struct request_sense_data *buf;
+
+ RT_ASSERT(func != RT_NULL);
+ RT_ASSERT(func->device != RT_NULL);
+ RT_ASSERT(cbw != RT_NULL);
+
+ LOG_D("_request_sense");
+
+ data = (struct mstorage*)func->user_data;
+ buf = (struct request_sense_data *)data->ep_in->buffer;
+
+ buf->ErrorCode = 0x70;
+ buf->Valid = 0;
+ buf->SenseKey = 2;
+ buf->Information[0] = 0;
+ buf->Information[1] = 0;
+ buf->Information[2] = 0;
+ buf->Information[3] = 0;
+ buf->AdditionalSenseLength = 0x0a;
+ buf->AdditionalSenseCode = 0x3a;
+ buf->AdditionalSenseCodeQualifier = 0;
+
+ data->cb_data_size = MIN(data->cb_data_size, SIZEOF_REQUEST_SENSE);
+ data->ep_in->request.buffer = (rt_uint8_t*)data->ep_in->buffer;
+ data->ep_in->request.size = data->cb_data_size;
+ data->ep_in->request.req_type = UIO_REQUEST_WRITE;
+ rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request);
+ data->status = STAT_CMD;
+
+ return data->cb_data_size;
+}
+
+/**
+ * This function will handle mode_sense_6 request.
+ *
+ * @param func the usb function object.
+ * @param cbw the command block wrapper.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_ssize_t _mode_sense_6(ufunction_t func, ustorage_cbw_t cbw)
+{
+ struct mstorage *data;
+ rt_uint8_t *buf;
+
+ RT_ASSERT(func != RT_NULL);
+ RT_ASSERT(func->device != RT_NULL);
+ RT_ASSERT(cbw != RT_NULL);
+
+ LOG_D("_mode_sense_6");
+
+ data = (struct mstorage*)func->user_data;
+ buf = data->ep_in->buffer;
+ buf[0] = 3;
+ buf[1] = 0;
+ buf[2] = 0;
+ buf[3] = 0;
+
+ data->cb_data_size = MIN(data->cb_data_size, SIZEOF_MODE_SENSE_6);
+ data->ep_in->request.buffer = buf;
+ data->ep_in->request.size = data->cb_data_size;
+ data->ep_in->request.req_type = UIO_REQUEST_WRITE;
+ rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request);
+ data->status = STAT_CMD;
+
+ return data->cb_data_size;
+}
+
+/**
+ * This function will handle read_capacities request.
+ *
+ * @param func the usb function object.
+ * @param cbw the command block wrapper.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_ssize_t _read_capacities(ufunction_t func, ustorage_cbw_t cbw)
+{
+ struct mstorage *data;
+ rt_uint8_t *buf;
+ rt_uint32_t sector_count, sector_size;
+
+ RT_ASSERT(func != RT_NULL);
+ RT_ASSERT(func->device != RT_NULL);
+ RT_ASSERT(cbw != RT_NULL);
+
+ LOG_D("_read_capacities");
+
+ data = (struct mstorage*)func->user_data;
+ buf = data->ep_in->buffer;
+ sector_count = data->geometry.sector_count;
+ sector_size = data->geometry.bytes_per_sector;
+
+ *(rt_uint32_t*)&buf[0] = 0x08000000;
+ buf[4] = sector_count >> 24;
+ buf[5] = 0xff & (sector_count >> 16);
+ buf[6] = 0xff & (sector_count >> 8);
+ buf[7] = 0xff & (sector_count);
+ buf[8] = 0x02;
+ buf[9] = 0xff & (sector_size >> 16);
+ buf[10] = 0xff & (sector_size >> 8);
+ buf[11] = 0xff & sector_size;
+
+ data->cb_data_size = MIN(data->cb_data_size, SIZEOF_READ_CAPACITIES);
+ data->ep_in->request.buffer = buf;
+ data->ep_in->request.size = data->cb_data_size;
+ data->ep_in->request.req_type = UIO_REQUEST_WRITE;
+ rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request);
+ data->status = STAT_CMD;
+
+ return data->cb_data_size;
+}
+
+/**
+ * This function will handle read_capacity request.
+ *
+ * @param func the usb function object.
+ * @param cbw the command block wapper.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_ssize_t _read_capacity(ufunction_t func, ustorage_cbw_t cbw)
+{
+ struct mstorage *data;
+
+ rt_uint8_t *buf;
+ rt_uint32_t sector_count, sector_size;
+
+ RT_ASSERT(func != RT_NULL);
+ RT_ASSERT(func->device != RT_NULL);
+ RT_ASSERT(cbw != RT_NULL);
+
+ LOG_D("_read_capacity");
+
+ data = (struct mstorage*)func->user_data;
+ buf = data->ep_in->buffer;
+ sector_count = data->geometry.sector_count - 1; /* Last Logical Block Address */
+ sector_size = data->geometry.bytes_per_sector;
+
+ buf[0] = sector_count >> 24;
+ buf[1] = 0xff & (sector_count >> 16);
+ buf[2] = 0xff & (sector_count >> 8);
+ buf[3] = 0xff & (sector_count);
+ buf[4] = 0x0;
+ buf[5] = 0xff & (sector_size >> 16);
+ buf[6] = 0xff & (sector_size >> 8);
+ buf[7] = 0xff & sector_size;
+
+ data->cb_data_size = MIN(data->cb_data_size, SIZEOF_READ_CAPACITY);
+ data->ep_in->request.buffer = buf;
+ data->ep_in->request.size = data->cb_data_size;
+ data->ep_in->request.req_type = UIO_REQUEST_WRITE;
+ rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request);
+ data->status = STAT_CMD;
+
+ return data->cb_data_size;
+}
+
+/**
+ * This function will handle read_10 request.
+ *
+ * @param func the usb function object.
+ * @param cbw the command block wrapper.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_ssize_t _read_10(ufunction_t func, ustorage_cbw_t cbw)
+{
+ struct mstorage *data;
+ rt_size_t size;
+
+ RT_ASSERT(func != RT_NULL);
+ RT_ASSERT(func->device != RT_NULL);
+ RT_ASSERT(cbw != RT_NULL);
+
+ data = (struct mstorage*)func->user_data;
+ data->block = cbw->cb[2]<<24 | cbw->cb[3]<<16 | cbw->cb[4]<<8 |
+ cbw->cb[5]<<0;
+ data->count = cbw->cb[7]<<8 | cbw->cb[8]<<0;
+
+ RT_ASSERT(data->count < data->geometry.sector_count);
+
+ data->csw_response.data_reside = data->cb_data_size;
+ size = rt_device_read(data->disk, data->block, data->ep_in->buffer, 1);
+ if(size == 0)
+ {
+ rt_kprintf("read data error\n");
+ }
+
+ data->ep_in->request.buffer = data->ep_in->buffer;
+ data->ep_in->request.size = data->geometry.bytes_per_sector;
+ data->ep_in->request.req_type = UIO_REQUEST_WRITE;
+ rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request);
+ data->status = STAT_SEND;
+
+ return data->geometry.bytes_per_sector;
+}
+
+/**
+ * This function will handle write_10 request.
+ *
+ * @param func the usb function object.
+ * @param cbw the command block wrapper.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_ssize_t _write_10(ufunction_t func, ustorage_cbw_t cbw)
+{
+ struct mstorage *data;
+
+ RT_ASSERT(func != RT_NULL);
+ RT_ASSERT(func->device != RT_NULL);
+ RT_ASSERT(cbw != RT_NULL);
+
+ data = (struct mstorage*)func->user_data;
+
+ data->block = cbw->cb[2]<<24 | cbw->cb[3]<<16 | cbw->cb[4]<<8 |
+ cbw->cb[5]<<0;
+ data->count = cbw->cb[7]<<8 | cbw->cb[8];
+ data->csw_response.data_reside = cbw->xfer_len;
+ data->size = data->count * data->geometry.bytes_per_sector;
+
+ LOG_D("_write_10 count 0x%x block 0x%x 0x%x",
+ data->count, data->block, data->geometry.sector_count);
+
+ data->csw_response.data_reside = data->cb_data_size;
+
+ data->ep_out->request.buffer = data->ep_out->buffer;
+ data->ep_out->request.size = data->geometry.bytes_per_sector;
+ data->ep_out->request.req_type = UIO_REQUEST_READ_FULL;
+ rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request);
+ data->status = STAT_RECEIVE;
+
+ return data->geometry.bytes_per_sector;
+}
+
+/**
+ * This function will handle verify_10 request.
+ *
+ * @param func the usb function object.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_ssize_t _verify_10(ufunction_t func, ustorage_cbw_t cbw)
+{
+ struct mstorage *data;
+
+ RT_ASSERT(func != RT_NULL);
+ RT_ASSERT(func->device != RT_NULL);
+
+ LOG_D("_verify_10");
+
+ data = (struct mstorage*)func->user_data;
+ data->csw_response.status = 0;
+
+ return 0;
+}
+
+static rt_ssize_t _start_stop(ufunction_t func,
+ ustorage_cbw_t cbw)
+{
+ struct mstorage *data;
+
+ RT_ASSERT(func != RT_NULL);
+ RT_ASSERT(func->device != RT_NULL);
+
+ LOG_D("_start_stop");
+
+ data = (struct mstorage*)func->user_data;
+ data->csw_response.status = 0;
+
+ return 0;
+}
+
+static rt_err_t _ep_in_handler(ufunction_t func, rt_size_t size)
+{
+ struct mstorage *data;
+
+ RT_ASSERT(func != RT_NULL);
+ RT_ASSERT(func->device != RT_NULL);
+
+ LOG_D("_ep_in_handler");
+
+ data = (struct mstorage*)func->user_data;
+
+ switch(data->status)
+ {
+ case STAT_CSW:
+ if(data->ep_in->request.size != SIZEOF_CSW)
+ {
+ rt_kprintf("Size of csw command error\n");
+ rt_usbd_ep_set_stall(func->device, data->ep_in);
+ }
+ else
+ {
+ LOG_D("return to cbw status");
+ data->ep_out->request.buffer = data->ep_out->buffer;
+ data->ep_out->request.size = SIZEOF_CBW;
+ data->ep_out->request.req_type = UIO_REQUEST_READ_FULL;
+ rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request);
+ data->status = STAT_CBW;
+ }
+ break;
+ case STAT_CMD:
+ if(data->csw_response.data_reside == 0xFF)
+ {
+ data->csw_response.data_reside = 0;
+ }
+ else
+ {
+ data->csw_response.data_reside -= data->ep_in->request.size;
+ if(data->csw_response.data_reside != 0)
+ {
+ LOG_D("data_reside %d, request %d",
+ data->csw_response.data_reside, data->ep_in->request.size);
+ if(data->processing->dir == DIR_OUT)
+ {
+ rt_usbd_ep_set_stall(func->device, data->ep_out);
+ }
+ else
+ {
+ //rt_kprintf("warning:in stall path but not stall\n");
+
+ /* FIXME: Disable the operation or the disk cannot work. */
+ //rt_usbd_ep_set_stall(func->device, data->ep_in);
+ }
+ data->csw_response.data_reside = 0;
+ }
+ }
+ _send_status(func);
+ break;
+ case STAT_SEND:
+ data->csw_response.data_reside -= data->ep_in->request.size;
+ data->count--;
+ data->block++;
+ if(data->count > 0 && data->csw_response.data_reside > 0)
+ {
+ if(rt_device_read(data->disk, data->block, data->ep_in->buffer, 1) == 0)
+ {
+ rt_kprintf("disk read error\n");
+ rt_usbd_ep_set_stall(func->device, data->ep_in);
+ return -RT_ERROR;
+ }
+
+ data->ep_in->request.buffer = data->ep_in->buffer;
+ data->ep_in->request.size = data->geometry.bytes_per_sector;
+ data->ep_in->request.req_type = UIO_REQUEST_WRITE;
+ rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request);
+ }
+ else
+ {
+ _send_status(func);
+ }
+ break;
+ }
+
+ return RT_EOK;
+}
+
+#ifdef MASS_CBW_DUMP
+static void cbw_dump(struct ustorage_cbw* cbw)
+{
+ RT_ASSERT(cbw != RT_NULL);
+
+ LOG_D("signature 0x%x", cbw->signature);
+ LOG_D("tag 0x%x", cbw->tag);
+ LOG_D("xfer_len 0x%x", cbw->xfer_len);
+ LOG_D("dflags 0x%x", cbw->dflags);
+ LOG_D("lun 0x%x", cbw->lun);
+ LOG_D("cb_len 0x%x", cbw->cb_len);
+ LOG_D("cb[0] 0x%x", cbw->cb[0]);
+}
+#endif
+
+static struct scsi_cmd* _find_cbw_command(rt_uint16_t cmd)
+{
+ int i;
+
+ for(i=0; i<sizeof(cmd_data)/sizeof(struct scsi_cmd); i++)
+ {
+ if(cmd_data[i].cmd == cmd)
+ return &cmd_data[i];
+ }
+
+ return RT_NULL;
+}
+
+static void _cb_len_calc(ufunction_t func, struct scsi_cmd* cmd,
+ ustorage_cbw_t cbw)
+{
+ struct mstorage *data;
+
+ RT_ASSERT(func != RT_NULL);
+ RT_ASSERT(cmd != RT_NULL);
+ RT_ASSERT(cbw != RT_NULL);
+
+ data = (struct mstorage*)func->user_data;
+ if(cmd->cmd_len == 6)
+ {
+ switch(cmd->type)
+ {
+ case COUNT:
+ data->cb_data_size = cbw->cb[4];
+ break;
+ case BLOCK_COUNT:
+ data->cb_data_size = cbw->cb[4] * data->geometry.bytes_per_sector;
+ break;
+ case FIXED:
+ data->cb_data_size = cmd->data_size;
+ break;
+ default:
+ break;
+ }
+ }
+ else if(cmd->cmd_len == 10)
+ {
+ switch(cmd->type)
+ {
+ case COUNT:
+ data->cb_data_size = cbw->cb[7]<<8 | cbw->cb[8];
+ break;
+ case BLOCK_COUNT:
+ data->cb_data_size = (cbw->cb[7]<<8 | cbw->cb[8]) *
+ data->geometry.bytes_per_sector;
+ break;
+ case FIXED:
+ data->cb_data_size = cmd->data_size;
+ break;
+ default:
+ break;
+ }
+ }
+
+ //workaround: for stability in full-speed mode
+ else if(cmd->cmd_len == 12)
+ {
+ switch(cmd->type)
+ {
+ case COUNT:
+ data->cb_data_size = cbw->cb[4];
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ rt_kprintf("cmd_len error %d\n", cmd->cmd_len);
+ }
+}
+
+static rt_bool_t _cbw_verify(ufunction_t func, struct scsi_cmd* cmd,
+ ustorage_cbw_t cbw)
+{
+ struct mstorage *data;
+
+ RT_ASSERT(cmd != RT_NULL);
+ RT_ASSERT(cbw != RT_NULL);
+ RT_ASSERT(func != RT_NULL);
+
+ data = (struct mstorage*)func->user_data;
+ if(cmd->cmd_len != cbw->cb_len)
+ {
+ rt_kprintf("cb_len error\n");
+ cmd->cmd_len = cbw->cb_len;
+ }
+
+ if(cbw->xfer_len > 0 && data->cb_data_size == 0)
+ {
+ rt_kprintf("xfer_len > 0 && data_size == 0\n");
+ return RT_FALSE;
+ }
+
+ if(cbw->xfer_len == 0 && data->cb_data_size > 0)
+ {
+ rt_kprintf("xfer_len == 0 && data_size > 0");
+ return RT_FALSE;
+ }
+
+ if(((cbw->dflags & USB_DIR_IN) && (cmd->dir == DIR_OUT)) ||
+ (!(cbw->dflags & USB_DIR_IN) && (cmd->dir == DIR_IN)))
+ {
+ rt_kprintf("dir error\n");
+ return RT_FALSE;
+ }
+
+ if(cbw->xfer_len > data->cb_data_size)
+ {
+ rt_kprintf("xfer_len > data_size\n");
+ return RT_FALSE;
+ }
+
+ if(cbw->xfer_len < data->cb_data_size)
+ {
+ rt_kprintf("xfer_len < data_size\n");
+ data->cb_data_size = cbw->xfer_len;
+ data->csw_response.status = 1;
+ }
+
+ return RT_TRUE;
+}
+
+static rt_ssize_t _cbw_handler(ufunction_t func, struct scsi_cmd* cmd,
+ ustorage_cbw_t cbw)
+{
+ struct mstorage *data;
+
+ RT_ASSERT(func != RT_NULL);
+ RT_ASSERT(cbw != RT_NULL);
+ RT_ASSERT(cmd->handler != RT_NULL);
+
+ data = (struct mstorage*)func->user_data;
+ data->processing = cmd;
+ return cmd->handler(func, cbw);
+}
+
+/**
+ * This function will handle mass storage bulk out endpoint request.
+ *
+ * @param func the usb function object.
+ * @param size request size.
+ *
+ * @return RT_EOK.
+ */
+static rt_err_t _ep_out_handler(ufunction_t func, rt_size_t size)
+{
+ struct mstorage *data;
+ struct scsi_cmd* cmd;
+ rt_size_t len;
+ struct ustorage_cbw* cbw;
+
+ RT_ASSERT(func != RT_NULL);
+ RT_ASSERT(func->device != RT_NULL);
+
+ LOG_D("_ep_out_handler %d", size);
+
+ data = (struct mstorage*)func->user_data;
+ cbw = (struct ustorage_cbw*)data->ep_out->buffer;
+ if(data->status == STAT_CBW)
+ {
+ /* dump cbw information */
+ if(cbw->signature != CBW_SIGNATURE || size != SIZEOF_CBW)
+ {
+ goto exit;
+ }
+
+ data->csw_response.signature = CSW_SIGNATURE;
+ data->csw_response.tag = cbw->tag;
+ data->csw_response.data_reside = cbw->xfer_len;
+ data->csw_response.status = 0;
+
+ LOG_D("ep_out reside %d", data->csw_response.data_reside);
+
+ cmd = _find_cbw_command(cbw->cb[0]);
+ if(cmd == RT_NULL)
+ {
+ rt_kprintf("can't find cbw command\n");
+ goto exit;
+ }
+
+ _cb_len_calc(func, cmd, cbw);
+ if(!_cbw_verify(func, cmd, cbw))
+ {
+ goto exit;
+ }
+
+ len = _cbw_handler(func, cmd, cbw);
+ if(len == 0)
+ {
+ _send_status(func);
+ }
+
+ return RT_EOK;
+ }
+ else if(data->status == STAT_RECEIVE)
+ {
+ LOG_D("write size %d block 0x%x oount 0x%x",
+ size, data->block, data->size);
+
+ data->size -= size;
+ data->csw_response.data_reside -= size;
+
+ rt_device_write(data->disk, data->block, data->ep_out->buffer, 1);
+
+ if(data->csw_response.data_reside != 0)
+ {
+ data->ep_out->request.buffer = data->ep_out->buffer;
+ data->ep_out->request.size = data->geometry.bytes_per_sector;
+ data->ep_out->request.req_type = UIO_REQUEST_READ_FULL;
+ rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request);
+ data->block ++;
+ }
+ else
+ {
+ _send_status(func);
+ }
+
+ return RT_EOK;
+ }
+
+exit:
+ if(data->csw_response.data_reside)
+ {
+ if(cbw->dflags & USB_DIR_IN)
+ {
+ rt_usbd_ep_set_stall(func->device, data->ep_in);
+ }
+ else
+ {
+ rt_usbd_ep_set_stall(func->device, data->ep_in);
+ rt_usbd_ep_set_stall(func->device, data->ep_out);
+ }
+ }
+ data->csw_response.status = 1;
+ _send_status(func);
+
+ return -RT_ERROR;
+}
+
+/**
+ * This function will handle mass storage interface request.
+ *
+ * @param func the usb function object.
+ * @param setup the setup request.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _interface_handler(ufunction_t func, ureq_t setup)
+{
+ rt_uint8_t lun = 0;
+
+ RT_ASSERT(func != RT_NULL);
+ RT_ASSERT(func->device != RT_NULL);
+ RT_ASSERT(setup != RT_NULL);
+
+ LOG_D("mstorage_interface_handler");
+
+ switch(setup->bRequest)
+ {
+ case USBREQ_GET_MAX_LUN:
+
+ LOG_D("USBREQ_GET_MAX_LUN");
+
+ if(setup->wValue || setup->wLength != 1)
+ {
+ rt_usbd_ep0_set_stall(func->device);
+ }
+ else
+ {
+ rt_usbd_ep0_write(func->device, &lun, setup->wLength);
+ }
+ break;
+ case USBREQ_MASS_STORAGE_RESET:
+
+ LOG_D("USBREQ_MASS_STORAGE_RESET");
+
+ if(setup->wValue || setup->wLength != 0)
+ {
+ rt_usbd_ep0_set_stall(func->device);
+ }
+ else
+ {
+ dcd_ep0_send_status(func->device->dcd);
+ }
+ break;
+ default:
+ rt_kprintf("unknown interface request\n");
+ break;
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * This function will run mass storage function, it will be called on handle set configuration request.
+ *
+ * @param func the usb function object.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _function_enable(ufunction_t func)
+{
+ struct mstorage *data;
+ RT_ASSERT(func != RT_NULL);
+ LOG_D("Mass storage function enabled");
+ data = (struct mstorage*)func->user_data;
+
+ data->disk = rt_device_find(RT_USB_MSTORAGE_DISK_NAME);
+ if(data->disk == RT_NULL)
+ {
+ rt_kprintf("no data->disk named %s\n", RT_USB_MSTORAGE_DISK_NAME);
+ return -RT_ERROR;
+ }
+
+#ifdef RT_USING_DFS_MNTTABLE
+ dfs_unmount_device(data->disk);
+#endif
+
+ if(rt_device_open(data->disk, RT_DEVICE_OFLAG_RDWR) != RT_EOK)
+ {
+ rt_kprintf("disk open error\n");
+ return -RT_ERROR;
+ }
+
+ if(rt_device_control(data->disk, RT_DEVICE_CTRL_BLK_GETGEOME,
+ (void*)&data->geometry) != RT_EOK)
+ {
+ rt_kprintf("get disk info error\n");
+ return -RT_ERROR;
+ }
+
+ data->ep_in->buffer = (rt_uint8_t*)rt_malloc(data->geometry.bytes_per_sector);
+ if(data->ep_in->buffer == RT_NULL)
+ {
+ rt_kprintf("no memory\n");
+ return -RT_ENOMEM;
+ }
+ data->ep_out->buffer = (rt_uint8_t*)rt_malloc(data->geometry.bytes_per_sector);
+ if(data->ep_out->buffer == RT_NULL)
+ {
+ rt_free(data->ep_in->buffer);
+ rt_kprintf("no memory\n");
+ return -RT_ENOMEM;
+ }
+
+ /* prepare to read CBW request */
+ data->ep_out->request.buffer = data->ep_out->buffer;
+ data->ep_out->request.size = SIZEOF_CBW;
+ data->ep_out->request.req_type = UIO_REQUEST_READ_FULL;
+ rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will stop mass storage function, it will be called on handle set configuration request.
+ *
+ * @param device the usb device object.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _function_disable(ufunction_t func)
+{
+ struct mstorage *data;
+ RT_ASSERT(func != RT_NULL);
+
+ LOG_D("Mass storage function disabled");
+
+ data = (struct mstorage*)func->user_data;
+ if(data->ep_in->buffer != RT_NULL)
+ {
+ rt_free(data->ep_in->buffer);
+ data->ep_in->buffer = RT_NULL;
+ }
+
+ if(data->ep_out->buffer != RT_NULL)
+ {
+ rt_free(data->ep_out->buffer);
+ data->ep_out->buffer = RT_NULL;
+ }
+ if(data->disk != RT_NULL)
+ {
+ rt_device_close(data->disk);
+#ifdef RT_USING_DFS_MNTTABLE
+ dfs_mount_device(data->disk);
+#endif
+ data->disk = RT_NULL;
+ }
+
+ data->status = STAT_CBW;
+
+ return RT_EOK;
+}
+
+static struct ufunction_ops ops =
+{
+ _function_enable,
+ _function_disable,
+ RT_NULL,
+};
+static rt_err_t _mstorage_descriptor_config(umass_desc_t desc, rt_uint8_t cintf_nr, rt_uint8_t device_is_hs)
+{
+#ifdef RT_USB_DEVICE_COMPOSITE
+ desc->iad_desc.bFirstInterface = cintf_nr;
+#endif
+ desc->ep_out_desc.wMaxPacketSize = device_is_hs ? 512 : 64;
+ desc->ep_in_desc.wMaxPacketSize = device_is_hs ? 512 : 64;
+ return RT_EOK;
+}
+/**
+ * This function will create a mass storage function instance.
+ *
+ * @param device the usb device object.
+ *
+ * @return RT_EOK on successful.
+ */
+ufunction_t rt_usbd_function_mstorage_create(udevice_t device)
+{
+ uintf_t intf;
+ struct mstorage *data;
+ ufunction_t func;
+ ualtsetting_t setting;
+ umass_desc_t mass_desc;
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+
+ /* set usb device string description */
+#ifdef RT_USB_DEVICE_COMPOSITE
+ rt_usbd_device_set_interface_string(device, MSTRORAGE_INTF_STR_INDEX, _ustring[2]);
+#else
+ rt_usbd_device_set_string(device, _ustring);
+#endif
+
+ /* create a mass storage function */
+ func = rt_usbd_function_new(device, &dev_desc, &ops);
+ device->dev_qualifier = &dev_qualifier;
+
+ /* allocate memory for mass storage function data */
+ data = (struct mstorage*)rt_malloc(sizeof(struct mstorage));
+ rt_memset(data, 0, sizeof(struct mstorage));
+ func->user_data = (void*)data;
+
+ /* create an interface object */
+ intf = rt_usbd_interface_new(device, _interface_handler);
+
+ /* create an alternate setting object */
+ setting = rt_usbd_altsetting_new(sizeof(struct umass_descriptor));
+
+ /* config desc in alternate setting */
+ rt_usbd_altsetting_config_descriptor(setting, &_mass_desc, (rt_off_t)&((umass_desc_t)0)->intf_desc);
+
+ /* configure the msc interface descriptor */
+ _mstorage_descriptor_config(setting->desc, intf->intf_num, device->dcd->device_is_hs);
+
+ /* create a bulk out and a bulk in endpoint */
+ mass_desc = (umass_desc_t)setting->desc;
+ data->ep_in = rt_usbd_endpoint_new(&mass_desc->ep_in_desc, _ep_in_handler);
+ data->ep_out = rt_usbd_endpoint_new(&mass_desc->ep_out_desc, _ep_out_handler);
+
+ /* add the bulk out and bulk in endpoint to the alternate setting */
+ rt_usbd_altsetting_add_endpoint(setting, data->ep_out);
+ rt_usbd_altsetting_add_endpoint(setting, data->ep_in);
+
+ /* add the alternate setting to the interface, then set default setting */
+ rt_usbd_interface_add_altsetting(intf, setting);
+ rt_usbd_set_altsetting(intf, 0);
+
+ /* add the interface to the mass storage function */
+ rt_usbd_function_add_interface(func, intf);
+
+ return func;
+}
+struct udclass msc_class =
+{
+ .rt_usbd_function_create = rt_usbd_function_mstorage_create
+};
+
+int rt_usbd_msc_class_register(void)
+{
+ rt_usbd_class_register(&msc_class);
+ return 0;
+}
+INIT_PREV_EXPORT(rt_usbd_msc_class_register);
+
+#endif
diff --git a/components/legacy/usb/usbdevice/class/mstorage.h b/components/legacy/usb/usbdevice/class/mstorage.h
new file mode 100644
index 0000000000..812be4c190
--- /dev/null
+++ b/components/legacy/usb/usbdevice/class/mstorage.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2012-10-01 Yi Qiu first version
+ * 2012-12-12 heyuanjie87 add MASS endpoints collection
+ */
+
+#ifndef __MSTORAGE_H__
+#define __MSTORAGE_H__
+
+#include <rtthread.h>
+
+#pragma pack(1)
+
+struct umass_descriptor
+{
+#ifdef RT_USB_DEVICE_COMPOSITE
+ struct uiad_descriptor iad_desc;
+#endif
+ struct uinterface_descriptor intf_desc;
+ struct uendpoint_descriptor ep_out_desc;
+ struct uendpoint_descriptor ep_in_desc;
+};
+typedef struct umass_descriptor* umass_desc_t;
+
+struct capacity_data
+{
+ rt_uint8_t LastLogicalBlockAddress[4];
+ rt_uint8_t BlockLengthInBytes[4];
+};
+
+struct request_sense_data
+{
+ rt_uint8_t ErrorCode:7;
+ rt_uint8_t Valid:1;
+ rt_uint8_t Reserved1;
+ rt_uint8_t SenseKey:4;
+ rt_uint8_t Reserved2:4;
+ rt_uint8_t Information[4];
+ rt_uint8_t AdditionalSenseLength;
+ rt_uint8_t Reserved3[4];
+ rt_uint8_t AdditionalSenseCode;
+ rt_uint8_t AdditionalSenseCodeQualifier;
+ rt_uint8_t Reserved4[4];
+}request_sense_data_t;
+
+#pragma pack()
+
+#endif
diff --git a/components/legacy/usb/usbdevice/class/ndis.h b/components/legacy/usb/usbdevice/class/ndis.h
new file mode 100644
index 0000000000..40a1ffb64e
--- /dev/null
+++ b/components/legacy/usb/usbdevice/class/ndis.h
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ */
+/*
+ * ndis.h
+ *
+ * Modified by Colin O'Flynn <[email protected]>
+ * ntddndis.h modified by Benedikt Spranger <[email protected]>
+ *
+ * Thanks to the cygwin development team,
+ * espacially to Casper S. Hornstrup <[email protected]>
+ *
+ * THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ * This source code is offered for use in the public domain. You may
+ * use, modify or distribute it freely.
+ *
+ * This code is distributed in the hope that it will be useful but
+ * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ * DISCLAIMED. This includes but is not limited to warranties of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#ifndef __NDIS_H__
+#define __NDIS_H__
+
+#define NDIS_STATUS_MULTICAST_FULL 0xC0010009
+#define NDIS_STATUS_MULTICAST_EXISTS 0xC001000A
+#define NDIS_STATUS_MULTICAST_NOT_FOUND 0xC001000B
+
+/* from drivers/net/sk98lin/h/skgepnmi.h */
+#define OID_PNP_CAPABILITIES 0xFD010100
+#define OID_PNP_SET_POWER 0xFD010101
+#define OID_PNP_QUERY_POWER 0xFD010102
+#define OID_PNP_ADD_WAKE_UP_PATTERN 0xFD010103
+#define OID_PNP_REMOVE_WAKE_UP_PATTERN 0xFD010104
+#define OID_PNP_ENABLE_WAKE_UP 0xFD010106
+
+enum NDIS_DEVICE_POWER_STATE
+{
+ NdisDeviceStateUnspecified = 0,
+ NdisDeviceStateD0,
+ NdisDeviceStateD1,
+ NdisDeviceStateD2,
+ NdisDeviceStateD3,
+ NdisDeviceStateMaximum
+};
+
+struct NDIS_PM_WAKE_UP_CAPABILITIES
+{
+ enum NDIS_DEVICE_POWER_STATE MinMagicPacketWakeUp;
+ enum NDIS_DEVICE_POWER_STATE MinPatternWakeUp;
+ enum NDIS_DEVICE_POWER_STATE MinLinkChangeWakeUp;
+};
+
+/* NDIS_PNP_CAPABILITIES.Flags constants */
+#define NDIS_DEVICE_WAKE_UP_ENABLE 0x00000001
+#define NDIS_DEVICE_WAKE_ON_PATTERN_MATCH_ENABLE 0x00000002
+#define NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE 0x00000004
+
+/* Required Object IDs (OIDs) */
+#define OID_GEN_SUPPORTED_LIST 0x00010101
+#define OID_GEN_HARDWARE_STATUS 0x00010102
+#define OID_GEN_MEDIA_SUPPORTED 0x00010103
+#define OID_GEN_MEDIA_IN_USE 0x00010104
+#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105
+#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106
+#define OID_GEN_LINK_SPEED 0x00010107
+#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108
+#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109
+#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A
+#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B
+#define OID_GEN_VENDOR_ID 0x0001010C
+#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D
+#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E
+#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F
+#define OID_GEN_DRIVER_VERSION 0x00010110
+#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111
+#define OID_GEN_PROTOCOL_OPTIONS 0x00010112
+#define OID_GEN_MAC_OPTIONS 0x00010113
+#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114
+#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115
+#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116
+#define OID_GEN_SUPPORTED_GUIDS 0x00010117
+#define OID_GEN_NETWORK_LAYER_ADDRESSES 0x00010118
+#define OID_GEN_TRANSPORT_HEADER_OFFSET 0x00010119
+#define OID_GEN_MACHINE_NAME 0x0001021A
+#define OID_GEN_RNDIS_CONFIG_PARAMETER 0x0001021B
+#define OID_GEN_VLAN_ID 0x0001021C
+
+/* Optional OIDs */
+#define OID_GEN_MEDIA_CAPABILITIES 0x00010201
+#define OID_GEN_PHYSICAL_MEDIUM 0x00010202
+
+/* Required statistics OIDs */
+#define OID_GEN_XMIT_OK 0x00020101
+#define OID_GEN_RCV_OK 0x00020102
+#define OID_GEN_XMIT_ERROR 0x00020103
+#define OID_GEN_RCV_ERROR 0x00020104
+#define OID_GEN_RCV_NO_BUFFER 0x00020105
+
+/* Optional statistics OIDs */
+#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201
+#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202
+#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203
+#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204
+#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205
+#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206
+#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207
+#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208
+#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209
+#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A
+#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B
+#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C
+#define OID_GEN_RCV_CRC_ERROR 0x0002020D
+#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E
+#define OID_GEN_GET_TIME_CAPS 0x0002020F
+#define OID_GEN_GET_NETCARD_TIME 0x00020210
+#define OID_GEN_NETCARD_LOAD 0x00020211
+#define OID_GEN_DEVICE_PROFILE 0x00020212
+#define OID_GEN_INIT_TIME_MS 0x00020213
+#define OID_GEN_RESET_COUNTS 0x00020214
+#define OID_GEN_MEDIA_SENSE_COUNTS 0x00020215
+#define OID_GEN_FRIENDLY_NAME 0x00020216
+#define OID_GEN_MINIPORT_INFO 0x00020217
+#define OID_GEN_RESET_VERIFY_PARAMETERS 0x00020218
+
+/* IEEE 802.3 (Ethernet) OIDs */
+#define NDIS_802_3_MAC_OPTION_PRIORITY 0x00000001
+
+#define OID_802_3_PERMANENT_ADDRESS 0x01010101
+#define OID_802_3_CURRENT_ADDRESS 0x01010102
+#define OID_802_3_MULTICAST_LIST 0x01010103
+#define OID_802_3_MAXIMUM_LIST_SIZE 0x01010104
+#define OID_802_3_MAC_OPTIONS 0x01010105
+#define OID_802_3_RCV_ERROR_ALIGNMENT 0x01020101
+#define OID_802_3_XMIT_ONE_COLLISION 0x01020102
+#define OID_802_3_XMIT_MORE_COLLISIONS 0x01020103
+#define OID_802_3_XMIT_DEFERRED 0x01020201
+#define OID_802_3_XMIT_MAX_COLLISIONS 0x01020202
+#define OID_802_3_RCV_OVERRUN 0x01020203
+#define OID_802_3_XMIT_UNDERRUN 0x01020204
+#define OID_802_3_XMIT_HEARTBEAT_FAILURE 0x01020205
+#define OID_802_3_XMIT_TIMES_CRS_LOST 0x01020206
+#define OID_802_3_XMIT_LATE_COLLISIONS 0x01020207
+
+/* Wireless LAN OIDs */
+#define OID_802_11_BSSID 0x0D010101 /* Q S */
+#define OID_802_11_SSID 0x0D010102 /* Q S */
+#define OID_802_11_NETWORK_TYPE_IN_USE 0x0D010204 /* Q S */
+#define OID_802_11_RSSI 0x0D010206 /* Q I */
+#define OID_802_11_BSSID_LIST 0x0D010217 /* Q */
+#define OID_802_11_BSSID_LIST_SCAN 0x0D01011A /* S */
+#define OID_802_11_INFRASTRUCTURE_MODE 0x0D010108 /* Q S */
+#define OID_802_11_SUPPORTED_RATES 0x0D01020E /* Q */
+#define OID_802_11_CONFIGURATION 0x0D010211 /* Q S */
+#define OID_802_11_ADD_WEP 0x0D010113 /* S */
+#define OID_802_11_WEP_STATUS 0x0D01011B /* Q S */
+#define OID_802_11_REMOVE_WEP 0x0D010114 /* S */
+#define OID_802_11_DISASSOCIATE 0x0D010115 /* S */
+#define OID_802_11_AUTHENTICATION_MODE 0x0D010118 /* Q S */
+#define OID_802_11_RELOAD_DEFAULTS 0x0D01011C /* S */
+
+/* OID_GEN_MINIPORT_INFO constants */
+#define NDIS_MINIPORT_BUS_MASTER 0x00000001
+#define NDIS_MINIPORT_WDM_DRIVER 0x00000002
+#define NDIS_MINIPORT_SG_LIST 0x00000004
+#define NDIS_MINIPORT_SUPPORTS_MEDIA_QUERY 0x00000008
+#define NDIS_MINIPORT_INDICATES_PACKETS 0x00000010
+#define NDIS_MINIPORT_IGNORE_PACKET_QUEUE 0x00000020
+#define NDIS_MINIPORT_IGNORE_REQUEST_QUEUE 0x00000040
+#define NDIS_MINIPORT_IGNORE_TOKEN_RING_ERRORS 0x00000080
+#define NDIS_MINIPORT_INTERMEDIATE_DRIVER 0x00000100
+#define NDIS_MINIPORT_IS_NDIS_5 0x00000200
+#define NDIS_MINIPORT_IS_CO 0x00000400
+#define NDIS_MINIPORT_DESERIALIZE 0x00000800
+#define NDIS_MINIPORT_REQUIRES_MEDIA_POLLING 0x00001000
+#define NDIS_MINIPORT_SUPPORTS_MEDIA_SENSE 0x00002000
+#define NDIS_MINIPORT_NETBOOT_CARD 0x00004000
+#define NDIS_MINIPORT_PM_SUPPORTED 0x00008000
+#define NDIS_MINIPORT_SUPPORTS_MAC_ADDRESS_OVERWRITE 0x00010000
+#define NDIS_MINIPORT_USES_SAFE_BUFFER_APIS 0x00020000
+#define NDIS_MINIPORT_HIDDEN 0x00040000
+#define NDIS_MINIPORT_SWENUM 0x00080000
+#define NDIS_MINIPORT_SURPRISE_REMOVE_OK 0x00100000
+#define NDIS_MINIPORT_NO_HALT_ON_SUSPEND 0x00200000
+#define NDIS_MINIPORT_HARDWARE_DEVICE 0x00400000
+#define NDIS_MINIPORT_SUPPORTS_CANCEL_SEND_PACKETS 0x00800000
+#define NDIS_MINIPORT_64BITS_DMA 0x01000000
+
+#define NDIS_MEDIUM_802_3 0x00000000
+#define NDIS_MEDIUM_802_5 0x00000001
+#define NDIS_MEDIUM_FDDI 0x00000002
+#define NDIS_MEDIUM_WAN 0x00000003
+#define NDIS_MEDIUM_LOCAL_TALK 0x00000004
+#define NDIS_MEDIUM_DIX 0x00000005
+#define NDIS_MEDIUM_ARCENT_RAW 0x00000006
+#define NDIS_MEDIUM_ARCENT_878_2 0x00000007
+#define NDIS_MEDIUM_ATM 0x00000008
+#define NDIS_MEDIUM_WIRELESS_LAN 0x00000009
+#define NDIS_MEDIUM_IRDA 0x0000000A
+#define NDIS_MEDIUM_BPC 0x0000000B
+#define NDIS_MEDIUM_CO_WAN 0x0000000C
+#define NDIS_MEDIUM_1394 0x0000000D
+
+#define NDIS_PACKET_TYPE_DIRECTED 0x00000001
+#define NDIS_PACKET_TYPE_MULTICAST 0x00000002
+#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004
+#define NDIS_PACKET_TYPE_BROADCAST 0x00000008
+#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x00000010
+#define NDIS_PACKET_TYPE_PROMISCUOUS 0x00000020
+#define NDIS_PACKET_TYPE_SMT 0x00000040
+#define NDIS_PACKET_TYPE_ALL_LOCAL 0x00000080
+#define NDIS_PACKET_TYPE_GROUP 0x00000100
+#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x00000200
+#define NDIS_PACKET_TYPE_FUNCTIONAL 0x00000400
+#define NDIS_PACKET_TYPE_MAC_FRAME 0x00000800
+
+#define NDIS_MEDIA_STATE_CONNECTED 0x00000000
+#define NDIS_MEDIA_STATE_DISCONNECTED 0x00000001
+
+#define NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA 0x00000001
+#define NDIS_MAC_OPTION_RECEIVE_SERIALIZED 0x00000002
+#define NDIS_MAC_OPTION_TRANSFERS_NOT_PEND 0x00000004
+#define NDIS_MAC_OPTION_NO_LOOPBACK 0x00000008
+#define NDIS_MAC_OPTION_FULL_DUPLEX 0x00000010
+#define NDIS_MAC_OPTION_EOTX_INDICATION 0x00000020
+#define NDIS_MAC_OPTION_8021P_PRIORITY 0x00000040
+#define NDIS_MAC_OPTION_RESERVED 0x80000000
+
+#endif /* __NDIS_H__ */
diff --git a/components/legacy/usb/usbdevice/class/rndis.c b/components/legacy/usb/usbdevice/class/rndis.c
new file mode 100644
index 0000000000..d3ea89ee0a
--- /dev/null
+++ b/components/legacy/usb/usbdevice/class/rndis.c
@@ -0,0 +1,1476 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2012-12-24 heyuanjie87 first version
+ * 2013-04-13 aozima update ethernet driver.
+ * 2013-04-26 aozima align the desc to 4byte.
+ * 2013-05-08 aozima pad a dummy when send MAX_PKT_SIZE.
+ * 2013-05-09 aozima add delay linkup feature.
+ * 2013-07-09 aozima support respone chain list.
+ * 2013-07-18 aozima re-initial respone chain list when RNDIS restart.
+ * 2017-11-25 ZYH fix it and add OS descriptor
+ * 2019-06-10 ZYH fix hot plug and delay linkup
+ */
+
+#include <rtdevice.h>
+#ifdef RT_USB_DEVICE_RNDIS
+#include "cdc.h"
+#include "rndis.h"
+#include "ndis.h"
+
+/* define RNDIS_DELAY_LINK_UP by menuconfig for delay linkup */
+
+#define DBG_LEVEL DBG_WARNING
+#define DBG_SECTION_NAME "RNDIS"
+#include <rtdbg.h>
+
+#define RNDIS_INTF_STR_INDEX 12
+/* RT-Thread LWIP ethernet interface */
+#include <netif/ethernetif.h>
+
+
+struct rt_rndis_response
+{
+ struct rt_list_node list;
+ const void * buffer;
+};
+
+#define MAX_ADDR_LEN 6
+struct rt_rndis_eth
+{
+ /* inherit from ethernet device */
+ struct eth_device parent;
+ struct ufunction *func;
+ /* interface address info */
+ rt_uint8_t host_addr[MAX_ADDR_LEN];
+ rt_uint8_t dev_addr[MAX_ADDR_LEN];
+
+#ifdef RNDIS_DELAY_LINK_UP
+ struct rt_timer timer;
+#endif /* RNDIS_DELAY_LINK_UP */
+
+ rt_align(4)
+ rt_uint8_t rx_pool[512];
+ rt_align(4)
+ rt_uint8_t tx_pool[512];
+
+ rt_uint32_t cmd_pool[2];
+ rt_align(4)
+ char rx_buffer[sizeof(struct rndis_packet_msg) + USB_ETH_MTU + 14];
+ rt_size_t rx_offset;
+ rt_size_t rx_length;
+ rt_bool_t rx_flag;
+ rt_bool_t rx_frist;
+
+ rt_align(4)
+ char tx_buffer[sizeof(struct rndis_packet_msg) + USB_ETH_MTU + 14];
+ struct rt_semaphore tx_buffer_free;
+
+ struct rt_list_node response_list;
+ rt_bool_t need_notify;
+ struct cdc_eps eps;
+};
+typedef struct rt_rndis_eth * rt_rndis_eth_t;
+static rt_uint32_t oid_packet_filter = 0x0000000;
+
+rt_align(4)
+static struct udevice_descriptor _dev_desc =
+{
+ USB_DESC_LENGTH_DEVICE, /* bLength */
+ USB_DESC_TYPE_DEVICE, /* type */
+ USB_BCD_VERSION, /* bcdUSB */
+ 0xEF, /* bDeviceClass */
+ 0x04, /* bDeviceSubClass */
+ 0x01, /* bDeviceProtocol */
+ USB_CDC_BUFSIZE, /* bMaxPacketSize0 */
+ _VENDOR_ID, /* idVendor */
+ _PRODUCT_ID, /* idProduct */
+ USB_BCD_DEVICE, /* bcdDevice */
+ USB_STRING_MANU_INDEX, /* iManufacturer */
+ USB_STRING_PRODUCT_INDEX, /* iProduct */
+ USB_STRING_SERIAL_INDEX, /* iSerialNumber */
+ USB_DYNAMIC /* bNumConfigurations */
+};
+
+/* communcation interface descriptor */
+rt_align(4)
+const static struct ucdc_comm_descriptor _comm_desc =
+{
+#ifdef RT_USB_DEVICE_COMPOSITE
+ /* Interface Association Descriptor */
+ {
+ USB_DESC_LENGTH_IAD,
+ USB_DESC_TYPE_IAD,
+ USB_DYNAMIC,
+ 0x02,
+ USB_CDC_CLASS_COMM,
+ USB_CDC_SUBCLASS_ACM,
+ USB_CDC_PROTOCOL_VENDOR,
+ 0x00,
+ },
+#endif
+ /* Interface Descriptor */
+ {
+ USB_DESC_LENGTH_INTERFACE,
+ USB_DESC_TYPE_INTERFACE,
+ USB_DYNAMIC,
+ 0x00,
+ 0x01,
+ USB_CDC_CLASS_COMM,
+ USB_CDC_SUBCLASS_ACM,
+ USB_CDC_PROTOCOL_VENDOR,
+#ifdef RT_USB_DEVICE_COMPOSITE
+ RNDIS_INTF_STR_INDEX,
+#else
+ 0x00,
+#endif
+ },
+ /* Header Functional Descriptor */
+ {
+ 0x05,
+ USB_CDC_CS_INTERFACE,
+ USB_CDC_SCS_HEADER,
+ 0x0110,
+ },
+ /* Call Management Functional Descriptor */
+ {
+ 0x05,
+ USB_CDC_CS_INTERFACE,
+ USB_CDC_SCS_CALL_MGMT,
+ 0x00,
+ USB_DYNAMIC,
+ },
+ /* Abstract Control Management Functional Descriptor */
+ {
+ 0x04,
+ USB_CDC_CS_INTERFACE,
+ USB_CDC_SCS_ACM,
+ 0x02,
+ },
+ /* Union Functional Descriptor */
+ {
+ 0x05,
+ USB_CDC_CS_INTERFACE,
+ USB_CDC_SCS_UNION,
+ USB_DYNAMIC,
+ USB_DYNAMIC,
+ },
+ /* Endpoint Descriptor */
+ {
+ USB_DESC_LENGTH_ENDPOINT,
+ USB_DESC_TYPE_ENDPOINT,
+ USB_DIR_IN | USB_DYNAMIC,
+ USB_EP_ATTR_INT,
+ 0x08,
+ 0x0A,
+ },
+};
+
+/* data interface descriptor */
+rt_align(4)
+const static struct ucdc_data_descriptor _data_desc =
+{
+ /* interface descriptor */
+ {
+ USB_DESC_LENGTH_INTERFACE,
+ USB_DESC_TYPE_INTERFACE,
+ USB_DYNAMIC,
+ 0x00,
+ 0x02,
+ USB_CDC_CLASS_DATA,
+ 0x00,
+ 0x00,
+ 0x00,
+ },
+ /* endpoint, bulk out */
+ {
+ USB_DESC_LENGTH_ENDPOINT,
+ USB_DESC_TYPE_ENDPOINT,
+ USB_DIR_OUT | USB_DYNAMIC,
+ USB_EP_ATTR_BULK,
+ USB_DYNAMIC,
+ 0x00,
+ },
+ /* endpoint, bulk in */
+ {
+ USB_DESC_LENGTH_ENDPOINT,
+ USB_DESC_TYPE_ENDPOINT,
+ USB_DYNAMIC | USB_DIR_IN,
+ USB_EP_ATTR_BULK,
+ USB_DYNAMIC,
+ 0x00,
+ },
+};
+
+rt_align(4)
+const static char* _ustring[] =
+{
+ "Language", /* LANGID */
+ "RT-Thread Team.", /* MANU */
+ "RT-Thread RNDIS device", /* PRODUCT */
+ "1.1.0", /* SERIAL */
+ "Configuration", /* CONFIG */
+ "Interface", /* INTERFACE */
+ USB_STRING_OS
+};
+
+rt_align(4)
+struct usb_os_function_comp_id_descriptor rndis_func_comp_id_desc =
+{
+ .bFirstInterfaceNumber = USB_DYNAMIC,
+ .reserved1 = 0x01,
+ .compatibleID = {'R', 'N', 'D', 'I', 'S', 0x00, 0x00, 0x00},
+ .subCompatibleID = {'5', '1', '6', '2', '0', '0', '1', 0x00},
+ .reserved2 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+
+//FS and HS needed
+rt_align(4)
+static struct usb_qualifier_descriptor dev_qualifier =
+{
+ sizeof(dev_qualifier), //bLength
+ USB_DESC_TYPE_DEVICEQUALIFIER, //bDescriptorType
+ 0x0200, //bcdUSB
+ USB_CLASS_CDC, //bDeviceClass
+ USB_CDC_SUBCLASS_ACM, //bDeviceSubClass
+ USB_CDC_PROTOCOL_VENDOR, //bDeviceProtocol
+ 64, //bMaxPacketSize0
+ 0x01, //bNumConfigurations
+ 0,
+};
+
+/* supported OIDs */
+rt_align(4)
+const static rt_uint32_t oid_supported_list[] =
+{
+ /* General OIDs */
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_VENDOR_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MEDIA_CONNECT_STATUS,
+
+ OID_GEN_PHYSICAL_MEDIUM,
+
+ /* General Statistic OIDs */
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+
+ /* Please configure us */
+ OID_GEN_RNDIS_CONFIG_PARAMETER,
+
+ /* 802.3 OIDs */
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+
+ /* 802.3 Statistic OIDs */
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS,
+
+ OID_802_3_MAC_OPTIONS,
+};
+
+static rt_uint8_t rndis_message_buffer[RNDIS_MESSAGE_BUFFER_SIZE];
+
+static void _rndis_response_available(ufunction_t func)
+{
+ rt_rndis_eth_t device = (rt_rndis_eth_t)func->user_data;
+ rt_uint32_t * data;
+ if(device->need_notify == RT_TRUE)
+ {
+ device->need_notify = RT_FALSE;
+ data = (rt_uint32_t *)device->eps.ep_cmd->buffer;
+ data[0] = RESPONSE_AVAILABLE;
+ data[1] = 0;
+ device->eps.ep_cmd->request.buffer = device->eps.ep_cmd->buffer;
+ device->eps.ep_cmd->request.size = 8;
+ device->eps.ep_cmd->request.req_type = UIO_REQUEST_WRITE;
+ rt_usbd_io_request(func->device, device->eps.ep_cmd, &device->eps.ep_cmd->request);
+ }
+}
+
+static rt_err_t _rndis_init_response(ufunction_t func, rndis_init_msg_t msg)
+{
+ rndis_init_cmplt_t resp;
+ struct rt_rndis_response * response;
+
+ response = rt_malloc(sizeof(struct rt_rndis_response));
+ resp = rt_malloc(sizeof(struct rndis_init_cmplt));
+
+ if( (response == RT_NULL) || (resp == RT_NULL) )
+ {
+ LOG_E("%s,%d: no memory!", __func__, __LINE__);
+
+ if(response != RT_NULL)
+ rt_free(response);
+
+ if(resp != RT_NULL)
+ rt_free(resp);
+
+ return -RT_ENOMEM;
+ }
+
+ resp->RequestId = msg->RequestId;
+ resp->MessageType = REMOTE_NDIS_INITIALIZE_CMPLT;
+ resp->MessageLength = sizeof(struct rndis_init_cmplt);
+ resp->MajorVersion = RNDIS_MAJOR_VERSION;
+ resp->MinorVersion = RNDIS_MAJOR_VERSION;
+ resp->Status = RNDIS_STATUS_SUCCESS;
+ resp->DeviceFlags = RNDIS_DF_CONNECTIONLESS;
+ resp->Medium = RNDIS_MEDIUM_802_3;
+ resp->MaxPacketsPerTransfer = 1;
+ resp->MaxTransferSize = USB_ETH_MTU + 58; /* Space for 1280 IP buffer, Ethernet Header,
+ RNDIS messages */
+ resp->PacketAlignmentFactor = 3;
+ resp->AfListOffset = 0;
+ resp->AfListSize = 0;
+
+ response->buffer = resp;
+
+ {
+ rt_base_t level = rt_hw_interrupt_disable();
+ rt_list_insert_before(&((rt_rndis_eth_t)func->user_data)->response_list, &response->list);
+ rt_hw_interrupt_enable(level);
+ }
+
+
+ return RT_EOK;
+}
+
+static rndis_query_cmplt_t _create_resp(rt_size_t size)
+{
+ rndis_query_cmplt_t resp;
+
+ resp = rt_malloc(sizeof(struct rndis_query_cmplt) + size);
+
+ if(resp == RT_NULL)
+ {
+ LOG_E("%s,%d: no memory!", __func__, __LINE__);
+ return RT_NULL;
+ }
+
+ resp->InformationBufferLength = size;
+
+ return resp;
+}
+
+static void _copy_resp(rndis_query_cmplt_t resp, const void * buffer)
+{
+ char * resp_buffer = (char *)resp + sizeof(struct rndis_query_cmplt);
+ rt_memcpy(resp_buffer, buffer, resp->InformationBufferLength);
+}
+
+static void _set_resp(rndis_query_cmplt_t resp, rt_uint32_t value)
+{
+ rt_uint32_t * response = (rt_uint32_t *)((char *)resp + sizeof(struct rndis_query_cmplt));
+ *response = value;
+}
+
+static rt_err_t _rndis_query_response(ufunction_t func,rndis_query_msg_t msg)
+{
+ rndis_query_cmplt_t resp = RT_NULL;
+ struct rt_rndis_response * response;
+ rt_err_t ret = RT_EOK;
+
+ switch (msg->Oid)
+ {
+ /*
+ * general OIDs
+ */
+ case OID_GEN_SUPPORTED_LIST:
+ resp = _create_resp(sizeof(oid_supported_list));
+ if(resp == RT_NULL) break;
+ _copy_resp(resp, oid_supported_list);
+ break;
+
+ case OID_GEN_PHYSICAL_MEDIUM:
+ resp = _create_resp(4);
+ if(resp == RT_NULL) break;
+ _set_resp(resp, NDIS_MEDIUM_802_3);
+ break;
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+ resp = _create_resp(4);
+ if(resp == RT_NULL) break;
+ _set_resp(resp, USB_ETH_MTU);
+ break;
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+ resp = _create_resp(4);
+ if(resp == RT_NULL) break;
+ _set_resp(resp, USB_ETH_MTU + RNDIS_MESSAGE_BUFFER_SIZE);
+ break;
+
+ case OID_GEN_LINK_SPEED:
+ resp = _create_resp(4);
+ if(resp == RT_NULL) break;
+ _set_resp(resp, (func->device->dcd->device_is_hs ? (480UL * 1000 *1000) : (12UL * 1000 * 1000)) / 100);
+ break;
+
+ case OID_GEN_MEDIA_CONNECT_STATUS:
+ /* link_status */
+ resp = _create_resp(4);
+ if(resp == RT_NULL) break;
+
+#ifdef RNDIS_DELAY_LINK_UP
+ if(((rt_rndis_eth_t)func->user_data)->parent.link_status)
+ {
+ _set_resp(resp, NDIS_MEDIA_STATE_CONNECTED);
+ }
+ else
+ {
+ _set_resp(resp, NDIS_MEDIA_STATE_DISCONNECTED);
+ }
+#else
+ _set_resp(resp, NDIS_MEDIA_STATE_CONNECTED);
+#endif /* RNDIS_DELAY_LINK_UP */
+ break;
+
+ case OID_GEN_VENDOR_ID:
+ resp = _create_resp(4);
+ if(resp == RT_NULL) break;
+ _set_resp(resp, 0x12345678); /* only for test */
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+ {
+ const char vendor_desc[] = "RT-Thread RNDIS";
+
+ resp = _create_resp(sizeof(vendor_desc));
+ if(resp == RT_NULL) break;
+ _copy_resp(resp, vendor_desc);
+ }
+ break;
+
+ case OID_GEN_VENDOR_DRIVER_VERSION:
+ resp = _create_resp(4);
+ if(resp == RT_NULL) break;
+ _set_resp(resp, 0x0000200);
+ break;
+
+ /* statistics OIDs */
+ case OID_GEN_XMIT_OK:
+ case OID_GEN_RCV_OK:
+ resp = _create_resp(4);
+ if(resp == RT_NULL) break;
+ _set_resp(resp, 1);
+ break;
+
+ case OID_GEN_XMIT_ERROR:
+ case OID_GEN_RCV_ERROR:
+ case OID_GEN_RCV_NO_BUFFER:
+ resp = _create_resp(4);
+ if(resp == RT_NULL) break;
+ _set_resp(resp, 0);
+ break;
+
+ /*
+ * ieee802.3 OIDs
+ */
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+ resp = _create_resp(4);
+ if(resp == RT_NULL) break;
+ _set_resp(resp, 1);
+ break;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+ case OID_802_3_CURRENT_ADDRESS:
+ resp = _create_resp(sizeof(((rt_rndis_eth_t)func->user_data)->host_addr));
+ if(resp == RT_NULL) break;
+ _copy_resp(resp, ((rt_rndis_eth_t)func->user_data)->host_addr);
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+ resp = _create_resp(4);
+ if(resp == RT_NULL) break;
+ _set_resp(resp, 0xE000000);
+ break;
+
+ case OID_802_3_MAC_OPTIONS:
+ resp = _create_resp(4);
+ if(resp == RT_NULL) break;
+ _set_resp(resp, 0);
+ break;
+
+ default:
+ LOG_W("Not support OID %X", msg->Oid);
+ ret = -RT_ERROR;
+ break;
+ }
+
+ response = rt_malloc(sizeof(struct rt_rndis_response));
+ if( (response == RT_NULL) || (resp == RT_NULL) )
+ {
+ LOG_E("%s,%d: no memory!", __func__, __LINE__);
+
+ if(response != RT_NULL)
+ rt_free(response);
+
+ if(resp != RT_NULL)
+ rt_free(resp);
+
+ return -RT_ENOMEM;
+ }
+
+ resp->RequestId = msg->RequestId;
+ resp->MessageType = REMOTE_NDIS_QUERY_CMPLT;
+ resp->InformationBufferOffset = 16;
+
+ resp->Status = RNDIS_STATUS_SUCCESS;
+ resp->MessageLength = sizeof(struct rndis_query_cmplt) + resp->InformationBufferLength;
+
+ response->buffer = resp;
+
+ {
+ rt_base_t level = rt_hw_interrupt_disable();
+ rt_list_insert_before(&((rt_rndis_eth_t)func->user_data)->response_list, &response->list);
+ rt_hw_interrupt_enable(level);
+ }
+
+ return ret;
+}
+
+static rt_err_t _rndis_set_response(ufunction_t func,rndis_set_msg_t msg)
+{
+ rndis_set_cmplt_t resp;
+ struct rt_rndis_response * response;
+
+ response = rt_malloc(sizeof(struct rt_rndis_response));
+ resp = rt_malloc(sizeof(struct rndis_set_cmplt));
+
+ if( (response == RT_NULL) || (resp == RT_NULL) )
+ {
+ LOG_E("%s,%d: no memory!", __func__, __LINE__);
+
+ if(response != RT_NULL)
+ rt_free(response);
+
+ if(resp != RT_NULL)
+ rt_free(resp);
+
+ return -RT_ENOMEM;
+ }
+
+ resp->RequestId = msg->RequestId;
+ resp->MessageType = REMOTE_NDIS_SET_CMPLT;
+ resp->MessageLength = sizeof(struct rndis_set_cmplt);
+
+ switch (msg->Oid)
+ {
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ oid_packet_filter = *((rt_uint32_t *)((rt_uint8_t *)&(msg->RequestId) + \
+ msg->InformationBufferOffset));
+ /* TODO: make complier happy */
+ oid_packet_filter = oid_packet_filter;
+
+ LOG_D("OID_GEN_CURRENT_PACKET_FILTER");
+
+#ifdef RNDIS_DELAY_LINK_UP
+ /* link up. */
+ rt_timer_start(&((rt_rndis_eth_t)func->user_data)->timer);
+#else
+ eth_device_linkchange(&((rt_rndis_eth_t)func->user_data)->parent, RT_TRUE);
+#endif /* RNDIS_DELAY_LINK_UP */
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+ break;
+
+ default:
+ LOG_W("Unknow rndis set 0x%02X", msg->Oid);
+ resp->Status = RNDIS_STATUS_FAILURE;
+ return RT_EOK;
+ }
+
+ resp->Status = RNDIS_STATUS_SUCCESS;
+
+ response->buffer = resp;
+
+ {
+ rt_base_t level = rt_hw_interrupt_disable();
+ rt_list_insert_before(&((rt_rndis_eth_t)func->user_data)->response_list, &response->list);
+ rt_hw_interrupt_enable(level);
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t _rndis_reset_response(ufunction_t func,rndis_set_msg_t msg)
+{
+ struct rndis_reset_cmplt * resp;
+ struct rt_rndis_response * response;
+
+ response = rt_malloc(sizeof(struct rt_rndis_response));
+ resp = rt_malloc(sizeof(struct rndis_reset_cmplt));
+
+ if( (response == RT_NULL) || (resp == RT_NULL) )
+ {
+ LOG_E("%s,%d: no memory!", __func__, __LINE__);
+
+ if(response != RT_NULL)
+ rt_free(response);
+
+ if(resp != RT_NULL)
+ rt_free(resp);
+
+ return -RT_ENOMEM;
+ }
+
+ /* reset packet filter */
+
+ oid_packet_filter = 0x0000000;
+
+ /* link down eth */
+
+ eth_device_linkchange(&((rt_rndis_eth_t)func->user_data)->parent, RT_FALSE);
+
+ /* reset eth rx tx */
+ ((rt_rndis_eth_t)func->user_data)->rx_frist = RT_TRUE;
+ ((rt_rndis_eth_t)func->user_data)->rx_flag = RT_FALSE;
+
+
+ resp->MessageType = REMOTE_NDIS_RESET_CMPLT;
+ resp->MessageLength = sizeof(struct rndis_reset_cmplt);
+ resp->Status = RNDIS_STATUS_SUCCESS;
+ resp->AddressingReset = 1;
+
+ response->buffer = resp;
+
+ {
+ rt_base_t level = rt_hw_interrupt_disable();
+ rt_list_insert_before(&((rt_rndis_eth_t)func->user_data)->response_list, &response->list);
+ rt_hw_interrupt_enable(level);
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t _rndis_keepalive_response(ufunction_t func,rndis_keepalive_msg_t msg)
+{
+ rndis_keepalive_cmplt_t resp;
+ struct rt_rndis_response * response;
+
+ response = rt_malloc(sizeof(struct rt_rndis_response));
+ resp = rt_malloc(sizeof(struct rndis_keepalive_cmplt));
+
+ if( (response == RT_NULL) || (resp == RT_NULL) )
+ {
+ LOG_E("%s,%d: no memory!", __func__, __LINE__);
+
+ if(response != RT_NULL)
+ rt_free(response);
+
+ if(resp != RT_NULL)
+ rt_free(resp);
+
+ return -RT_ENOMEM;
+ }
+
+ resp->MessageType = REMOTE_NDIS_KEEPALIVE_CMPLT;
+ resp->MessageLength = sizeof(struct rndis_keepalive_cmplt);
+ resp->Status = RNDIS_STATUS_SUCCESS;
+
+ response->buffer = resp;
+
+ {
+ rt_base_t level = rt_hw_interrupt_disable();
+ rt_list_insert_before(&((rt_rndis_eth_t)func->user_data)->response_list, &response->list);
+ rt_hw_interrupt_enable(level);
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t _rndis_msg_parser(ufunction_t func, rt_uint8_t *msg)
+{
+ rt_err_t ret = -RT_ERROR;
+
+ switch (((rndis_gen_msg_t) msg)->MessageType)
+ {
+ case REMOTE_NDIS_INITIALIZE_MSG:
+ LOG_D("REMOTE_NDIS_INITIALIZE_MSG");
+ ret = _rndis_init_response(func, (rndis_init_msg_t) msg);
+ break;
+
+ case REMOTE_NDIS_HALT_MSG:
+ LOG_D("REMOTE_NDIS_HALT_MSG");
+ /* link down. */
+ eth_device_linkchange(&((rt_rndis_eth_t)func->user_data)->parent, RT_FALSE);
+
+ /* reset eth rx tx */
+ ((rt_rndis_eth_t)func->user_data)->rx_frist = RT_TRUE;
+ ((rt_rndis_eth_t)func->user_data)->rx_flag = RT_FALSE;
+ break;
+
+ case REMOTE_NDIS_QUERY_MSG:
+ LOG_D("REMOTE_NDIS_QUERY_MSG");
+ ret = _rndis_query_response(func,(rndis_query_msg_t) msg);
+ break;
+
+ case REMOTE_NDIS_SET_MSG:
+ LOG_D("REMOTE_NDIS_SET_MSG");
+ ret = _rndis_set_response(func,(rndis_set_msg_t) msg);
+ break;
+
+ case REMOTE_NDIS_RESET_MSG:
+ LOG_D("REMOTE_NDIS_RESET_MSG");
+ ret = _rndis_reset_response(func,(rndis_set_msg_t) msg);
+ break;
+
+ case REMOTE_NDIS_KEEPALIVE_MSG:
+ LOG_D("REMOTE_NDIS_KEEPALIVE_MSG");
+ ret = _rndis_keepalive_response(func,(rndis_keepalive_msg_t) msg);
+ break;
+
+ default:
+ LOG_W("not support RNDIS msg %X", ((rndis_gen_msg_t) msg)->MessageType);
+ ret = -RT_ERROR;
+ break;
+ }
+
+ if (ret == RT_EOK)
+ _rndis_response_available(func);
+
+ return ret;
+}
+
+static ufunction_t function = RT_NULL;
+static rt_err_t send_encapsulated_command_done(udevice_t device, rt_size_t size)
+{
+ if(function != RT_NULL)
+ {
+ dcd_ep0_send_status(device->dcd);
+ _rndis_msg_parser(function, rndis_message_buffer);
+ function = RT_NULL;
+ }
+ return RT_EOK;
+}
+//#error here have bug ep 0x82 send failed
+static rt_err_t _rndis_send_encapsulated_command(ufunction_t func, ureq_t setup)
+{
+ RT_ASSERT(setup->wLength <= sizeof(rndis_message_buffer));
+ function = func;
+ rt_usbd_ep0_read(func->device,rndis_message_buffer,setup->wLength,send_encapsulated_command_done);
+
+ return RT_EOK;
+}
+
+static rt_err_t _rndis_get_encapsulated_response(ufunction_t func, ureq_t setup)
+{
+ rndis_gen_msg_t msg;
+ struct rt_rndis_response * response;
+
+ if(rt_list_isempty(&((rt_rndis_eth_t)func->user_data)->response_list))
+ {
+ LOG_D("response_list is empty!");
+ ((rt_rndis_eth_t)func->user_data)->need_notify = RT_TRUE;
+ return RT_EOK;
+ }
+
+ response = (struct rt_rndis_response *)((rt_rndis_eth_t)func->user_data)->response_list.next;
+
+ msg = (rndis_gen_msg_t)response->buffer;
+ rt_usbd_ep0_write(func->device, (void*)msg, msg->MessageLength);
+
+ {
+ rt_base_t level = rt_hw_interrupt_disable();
+ rt_list_remove(&response->list);
+ rt_hw_interrupt_enable(level);
+ }
+
+ rt_free((void *)response->buffer);
+ rt_free(response);
+
+ if(!rt_list_isempty(&((rt_rndis_eth_t)func->user_data)->response_list))
+ {
+ rt_uint32_t * data;
+
+ LOG_I("auto append next response!");
+ data = (rt_uint32_t *)((rt_rndis_eth_t)func->user_data)->eps.ep_cmd->buffer;
+ data[0] = RESPONSE_AVAILABLE;
+ data[1] = 0;
+ ((rt_rndis_eth_t)func->user_data)->eps.ep_cmd->request.buffer = ((rt_rndis_eth_t)func->user_data)->eps.ep_cmd->buffer;
+ ((rt_rndis_eth_t)func->user_data)->eps.ep_cmd->request.size = 8;
+ ((rt_rndis_eth_t)func->user_data)->eps.ep_cmd->request.req_type = UIO_REQUEST_WRITE;
+ rt_usbd_io_request(func->device, ((rt_rndis_eth_t)func->user_data)->eps.ep_cmd, &((rt_rndis_eth_t)func->user_data)->eps.ep_cmd->request);
+ }
+ else
+ {
+ ((rt_rndis_eth_t)func->user_data)->need_notify = RT_TRUE;
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * This function will handle rndis interface request.
+ *
+ * @param device the usb device object.
+ * @param setup the setup request.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _interface_handler(ufunction_t func, ureq_t setup)
+{
+ RT_ASSERT(func != RT_NULL);
+ RT_ASSERT(setup != RT_NULL);
+
+ switch(setup->bRequest)
+ {
+ case CDC_SEND_ENCAPSULATED_COMMAND:
+ _rndis_send_encapsulated_command(func, setup);
+ break;
+
+ case CDC_GET_ENCAPSULATED_RESPONSE:
+ _rndis_get_encapsulated_response(func, setup);
+ break;
+
+ default:
+ LOG_W("unkown setup->request 0x%02X !", setup->bRequest);
+ break;
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * This function will handle rndis bulk in endpoint request.
+ *
+ * @param device the usb device object.
+ * @param size request size.
+ *
+ * @return RT_EOK.
+ */
+
+static rt_err_t _ep_in_handler(ufunction_t func, rt_size_t size)
+{
+ rt_sem_release(&((rt_rndis_eth_t)func->user_data)->tx_buffer_free);
+ return RT_EOK;
+}
+
+/**
+ * This function will handle RNDIS bulk out endpoint request.
+ *
+ * @param device the usb device object.
+ * @param size request size.
+ *
+ * @return RT_EOK.
+ */
+static rt_err_t _ep_out_handler(ufunction_t func, rt_size_t size)
+{
+ cdc_eps_t eps;
+ char* data = RT_NULL;
+
+ eps = (cdc_eps_t)&((rt_rndis_eth_t)func->user_data)->eps;
+ data = (char*)eps->ep_out->buffer;
+
+ if(((rt_rndis_eth_t)func->user_data)->rx_frist == RT_TRUE)
+ {
+ rndis_packet_msg_t msg = (rndis_packet_msg_t)data;
+
+ ((rt_rndis_eth_t)func->user_data)->rx_length = msg->DataLength;
+ ((rt_rndis_eth_t)func->user_data)->rx_offset = 0;
+
+ if (size >= 44)
+ {
+ data += sizeof(struct rndis_packet_msg);
+ size -= sizeof(struct rndis_packet_msg);
+ ((rt_rndis_eth_t)func->user_data)->rx_frist = RT_FALSE;
+ rt_memcpy(&((rt_rndis_eth_t)func->user_data)->rx_buffer[((rt_rndis_eth_t)func->user_data)->rx_offset], data, size);
+ ((rt_rndis_eth_t)func->user_data)->rx_offset += size;
+ }
+ }
+ else
+ {
+ rt_memcpy(&((rt_rndis_eth_t)func->user_data)->rx_buffer[((rt_rndis_eth_t)func->user_data)->rx_offset], data, size);
+ ((rt_rndis_eth_t)func->user_data)->rx_offset += size;
+ }
+
+ if(((rt_rndis_eth_t)func->user_data)->rx_offset >= ((rt_rndis_eth_t)func->user_data)->rx_length)
+ {
+ ((rt_rndis_eth_t)func->user_data)->rx_frist = RT_TRUE;
+ ((rt_rndis_eth_t)func->user_data)->rx_flag = RT_TRUE;
+ eth_device_ready(&(((rt_rndis_eth_t)func->user_data)->parent));
+ }
+ else
+ {
+ eps->ep_out->request.buffer = eps->ep_out->buffer;
+ eps->ep_out->request.size = EP_MAXPACKET(eps->ep_out);
+ eps->ep_out->request.req_type = UIO_REQUEST_READ_BEST;
+ rt_usbd_io_request(func->device, eps->ep_out, &eps->ep_out->request);
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * This function will handle RNDIS interrupt in endpoint request.
+ *
+ * @param device the usb device object.
+ * @param size request size.
+ *
+ * @return RT_EOK.
+ */
+static rt_err_t _ep_cmd_handler(ufunction_t func, rt_size_t size)
+{
+// _rndis_response_available(func);
+ return RT_EOK;
+}
+
+/**
+ * This function will run cdc class, it will be called on handle set configuration request.
+ *
+ * @param device the usb device object.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _function_enable(ufunction_t func)
+{
+ cdc_eps_t eps;
+
+ LOG_I("plugged in");
+
+ eps = (cdc_eps_t)&((rt_rndis_eth_t)func->user_data)->eps;
+ eps->ep_in->buffer = ((rt_rndis_eth_t)func->user_data)->tx_pool;
+ eps->ep_out->buffer = ((rt_rndis_eth_t)func->user_data)->rx_pool;
+ eps->ep_cmd->buffer = (rt_uint8_t*)((rt_rndis_eth_t)func->user_data)->cmd_pool;
+
+ eps->ep_out->request.buffer = eps->ep_out->buffer;
+ eps->ep_out->request.size = EP_MAXPACKET(eps->ep_out);
+ eps->ep_out->request.req_type = UIO_REQUEST_READ_BEST;
+ rt_usbd_io_request(func->device, eps->ep_out, &eps->ep_out->request);
+
+ ((rt_rndis_eth_t)func->user_data)->rx_flag = RT_FALSE;
+ ((rt_rndis_eth_t)func->user_data)->rx_frist = RT_TRUE;
+ // eth_device_ready(&(((rt_rndis_eth_t)func->user_data)->parent));
+
+#ifdef RNDIS_DELAY_LINK_UP
+ /* stop link up timer. */
+ rt_timer_stop(&((rt_rndis_eth_t)func->user_data)->timer);
+#endif /* RNDIS_DELAY_LINK_UP */
+
+ /* clean resp chain list. */
+ {
+ struct rt_rndis_response * response;
+ rt_base_t level = rt_hw_interrupt_disable();
+
+ while(!rt_list_isempty(&((rt_rndis_eth_t)func->user_data)->response_list))
+ {
+ response = (struct rt_rndis_response *)((rt_rndis_eth_t)func->user_data)->response_list.next;
+
+ rt_list_remove(&response->list);
+ rt_free((void *)response->buffer);
+ rt_free(response);
+ }
+
+ ((rt_rndis_eth_t)func->user_data)->need_notify = RT_TRUE;
+ rt_hw_interrupt_enable(level);
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * This function will stop cdc class, it will be called on handle set configuration request.
+ *
+ * @param device the usb device object.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _function_disable(ufunction_t func)
+{
+ LOG_I("plugged out");
+
+#ifdef RNDIS_DELAY_LINK_UP
+ /* stop link up timer. */
+ rt_timer_stop(&((rt_rndis_eth_t)func->user_data)->timer);
+#endif /* RNDIS_DELAY_LINK_UP */
+
+ /* clean resp chain list. */
+ {
+ struct rt_rndis_response * response;
+ rt_base_t level = rt_hw_interrupt_disable();
+
+ while(!rt_list_isempty(&((rt_rndis_eth_t)func->user_data)->response_list))
+ {
+ response = (struct rt_rndis_response *)((rt_rndis_eth_t)func->user_data)->response_list.next;
+ LOG_D("remove resp chain list!");
+
+ rt_list_remove(&response->list);
+ rt_free((void *)response->buffer);
+ rt_free(response);
+ }
+
+ ((rt_rndis_eth_t)func->user_data)->need_notify = RT_TRUE;
+ rt_hw_interrupt_enable(level);
+ }
+
+
+ /* link down. */
+ eth_device_linkchange(&((rt_rndis_eth_t)func->user_data)->parent, RT_FALSE);
+
+ /* reset eth rx tx */
+ ((rt_rndis_eth_t)func->user_data)->rx_frist = RT_TRUE;
+ ((rt_rndis_eth_t)func->user_data)->rx_flag = RT_FALSE;
+
+ return RT_EOK;
+}
+
+
+static struct ufunction_ops ops =
+{
+ _function_enable,
+ _function_disable,
+ RT_NULL,
+};
+
+/**
+ * This function will configure cdc descriptor.
+ *
+ * @param comm the communication interface number.
+ * @param data the data interface number.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _cdc_descriptor_config(ucdc_comm_desc_t comm, rt_uint8_t cintf_nr, ucdc_data_desc_t data, rt_uint8_t dintf_nr, rt_uint8_t device_is_hs)
+{
+ comm->call_mgmt_desc.data_interface = dintf_nr;
+ comm->union_desc.master_interface = cintf_nr;
+ comm->union_desc.slave_interface0 = dintf_nr;
+#ifdef RT_USB_DEVICE_COMPOSITE
+ comm->iad_desc.bFirstInterface = cintf_nr;
+#endif
+ data->ep_out_desc.wMaxPacketSize = device_is_hs ? 512 : 64;
+ data->ep_in_desc.wMaxPacketSize = device_is_hs ? 512 : 64;
+ return RT_EOK;
+}
+
+#ifdef RT_USING_LWIP
+/* initialize the interface */
+static rt_err_t rt_rndis_eth_init(rt_device_t dev)
+{
+ return RT_EOK;
+}
+
+static rt_err_t rt_rndis_eth_open(rt_device_t dev, rt_uint16_t oflag)
+{
+ return RT_EOK;
+}
+
+static rt_err_t rt_rndis_eth_close(rt_device_t dev)
+{
+ return RT_EOK;
+}
+
+static rt_ssize_t rt_rndis_eth_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
+{
+ rt_set_errno(-RT_ENOSYS);
+ return 0;
+}
+
+static rt_ssize_t rt_rndis_eth_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
+{
+ rt_set_errno(-RT_ENOSYS);
+ return 0;
+}
+static rt_err_t rt_rndis_eth_control(rt_device_t dev, int cmd, void *args)
+{
+ rt_rndis_eth_t rndis_eth_dev = (rt_rndis_eth_t)dev;
+ switch(cmd)
+ {
+ case NIOCTL_GADDR:
+ /* get mac address */
+ if(args) rt_memcpy(args, rndis_eth_dev->dev_addr, MAX_ADDR_LEN);
+ else return -RT_ERROR;
+ break;
+
+ default :
+ break;
+ }
+
+ return RT_EOK;
+}
+
+/* ethernet device interface */
+
+
+/* reception packet. */
+struct pbuf *rt_rndis_eth_rx(rt_device_t dev)
+{
+ struct pbuf* p = RT_NULL;
+ rt_uint32_t offset = 0;
+ rt_rndis_eth_t device = (rt_rndis_eth_t)dev;
+ if(device->rx_flag == RT_FALSE)
+ {
+ return p;
+ }
+
+ if(device->rx_length != 0)
+ {
+ /* allocate buffer */
+ p = pbuf_alloc(PBUF_LINK, device->rx_length, PBUF_RAM);
+ if (p != RT_NULL)
+ {
+ struct pbuf* q;
+
+ for (q = p; q != RT_NULL; q= q->next)
+ {
+ /* Copy the received frame into buffer from memory pointed by the current ETHERNET DMA Rx descriptor */
+ rt_memcpy(q->payload,
+ (rt_uint8_t *)((device->rx_buffer) + offset),
+ q->len);
+ offset += q->len;
+ }
+ }
+ }
+
+ {
+ device->rx_flag = RT_FALSE;
+ device->eps.ep_out->request.buffer = device->eps.ep_out->buffer;
+ device->eps.ep_out->request.size = EP_MAXPACKET(device->eps.ep_out);
+ device->eps.ep_out->request.req_type = UIO_REQUEST_READ_BEST;
+ rt_usbd_io_request(device->func->device, device->eps.ep_out, &device->eps.ep_out->request);
+ }
+
+ return p;
+}
+
+/* transmit packet. */
+rt_err_t rt_rndis_eth_tx(rt_device_t dev, struct pbuf* p)
+{
+ struct pbuf* q;
+ char * buffer;
+ rt_err_t result = RT_EOK;
+ rt_rndis_eth_t device = (rt_rndis_eth_t)dev;
+
+ if(!device->parent.link_status)
+ {
+ LOG_I("linkdown, drop pkg");
+ return RT_EOK;
+ }
+
+ //RT_ASSERT(p->tot_len < sizeof(device->tx_buffer));
+ if(p->tot_len > sizeof(device->tx_buffer))
+ {
+ LOG_W("RNDIS MTU is:%d, but the send packet size is %d",
+ sizeof(device->tx_buffer), p->tot_len);
+ p->tot_len = sizeof(device->tx_buffer);
+ }
+
+ /* wait for buffer free. */
+ result = rt_sem_take(&device->tx_buffer_free, rt_tick_from_millisecond(1000));
+ if(result != RT_EOK)
+ {
+ LOG_W("wait for buffer free timeout");
+ /* if cost 1s to wait send done it said that connection is close . drop it */
+ rt_sem_release(&device->tx_buffer_free);
+ return result;
+ }
+
+ buffer = (char *)&device->tx_buffer + sizeof(struct rndis_packet_msg);
+ for (q = p; q != NULL; q = q->next)
+ {
+ rt_memcpy(buffer, q->payload, q->len);
+ buffer += q->len;
+ }
+
+ /* send */
+ {
+ rndis_packet_msg_t msg;
+
+ msg = (rndis_packet_msg_t)&device->tx_buffer;
+
+ msg->MessageType = REMOTE_NDIS_PACKET_MSG;
+ msg->DataOffset = sizeof(struct rndis_packet_msg) - 8;
+ msg->DataLength = p->tot_len;
+ msg->OOBDataLength = 0;
+ msg->OOBDataOffset = 0;
+ msg->NumOOBDataElements = 0;
+ msg->PerPacketInfoOffset = 0;
+ msg->PerPacketInfoLength = 0;
+ msg->VcHandle = 0;
+ msg->Reserved = 0;
+ msg->MessageLength = sizeof(struct rndis_packet_msg) + p->tot_len;
+
+ if((msg->MessageLength & 0x3F) == 0)
+ {
+ /* pad a dummy. */
+ msg->MessageLength += 1;
+ }
+
+ device->eps.ep_in->request.buffer = (void *)&device->tx_buffer;
+ device->eps.ep_in->request.size = msg->MessageLength;
+ device->eps.ep_in->request.req_type = UIO_REQUEST_WRITE;
+ rt_usbd_io_request(device->func->device, device->eps.ep_in, &device->eps.ep_in->request);
+ }
+
+ return result;
+}
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops rndis_device_ops =
+{
+ rt_rndis_eth_init,
+ rt_rndis_eth_open,
+ rt_rndis_eth_close,
+ rt_rndis_eth_read,
+ rt_rndis_eth_write,
+ rt_rndis_eth_control
+};
+#endif
+
+#endif /* RT_USING_LWIP */
+
+#ifdef RNDIS_DELAY_LINK_UP
+
+/**
+ * This function will set rndis connect status.
+ *
+ * @param device the usb device object.
+ * @param status the connect status.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _rndis_indicate_status_msg(ufunction_t func, rt_uint32_t status)
+{
+ rndis_indicate_status_msg_t resp;
+ struct rt_rndis_response * response;
+
+ response = rt_malloc(sizeof(struct rt_rndis_response));
+ resp = rt_malloc(sizeof(struct rndis_indicate_status_msg));
+
+ if( (response == RT_NULL) || (resp == RT_NULL) )
+ {
+ LOG_E("%s,%d: no memory!", __func__, __LINE__);
+
+ if(response != RT_NULL)
+ rt_free(response);
+
+ if(resp != RT_NULL)
+ rt_free(resp);
+
+ return -RT_ENOMEM;
+ }
+
+ resp->MessageType = REMOTE_NDIS_INDICATE_STATUS_MSG;
+ resp->MessageLength = 20; /* sizeof(struct rndis_indicate_status_msg) */
+ resp->Status = status;
+ resp->StatusBufferLength = 0;
+ resp->StatusBufferOffset = 0;
+
+ response->buffer = resp;
+ {
+ rt_base_t level = rt_hw_interrupt_disable();
+ rt_list_insert_before(&((rt_rndis_eth_t)func->user_data)->response_list, &response->list);
+ rt_hw_interrupt_enable(level);
+ }
+
+ _rndis_response_available(func);
+
+ return RT_EOK;
+}
+
+/* the delay linkup timer handler. */
+static void timer_timeout(void* parameter)
+{
+ LOG_I("delay link up!");
+ _rndis_indicate_status_msg(((rt_rndis_eth_t)parameter)->func,
+ RNDIS_STATUS_MEDIA_CONNECT);
+ eth_device_linkchange(&((rt_rndis_eth_t)parameter)->parent, RT_TRUE);
+}
+#endif /* RNDIS_DELAY_LINK_UP */
+
+/**
+ * This function will create a cdc rndis class instance.
+ *
+ * @param device the usb device object.
+ *
+ * @return RT_EOK on successful.
+ */
+ufunction_t rt_usbd_function_rndis_create(udevice_t device)
+{
+ ufunction_t cdc;
+ rt_rndis_eth_t _rndis;
+ cdc_eps_t eps;
+ uintf_t intf_comm, intf_data;
+ ualtsetting_t comm_setting, data_setting;
+ ucdc_data_desc_t data_desc;
+ ucdc_comm_desc_t comm_desc;
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+
+ /* set usb device string description */
+#ifdef RT_USB_DEVICE_COMPOSITE
+ rt_usbd_device_set_interface_string(device, RNDIS_INTF_STR_INDEX, _ustring[2]);
+#else
+ rt_usbd_device_set_string(device, _ustring);
+#endif
+ /* create a cdc class */
+ cdc = rt_usbd_function_new(device, &_dev_desc, &ops);
+ rt_usbd_device_set_qualifier(device, &dev_qualifier);
+ _rndis= rt_malloc(sizeof(struct rt_rndis_eth));
+
+ if(_rndis == RT_NULL)
+ {
+ LOG_E("%s,%d: no memory!", __func__, __LINE__);
+ return RT_NULL;
+ }
+
+ rt_memset(_rndis, 0, sizeof(struct rt_rndis_eth));
+ cdc->user_data = _rndis;
+
+ _rndis->func = cdc;
+ /* create a cdc class endpoints collection */
+ eps = &_rndis->eps;
+ /* create a cdc communication interface and a cdc data interface */
+ intf_comm = rt_usbd_interface_new(device, _interface_handler);
+ intf_data = rt_usbd_interface_new(device, _interface_handler);
+
+ if((intf_comm == RT_NULL) || (intf_data == RT_NULL))
+ {
+ LOG_E("%s,%d: no memory!", __func__, __LINE__);
+
+ if(intf_comm != RT_NULL)
+ rt_free(intf_comm);
+
+ if(intf_data != RT_NULL)
+ rt_free(intf_data);
+
+ return RT_NULL;
+ }
+
+ /* create a communication alternate setting and a data alternate setting */
+ comm_setting = rt_usbd_altsetting_new(sizeof(struct ucdc_comm_descriptor));
+ data_setting = rt_usbd_altsetting_new(sizeof(struct ucdc_data_descriptor));
+
+ /* config desc in alternate setting */
+ rt_usbd_altsetting_config_descriptor(comm_setting, &_comm_desc,
+ (rt_off_t)&((ucdc_comm_desc_t)0)->intf_desc);
+ rt_usbd_altsetting_config_descriptor(data_setting, &_data_desc, 0);
+ /* configure the cdc interface descriptor */
+ _cdc_descriptor_config(comm_setting->desc, intf_comm->intf_num, data_setting->desc, intf_data->intf_num, device->dcd->device_is_hs);
+
+ /* create a command endpoint */
+ comm_desc = (ucdc_comm_desc_t)comm_setting->desc;
+ eps->ep_cmd = rt_usbd_endpoint_new(&comm_desc->ep_desc, _ep_cmd_handler);
+ /* add the command endpoint to the cdc communication interface */
+ rt_usbd_altsetting_add_endpoint(comm_setting, eps->ep_cmd);
+
+ /* add the communication alternate setting to the communication interface,
+ then set default setting of the interface */
+ rt_usbd_interface_add_altsetting(intf_comm, comm_setting);
+ rt_usbd_set_altsetting(intf_comm, 0);
+ /* add the communication interface to the cdc class */
+ rt_usbd_function_add_interface(cdc, intf_comm);
+
+ /* create a bulk in and a bulk out endpoint */
+ data_desc = (ucdc_data_desc_t)data_setting->desc;
+ eps->ep_out = rt_usbd_endpoint_new(&data_desc->ep_out_desc, _ep_out_handler);
+ eps->ep_in = rt_usbd_endpoint_new(&data_desc->ep_in_desc, _ep_in_handler);
+
+ /* add the bulk out and bulk in endpoints to the data alternate setting */
+ rt_usbd_altsetting_add_endpoint(data_setting, eps->ep_in);
+ rt_usbd_altsetting_add_endpoint(data_setting, eps->ep_out);
+
+ /* add the data alternate setting to the data interface
+ then set default setting of the interface */
+ rt_usbd_interface_add_altsetting(intf_data, data_setting);
+ rt_usbd_set_altsetting(intf_data, 0);
+
+ /* add the cdc data interface to cdc class */
+ rt_usbd_function_add_interface(cdc, intf_data);
+
+ rt_usbd_os_comp_id_desc_add_os_func_comp_id_desc(device->os_comp_id_desc, &rndis_func_comp_id_desc);
+
+
+#ifdef RT_USING_LWIP
+
+ rt_list_init(&_rndis->response_list);
+ _rndis->need_notify = RT_TRUE;
+
+ rt_sem_init(&_rndis->tx_buffer_free, "ue_tx", 1, RT_IPC_FLAG_FIFO);
+
+#ifdef RNDIS_DELAY_LINK_UP
+ rt_timer_init(&_rndis->timer,
+ "RNDIS",
+ timer_timeout,
+ _rndis,
+ RT_TICK_PER_SECOND * 2,
+ RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER);
+#endif /* RNDIS_DELAY_LINK_UP */
+
+ /* OUI 00-00-00, only for test. */
+ _rndis->dev_addr[0] = 0x34;
+ _rndis->dev_addr[1] = 0x97;
+ _rndis->dev_addr[2] = 0xF6;
+ /* generate random MAC. */
+ _rndis->dev_addr[3] = 0x94;//*(const rt_uint8_t *)(0x1fff7a10);
+ _rndis->dev_addr[4] = 0xEA;//*(const rt_uint8_t *)(0x1fff7a14);
+ _rndis->dev_addr[5] = 0x12;//(const rt_uint8_t *)(0x1fff7a18);
+ /* OUI 00-00-00, only for test. */
+ _rndis->host_addr[0] = 0x34;
+ _rndis->host_addr[1] = 0x97;
+ _rndis->host_addr[2] = 0xF6;
+ /* generate random MAC. */
+ _rndis->host_addr[3] = 0x94;//*(const rt_uint8_t *)(0x0FE081F0);
+ _rndis->host_addr[4] = 0xEA;//*(const rt_uint8_t *)(0x0FE081F1);
+ _rndis->host_addr[5] = 0x13;//*(const rt_uint8_t *)(0x0FE081F2);
+
+#ifdef RT_USING_DEVICE_OPS
+ _rndis->parent.parent.ops = &rndis_device_ops;
+#else
+ _rndis->parent.parent.init = rt_rndis_eth_init;
+ _rndis->parent.parent.open = rt_rndis_eth_open;
+ _rndis->parent.parent.close = rt_rndis_eth_close;
+ _rndis->parent.parent.read = rt_rndis_eth_read;
+ _rndis->parent.parent.write = rt_rndis_eth_write;
+ _rndis->parent.parent.control = rt_rndis_eth_control;
+#endif
+ _rndis->parent.parent.user_data = device;
+
+ _rndis->parent.eth_rx = rt_rndis_eth_rx;
+ _rndis->parent.eth_tx = rt_rndis_eth_tx;
+
+ /* register eth device */
+ eth_device_init(&((rt_rndis_eth_t)cdc->user_data)->parent, "u0");
+
+#endif /* RT_USING_LWIP */
+
+ return cdc;
+}
+
+struct udclass rndis_class =
+{
+ .rt_usbd_function_create = rt_usbd_function_rndis_create
+};
+
+int rt_usbd_rndis_class_register(void)
+{
+ rt_usbd_class_register(&rndis_class);
+ return 0;
+}
+INIT_PREV_EXPORT(rt_usbd_rndis_class_register);
+
+#endif /* RT_USB_DEVICE_RNDIS */
diff --git a/components/legacy/usb/usbdevice/class/rndis.h b/components/legacy/usb/usbdevice/class/rndis.h
new file mode 100644
index 0000000000..c862b82c01
--- /dev/null
+++ b/components/legacy/usb/usbdevice/class/rndis.h
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2012-12-24 heyuanjie87 first version
+ */
+
+#ifndef __RNDIS_H__
+#define __RNDIS_H__
+
+#include <rtthread.h>
+
+#define USB_ETH_MTU 1500+14
+#define RNDIS_MESSAGE_BUFFER_SIZE 128
+
+#define RESPONSE_AVAILABLE 0x00000001
+
+/* Remote NDIS version numbers */
+#define RNDIS_MAJOR_VERSION 1
+#define RNDIS_MINOR_VERSION 0
+
+/* common status values */
+#define RNDIS_STATUS_SUCCESS 0X00000000
+#define RNDIS_STATUS_FAILURE 0XC0000001
+#define RNDIS_STATUS_INVALID_DATA 0XC0010015
+#define RNDIS_STATUS_NOT_SUPPORTED 0XC00000BB
+#define RNDIS_STATUS_MEDIA_CONNECT 0X4001000B
+#define RNDIS_STATUS_MEDIA_DISCONNECT 0X4001000C
+
+/* Remote NDIS message types */
+#define REMOTE_NDIS_PACKET_MSG 0x00000001
+#define REMOTE_NDIS_INITIALIZE_MSG 0X00000002
+#define REMOTE_NDIS_HALT_MSG 0X00000003
+#define REMOTE_NDIS_QUERY_MSG 0X00000004
+#define REMOTE_NDIS_SET_MSG 0X00000005
+#define REMOTE_NDIS_RESET_MSG 0X00000006
+#define REMOTE_NDIS_INDICATE_STATUS_MSG 0X00000007
+#define REMOTE_NDIS_KEEPALIVE_MSG 0X00000008
+#define REMOTE_NDIS_INITIALIZE_CMPLT 0X80000002
+#define REMOTE_NDIS_QUERY_CMPLT 0X80000004
+#define REMOTE_NDIS_SET_CMPLT 0X80000005
+#define REMOTE_NDIS_RESET_CMPLT 0X80000006
+#define REMOTE_NDIS_KEEPALIVE_CMPLT 0X80000008
+
+/* device flags */
+#define RNDIS_DF_CONNECTIONLESS 0x00000001
+#define RNDIS_DF_CONNECTION_ORIENTED 0x00000002
+/* mediums */
+#define RNDIS_MEDIUM_802_3 0x00000000
+
+struct ucls_rndis
+{
+ uep_t notify;
+ rt_uint32_t filter;
+ rt_bool_t header;
+ rt_uint8_t rndis_state;
+ rt_uint8_t media_state;
+ rt_uint8_t ethaddr[6];
+};
+
+/* Remote NDIS generic message type */
+struct rndis_gen_msg
+{
+ rt_uint32_t MessageType;
+ rt_uint32_t MessageLength;
+};
+typedef struct rndis_gen_msg* rndis_gen_msg_t;
+
+struct rndis_packet_msg
+{
+ rt_uint32_t MessageType;
+ rt_uint32_t MessageLength;
+ rt_uint32_t DataOffset;
+ rt_uint32_t DataLength;
+ rt_uint32_t OOBDataOffset;
+ rt_uint32_t OOBDataLength;
+ rt_uint32_t NumOOBDataElements;
+ rt_uint32_t PerPacketInfoOffset;
+ rt_uint32_t PerPacketInfoLength;
+ rt_uint32_t VcHandle;
+ rt_uint32_t Reserved;
+};
+typedef struct rndis_packet_msg* rndis_packet_msg_t;
+
+/* Remote NDIS Initialize Message */
+struct rndis_init_msg
+{
+ rt_uint32_t MessageType;
+ rt_uint32_t MessageLength;
+ rt_uint32_t RequestId;
+ rt_uint32_t MajorVersion;
+ rt_uint32_t MinorVersion;
+ rt_uint32_t MaxTransferSize;
+};
+typedef struct rndis_init_msg* rndis_init_msg_t;
+
+/* Response */
+struct rndis_init_cmplt
+{
+ rt_uint32_t MessageType;
+ rt_uint32_t MessageLength;
+ rt_uint32_t RequestId;
+ rt_uint32_t Status;
+ rt_uint32_t MajorVersion;
+ rt_uint32_t MinorVersion;
+ rt_uint32_t DeviceFlags;
+ rt_uint32_t Medium;
+ rt_uint32_t MaxPacketsPerTransfer;
+ rt_uint32_t MaxTransferSize;
+ rt_uint32_t PacketAlignmentFactor;
+ rt_uint32_t AfListOffset;
+ rt_uint32_t AfListSize;
+};
+typedef struct rndis_init_cmplt* rndis_init_cmplt_t;
+
+/* Remote NDIS Halt Message */
+struct rndis_halt_msg
+{
+ rt_uint32_t MessageType;
+ rt_uint32_t MessageLength;
+ rt_uint32_t RequestId;
+};
+
+/* Remote NDIS Query Message */
+struct rndis_query_msg
+{
+ rt_uint32_t MessageType;
+ rt_uint32_t MessageLength;
+ rt_uint32_t RequestId;
+ rt_uint32_t Oid;
+ rt_uint32_t InformationBufferLength;
+ rt_uint32_t InformationBufferOffset;
+ rt_uint32_t DeviceVcHandle;
+};
+typedef struct rndis_query_msg* rndis_query_msg_t;
+
+/* Response */
+struct rndis_query_cmplt
+{
+ rt_uint32_t MessageType;
+ rt_uint32_t MessageLength;
+ rt_uint32_t RequestId;
+ rt_uint32_t Status;
+ rt_uint32_t InformationBufferLength;
+ rt_uint32_t InformationBufferOffset;
+};
+typedef struct rndis_query_cmplt* rndis_query_cmplt_t;
+
+/* Remote NDIS Set Message */
+struct rndis_set_msg
+{
+ rt_uint32_t MessageType;
+ rt_uint32_t MessageLength;
+ rt_uint32_t RequestId;
+ rt_uint32_t Oid;
+ rt_uint32_t InformationBufferLength;
+ rt_uint32_t InformationBufferOffset;
+ rt_uint32_t DeviceVcHandle;
+};
+typedef struct rndis_set_msg* rndis_set_msg_t;
+
+/* Response */
+struct rndis_set_cmplt
+{
+ rt_uint32_t MessageType;
+ rt_uint32_t MessageLength;
+ rt_uint32_t RequestId;
+ rt_uint32_t Status;
+};
+typedef struct rndis_set_cmplt* rndis_set_cmplt_t;
+
+/* Remote NDIS Soft Reset Message */
+struct rndis_reset_msg
+{
+ rt_uint32_t MessageType;
+ rt_uint32_t MessageLength;
+ rt_uint32_t Reserved;
+};
+
+/* Remote NDIS Soft Reset Response */
+struct rndis_reset_cmplt
+{
+ rt_uint32_t MessageType;
+ rt_uint32_t MessageLength;
+ rt_uint32_t Status;
+ rt_uint32_t AddressingReset;
+};
+
+/* Remote NDIS Indicate Status Message */
+struct rndis_indicate_status_msg
+{
+ rt_uint32_t MessageType;
+ rt_uint32_t MessageLength;
+ rt_uint32_t Status;
+ rt_uint32_t StatusBufferLength;
+ rt_uint32_t StatusBufferOffset;
+};
+typedef struct rndis_indicate_status_msg* rndis_indicate_status_msg_t;
+
+struct rndis_keepalive_msg
+{
+ rt_uint32_t MessageType;
+ rt_uint32_t MessageLength;
+ rt_uint32_t RequestID;
+};
+typedef struct rndis_keepalive_msg* rndis_keepalive_msg_t;
+
+/* Response: */
+struct rndis_keepalive_cmplt
+{
+ rt_uint32_t MessageType;
+ rt_uint32_t MessageLength;
+ rt_uint32_t RequestId;
+ rt_uint32_t Status;
+};
+typedef struct rndis_keepalive_cmplt* rndis_keepalive_cmplt_t;
+
+
+
+
+
+
+
+#endif
diff --git a/components/legacy/usb/usbdevice/class/uaudioreg.h b/components/legacy/usb/usbdevice/class/uaudioreg.h
new file mode 100644
index 0000000000..eea3c2f053
--- /dev/null
+++ b/components/legacy/usb/usbdevice/class/uaudioreg.h
@@ -0,0 +1,419 @@
+/* $NetBSD: uaudioreg.h,v 1.15.38.1 2012/06/02 11:09:29 mrg Exp $ */
+
+/*
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson ([email protected]) at
+ * Carlstedt Research & Technology.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <rtdef.h>
+#include <stdint.h>
+
+typedef uint8_t uByte;
+typedef uint16_t uWord;
+
+#define UPACKED __attribute__ ((packed))
+
+#define UAUDIO_VERSION 0x100
+
+#define USB_SUBCLASS_AUDIOCONTROL 1
+#define USB_SUBCLASS_AUDIOSTREAMING 2
+#define USB_SUBCLASS_AUDIOMIDISTREAM 3
+
+#define UDESC_CS_CONFIG 0x22
+#define UDESC_CS_STRING 0x23
+#define UDESC_CS_INTERFACE 0x24
+#define UDESC_CS_ENDPOINT 0x25
+
+#define UDESCSUB_AC_HEADER 1
+#define UDESCSUB_AC_INPUT 2
+#define UDESCSUB_AC_OUTPUT 3
+#define UDESCSUB_AC_MIXER 4
+#define UDESCSUB_AC_SELECTOR 5
+#define UDESCSUB_AC_FEATURE 6
+#define UDESCSUB_AC_PROCESSING 7
+#define UDESCSUB_AC_EXTENSION 8
+
+#ifndef AUFMT_MAX_FREQUENCIES
+#define AUFMT_MAX_FREQUENCIES 1
+#endif
+
+/* The first fields are identical to usb_endpoint_descriptor_t */
+typedef struct {
+ uByte bLength;
+ uByte bDescriptorType;
+ uByte bEndpointAddress;
+ uByte bmAttributes;
+ uWord wMaxPacketSize;
+ uByte bInterval;
+ /*
+ * The following two entries are only used by the Audio Class.
+ * And according to the specs the Audio Class is the only one
+ * allowed to extend the endpoint descriptor.
+ * Who knows what goes on in the minds of the people in the USB
+ * standardization? :-(
+ */
+ uByte bRefresh;
+ uByte bSynchAddress;
+} UPACKED usb_endpoint_descriptor_audio_t;
+
+/* generic, for iteration */
+typedef struct {
+ uByte bLength;
+ uByte bDescriptorType;
+ uByte bDescriptorSubtype;
+} UPACKED uaudio_cs_descriptor_t;
+
+struct usb_audio_control_descriptor {
+ uByte bLength;
+ uByte bDescriptorType;
+ uByte bDescriptorSubtype;
+ uWord bcdADC;
+ uWord wTotalLength;
+ uByte bInCollection;
+ uByte baInterfaceNr[1];
+} UPACKED;
+
+struct usb_audio_streaming_interface_descriptor {
+ uByte bLength;
+ uByte bDescriptorType;
+ uByte bDescriptorSubtype;
+ uByte bTerminalLink;
+ uByte bDelay;
+ uWord wFormatTag;
+} UPACKED;
+
+struct usb_audio_streaming_endpoint_descriptor {
+ uByte bLength;
+ uByte bDescriptorType;
+ uByte bDescriptorSubtype;
+ uByte bmAttributes;
+#define UA_SED_FREQ_CONTROL 0x01
+#define UA_SED_PITCH_CONTROL 0x02
+#define UA_SED_MAXPACKETSONLY 0x80
+ uByte bLockDelayUnits;
+ uWord wLockDelay;
+} UPACKED;
+
+struct usb_audio_streaming_type1_descriptor {
+ uByte bLength;
+ uByte bDescriptorType;
+ uByte bDescriptorSubtype;
+ uByte bFormatType;
+ uByte bNrChannels;
+ uByte bSubFrameSize;
+ uByte bBitResolution;
+ uByte bSamFreqType;
+#define UA_SAMP_CONTNUOUS 0
+ uByte tSamFreq[3*AUFMT_MAX_FREQUENCIES];
+#define UA_GETSAMP(p, n) ((p)->tSamFreq[(n)*3+0] | ((p)->tSamFreq[(n)*3+1] << 8) | ((p)->tSamFreq[(n)*3+2] << 16))
+#define UA_SAMP_LO(p) UA_GETSAMP(p, 0)
+#define UA_SAMP_HI(p) UA_GETSAMP(p, 1)
+} UPACKED;
+
+struct usb_audio_cluster {
+ uByte bNrChannels;
+ uWord wChannelConfig;
+#define UA_CHANNEL_LEFT 0x0001
+#define UA_CHANNEL_RIGHT 0x0002
+#define UA_CHANNEL_CENTER 0x0004
+#define UA_CHANNEL_LFE 0x0008
+#define UA_CHANNEL_L_SURROUND 0x0010
+#define UA_CHANNEL_R_SURROUND 0x0020
+#define UA_CHANNEL_L_CENTER 0x0040
+#define UA_CHANNEL_R_CENTER 0x0080
+#define UA_CHANNEL_SURROUND 0x0100
+#define UA_CHANNEL_L_SIDE 0x0200
+#define UA_CHANNEL_R_SIDE 0x0400
+#define UA_CHANNEL_TOP 0x0800
+ uByte iChannelNames;
+} UPACKED;
+
+/* Shared by all units and terminals */
+struct usb_audio_unit {
+ uByte bLength;
+ uByte bDescriptorType;
+ uByte bDescriptorSubtype;
+ uByte bUnitId;
+};
+
+/* UDESCSUB_AC_INPUT */
+struct usb_audio_input_terminal {
+ uByte bLength;
+ uByte bDescriptorType;
+ uByte bDescriptorSubtype;
+ uByte bTerminalId;
+ uWord wTerminalType;
+ uByte bAssocTerminal;
+ uByte bNrChannels;
+ uWord wChannelConfig;
+ uByte iChannelNames;
+ uByte iTerminal;
+} UPACKED;
+
+/* UDESCSUB_AC_OUTPUT */
+struct usb_audio_output_terminal {
+ uByte bLength;
+ uByte bDescriptorType;
+ uByte bDescriptorSubtype;
+ uByte bTerminalId;
+ uWord wTerminalType;
+ uByte bAssocTerminal;
+ uByte bSourceId;
+ uByte iTerminal;
+} UPACKED;
+
+/* UDESCSUB_AC_MIXER */
+struct usb_audio_mixer_unit {
+ uByte bLength;
+ uByte bDescriptorType;
+ uByte bDescriptorSubtype;
+ uByte bUnitId;
+ uByte bNrInPins;
+ uByte baSourceId[255]; /* [bNrInPins] */
+ /* struct usb_audio_mixer_unit_1 */
+} UPACKED;
+struct usb_audio_mixer_unit_1 {
+ uByte bNrChannels;
+ uWord wChannelConfig;
+ uByte iChannelNames;
+ uByte bmControls[255]; /* [bNrChannels] */
+ /*uByte iMixer;*/
+} UPACKED;
+
+/* UDESCSUB_AC_SELECTOR */
+struct usb_audio_selector_unit {
+ uByte bLength;
+ uByte bDescriptorType;
+ uByte bDescriptorSubtype;
+ uByte bUnitId;
+ uByte bNrInPins;
+ uByte baSourceId[255]; /* [bNrInPins] */
+ /* uByte iSelector; */
+} UPACKED;
+
+/* UDESCSUB_AC_FEATURE */
+struct usb_audio_feature_unit {
+ uByte bLength;
+ uByte bDescriptorType;
+ uByte bDescriptorSubtype;
+ uByte bUnitId;
+ uByte bSourceId;
+ uByte bControlSize;
+ uByte bmaControls[2]; /* size for more than enough */
+ /* uByte iFeature; */
+} UPACKED;
+
+/* UDESCSUB_AC_PROCESSING */
+struct usb_audio_processing_unit {
+ uByte bLength;
+ uByte bDescriptorType;
+ uByte bDescriptorSubtype;
+ uByte bUnitId;
+ uWord wProcessType;
+ uByte bNrInPins;
+ uByte baSourceId[255]; /* [bNrInPins] */
+ /* struct usb_audio_processing_unit_1 */
+} UPACKED;
+struct usb_audio_processing_unit_1{
+ uByte bNrChannels;
+ uWord wChannelConfig;
+ uByte iChannelNames;
+ uByte bControlSize;
+ uByte bmControls[255]; /* [bControlSize] */
+#define UA_PROC_ENABLE_MASK 1
+} UPACKED;
+
+struct usb_audio_processing_unit_updown {
+ uByte iProcessing;
+ uByte bNrModes;
+ uWord waModes[255]; /* [bNrModes] */
+} UPACKED;
+
+/* UDESCSUB_AC_EXTENSION */
+struct usb_audio_extension_unit {
+ uByte bLength;
+ uByte bDescriptorType;
+ uByte bDescriptorSubtype;
+ uByte bUnitId;
+ uWord wExtensionCode;
+ uByte bNrInPins;
+ uByte baSourceId[255]; /* [bNrInPins] */
+ /* struct usb_audio_extension_unit_1 */
+} UPACKED;
+struct usb_audio_extension_unit_1 {
+ uByte bNrChannels;
+ uWord wChannelConfig;
+ uByte iChannelNames;
+ uByte bControlSize;
+ uByte bmControls[255]; /* [bControlSize] */
+#define UA_EXT_ENABLE_MASK 1
+#define UA_EXT_ENABLE 1
+ /*uByte iExtension;*/
+} UPACKED;
+
+/* USB terminal types */
+#define UAT_UNDEFINED 0x0100
+#define UAT_STREAM 0x0101
+#define UAT_VENDOR 0x01ff
+/* input terminal types */
+#define UATI_UNDEFINED 0x0200
+#define UATI_MICROPHONE 0x0201
+#define UATI_DESKMICROPHONE 0x0202
+#define UATI_PERSONALMICROPHONE 0x0203
+#define UATI_OMNIMICROPHONE 0x0204
+#define UATI_MICROPHONEARRAY 0x0205
+#define UATI_PROCMICROPHONEARR 0x0206
+/* output terminal types */
+#define UATO_UNDEFINED 0x0300
+#define UATO_SPEAKER 0x0301
+#define UATO_HEADPHONES 0x0302
+#define UATO_DISPLAYAUDIO 0x0303
+#define UATO_DESKTOPSPEAKER 0x0304
+#define UATO_ROOMSPEAKER 0x0305
+#define UATO_COMMSPEAKER 0x0306
+#define UATO_SUBWOOFER 0x0307
+/* bidir terminal types */
+#define UATB_UNDEFINED 0x0400
+#define UATB_HANDSET 0x0401
+#define UATB_HEADSET 0x0402
+#define UATB_SPEAKERPHONE 0x0403
+#define UATB_SPEAKERPHONEESUP 0x0404
+#define UATB_SPEAKERPHONEECANC 0x0405
+/* telephony terminal types */
+#define UATT_UNDEFINED 0x0500
+#define UATT_PHONELINE 0x0501
+#define UATT_TELEPHONE 0x0502
+#define UATT_DOWNLINEPHONE 0x0503
+/* external terminal types */
+#define UATE_UNDEFINED 0x0600
+#define UATE_ANALOGCONN 0x0601
+#define UATE_DIGITALAUIFC 0x0602
+#define UATE_LINECONN 0x0603
+#define UATE_LEGACYCONN 0x0604
+#define UATE_SPDIF 0x0605
+#define UATE_1394DA 0x0606
+#define UATE_1394DV 0x0607
+/* embedded function terminal types */
+#define UATF_UNDEFINED 0x0700
+#define UATF_CALIBNOISE 0x0701
+#define UATF_EQUNOISE 0x0702
+#define UATF_CDPLAYER 0x0703
+#define UATF_DAT 0x0704
+#define UATF_DCC 0x0705
+#define UATF_MINIDISK 0x0706
+#define UATF_ANALOGTAPE 0x0707
+#define UATF_PHONOGRAPH 0x0708
+#define UATF_VCRAUDIO 0x0709
+#define UATF_VIDEODISCAUDIO 0x070a
+#define UATF_DVDAUDIO 0x070b
+#define UATF_TVTUNERAUDIO 0x070c
+#define UATF_SATELLITE 0x070d
+#define UATF_CABLETUNER 0x070e
+#define UATF_DSS 0x070f
+#define UATF_RADIORECV 0x0710
+#define UATF_RADIOXMIT 0x0711
+#define UATF_MULTITRACK 0x0712
+#define UATF_SYNTHESIZER 0x0713
+
+
+#define SET_CUR 0x01
+#define GET_CUR 0x81
+#define SET_MIN 0x02
+#define GET_MIN 0x82
+#define SET_MAX 0x03
+#define GET_MAX 0x83
+#define SET_RES 0x04
+#define GET_RES 0x84
+#define SET_MEM 0x05
+#define GET_MEM 0x85
+#define GET_STAT 0xff
+
+#define MUTE_CONTROL 0x01
+#define VOLUME_CONTROL 0x02
+#define BASS_CONTROL 0x03
+#define MID_CONTROL 0x04
+#define TREBLE_CONTROL 0x05
+#define GRAPHIC_EQUALIZER_CONTROL 0x06
+#define AGC_CONTROL 0x07
+#define DELAY_CONTROL 0x08
+#define BASS_BOOST_CONTROL 0x09
+#define LOUDNESS_CONTROL 0x0a
+
+#define FU_MASK(u) (1 << ((u)-1))
+
+#define MASTER_CHAN 0
+
+#define AS_GENERAL 1
+#define FORMAT_TYPE 2
+#define FORMAT_SPECIFIC 3
+
+#define UA_FMT_PCM 1
+#define UA_FMT_PCM8 2
+#define UA_FMT_IEEE_FLOAT 3
+#define UA_FMT_ALAW 4
+#define UA_FMT_MULAW 5
+#define UA_FMT_MPEG 0x1001
+#define UA_FMT_AC3 0x1002
+
+#define SAMPLING_FREQ_CONTROL 0x01
+#define PITCH_CONTROL 0x02
+
+#define FORMAT_TYPE_UNDEFINED 0
+#define FORMAT_TYPE_I 1
+#define FORMAT_TYPE_II 2
+#define FORMAT_TYPE_III 3
+
+#define UA_PROC_MASK(n) (1<< ((n)-1))
+#define PROCESS_UNDEFINED 0
+#define XX_ENABLE_CONTROL 1
+#define UPDOWNMIX_PROCESS 1
+#define UD_ENABLE_CONTROL 1
+#define UD_MODE_SELECT_CONTROL 2
+#define DOLBY_PROLOGIC_PROCESS 2
+#define DP_ENABLE_CONTROL 1
+#define DP_MODE_SELECT_CONTROL 2
+#define P3D_STEREO_EXTENDER_PROCESS 3
+#define P3D_ENABLE_CONTROL 1
+#define P3D_SPACIOUSNESS_CONTROL 2
+#define REVERBATION_PROCESS 4
+#define RV_ENABLE_CONTROL 1
+#define RV_LEVEL_CONTROL 2
+#define RV_TIME_CONTROL 3
+#define RV_FEEDBACK_CONTROL 4
+#define CHORUS_PROCESS 5
+#define CH_ENABLE_CONTROL 1
+#define CH_LEVEL_CONTROL 2
+#define CH_RATE_CONTROL 3
+#define CH_DEPTH_CONTROL 4
+#define DYN_RANGE_COMP_PROCESS 6
+#define DR_ENABLE_CONTROL 1
+#define DR_COMPRESSION_RATE_CONTROL 2
+#define DR_MAXAMPL_CONTROL 3
+#define DR_THRESHOLD_CONTROL 4
+#define DR_ATTACK_TIME_CONTROL 5
+#define DR_RELEASE_TIME_CONTROL 6
diff --git a/components/legacy/usb/usbdevice/class/winusb.c b/components/legacy/usb/usbdevice/class/winusb.c
new file mode 100644
index 0000000000..f39dab9f06
--- /dev/null
+++ b/components/legacy/usb/usbdevice/class/winusb.c
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2017-11-16 ZYH first version
+ */
+#include <rthw.h>
+#include <rtdevice.h>
+#include <drivers/usb_device.h>
+#include "winusb.h"
+struct winusb_device
+{
+ struct rt_device parent;
+ void (*cmd_handler)(rt_uint8_t *buffer,rt_size_t size);
+ rt_uint8_t cmd_buff[256];
+ uep_t ep_out;
+ uep_t ep_in;
+};
+#define WINUSB_INTF_STR_INDEX 13
+typedef struct winusb_device * winusb_device_t;
+
+rt_align(4)
+static struct udevice_descriptor dev_desc =
+{
+ USB_DESC_LENGTH_DEVICE, //bLength;
+ USB_DESC_TYPE_DEVICE, //type;
+ USB_BCD_VERSION, //bcdUSB;
+ 0x00, //bDeviceClass;
+ 0x00, //bDeviceSubClass;
+ 0x00, //bDeviceProtocol;
+ 0x40, //bMaxPacketSize0;
+ _VENDOR_ID, //idVendor;
+ _PRODUCT_ID, //idProduct;
+ USB_BCD_DEVICE, //bcdDevice;
+ USB_STRING_MANU_INDEX, //iManufacturer;
+ USB_STRING_PRODUCT_INDEX, //iProduct;
+ USB_STRING_SERIAL_INDEX, //iSerialNumber;
+ USB_DYNAMIC, //bNumConfigurations;
+};
+
+//FS and HS needed
+rt_align(4)
+static struct usb_qualifier_descriptor dev_qualifier =
+{
+ sizeof(dev_qualifier), //bLength
+ USB_DESC_TYPE_DEVICEQUALIFIER, //bDescriptorType
+ 0x0200, //bcdUSB
+ 0xFF, //bDeviceClass
+ 0x00, //bDeviceSubClass
+ 0x00, //bDeviceProtocol
+ 64, //bMaxPacketSize0
+ 0x01, //bNumConfigurations
+ 0,
+};
+
+rt_align(4)
+struct winusb_descriptor _winusb_desc =
+{
+#ifdef RT_USB_DEVICE_COMPOSITE
+ /* Interface Association Descriptor */
+ {
+ USB_DESC_LENGTH_IAD,
+ USB_DESC_TYPE_IAD,
+ USB_DYNAMIC,
+ 0x01,
+ 0xFF,
+ 0x00,
+ 0x00,
+ 0x00,
+ },
+#endif
+ /*interface descriptor*/
+ {
+ USB_DESC_LENGTH_INTERFACE, //bLength;
+ USB_DESC_TYPE_INTERFACE, //type;
+ USB_DYNAMIC, //bInterfaceNumber;
+ 0x00, //bAlternateSetting;
+ 0x02, //bNumEndpoints
+ 0xFF, //bInterfaceClass;
+ 0x00, //bInterfaceSubClass;
+ 0x00, //bInterfaceProtocol;
+#ifdef RT_USB_DEVICE_COMPOSITE
+ WINUSB_INTF_STR_INDEX,
+#else
+ 0x00, //iInterface;
+#endif
+ },
+ /*endpoint descriptor*/
+ {
+ USB_DESC_LENGTH_ENDPOINT,
+ USB_DESC_TYPE_ENDPOINT,
+ USB_DYNAMIC | USB_DIR_OUT,
+ USB_EP_ATTR_BULK,
+ USB_DYNAMIC,
+ 0x00,
+ },
+ /*endpoint descriptor*/
+ {
+ USB_DESC_LENGTH_ENDPOINT,
+ USB_DESC_TYPE_ENDPOINT,
+ USB_DYNAMIC | USB_DIR_IN,
+ USB_EP_ATTR_BULK,
+ USB_DYNAMIC,
+ 0x00,
+ },
+};
+
+rt_align(4)
+const static char* _ustring[] =
+{
+ "Language",
+ "RT-Thread Team.",
+ "RTT Win USB",
+ "32021919830108",
+ "Configuration",
+ "Interface",
+ USB_STRING_OS//must be
+};
+
+rt_align(4)
+struct usb_os_proerty winusb_proerty[] =
+{
+ USB_OS_PROPERTY_DESC(USB_OS_PROPERTY_TYPE_REG_SZ,"DeviceInterfaceGUID",RT_WINUSB_GUID),
+};
+
+rt_align(4)
+struct usb_os_function_comp_id_descriptor winusb_func_comp_id_desc =
+{
+ .bFirstInterfaceNumber = USB_DYNAMIC,
+ .reserved1 = 0x01,
+ .compatibleID = {'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00},
+ .subCompatibleID = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ .reserved2 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+
+static rt_err_t _ep_out_handler(ufunction_t func, rt_size_t size)
+{
+ winusb_device_t winusb_device = (winusb_device_t)func->user_data;
+ if(winusb_device->parent.rx_indicate != RT_NULL)
+ {
+ winusb_device->parent.rx_indicate(&winusb_device->parent, size);
+ }
+ return RT_EOK;
+}
+
+static rt_err_t _ep_in_handler(ufunction_t func, rt_size_t size)
+{
+ winusb_device_t winusb_device = (winusb_device_t)func->user_data;
+ if(winusb_device->parent.tx_complete != RT_NULL)
+ {
+ winusb_device->parent.tx_complete(&winusb_device->parent, winusb_device->ep_in->buffer);
+ }
+ return RT_EOK;
+}
+static ufunction_t cmd_func = RT_NULL;
+static rt_err_t _ep0_cmd_handler(udevice_t device, rt_size_t size)
+{
+ winusb_device_t winusb_device;
+
+ if(cmd_func != RT_NULL)
+ {
+ winusb_device = (winusb_device_t)cmd_func->user_data;
+ cmd_func = RT_NULL;
+ if(winusb_device->cmd_handler != RT_NULL)
+ {
+ winusb_device->cmd_handler(winusb_device->cmd_buff,size);
+ }
+ }
+ dcd_ep0_send_status(device->dcd);
+ return RT_EOK;
+}
+static rt_err_t _ep0_cmd_read(ufunction_t func, ureq_t setup)
+{
+ winusb_device_t winusb_device = (winusb_device_t)func->user_data;
+ cmd_func = func;
+ rt_usbd_ep0_read(func->device,winusb_device->cmd_buff,setup->wLength,_ep0_cmd_handler);
+ return RT_EOK;
+}
+static rt_err_t _interface_handler(ufunction_t func, ureq_t setup)
+{
+ switch(setup->bRequest)
+ {
+ case 'A':
+ switch(setup->wIndex)
+ {
+ case 0x05:
+ usbd_os_proerty_descriptor_send(func,setup,winusb_proerty,sizeof(winusb_proerty)/sizeof(winusb_proerty[0]));
+ break;
+ }
+ break;
+ case 0x0A://customer
+ _ep0_cmd_read(func, setup);
+ break;
+ }
+
+ return RT_EOK;
+}
+static rt_err_t _function_enable(ufunction_t func)
+{
+ RT_ASSERT(func != RT_NULL);
+ return RT_EOK;
+}
+static rt_err_t _function_disable(ufunction_t func)
+{
+ RT_ASSERT(func != RT_NULL);
+ return RT_EOK;
+}
+
+static struct ufunction_ops ops =
+{
+ _function_enable,
+ _function_disable,
+ RT_NULL,
+};
+
+static rt_err_t _winusb_descriptor_config(winusb_desc_t winusb, rt_uint8_t cintf_nr, rt_uint8_t device_is_hs)
+{
+#ifdef RT_USB_DEVICE_COMPOSITE
+ winusb->iad_desc.bFirstInterface = cintf_nr;
+#endif
+ winusb->ep_out_desc.wMaxPacketSize = device_is_hs ? 512 : 64;
+ winusb->ep_in_desc.wMaxPacketSize = device_is_hs ? 512 : 64;
+ winusb_func_comp_id_desc.bFirstInterfaceNumber = cintf_nr;
+ return RT_EOK;
+}
+
+static rt_ssize_t win_usb_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
+{
+ if(((ufunction_t)dev->user_data)->device->state != USB_STATE_CONFIGURED)
+ {
+ return 0;
+ }
+ winusb_device_t winusb_device = (winusb_device_t)dev;
+ winusb_device->ep_out->buffer = buffer;
+ winusb_device->ep_out->request.buffer = buffer;
+ winusb_device->ep_out->request.size = size;
+ winusb_device->ep_out->request.req_type = UIO_REQUEST_READ_FULL;
+ rt_usbd_io_request(((ufunction_t)dev->user_data)->device,winusb_device->ep_out,&winusb_device->ep_out->request);
+ return size;
+}
+static rt_ssize_t win_usb_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
+{
+ if(((ufunction_t)dev->user_data)->device->state != USB_STATE_CONFIGURED)
+ {
+ return 0;
+ }
+ winusb_device_t winusb_device = (winusb_device_t)dev;
+ winusb_device->ep_in->buffer = (void *)buffer;
+ winusb_device->ep_in->request.buffer = winusb_device->ep_in->buffer;
+ winusb_device->ep_in->request.size = size;
+ winusb_device->ep_in->request.req_type = UIO_REQUEST_WRITE;
+ rt_usbd_io_request(((ufunction_t)dev->user_data)->device,winusb_device->ep_in,&winusb_device->ep_in->request);
+ return size;
+}
+static rt_err_t win_usb_control(rt_device_t dev, int cmd, void *args)
+{
+ winusb_device_t winusb_device = (winusb_device_t)dev;
+ if(RT_DEVICE_CTRL_CONFIG == cmd)
+ {
+ winusb_device->cmd_handler = (void(*)(rt_uint8_t*,rt_size_t))args;
+ }
+ return RT_EOK;
+}
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops winusb_device_ops =
+{
+ RT_NULL,
+ RT_NULL,
+ RT_NULL,
+ win_usb_read,
+ win_usb_write,
+ win_usb_control,
+};
+#endif
+
+static rt_err_t rt_usb_winusb_init(ufunction_t func)
+{
+ winusb_device_t winusb_device = (winusb_device_t)func->user_data;
+ winusb_device->parent.type = RT_Device_Class_Miscellaneous;
+
+#ifdef RT_USING_DEVICE_OPS
+ winusb_device->parent.ops = &winusb_device_ops;
+#else
+ winusb_device->parent.init = RT_NULL;
+ winusb_device->parent.open = RT_NULL;
+ winusb_device->parent.close = RT_NULL;
+ winusb_device->parent.read = win_usb_read;
+ winusb_device->parent.write = win_usb_write;
+ winusb_device->parent.control = win_usb_control;
+#endif
+
+ winusb_device->parent.user_data = func;
+
+
+ return rt_device_register(&winusb_device->parent, "winusb", RT_DEVICE_FLAG_RDWR);
+}
+
+ufunction_t rt_usbd_function_winusb_create(udevice_t device)
+{
+ ufunction_t func;
+ winusb_device_t winusb_device;
+
+ uintf_t winusb_intf;
+ ualtsetting_t winusb_setting;
+ winusb_desc_t winusb_desc;
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+
+ /* set usb device string description */
+#ifdef RT_USB_DEVICE_COMPOSITE
+ rt_usbd_device_set_interface_string(device, WINUSB_INTF_STR_INDEX, _ustring[2]);
+#else
+ rt_usbd_device_set_string(device, _ustring);
+#endif
+
+ /* create a cdc function */
+ func = rt_usbd_function_new(device, &dev_desc, &ops);
+ rt_usbd_device_set_qualifier(device, &dev_qualifier);
+
+ /* allocate memory for cdc vcom data */
+ winusb_device = (winusb_device_t)rt_malloc(sizeof(struct winusb_device));
+ if (winusb_device == NULL)
+ return RT_NULL;
+ rt_memset((void *)winusb_device, 0, sizeof(struct winusb_device));
+ func->user_data = (void*)winusb_device;
+ /* create an interface object */
+ winusb_intf = rt_usbd_interface_new(device, _interface_handler);
+
+ /* create an alternate setting object */
+ winusb_setting = rt_usbd_altsetting_new(sizeof(struct winusb_descriptor));
+
+ /* config desc in alternate setting */
+ rt_usbd_altsetting_config_descriptor(winusb_setting, &_winusb_desc, (rt_off_t)&((winusb_desc_t)0)->intf_desc);
+
+ /* configure the hid interface descriptor */
+ _winusb_descriptor_config(winusb_setting->desc, winusb_intf->intf_num, device->dcd->device_is_hs);
+
+ /* create endpoint */
+ winusb_desc = (winusb_desc_t)winusb_setting->desc;
+ winusb_device->ep_out = rt_usbd_endpoint_new(&winusb_desc->ep_out_desc, _ep_out_handler);
+ winusb_device->ep_in = rt_usbd_endpoint_new(&winusb_desc->ep_in_desc, _ep_in_handler);
+
+ /* add the int out and int in endpoint to the alternate setting */
+ rt_usbd_altsetting_add_endpoint(winusb_setting, winusb_device->ep_out);
+ rt_usbd_altsetting_add_endpoint(winusb_setting, winusb_device->ep_in);
+
+ /* add the alternate setting to the interface, then set default setting */
+ rt_usbd_interface_add_altsetting(winusb_intf, winusb_setting);
+ rt_usbd_set_altsetting(winusb_intf, 0);
+
+ /* add the interface to the mass storage function */
+ rt_usbd_function_add_interface(func, winusb_intf);
+
+ rt_usbd_os_comp_id_desc_add_os_func_comp_id_desc(device->os_comp_id_desc, &winusb_func_comp_id_desc);
+ /* initilize winusb */
+ rt_usb_winusb_init(func);
+ return func;
+}
+
+struct udclass winusb_class =
+{
+ .rt_usbd_function_create = rt_usbd_function_winusb_create
+};
+
+int rt_usbd_winusb_class_register(void)
+{
+ rt_usbd_class_register(&winusb_class);
+ return 0;
+}
+INIT_PREV_EXPORT(rt_usbd_winusb_class_register);
diff --git a/components/legacy/usb/usbdevice/class/winusb.h b/components/legacy/usb/usbdevice/class/winusb.h
new file mode 100644
index 0000000000..06325a0b03
--- /dev/null
+++ b/components/legacy/usb/usbdevice/class/winusb.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2017-11-16 ZYH first version
+ */
+#ifndef __WINUSB_H__
+#define __WINUSB_H__
+#include <rtthread.h>
+struct winusb_descriptor
+{
+#ifdef RT_USB_DEVICE_COMPOSITE
+ struct uiad_descriptor iad_desc;
+#endif
+ struct uinterface_descriptor intf_desc;
+ struct uendpoint_descriptor ep_out_desc;
+ struct uendpoint_descriptor ep_in_desc;
+};
+typedef struct winusb_descriptor* winusb_desc_t;
+
+#endif
diff --git a/components/legacy/usb/usbdevice/core/usbdevice.c b/components/legacy/usb/usbdevice/core/usbdevice.c
new file mode 100644
index 0000000000..eaa80217c8
--- /dev/null
+++ b/components/legacy/usb/usbdevice/core/usbdevice.c
@@ -0,0 +1,164 @@
+/*
+ * File : hid.c
+ * COPYRIGHT (C) 2006 - 2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2012-10-02 Yi Qiu first version
+ */
+
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <rtservice.h>
+
+#ifdef RT_USING_USB_DEVICE
+
+#define USB_DEVICE_CONTROLLER_NAME "usbd"
+
+#ifdef RT_USB_DEVICE_COMPOSITE
+const static char* ustring[] =
+{
+ "Language",
+ "RT-Thread Team.",
+ "RTT Composite Device",
+ "320219198301",
+ "Configuration",
+ "Interface",
+ USB_STRING_OS
+};
+
+static struct udevice_descriptor compsit_desc =
+{
+ USB_DESC_LENGTH_DEVICE, //bLength;
+ USB_DESC_TYPE_DEVICE, //type;
+ USB_BCD_VERSION, //bcdUSB;
+ USB_CLASS_MISC, //bDeviceClass;
+ 0x02, //bDeviceSubClass;
+ 0x01, //bDeviceProtocol;
+ 0x40, //bMaxPacketSize0;
+ _VENDOR_ID, //idVendor;
+ _PRODUCT_ID, //idProduct;
+ USB_BCD_DEVICE, //bcdDevice;
+ USB_STRING_MANU_INDEX, //iManufacturer;
+ USB_STRING_PRODUCT_INDEX, //iProduct;
+ USB_STRING_SERIAL_INDEX, //iSerialNumber;
+ USB_DYNAMIC, //bNumConfigurations;
+};
+
+//FS and HS needed
+static struct usb_qualifier_descriptor dev_qualifier =
+{
+ sizeof(dev_qualifier), //bLength
+ USB_DESC_TYPE_DEVICEQUALIFIER, //bDescriptorType
+ 0x0200, //bcdUSB
+ USB_CLASS_MISC, //bDeviceClass
+ 0x02, //bDeviceSubClass
+ 0x01, //bDeviceProtocol
+ 64, //bMaxPacketSize0
+ 0x01, //bNumConfigurations
+ 0,
+};
+#endif
+
+struct usb_os_comp_id_descriptor usb_comp_id_desc =
+{
+ //head section
+ {
+ USB_DYNAMIC,
+ 0x0100,
+ 0x04,
+ USB_DYNAMIC,
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ },
+};
+static rt_list_t class_list;
+int rt_usbd_class_list_init(void)
+{
+ rt_list_init(&class_list);
+ return 0;
+}
+INIT_BOARD_EXPORT(rt_usbd_class_list_init);
+
+rt_err_t rt_usbd_class_register(udclass_t udclass)
+{
+#ifndef RT_USB_DEVICE_COMPOSITE
+ if(!rt_list_isempty(&class_list))
+ {
+ rt_kprintf("[D/USBD] If you want to use usb composite device please define RT_USB_DEVICE_COMPOSITE\n");
+ return -RT_ERROR;
+ }
+#endif
+ rt_list_insert_before(&class_list,&udclass->list);
+ return RT_EOK;
+}
+
+rt_err_t rt_usb_device_init(void)
+{
+ rt_device_t udc;
+ udevice_t udevice;
+ uconfig_t cfg;
+ ufunction_t func;
+ rt_list_t *i;
+ udclass_t udclass;
+
+ if(rt_list_isempty(&class_list))
+ {
+ rt_kprintf("[D/USBD] No class register on usb device\n");
+ return -RT_ERROR;
+ }
+ /* create and startup usb device thread */
+ rt_usbd_core_init();
+
+ /* create a device object */
+ udevice = rt_usbd_device_new();
+
+ udc = rt_device_find(USB_DEVICE_CONTROLLER_NAME);
+ if(udc == RT_NULL)
+ {
+ rt_kprintf("can't find usb device controller %s\n", USB_DEVICE_CONTROLLER_NAME);
+ return -RT_ERROR;
+ }
+
+ /* set usb controller driver to the device */
+ rt_usbd_device_set_controller(udevice, (udcd_t)udc);
+
+ /* create a configuration object */
+ cfg = rt_usbd_config_new();
+
+ rt_usbd_device_set_os_comp_id_desc(udevice, &usb_comp_id_desc);
+
+ for(i = class_list.next; i!= &class_list; i = i->next)
+ {
+ /* get a class creater */
+ udclass = rt_list_entry(i, struct udclass, list);
+ /* create a function object */
+ func = udclass->rt_usbd_function_create(udevice);
+ /* add the function to the configuration */
+ rt_usbd_config_add_function(cfg, func);
+ }
+ /* set device descriptor to the device */
+#ifdef RT_USB_DEVICE_COMPOSITE
+ rt_usbd_device_set_descriptor(udevice, &compsit_desc);
+ rt_usbd_device_set_string(udevice, ustring);
+ if(udevice->dcd->device_is_hs)
+ {
+ rt_usbd_device_set_qualifier(udevice, &dev_qualifier);
+ }
+#else
+ rt_usbd_device_set_descriptor(udevice, func->dev_desc);
+#endif
+
+ /* add the configuration to the device */
+ rt_usbd_device_add_config(udevice, cfg);
+
+ /* initialize usb device controller */
+ rt_device_init(udc);
+
+ /* set default configuration to 1 */
+ rt_usbd_set_config(udevice, 1);
+
+ return RT_EOK;
+}
+#endif
diff --git a/components/legacy/usb/usbdevice/core/usbdevice_core.c b/components/legacy/usb/usbdevice/core/usbdevice_core.c
new file mode 100644
index 0000000000..015473ffde
--- /dev/null
+++ b/components/legacy/usb/usbdevice/core/usbdevice_core.c
@@ -0,0 +1,2269 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2012-10-01 Yi Qiu first version
+ * 2012-12-12 heyuanjie87 change endpoint and function handler
+ * 2012-12-30 heyuanjie87 change inferface handler
+ * 2013-04-26 aozima add DEVICEQUALIFIER support.
+ * 2013-07-25 Yi Qiu update for USB CV test
+ * 2017-11-15 ZYH fix ep0 transform error
+ */
+
+#include <rtthread.h>
+#include "drivers/usb_common.h"
+#include "drivers/usb_device.h"
+
+#define DBG_TAG "usbdevice.core"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+static rt_list_t device_list;
+
+static rt_ssize_t rt_usbd_ep_write(udevice_t device, uep_t ep, void *buffer, rt_size_t size);
+static rt_ssize_t rt_usbd_ep_read_prepare(udevice_t device, uep_t ep, void *buffer, rt_size_t size);
+static rt_err_t rt_usbd_ep_assign(udevice_t device, uep_t ep);
+rt_err_t rt_usbd_ep_unassign(udevice_t device, uep_t ep);
+
+/**
+ * This function will handle get_device_descriptor bRequest.
+ *
+ * @param device the usb device object.
+ * @param setup the setup bRequest.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _get_device_descriptor(struct udevice* device, ureq_t setup)
+{
+ rt_size_t size;
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(setup != RT_NULL);
+
+ LOG_D("_get_device_descriptor");
+
+ /* device descriptor wLength should less than USB_DESC_LENGTH_DEVICE*/
+ size = (setup->wLength > USB_DESC_LENGTH_DEVICE) ?
+ USB_DESC_LENGTH_DEVICE : setup->wLength;
+
+ /* send device descriptor to endpoint 0 */
+ rt_usbd_ep0_write(device, (rt_uint8_t*) &device->dev_desc, size);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will handle get_config_descriptor bRequest.
+ *
+ * @param device the usb device object.
+ * @param setup the setup bRequest.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _get_config_descriptor(struct udevice* device, ureq_t setup)
+{
+ rt_size_t size;
+ ucfg_desc_t cfg_desc;
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(setup != RT_NULL);
+
+ LOG_D("_get_config_descriptor");
+
+ cfg_desc = &device->curr_cfg->cfg_desc;
+ size = (setup->wLength > cfg_desc->wTotalLength) ?
+ cfg_desc->wTotalLength : setup->wLength;
+
+ /* send configuration descriptor to endpoint 0 */
+ rt_usbd_ep0_write(device, (rt_uint8_t*)cfg_desc, size);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will handle get_string_descriptor bRequest.
+ *
+ * @param device the usb device object.
+ * @param setup the setup bRequest.
+ *
+ * @return RT_EOK on successful, -RT_ERROR on invalid bRequest.
+ */
+static rt_err_t _get_string_descriptor(struct udevice* device, ureq_t setup)
+{
+ struct ustring_descriptor str_desc;
+ rt_uint8_t index, i;
+ rt_uint32_t len;
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(setup != RT_NULL);
+
+ LOG_D("_get_string_descriptor");
+
+ str_desc.type = USB_DESC_TYPE_STRING;
+ index = setup->wValue & 0xFF;
+
+ if(index == 0xEE)
+ {
+ index = USB_STRING_OS_INDEX;
+ }
+
+ if(index > USB_STRING_MAX)
+ {
+ rt_kprintf("unknown string index\n");
+ rt_usbd_ep0_set_stall(device);
+ return -RT_ERROR;
+ }
+ else if(index == USB_STRING_LANGID_INDEX)
+ {
+ str_desc.bLength = 4;
+ str_desc.String[0] = 0x09;
+ str_desc.String[1] = 0x04;
+ }
+ else
+ {
+ if(index < 5)
+ len = rt_strlen(device->str[index]);
+ else
+ len = rt_strlen(device->str_intf[index]);
+ str_desc.bLength = len*2 + 2;
+
+ for(i=0; i<len; i++)
+ {
+ if(index < 5)
+ str_desc.String[i*2] = device->str[index][i];
+ else
+ str_desc.String[i*2] = device->str_intf[index][i];
+ str_desc.String[i*2 + 1] = 0;
+ }
+ }
+
+ if (setup->wLength > str_desc.bLength)
+ len = str_desc.bLength;
+ else
+ len = setup->wLength;
+
+ /* send string descriptor to endpoint 0 */
+ rt_usbd_ep0_write(device, (rt_uint8_t*)&str_desc, len);
+
+ return RT_EOK;
+}
+
+static rt_err_t _get_qualifier_descriptor(struct udevice* device, ureq_t setup)
+{
+ LOG_D("_get_qualifier_descriptor");
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(setup != RT_NULL);
+
+ if(device->dev_qualifier && device->dcd->device_is_hs)
+ {
+ /* send device qualifier descriptor to endpoint 0 */
+ rt_usbd_ep0_write(device, (rt_uint8_t*)device->dev_qualifier,
+ sizeof(struct usb_qualifier_descriptor));
+ }
+ else
+ {
+ rt_usbd_ep0_set_stall(device);
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * This function will handle get_descriptor bRequest.
+ *
+ * @param device the usb device object.
+ * @param setup the setup bRequest.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _get_descriptor(struct udevice* device, ureq_t setup)
+{
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(setup != RT_NULL);
+
+ if(setup->request_type == USB_REQ_TYPE_DIR_IN)
+ {
+ switch(setup->wValue >> 8)
+ {
+ case USB_DESC_TYPE_DEVICE:
+ _get_device_descriptor(device, setup);
+ break;
+ case USB_DESC_TYPE_CONFIGURATION:
+ _get_config_descriptor(device, setup);
+ break;
+ case USB_DESC_TYPE_STRING:
+ _get_string_descriptor(device, setup);
+ break;
+ case USB_DESC_TYPE_DEVICEQUALIFIER:
+ /* If a full-speed only device (with a device descriptor version number equal to 0200H) receives a
+ GetDescriptor() request for a device_qualifier, it must respond with a request error. The host must not make
+ a request for an other_speed_configuration descriptor unless it first successfully retrieves the
+ device_qualifier descriptor. */
+ if(device->dcd->device_is_hs)
+ {
+ _get_qualifier_descriptor(device, setup);
+ }
+ else
+ {
+ rt_usbd_ep0_set_stall(device);
+ }
+ break;
+ case USB_DESC_TYPE_OTHERSPEED:
+ _get_config_descriptor(device, setup);
+ break;
+ default:
+ rt_kprintf("unsupported descriptor request\n");
+ rt_usbd_ep0_set_stall(device);
+ break;
+ }
+ }
+ else
+ {
+ rt_kprintf("request direction error\n");
+ rt_usbd_ep0_set_stall(device);
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * This function will handle get_interface bRequest.
+ *
+ * @param device the usb device object.
+ * @param setup the setup bRequest.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _get_interface(struct udevice* device, ureq_t setup)
+{
+ rt_uint8_t value;
+ uintf_t intf;
+ ufunction_t func;
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(setup != RT_NULL);
+
+ LOG_D("_get_interface");
+
+ if (device->state != USB_STATE_CONFIGURED)
+ {
+ rt_usbd_ep0_set_stall(device);
+ return -RT_ERROR;
+ }
+
+ /* find the specified interface and its alternate setting */
+ intf = rt_usbd_find_interface(device, setup->wIndex & 0xFF, &func);
+ value = intf->curr_setting->intf_desc->bAlternateSetting;
+
+ /* send the interface alternate setting to endpoint 0*/
+ rt_usbd_ep0_write(device, &value, 1);
+
+ if (intf->handler)
+ {
+ intf->handler(func, setup);
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * This function will handle set_interface bRequest.
+ *
+ * @param device the usb device object.
+ * @param setup the setup bRequest.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _set_interface(struct udevice* device, ureq_t setup)
+{
+ ufunction_t func;
+ uintf_t intf;
+ uep_t ep;
+ struct rt_list_node* i;
+ ualtsetting_t setting;
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(setup != RT_NULL);
+
+ LOG_D("_set_interface");
+
+ if (device->state != USB_STATE_CONFIGURED)
+ {
+ rt_usbd_ep0_set_stall(device);
+ return -RT_ERROR;
+ }
+
+ /* find the specified interface */
+ intf = rt_usbd_find_interface(device, setup->wIndex & 0xFF, &func);
+
+ /* set alternate setting to the interface */
+ rt_usbd_set_altsetting(intf, setup->wValue & 0xFF);
+ setting = intf->curr_setting;
+
+ /* start all endpoints of the interface alternate setting */
+ for(i=setting->ep_list.next; i != &setting->ep_list; i=i->next)
+ {
+ ep = (uep_t)rt_list_entry(i, struct uendpoint, list);
+ dcd_ep_disable(device->dcd, ep);
+ dcd_ep_enable(device->dcd, ep);
+ }
+ dcd_ep0_send_status(device->dcd);
+
+ if (intf->handler)
+ {
+ intf->handler(func, setup);
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * This function will handle get_config bRequest.
+ *
+ * @param device the usb device object.
+ * @param setup the setup bRequest.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _get_config(struct udevice* device, ureq_t setup)
+{
+ rt_uint8_t value;
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(setup != RT_NULL);
+ RT_ASSERT(device->curr_cfg != RT_NULL);
+
+ LOG_D("_get_config");
+
+ if (device->state == USB_STATE_CONFIGURED)
+ {
+ /* get current configuration */
+ value = device->curr_cfg->cfg_desc.bConfigurationValue;
+ }
+ else
+ {
+ value = 0;
+ }
+ /* write the current configuration to endpoint 0 */
+ rt_usbd_ep0_write(device, &value, 1);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will handle set_config bRequest.
+ *
+ * @param device the usb device object.
+ * @param setup the setup bRequest.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _set_config(struct udevice* device, ureq_t setup)
+{
+ struct rt_list_node *i, *j, *k;
+ uconfig_t cfg;
+ uintf_t intf;
+ ualtsetting_t setting;
+ uep_t ep;
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(setup != RT_NULL);
+
+ LOG_D("_set_config");
+
+ if (setup->wValue > device->dev_desc.bNumConfigurations)
+ {
+ rt_usbd_ep0_set_stall(device);
+ return -RT_ERROR;
+ }
+
+ if (setup->wValue == 0)
+ {
+ LOG_D("address state");
+ device->state = USB_STATE_ADDRESS;
+
+ goto _exit;
+ }
+
+ /* set current configuration */
+ rt_usbd_set_config(device, setup->wValue);
+ cfg = device->curr_cfg;
+
+ for (i=cfg->func_list.next; i!=&cfg->func_list; i=i->next)
+ {
+ /* run all functiones and their endpoints in the configuration */
+ ufunction_t func = (ufunction_t)rt_list_entry(i, struct ufunction, list);
+ for(j=func->intf_list.next; j!=&func->intf_list; j=j->next)
+ {
+ intf = (uintf_t)rt_list_entry(j, struct uinterface, list);
+ setting = intf->curr_setting;
+ for(k=setting->ep_list.next; k != &setting->ep_list; k=k->next)
+ {
+ ep = (uep_t)rt_list_entry(k, struct uendpoint, list);
+
+ /* first disable then enable an endpoint */
+ dcd_ep_disable(device->dcd, ep);
+ dcd_ep_enable(device->dcd, ep);
+ }
+ }
+ /* after enabled endpoints, then enable function */
+ FUNC_ENABLE(func);
+ }
+
+ device->state = USB_STATE_CONFIGURED;
+
+_exit:
+ /* issue status stage */
+ dcd_ep0_send_status(device->dcd);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will handle set_address bRequest.
+ *
+ * @param device the usb device object.
+ * @param setup the setup bRequest.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _set_address(struct udevice* device, ureq_t setup)
+{
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(setup != RT_NULL);
+
+ /* set address in device control driver */
+ dcd_set_address(device->dcd, setup->wValue);
+
+ /* issue status stage */
+ dcd_ep0_send_status(device->dcd);
+
+ LOG_D("_set_address");
+
+ device->state = USB_STATE_ADDRESS;
+
+ return RT_EOK;
+}
+
+/**
+ * This function will handle standard bRequest to
+ * interface that defined in function-specifics
+ *
+ * @param device the usb device object.
+ * @param setup the setup bRequest.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _request_interface(struct udevice* device, ureq_t setup)
+{
+ uintf_t intf;
+ ufunction_t func;
+ rt_err_t ret;
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(setup != RT_NULL);
+
+ LOG_D("_request_interface");
+
+ intf = rt_usbd_find_interface(device, setup->wIndex & 0xFF, &func);
+ if (intf != RT_NULL)
+ {
+ ret = intf->handler(func, setup);
+ }
+ else
+ {
+ ret = -RT_ERROR;
+ }
+
+ return ret;
+}
+
+/**
+ * This function will handle standard bRequest.
+ *
+ * @param device the usb device object.
+ * @param setup the setup bRequest.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _standard_request(struct udevice* device, ureq_t setup)
+{
+ udcd_t dcd;
+ rt_uint16_t value = 0;
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(setup != RT_NULL);
+
+ dcd = device->dcd;
+
+ switch(setup->request_type & USB_REQ_TYPE_RECIPIENT_MASK)
+ {
+ case USB_REQ_TYPE_DEVICE:
+ switch(setup->bRequest)
+ {
+ case USB_REQ_GET_STATUS:
+ rt_usbd_ep0_write(device, &value, 2);
+ break;
+ case USB_REQ_CLEAR_FEATURE:
+ rt_usbd_clear_feature(device, setup->wValue, setup->wIndex);
+ dcd_ep0_send_status(dcd);
+ break;
+ case USB_REQ_SET_FEATURE:
+ rt_usbd_set_feature(device, setup->wValue, setup->wIndex);
+ break;
+ case USB_REQ_SET_ADDRESS:
+ _set_address(device, setup);
+ break;
+ case USB_REQ_GET_DESCRIPTOR:
+ _get_descriptor(device, setup);
+ break;
+ case USB_REQ_SET_DESCRIPTOR:
+ rt_usbd_ep0_set_stall(device);
+ break;
+ case USB_REQ_GET_CONFIGURATION:
+ _get_config(device, setup);
+ break;
+ case USB_REQ_SET_CONFIGURATION:
+ _set_config(device, setup);
+ break;
+ default:
+ rt_kprintf("unknown device request\n");
+ rt_usbd_ep0_set_stall(device);
+ break;
+ }
+ break;
+ case USB_REQ_TYPE_INTERFACE:
+ switch(setup->bRequest)
+ {
+ case USB_REQ_GET_INTERFACE:
+ _get_interface(device, setup);
+ break;
+ case USB_REQ_SET_INTERFACE:
+ _set_interface(device, setup);
+ break;
+ default:
+ if (_request_interface(device, setup) != RT_EOK)
+ {
+ rt_kprintf("unknown interface request\n");
+ rt_usbd_ep0_set_stall(device);
+ return -RT_ERROR;
+ }
+ else
+ break;
+ }
+ break;
+ case USB_REQ_TYPE_ENDPOINT:
+ switch(setup->bRequest)
+ {
+ case USB_REQ_GET_STATUS:
+ {
+ uep_t ep;
+
+ ep = rt_usbd_find_endpoint(device, RT_NULL, setup->wIndex);
+ value = ep->stalled;
+ rt_usbd_ep0_write(device, &value, 2);
+ }
+ break;
+ case USB_REQ_CLEAR_FEATURE:
+ {
+ uep_t ep;
+ uio_request_t req;
+ struct rt_list_node *node;
+
+ ep = rt_usbd_find_endpoint(device, RT_NULL, setup->wIndex);
+ if(USB_EP_HALT == setup->wValue && ep->stalled == RT_TRUE)
+ {
+ rt_usbd_clear_feature(device, setup->wValue, setup->wIndex);
+ dcd_ep0_send_status(dcd);
+ ep->stalled = RT_FALSE;
+
+ for (node = ep->request_list.next; node != &ep->request_list; node = node->next)
+ {
+ req = (uio_request_t)rt_list_entry(node, struct uio_request, list);
+ rt_usbd_io_request(device, ep, req);
+ LOG_D("fired a request");
+ }
+
+ rt_list_init(&ep->request_list);
+ }
+ }
+ break;
+ case USB_REQ_SET_FEATURE:
+ {
+ uep_t ep;
+
+ if(USB_EP_HALT == setup->wValue)
+ {
+ ep = rt_usbd_find_endpoint(device, RT_NULL, setup->wIndex);
+ ep->stalled = RT_TRUE;
+ rt_usbd_set_feature(device, setup->wValue, setup->wIndex);
+ dcd_ep0_send_status(dcd);
+ }
+ }
+ break;
+ case USB_REQ_SYNCH_FRAME:
+ break;
+ default:
+ rt_kprintf("unknown endpoint request\n");
+ rt_usbd_ep0_set_stall(device);
+ break;
+ }
+ break;
+ case USB_REQ_TYPE_OTHER:
+ rt_kprintf("unknown other type request\n");
+ rt_usbd_ep0_set_stall(device);
+ break;
+ default:
+ rt_kprintf("unknown type request\n");
+ rt_usbd_ep0_set_stall(device);
+ break;
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * This function will handle function bRequest.
+ *
+ * @param device the usb device object.
+ * @param setup the setup bRequest.
+ *
+ * @return RT_EOK on successful, -RT_ERROR on invalid bRequest.
+ */
+static rt_err_t _function_request(udevice_t device, ureq_t setup)
+{
+ uintf_t intf;
+ ufunction_t func;
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(setup != RT_NULL);
+
+ /* verify bRequest wValue */
+ if(setup->wIndex > device->curr_cfg->cfg_desc.bNumInterfaces)
+ {
+ rt_usbd_ep0_set_stall(device);
+ return -RT_ERROR;
+ }
+
+ switch(setup->request_type & USB_REQ_TYPE_RECIPIENT_MASK)
+ {
+ case USB_REQ_TYPE_INTERFACE:
+ intf = rt_usbd_find_interface(device, setup->wIndex & 0xFF, &func);
+ if(intf == RT_NULL)
+ {
+ rt_kprintf("unkwown interface request\n");
+ rt_usbd_ep0_set_stall(device);
+ }
+ else
+ {
+ intf->handler(func, setup);
+ }
+ break;
+ case USB_REQ_TYPE_ENDPOINT:
+ break;
+ default:
+ rt_kprintf("unknown function request type\n");
+ rt_usbd_ep0_set_stall(device);
+ break;
+ }
+
+ return RT_EOK;
+}
+static rt_err_t _vendor_request(udevice_t device, ureq_t setup)
+{
+ static rt_uint8_t * usb_comp_id_desc = RT_NULL;
+ static rt_uint32_t usb_comp_id_desc_size = 0;
+ usb_os_func_comp_id_desc_t func_comp_id_desc;
+ uintf_t intf;
+ ufunction_t func;
+ switch(setup->bRequest)
+ {
+ case 'A':
+ switch(setup->wIndex)
+ {
+ case 0x04:
+ if(rt_list_len(&device->os_comp_id_desc->func_desc) == 0)
+ {
+ rt_usbd_ep0_set_stall(device);
+ return RT_EOK;
+ }
+ if(usb_comp_id_desc == RT_NULL)
+ {
+ rt_uint8_t * pusb_comp_id_desc;
+ rt_list_t *p;
+ usb_comp_id_desc_size = sizeof(struct usb_os_header_comp_id_descriptor) +
+ (sizeof(struct usb_os_function_comp_id_descriptor)-sizeof(rt_list_t))*rt_list_len(&device->os_comp_id_desc->func_desc);
+
+ usb_comp_id_desc = (rt_uint8_t *)rt_malloc(usb_comp_id_desc_size);
+ RT_ASSERT(usb_comp_id_desc != RT_NULL);
+ device->os_comp_id_desc->head_desc.dwLength = usb_comp_id_desc_size;
+ pusb_comp_id_desc = usb_comp_id_desc;
+ rt_memcpy((void *)pusb_comp_id_desc,(void *)&device->os_comp_id_desc->head_desc,sizeof(struct usb_os_header_comp_id_descriptor));
+ pusb_comp_id_desc += sizeof(struct usb_os_header_comp_id_descriptor);
+
+ for (p = device->os_comp_id_desc->func_desc.next; p != &device->os_comp_id_desc->func_desc; p = p->next)
+ {
+ func_comp_id_desc = rt_list_entry(p,struct usb_os_function_comp_id_descriptor,list);
+ rt_memcpy(pusb_comp_id_desc,(void *)&func_comp_id_desc->bFirstInterfaceNumber,
+ sizeof(struct usb_os_function_comp_id_descriptor)-sizeof(rt_list_t));
+ pusb_comp_id_desc += sizeof(struct usb_os_function_comp_id_descriptor)-sizeof(rt_list_t);
+ }
+ }
+ rt_usbd_ep0_write(device, (void*)usb_comp_id_desc, setup->wLength);
+ break;
+ case 0x05:
+ intf = rt_usbd_find_interface(device, setup->wValue & 0xFF, &func);
+ if(intf != RT_NULL)
+ {
+ intf->handler(func, setup);
+ }
+ break;
+ }
+
+ break;
+ }
+ return RT_EOK;
+}
+static rt_err_t _dump_setup_packet(ureq_t setup)
+{
+ LOG_D("[");
+ LOG_D(" setup_request : 0x%x",
+ setup->request_type);
+ LOG_D(" value : 0x%x", setup->wValue);
+ LOG_D(" length : 0x%x", setup->wLength);
+ LOG_D(" index : 0x%x", setup->wIndex);
+ LOG_D(" request : 0x%x", setup->bRequest);
+ LOG_D("]");
+
+ return RT_EOK;
+}
+
+/**
+ * This function will handle setup bRequest.
+ *
+ * @param device the usb device object.
+ * @param setup the setup bRequest.
+ *
+ * @return RT_EOK on successful, -RT_ERROR on invalid bRequest.
+ */
+static rt_err_t _setup_request(udevice_t device, ureq_t setup)
+{
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(setup != RT_NULL);
+
+ _dump_setup_packet(setup);
+
+ switch((setup->request_type & USB_REQ_TYPE_MASK))
+ {
+ case USB_REQ_TYPE_STANDARD:
+ _standard_request(device, setup);
+ break;
+ case USB_REQ_TYPE_CLASS:
+ _function_request(device, setup);
+ break;
+ case USB_REQ_TYPE_VENDOR:
+ _vendor_request(device, setup);
+ break;
+ default:
+ rt_kprintf("unknown setup request type\n");
+ rt_usbd_ep0_set_stall(device);
+ return -RT_ERROR;
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * This function will hanle data notify event.
+ *
+ * @param device the usb device object.
+ * @param ep_msg the endpoint message.
+ *
+ * @return RT_EOK.
+ */
+static rt_err_t _data_notify(udevice_t device, struct ep_msg* ep_msg)
+{
+ uep_t ep;
+ ufunction_t func;
+ rt_size_t size = 0;
+
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(ep_msg != RT_NULL);
+
+ if (device->state != USB_STATE_CONFIGURED)
+ {
+ return -RT_ERROR;
+ }
+
+ ep = rt_usbd_find_endpoint(device, &func, ep_msg->ep_addr);
+ if(ep == RT_NULL)
+ {
+ rt_kprintf("invalid endpoint\n");
+ return -RT_ERROR;
+ }
+
+ if(EP_ADDRESS(ep) & USB_DIR_IN)
+ {
+ size = ep_msg->size;
+ if(ep->request.remain_size >= EP_MAXPACKET(ep))
+ {
+ dcd_ep_write(device->dcd, EP_ADDRESS(ep), ep->request.buffer, EP_MAXPACKET(ep));
+ ep->request.remain_size -= EP_MAXPACKET(ep);
+ ep->request.buffer += EP_MAXPACKET(ep);
+ }
+ else if(ep->request.remain_size > 0)
+ {
+ dcd_ep_write(device->dcd, EP_ADDRESS(ep), ep->request.buffer, ep->request.remain_size);
+ ep->request.remain_size = 0;
+ }
+ else
+ {
+ EP_HANDLER(ep, func, size);
+ }
+ }
+ else
+ {
+ size = ep_msg->size;
+ if(ep->request.remain_size == 0)
+ {
+ return RT_EOK;
+ }
+
+ if(size == 0)
+ {
+ size = dcd_ep_read(device->dcd, EP_ADDRESS(ep), ep->request.buffer);
+ }
+ ep->request.remain_size -= size;
+ ep->request.buffer += size;
+
+ if(ep->request.req_type == UIO_REQUEST_READ_BEST)
+ {
+ EP_HANDLER(ep, func, size);
+ }
+ else if(ep->request.remain_size == 0)
+ {
+ EP_HANDLER(ep, func, ep->request.size);
+ }
+ else
+ {
+ dcd_ep_read_prepare(device->dcd, EP_ADDRESS(ep), ep->request.buffer, ep->request.remain_size > EP_MAXPACKET(ep) ? EP_MAXPACKET(ep) : ep->request.remain_size);
+ }
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t _ep0_out_notify(udevice_t device, struct ep_msg* ep_msg)
+{
+ uep_t ep0;
+ rt_size_t size;
+
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(ep_msg != RT_NULL);
+ RT_ASSERT(device->dcd != RT_NULL);
+
+ ep0 = &device->dcd->ep0;
+ size = ep_msg->size;
+
+ if(ep0->request.remain_size == 0)
+ {
+ return RT_EOK;
+ }
+ if(size == 0)
+ {
+ size = dcd_ep_read(device->dcd, EP0_OUT_ADDR, ep0->request.buffer);
+ if(size == 0)
+ {
+ return RT_EOK;
+ }
+ }
+
+ ep0->request.remain_size -= size;
+ ep0->request.buffer += size;
+ if(ep0->request.remain_size == 0)
+ {
+ /* invoke callback */
+ if(ep0->rx_indicate != RT_NULL)
+ {
+ ep0->rx_indicate(device, size);
+ }
+ }
+ else
+ {
+ rt_usbd_ep0_read(device, ep0->request.buffer, ep0->request.remain_size,ep0->rx_indicate);
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * This function will notity sof event to all of function.
+ *
+ * @param device the usb device object.
+ *
+ * @return RT_EOK.
+ */
+static rt_err_t _sof_notify(udevice_t device)
+{
+ struct rt_list_node *i;
+ ufunction_t func;
+
+ RT_ASSERT(device != RT_NULL);
+
+ /* to notity every function that sof event comes */
+ for (i=device->curr_cfg->func_list.next;
+ i!=&device->curr_cfg->func_list; i=i->next)
+ {
+ func = (ufunction_t)rt_list_entry(i, struct ufunction, list);
+ if(func->ops->sof_handler != RT_NULL)
+ func->ops->sof_handler(func);
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * This function will disable all USB functions.
+ *
+ * @param device the usb device object.
+ *
+ * @return RT_EOK.
+ */
+static rt_err_t _stop_notify(udevice_t device)
+{
+ struct rt_list_node *i;
+ ufunction_t func;
+
+ RT_ASSERT(device != RT_NULL);
+
+ /* to notity every function */
+ for (i = device->curr_cfg->func_list.next;
+ i != &device->curr_cfg->func_list;
+ i = i->next)
+ {
+ func = (ufunction_t)rt_list_entry(i, struct ufunction, list);
+ FUNC_DISABLE(func);
+ }
+
+ return RT_EOK;
+}
+
+static rt_ssize_t rt_usbd_ep_write(udevice_t device, uep_t ep, void *buffer, rt_size_t size)
+{
+ rt_uint16_t maxpacket;
+
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(device->dcd != RT_NULL);
+ RT_ASSERT(ep != RT_NULL);
+
+ rt_enter_critical();
+ maxpacket = EP_MAXPACKET(ep);
+ if(ep->request.remain_size >= maxpacket)
+ {
+ dcd_ep_write(device->dcd, EP_ADDRESS(ep), ep->request.buffer, maxpacket);
+ ep->request.remain_size -= maxpacket;
+ ep->request.buffer += maxpacket;
+ }
+ else
+ {
+ dcd_ep_write(device->dcd, EP_ADDRESS(ep), ep->request.buffer,
+ ep->request.remain_size);
+ ep->request.remain_size = 0;
+ }
+ rt_exit_critical();
+ return size;
+}
+
+static rt_ssize_t rt_usbd_ep_read_prepare(udevice_t device, uep_t ep, void *buffer, rt_size_t size)
+{
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(device->dcd != RT_NULL);
+ RT_ASSERT(ep != RT_NULL);
+ RT_ASSERT(buffer != RT_NULL);
+ RT_ASSERT(ep->ep_desc != RT_NULL);
+
+ return dcd_ep_read_prepare(device->dcd, EP_ADDRESS(ep), buffer, size > EP_MAXPACKET(ep) ? EP_MAXPACKET(ep) : size);
+}
+
+/**
+ * This function will create an usb device object.
+ *
+ * @param ustring the usb string array to contain string descriptor.
+ *
+ * @return an usb device object on success, RT_NULL on fail.
+ */
+udevice_t rt_usbd_device_new(void)
+{
+ udevice_t udevice;
+
+ LOG_D("rt_usbd_device_new");
+
+ /* allocate memory for the object */
+ udevice = (udevice_t)rt_malloc(sizeof(struct udevice));
+ if(udevice == RT_NULL)
+ {
+ rt_kprintf("alloc memory failed\n");
+ return RT_NULL;
+ }
+ rt_memset(udevice, 0, sizeof(struct udevice));
+
+ /* to initialize configuration list */
+ rt_list_init(&udevice->cfg_list);
+
+ /* insert the device object to device list */
+ rt_list_insert_before(&device_list, &udevice->list);
+
+ return udevice;
+}
+
+/**
+ * This function will set usb device string description.
+ *
+ * @param device the usb device object.
+ * @param ustring pointer to string pointer array.
+ *
+ * @return RT_EOK.
+ */
+rt_err_t rt_usbd_device_set_string(udevice_t device, const char** ustring)
+{
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(ustring != RT_NULL);
+
+ /* set string descriptor array to the device object */
+ device->str = ustring;
+
+ return RT_EOK;
+}
+
+/**
+ * This function will set usb device interface string description.
+ *
+ * @param device the usb device object.
+ * @param index of interface string
+ * @param string pointer to interface string description.
+ *
+ * @return RT_EOK.
+ */
+rt_err_t rt_usbd_device_set_interface_string(udevice_t device, int index, const char* string)
+{
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(string != RT_NULL);
+ RT_ASSERT(index < MAX_INTF_STR);
+
+ /* set string descriptor array to the device object */
+ device->str_intf[index] = string;
+
+ return RT_EOK;
+}
+
+rt_err_t rt_usbd_device_set_os_comp_id_desc(udevice_t device, usb_os_comp_id_desc_t os_comp_id_desc)
+{
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(os_comp_id_desc != RT_NULL);
+
+ /* set string descriptor array to the device object */
+ device->os_comp_id_desc = os_comp_id_desc;
+ rt_list_init(&device->os_comp_id_desc->func_desc);
+ return RT_EOK;
+}
+
+rt_err_t rt_usbd_device_set_qualifier(udevice_t device, struct usb_qualifier_descriptor* qualifier)
+{
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(qualifier != RT_NULL);
+
+ device->dev_qualifier = qualifier;
+
+ return RT_EOK;
+}
+
+/**
+ * This function will set an usb controller driver to a device.
+ *
+ * @param device the usb device object.
+ * @param dcd the usb device controller driver.
+ *
+ * @return RT_EOK on successful.
+ */
+rt_err_t rt_usbd_device_set_controller(udevice_t device, udcd_t dcd)
+{
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(dcd != RT_NULL);
+
+ /* set usb device controller driver to the device */
+ device->dcd = dcd;
+
+ return RT_EOK;
+}
+
+/**
+ * This function will set an usb device descriptor to a device.
+ *
+ * @param device the usb device object.
+ * @param dev_desc the usb device descriptor.
+ *
+ * @return RT_EOK on successful.
+ */
+rt_err_t rt_usbd_device_set_descriptor(udevice_t device, udev_desc_t dev_desc)
+{
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(dev_desc != RT_NULL);
+
+ /* copy the usb device descriptor to the device */
+ rt_memcpy((void *)&device->dev_desc, (void *)dev_desc, USB_DESC_LENGTH_DEVICE);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will create an usb configuration object.
+ *
+ * @param none.
+ *
+ * @return an usb configuration object.
+ */
+uconfig_t rt_usbd_config_new(void)
+{
+ uconfig_t cfg;
+
+ LOG_D("rt_usbd_config_new");
+
+ /* allocate memory for the object */
+ cfg = (uconfig_t)rt_malloc(sizeof(struct uconfig));
+ if(cfg == RT_NULL)
+ {
+ rt_kprintf("alloc memory failed\n");
+ return RT_NULL;
+ }
+ rt_memset(cfg, 0, sizeof(struct uconfig));
+
+ /* set default wValue */
+ cfg->cfg_desc.bLength = USB_DESC_LENGTH_CONFIG;
+ cfg->cfg_desc.type = USB_DESC_TYPE_CONFIGURATION;
+ cfg->cfg_desc.wTotalLength = USB_DESC_LENGTH_CONFIG;
+ cfg->cfg_desc.bmAttributes = 0xC0;
+ cfg->cfg_desc.MaxPower = 0x32;
+
+ /* to initialize function object list */
+ rt_list_init(&cfg->func_list);
+
+ return cfg;
+}
+
+/**
+ * This function will create an usb interface object.
+ *
+ * @param device the usb device object.
+ * @handler the callback handler of object
+ *
+ * @return an usb interface object on success, RT_NULL on fail.
+ */
+uintf_t rt_usbd_interface_new(udevice_t device, uintf_handler_t handler)
+{
+ uintf_t intf;
+
+ LOG_D("rt_usbd_interface_new");
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+
+ /* allocate memory for the object */
+ intf = (uintf_t)rt_malloc(sizeof(struct uinterface));
+ if(intf == RT_NULL)
+ {
+ rt_kprintf("alloc memory failed\n");
+ return RT_NULL;
+ }
+ intf->intf_num = device->nr_intf;
+ device->nr_intf++;
+ intf->handler = handler;
+ intf->curr_setting = RT_NULL;
+
+ /* to initialize the alternate setting object list */
+ rt_list_init(&intf->setting_list);
+
+ return intf;
+}
+
+/**
+ * This function will create an usb alternate setting object.
+ *
+ * @param intf_desc the interface descriptor.
+ * @desc_size the size of the interface descriptor.
+ *
+ * @return an usb alternate setting object on success, RT_NULL on fail.
+ */
+ualtsetting_t rt_usbd_altsetting_new(rt_size_t desc_size)
+{
+ ualtsetting_t setting;
+
+ LOG_D("rt_usbd_altsetting_new");
+
+ /* parameter check */
+ RT_ASSERT(desc_size > 0);
+
+ /* allocate memory for the object */
+ setting = (ualtsetting_t)rt_malloc(sizeof(struct ualtsetting));
+ if(setting == RT_NULL)
+ {
+ rt_kprintf("alloc memory failed\n");
+ return RT_NULL;
+ }
+ /* allocate memory for the desc */
+ setting->desc = rt_malloc(desc_size);
+ if (setting->desc == RT_NULL)
+ {
+ rt_kprintf("alloc desc memory failed\n");
+ rt_free(setting);
+ return RT_NULL;
+ }
+
+ setting->desc_size = desc_size;
+ setting->intf_desc = RT_NULL;
+
+ /* to initialize endpoint list */
+ rt_list_init(&setting->ep_list);
+
+ return setting;
+}
+
+/**
+ * This function will config an desc in alternate setting object.
+ *
+ * @param setting the altsetting to be config.
+ * @param desc use it to init desc in setting.
+ * @param intf_pos the offset of interface descriptor in desc.
+ *
+ * @return RT_EOK.
+ */
+rt_err_t rt_usbd_altsetting_config_descriptor(ualtsetting_t setting, const void* desc, rt_off_t intf_pos)
+{
+ RT_ASSERT(setting != RT_NULL);
+ RT_ASSERT(setting->desc !=RT_NULL);
+
+ rt_memcpy(setting->desc, desc, setting->desc_size);
+ setting->intf_desc = (uintf_desc_t)((char*)setting->desc + intf_pos);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will create an usb function object.
+ *
+ * @param device the usb device object.
+ * @param dev_desc the device descriptor.
+ * @param ops the operation set.
+ *
+ * @return an usb function object on success, RT_NULL on fail.
+ */
+ufunction_t rt_usbd_function_new(udevice_t device, udev_desc_t dev_desc,
+ ufunction_ops_t ops)
+{
+ ufunction_t func;
+
+ LOG_D("rt_usbd_function_new");
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(dev_desc != RT_NULL);
+
+ /* allocate memory for the object */
+ func = (ufunction_t)rt_malloc(sizeof(struct ufunction));
+ if(func == RT_NULL)
+ {
+ rt_kprintf("alloc memory failed\n");
+ return RT_NULL;
+ }
+ func->dev_desc = dev_desc;
+ func->ops = ops;
+ func->device = device;
+ func->enabled = RT_FALSE;
+
+ /* to initialize interface list */
+ rt_list_init(&func->intf_list);
+
+ return func;
+}
+
+/**
+ * This function will create an usb endpoint object.
+ *
+ * @param ep_desc the endpoint descriptor.
+ * @handler the callback handler of object
+ *
+ * @return an usb endpoint object on success, RT_NULL on fail.
+ */
+uep_t rt_usbd_endpoint_new(uep_desc_t ep_desc, udep_handler_t handler)
+{
+ uep_t ep;
+
+ LOG_D("rt_usbd_endpoint_new");
+
+ /* parameter check */
+ RT_ASSERT(ep_desc != RT_NULL);
+
+ /* allocate memory for the object */
+ ep = (uep_t)rt_malloc(sizeof(struct uendpoint));
+ if(ep == RT_NULL)
+ {
+ rt_kprintf("alloc memory failed\n");
+ return RT_NULL;
+ }
+ ep->ep_desc = ep_desc;
+ ep->handler = handler;
+ ep->buffer = RT_NULL;
+ ep->stalled = RT_FALSE;
+ rt_list_init(&ep->request_list);
+
+ return ep;
+}
+
+/**
+ * This function will find an usb device object.
+ *
+ * @dcd usd device controller driver.
+ *
+ * @return an usb device object on found or RT_NULL on not found.
+ */
+udevice_t rt_usbd_find_device(udcd_t dcd)
+{
+ struct rt_list_node* node;
+ udevice_t device;
+
+ /* parameter check */
+ RT_ASSERT(dcd != RT_NULL);
+
+ /* search a device in the the device list */
+ for (node = device_list.next; node != &device_list; node = node->next)
+ {
+ device = (udevice_t)rt_list_entry(node, struct udevice, list);
+ if(device->dcd == dcd) return device;
+ }
+
+ rt_kprintf("can't find device\n");
+ return RT_NULL;
+}
+
+/**
+ * This function will find an usb configuration object.
+ *
+ * @param device the usb device object.
+ * @param wValue the configuration number.
+ *
+ * @return an usb configuration object on found or RT_NULL on not found.
+ */
+uconfig_t rt_usbd_find_config(udevice_t device, rt_uint8_t value)
+{
+ struct rt_list_node* node;
+ uconfig_t cfg = RT_NULL;
+
+ LOG_D("rt_usbd_find_config");
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(value <= device->dev_desc.bNumConfigurations);
+
+ /* search a configration in the the device */
+ for (node = device->cfg_list.next; node != &device->cfg_list; node = node->next)
+ {
+ cfg = (uconfig_t)rt_list_entry(node, struct udevice, list);
+ if(cfg->cfg_desc.bConfigurationValue == value)
+ {
+ return cfg;
+ }
+ }
+
+ rt_kprintf("can't find configuration %d\n", value);
+ return RT_NULL;
+}
+
+/**
+ * This function will find an usb interface object.
+ *
+ * @param device the usb device object.
+ * @param wValue the interface number.
+ *
+ * @return an usb configuration object on found or RT_NULL on not found.
+ */
+uintf_t rt_usbd_find_interface(udevice_t device, rt_uint8_t value, ufunction_t *pfunc)
+{
+ struct rt_list_node *i, *j;
+ ufunction_t func;
+ uintf_t intf;
+
+ LOG_D("rt_usbd_find_interface");
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(value < device->nr_intf);
+
+ /* search an interface in the current configuration */
+ for (i=device->curr_cfg->func_list.next;
+ i!=&device->curr_cfg->func_list; i=i->next)
+ {
+ func = (ufunction_t)rt_list_entry(i, struct ufunction, list);
+ for(j=func->intf_list.next; j!=&func->intf_list; j=j->next)
+ {
+ intf = (uintf_t)rt_list_entry(j, struct uinterface, list);
+ if(intf->intf_num == value)
+ {
+ if (pfunc != RT_NULL)
+ *pfunc = func;
+ return intf;
+ }
+ }
+ }
+
+ rt_kprintf("can't find interface %d\n", value);
+ return RT_NULL;
+}
+
+/**
+ * This function will find an usb interface alternate setting object.
+ *
+ * @param device the usb device object.
+ * @param wValue the alternate setting number.
+ *
+ * @return an usb interface alternate setting object on found or RT_NULL on not found.
+ */
+ualtsetting_t rt_usbd_find_altsetting(uintf_t intf, rt_uint8_t value)
+{
+ struct rt_list_node *i;
+ ualtsetting_t setting;
+
+ LOG_D("rt_usbd_find_altsetting");
+
+ /* parameter check */
+ RT_ASSERT(intf != RT_NULL);
+
+ if(intf->curr_setting != RT_NULL)
+ {
+ /* if the wValue equal to the current alternate setting, then do not search */
+ if(intf->curr_setting->intf_desc->bAlternateSetting == value)
+ return intf->curr_setting;
+ }
+
+ /* search a setting in the alternate setting list */
+ for(i=intf->setting_list.next; i!=&intf->setting_list; i=i->next)
+ {
+ setting =(ualtsetting_t)rt_list_entry(i, struct ualtsetting, list);
+ if(setting->intf_desc->bAlternateSetting == value)
+ return setting;
+ }
+
+ rt_kprintf("can't find alternate setting %d\n", value);
+ return RT_NULL;
+}
+
+/**
+ * This function will find an usb endpoint object.
+ *
+ * @param device the usb device object.
+ * @param ep_addr endpoint address.
+ *
+ * @return an usb endpoint object on found or RT_NULL on not found.
+ */
+uep_t rt_usbd_find_endpoint(udevice_t device, ufunction_t* pfunc, rt_uint8_t ep_addr)
+{
+ uep_t ep;
+ struct rt_list_node *i, *j, *k;
+ ufunction_t func;
+ uintf_t intf;
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+
+ /* search a endpoint in the current configuration */
+ for (i=device->curr_cfg->func_list.next; i!=&device->curr_cfg->func_list; i=i->next)
+ {
+ func = (ufunction_t)rt_list_entry(i, struct ufunction, list);
+ for(j=func->intf_list.next; j!=&func->intf_list; j=j->next)
+ {
+ intf = (uintf_t)rt_list_entry(j, struct uinterface, list);
+ for(k=intf->curr_setting->ep_list.next;
+ k!=&intf->curr_setting->ep_list; k=k->next)
+ {
+ ep = (uep_t)rt_list_entry(k, struct uendpoint, list);
+ if(EP_ADDRESS(ep) == ep_addr)
+ {
+ if (pfunc != RT_NULL)
+ *pfunc = func;
+ return ep;
+ }
+ }
+ }
+ }
+
+ rt_kprintf("can't find endpoint 0x%x\n", ep_addr);
+ return RT_NULL;
+}
+
+/**
+ * This function will add a configuration to an usb device.
+ *
+ * @param device the usb device object.
+ * @param cfg the configuration object.
+ *
+ * @return RT_EOK.
+ */
+rt_err_t rt_usbd_device_add_config(udevice_t device, uconfig_t cfg)
+{
+ struct rt_list_node *i, *j, *k, *m;
+ ufunction_t func;
+ uintf_t intf;
+ ualtsetting_t altsetting;
+ uep_t ep;
+
+ LOG_D("rt_usbd_device_add_config");
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(cfg != RT_NULL);
+
+ /* set configuration number to the configuration descriptor */
+ cfg->cfg_desc.bConfigurationValue = device->dev_desc.bNumConfigurations + 1;
+ device->dev_desc.bNumConfigurations++;
+
+ for (i=cfg->func_list.next; i!=&cfg->func_list; i=i->next)
+ {
+ func = (ufunction_t)rt_list_entry(i, struct ufunction, list);
+
+ for(j=func->intf_list.next; j!=&func->intf_list; j=j->next)
+ {
+ intf = (uintf_t)rt_list_entry(j, struct uinterface, list);
+ cfg->cfg_desc.bNumInterfaces++;
+
+ for(k=intf->setting_list.next; k!=&intf->setting_list;k=k->next)
+ {
+ altsetting = (ualtsetting_t)rt_list_entry(k, struct ualtsetting, list);
+
+ /* allocate address for every endpoint in the interface alternate setting */
+ for(m=altsetting->ep_list.next; m!=&altsetting->ep_list; m=m->next)
+ {
+ ep = (uep_t)rt_list_entry(m, struct uendpoint, list);
+ if(rt_usbd_ep_assign(device, ep) != RT_EOK)
+ {
+ rt_kprintf("endpoint assign error\n");
+ }
+ }
+
+ /* construct complete configuration descriptor */
+ rt_memcpy((void*)&cfg->cfg_desc.data[cfg->cfg_desc.wTotalLength - USB_DESC_LENGTH_CONFIG],
+ (void*)altsetting->desc,
+ altsetting->desc_size);
+ cfg->cfg_desc.wTotalLength += altsetting->desc_size;
+ }
+ }
+ }
+
+ /* insert the configuration to the list */
+ rt_list_insert_before(&device->cfg_list, &cfg->list);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will add a function to a configuration.
+ *
+ * @param cfg the configuration object.
+ * @param func the function object.
+ *
+ * @return RT_EOK.
+ */
+rt_err_t rt_usbd_config_add_function(uconfig_t cfg, ufunction_t func)
+{
+ LOG_D("rt_usbd_config_add_function");
+
+ /* parameter check */
+ RT_ASSERT(cfg != RT_NULL);
+ RT_ASSERT(func != RT_NULL);
+
+ /* insert the function to the list */
+ rt_list_insert_before(&cfg->func_list, &func->list);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will add an interface to a function.
+ *
+ * @param func the function object.
+ * @param intf the interface object.
+ *
+ * @return RT_EOK.
+ */
+rt_err_t rt_usbd_function_add_interface(ufunction_t func, uintf_t intf)
+{
+
+ LOG_D("rt_usbd_function_add_interface");
+
+ /* parameter check */
+ RT_ASSERT(func != RT_NULL);
+ RT_ASSERT(intf != RT_NULL);
+
+ /* insert the interface to the list */
+ rt_list_insert_before(&func->intf_list, &intf->list);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will add an alternate setting to an interface.
+ *
+ * @param intf the interface object.
+ * @param setting the alternate setting object.
+ *
+ * @return RT_EOK.
+ */
+rt_err_t rt_usbd_interface_add_altsetting(uintf_t intf, ualtsetting_t setting)
+{
+ LOG_D("rt_usbd_interface_add_altsetting");
+
+ /* parameter check */
+ RT_ASSERT(intf != RT_NULL);
+ RT_ASSERT(setting != RT_NULL);
+
+ setting->intf_desc->bInterfaceNumber = intf->intf_num;
+
+ /* insert the alternate setting to the list */
+ rt_list_insert_before(&intf->setting_list, &setting->list);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will add an endpoint to an alternate setting.
+ *
+ * @param setting the alternate setting object.
+ * @param ep the endpoint object.
+ *
+ * @return RT_EOK.
+ */
+rt_err_t rt_usbd_altsetting_add_endpoint(ualtsetting_t setting, uep_t ep)
+{
+ LOG_D("rt_usbd_altsetting_add_endpoint");
+
+ /* parameter check */
+ RT_ASSERT(setting != RT_NULL);
+ RT_ASSERT(ep != RT_NULL);
+
+ /* insert the endpoint to the list */
+ rt_list_insert_before(&setting->ep_list, &ep->list);
+
+ return RT_EOK;
+}
+
+rt_err_t rt_usbd_os_comp_id_desc_add_os_func_comp_id_desc(usb_os_comp_id_desc_t os_comp_id_desc, usb_os_func_comp_id_desc_t os_func_comp_id_desc)
+{
+ RT_ASSERT(os_comp_id_desc != RT_NULL);
+ RT_ASSERT(os_func_comp_id_desc != RT_NULL);
+ rt_list_insert_before(&os_comp_id_desc->func_desc, &os_func_comp_id_desc->list);
+ os_comp_id_desc->head_desc.bCount++;
+ return RT_EOK;
+}
+
+/**
+ * This function will set an alternate setting for an interface.
+ *
+ * @param intf_desc the interface descriptor.
+ * @param wValue the alternate setting number.
+ *
+ * @return RT_EOK.
+ */
+rt_err_t rt_usbd_set_altsetting(uintf_t intf, rt_uint8_t value)
+{
+ ualtsetting_t setting;
+
+ LOG_D("rt_usbd_set_altsetting");
+
+ /* parameter check */
+ RT_ASSERT(intf != RT_NULL);
+
+ /* find an alternate setting */
+ setting = rt_usbd_find_altsetting(intf, value);
+
+ /* set as current alternate setting */
+ intf->curr_setting = setting;
+
+ return RT_EOK;
+}
+
+/**
+ * This function will set a configuration for an usb device.
+ *
+ * @param device the usb device object.
+ * @param wValue the configuration number.
+ *
+ * @return RT_EOK.
+ */
+rt_err_t rt_usbd_set_config(udevice_t device, rt_uint8_t value)
+{
+ uconfig_t cfg;
+
+ LOG_D("rt_usbd_set_config");
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(value <= device->dev_desc.bNumConfigurations);
+
+ /* find a configuration */
+ cfg = rt_usbd_find_config(device, value);
+
+ /* set as current configuration */
+ device->curr_cfg = cfg;
+
+ dcd_set_config(device->dcd, value);
+
+ return RT_TRUE;
+}
+
+/**
+ * This function will bRequest an IO transaction.
+ *
+ * @param device the usb device object.
+ * @param ep the endpoint object.
+ * @param req IO bRequest.
+ *
+ * @return RT_EOK.
+ */
+rt_size_t rt_usbd_io_request(udevice_t device, uep_t ep, uio_request_t req)
+{
+ rt_size_t size = 0;
+
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(req != RT_NULL);
+
+ if(ep->stalled == RT_FALSE)
+ {
+ switch(req->req_type)
+ {
+ case UIO_REQUEST_READ_BEST:
+ case UIO_REQUEST_READ_FULL:
+ ep->request.remain_size = ep->request.size;
+ size = rt_usbd_ep_read_prepare(device, ep, req->buffer, req->size);
+ break;
+ case UIO_REQUEST_WRITE:
+ ep->request.remain_size = ep->request.size;
+ size = rt_usbd_ep_write(device, ep, req->buffer, req->size);
+ break;
+ default:
+ rt_kprintf("unknown request type\n");
+ break;
+ }
+ }
+ else
+ {
+ rt_list_insert_before(&ep->request_list, &req->list);
+ LOG_D("suspend a request");
+ }
+
+ return size;
+}
+
+/**
+ * This function will set feature for an usb device.
+ *
+ * @param device the usb device object.
+ * @param wValue the configuration number.
+ *
+ * @return RT_EOK.
+ */
+rt_err_t rt_usbd_set_feature(udevice_t device, rt_uint16_t value, rt_uint16_t index)
+{
+ RT_ASSERT(device != RT_NULL);
+
+ if (value == USB_FEATURE_DEV_REMOTE_WAKEUP)
+ {
+ LOG_D("set feature remote wakeup");
+ }
+ else if (value == USB_FEATURE_ENDPOINT_HALT)
+ {
+ LOG_D("set feature stall");
+ dcd_ep_set_stall(device->dcd, (rt_uint32_t)(index & 0xFF));
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * This function will clear feature for an usb device.
+ *
+ * @param device the usb device object.
+ * @param wValue the configuration number.
+ *
+ * @return RT_EOK.
+ */
+rt_err_t rt_usbd_clear_feature(udevice_t device, rt_uint16_t value, rt_uint16_t index)
+{
+ RT_ASSERT(device != RT_NULL);
+
+ if (value == USB_FEATURE_DEV_REMOTE_WAKEUP)
+ {
+ LOG_D("clear feature remote wakeup");
+ }
+ else if (value == USB_FEATURE_ENDPOINT_HALT)
+ {
+ LOG_D("clear feature stall");
+ dcd_ep_clear_stall(device->dcd, (rt_uint32_t)(index & 0xFF));
+ }
+
+ return RT_EOK;
+}
+
+rt_err_t rt_usbd_ep0_set_stall(udevice_t device)
+{
+ RT_ASSERT(device != RT_NULL);
+
+ return dcd_ep_set_stall(device->dcd, 0x80);
+}
+
+rt_err_t rt_usbd_ep0_clear_stall(udevice_t device)
+{
+ RT_ASSERT(device != RT_NULL);
+
+ return dcd_ep_clear_stall(device->dcd, 0x80);
+}
+
+rt_err_t rt_usbd_ep_set_stall(udevice_t device, uep_t ep)
+{
+ rt_err_t ret;
+
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(ep != RT_NULL);
+ RT_ASSERT(ep->ep_desc != RT_NULL);
+
+ ret = dcd_ep_set_stall(device->dcd, EP_ADDRESS(ep));
+ if(ret == RT_EOK)
+ {
+ ep->stalled = RT_TRUE;
+ }
+
+ return ret;
+}
+
+rt_err_t rt_usbd_ep_clear_stall(udevice_t device, uep_t ep)
+{
+ rt_err_t ret;
+
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(ep != RT_NULL);
+ RT_ASSERT(ep->ep_desc != RT_NULL);
+
+ ret = dcd_ep_clear_stall(device->dcd, EP_ADDRESS(ep));
+ if(ret == RT_EOK)
+ {
+ ep->stalled = RT_FALSE;
+ }
+
+ return ret;
+}
+
+static rt_err_t rt_usbd_ep_assign(udevice_t device, uep_t ep)
+{
+ int i = 0;
+
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(device->dcd != RT_NULL);
+ RT_ASSERT(device->dcd->ep_pool != RT_NULL);
+ RT_ASSERT(ep != RT_NULL);
+ RT_ASSERT(ep->ep_desc != RT_NULL);
+
+ while(device->dcd->ep_pool[i].addr != 0xFF)
+ {
+ if(device->dcd->ep_pool[i].status == ID_UNASSIGNED &&
+ ep->ep_desc->bmAttributes == device->dcd->ep_pool[i].type && (EP_ADDRESS(ep) & 0x80) == device->dcd->ep_pool[i].dir)
+ {
+ EP_ADDRESS(ep) |= device->dcd->ep_pool[i].addr;
+ ep->id = &device->dcd->ep_pool[i];
+ device->dcd->ep_pool[i].status = ID_ASSIGNED;
+
+ LOG_D("assigned %d", device->dcd->ep_pool[i].addr);
+ return RT_EOK;
+ }
+
+ i++;
+ }
+
+ return -RT_ERROR;
+}
+
+rt_err_t rt_usbd_ep_unassign(udevice_t device, uep_t ep)
+{
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(device->dcd != RT_NULL);
+ RT_ASSERT(device->dcd->ep_pool != RT_NULL);
+ RT_ASSERT(ep != RT_NULL);
+ RT_ASSERT(ep->ep_desc != RT_NULL);
+
+ ep->id->status = ID_UNASSIGNED;
+
+ return RT_EOK;
+}
+
+rt_err_t rt_usbd_ep0_setup_handler(udcd_t dcd, struct urequest* setup)
+{
+ struct udev_msg msg;
+ rt_size_t size;
+
+ RT_ASSERT(dcd != RT_NULL);
+
+ if(setup == RT_NULL)
+ {
+ size = dcd_ep_read(dcd, EP0_OUT_ADDR, (void*)&msg.content.setup);
+ if(size != sizeof(struct urequest))
+ {
+ rt_kprintf("read setup packet error\n");
+ return -RT_ERROR;
+ }
+ }
+ else
+ {
+ rt_memcpy((void*)&msg.content.setup, (void*)setup, sizeof(struct urequest));
+ }
+
+ msg.type = USB_MSG_SETUP_NOTIFY;
+ msg.dcd = dcd;
+ rt_usbd_event_signal(&msg);
+
+ return RT_EOK;
+}
+
+rt_err_t rt_usbd_ep0_in_handler(udcd_t dcd)
+{
+ rt_int32_t remain, mps;
+
+ RT_ASSERT(dcd != RT_NULL);
+
+ if (dcd->stage != STAGE_DIN)
+ return RT_EOK;
+
+ mps = dcd->ep0.id->maxpacket;
+ dcd->ep0.request.remain_size -= mps;
+ remain = dcd->ep0.request.remain_size;
+
+ if (remain > 0)
+ {
+ if (remain >= mps)
+ {
+ remain = mps;
+ }
+
+ dcd->ep0.request.buffer += mps;
+ dcd_ep_write(dcd, EP0_IN_ADDR, dcd->ep0.request.buffer, remain);
+ }
+ else
+ {
+ /* last packet is MPS multiple, so send ZLP packet */
+ if ((remain == 0) && (dcd->ep0.request.size > 0))
+ {
+ dcd->ep0.request.size = 0;
+ dcd_ep_write(dcd, EP0_IN_ADDR, RT_NULL, 0);
+ }
+ else
+ {
+ /* receive status */
+ dcd->stage = STAGE_STATUS_OUT;
+ dcd_ep_read_prepare(dcd, EP0_OUT_ADDR, RT_NULL, 0);
+ }
+ }
+
+ return RT_EOK;
+}
+
+rt_err_t rt_usbd_ep0_out_handler(udcd_t dcd, rt_size_t size)
+{
+ struct udev_msg msg;
+
+ RT_ASSERT(dcd != RT_NULL);
+
+ msg.type = USB_MSG_EP0_OUT;
+ msg.dcd = dcd;
+ msg.content.ep_msg.size = size;
+ rt_usbd_event_signal(&msg);
+
+ return RT_EOK;
+}
+
+rt_err_t rt_usbd_ep_in_handler(udcd_t dcd, rt_uint8_t address, rt_size_t size)
+{
+ struct udev_msg msg;
+
+ RT_ASSERT(dcd != RT_NULL);
+
+ msg.type = USB_MSG_DATA_NOTIFY;
+ msg.dcd = dcd;
+ msg.content.ep_msg.ep_addr = address;
+ msg.content.ep_msg.size = size;
+ rt_usbd_event_signal(&msg);
+
+ return RT_EOK;
+}
+
+rt_err_t rt_usbd_ep_out_handler(udcd_t dcd, rt_uint8_t address, rt_size_t size)
+{
+ struct udev_msg msg;
+
+ RT_ASSERT(dcd != RT_NULL);
+
+ msg.type = USB_MSG_DATA_NOTIFY;
+ msg.dcd = dcd;
+ msg.content.ep_msg.ep_addr = address;
+ msg.content.ep_msg.size = size;
+ rt_usbd_event_signal(&msg);
+
+ return RT_EOK;
+}
+
+rt_err_t rt_usbd_reset_handler(udcd_t dcd)
+{
+ struct udev_msg msg;
+
+ RT_ASSERT(dcd != RT_NULL);
+
+ msg.type = USB_MSG_RESET;
+ msg.dcd = dcd;
+ rt_usbd_event_signal(&msg);
+
+ return RT_EOK;
+}
+
+rt_err_t rt_usbd_connect_handler(udcd_t dcd)
+{
+ struct udev_msg msg;
+
+ RT_ASSERT(dcd != RT_NULL);
+
+ msg.type = USB_MSG_PLUG_IN;
+ msg.dcd = dcd;
+ rt_usbd_event_signal(&msg);
+
+ return RT_EOK;
+}
+
+rt_err_t rt_usbd_disconnect_handler(udcd_t dcd)
+{
+ struct udev_msg msg;
+
+ RT_ASSERT(dcd != RT_NULL);
+
+ msg.type = USB_MSG_PLUG_OUT;
+ msg.dcd = dcd;
+ rt_usbd_event_signal(&msg);
+
+ return RT_EOK;
+}
+
+rt_err_t rt_usbd_sof_handler(udcd_t dcd)
+{
+ struct udev_msg msg;
+
+ RT_ASSERT(dcd != RT_NULL);
+
+ msg.type = USB_MSG_SOF;
+ msg.dcd = dcd;
+ rt_usbd_event_signal(&msg);
+
+ return RT_EOK;
+}
+
+rt_size_t rt_usbd_ep0_write(udevice_t device, void *buffer, rt_size_t size)
+{
+ uep_t ep0;
+ rt_size_t sent_size = 0;
+
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(device->dcd != RT_NULL);
+ RT_ASSERT(buffer != RT_NULL);
+ RT_ASSERT(size > 0);
+
+ ep0 = &device->dcd->ep0;
+ ep0->request.size = size;
+ ep0->request.buffer = (rt_uint8_t *)buffer;
+ ep0->request.remain_size = size;
+ if(size >= ep0->id->maxpacket)
+ {
+ sent_size = ep0->id->maxpacket;
+ }
+ else
+ {
+ sent_size = size;
+ }
+ device->dcd->stage = STAGE_DIN;
+
+ return dcd_ep_write(device->dcd, EP0_IN_ADDR, ep0->request.buffer, sent_size);
+}
+
+rt_size_t rt_usbd_ep0_read(udevice_t device, void *buffer, rt_size_t size,
+ rt_err_t (*rx_ind)(udevice_t device, rt_size_t size))
+{
+ uep_t ep0;
+ rt_size_t read_size = 0;
+
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(device->dcd != RT_NULL);
+ RT_ASSERT(buffer != RT_NULL);
+
+ ep0 = &device->dcd->ep0;
+ ep0->request.buffer = (rt_uint8_t *)buffer;
+ ep0->request.remain_size = size;
+ ep0->rx_indicate = rx_ind;
+ if(size >= ep0->id->maxpacket)
+ {
+ read_size = ep0->id->maxpacket;
+ }
+ else
+ {
+ read_size = size;
+ }
+ device->dcd->stage = STAGE_DOUT;
+ dcd_ep_read_prepare(device->dcd, EP0_OUT_ADDR, buffer, read_size);
+
+ return size;
+}
+
+static struct rt_messagequeue usb_mq;
+
+/**
+ * This function is the main entry of usb device thread, it is in charge of
+ * processing all messages received from the usb message buffer.
+ *
+ * @param parameter the parameter of the usb device thread.
+ *
+ * @return none.
+ */
+static void rt_usbd_thread_entry(void* parameter)
+{
+ while(1)
+ {
+ struct udev_msg msg;
+ udevice_t device;
+
+ /* receive message */
+ if(rt_mq_recv(&usb_mq, &msg, sizeof(struct udev_msg),
+ RT_WAITING_FOREVER) < 0)
+ continue;
+
+ device = rt_usbd_find_device(msg.dcd);
+ if(device == RT_NULL)
+ {
+ rt_kprintf("invalid usb device\n");
+ continue;
+ }
+
+ LOG_D("message type %d", msg.type);
+
+ switch (msg.type)
+ {
+ case USB_MSG_SOF:
+ _sof_notify(device);
+ break;
+ case USB_MSG_DATA_NOTIFY:
+ /* some buggy drivers will have USB_MSG_DATA_NOTIFY before the core
+ * got configured. */
+ _data_notify(device, &msg.content.ep_msg);
+ break;
+ case USB_MSG_SETUP_NOTIFY:
+ _setup_request(device, &msg.content.setup);
+ break;
+ case USB_MSG_EP0_OUT:
+ _ep0_out_notify(device, &msg.content.ep_msg);
+ break;
+ case USB_MSG_RESET:
+ LOG_D("reset %d", device->state);
+ if (device->state == USB_STATE_ADDRESS || device->state == USB_STATE_CONFIGURED)
+ _stop_notify(device);
+ device->state = USB_STATE_NOTATTACHED;
+ break;
+ case USB_MSG_PLUG_IN:
+ device->state = USB_STATE_ATTACHED;
+ break;
+ case USB_MSG_PLUG_OUT:
+ device->state = USB_STATE_NOTATTACHED;
+ _stop_notify(device);
+ break;
+ default:
+ rt_kprintf("unknown msg type %d\n", msg.type);
+ break;
+ }
+ }
+}
+
+/**
+ * This function will post an message to usb message queue,
+ *
+ * @param msg the message to be posted
+ * @param size the size of the message .
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbd_event_signal(struct udev_msg* msg)
+{
+ RT_ASSERT(msg != RT_NULL);
+
+ /* send message to usb message queue */
+ return rt_mq_send(&usb_mq, (void*)msg, sizeof(struct udev_msg));
+}
+
+
+rt_align(RT_ALIGN_SIZE)
+static rt_uint8_t usb_thread_stack[RT_USBD_THREAD_STACK_SZ];
+static struct rt_thread usb_thread;
+#define USBD_MQ_MSG_SZ 32
+#define USBD_MQ_MAX_MSG 16
+/* internal of the message queue: every message is associated with a pointer,
+ * so in order to recveive USBD_MQ_MAX_MSG messages, we have to allocate more
+ * than USBD_MQ_MSG_SZ*USBD_MQ_MAX_MSG memory. */
+static rt_uint8_t usb_mq_pool[(USBD_MQ_MSG_SZ+sizeof(void*))*USBD_MQ_MAX_MSG];
+
+/**
+ * This function will initialize usb device thread.
+ *
+ * @return none.
+ *
+ */
+rt_err_t rt_usbd_core_init(void)
+{
+ rt_list_init(&device_list);
+
+ /* create an usb message queue */
+ rt_mq_init(&usb_mq,
+ "usbd",
+ usb_mq_pool, USBD_MQ_MSG_SZ,
+ sizeof(usb_mq_pool),
+ RT_IPC_FLAG_FIFO);
+
+ /* init usb device thread */
+ rt_thread_init(&usb_thread,
+ "usbd",
+ rt_usbd_thread_entry, RT_NULL,
+ usb_thread_stack, RT_USBD_THREAD_STACK_SZ,
+ RT_USBD_THREAD_PRIO, 20);
+ /* rt_thread_init should always be OK, so start the thread without further
+ * checking. */
+ return rt_thread_startup(&usb_thread);
+}
+
diff --git a/components/legacy/usb/usbhost/SConscript b/components/legacy/usb/usbhost/SConscript
new file mode 100644
index 0000000000..aa5385d52a
--- /dev/null
+++ b/components/legacy/usb/usbhost/SConscript
@@ -0,0 +1,34 @@
+Import('RTT_ROOT')
+from building import *
+
+cwd = GetCurrentDir()
+src = Split("""
+core/usbhost_core.c
+core/driver.c
+core/usbhost.c
+core/hub.c
+""")
+
+if GetDepend('RT_USBH_ADK'):
+ src += Glob('class/adk.c')
+ src += Glob('class/adkapp.c')
+
+if GetDepend('RT_USBH_MSTORAGE'):
+ src += Glob('class/mass.c')
+ src += Glob('class/udisk.c')
+
+if GetDepend('RT_USBH_HID'):
+ src += Glob('class/hid.c')
+
+if GetDepend('RT_USBH_HID_MOUSE'):
+ src += Glob('class/umouse.c')
+
+if GetDepend('RT_USBH_HID_KEYBOARD'):
+ src += Glob('class/ukbd.c')
+
+CPPPATH = [cwd, cwd + '/class', cwd + '/core', \
+ cwd + '/include', cwd + '../../../include']
+
+group = DefineGroup('rt_usbh', src, depend = ['RT_USING_USB_HOST'], CPPPATH = CPPPATH)
+
+Return('group')
diff --git a/components/legacy/usb/usbhost/class/adk.c b/components/legacy/usb/usbhost/class/adk.c
new file mode 100644
index 0000000000..4c51fa8692
--- /dev/null
+++ b/components/legacy/usb/usbhost/class/adk.c
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2011-12-12 Yi Qiu first version
+ */
+
+#include <rtthread.h>
+#include <drivers/usb_host.h>
+#include "adk.h"
+
+#ifdef RT_USBH_ADK
+
+#define DBG_TAG "usbhost.adk"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+static struct uclass_driver adk_driver;
+static const char* _adk_manufacturer = RT_NULL;
+static const char* _adk_model = RT_NULL;
+static const char* _adk_description = RT_NULL;
+static const char* _adk_version = RT_NULL;
+static const char* _adk_uri = RT_NULL;
+static const char* _adk_serial = RT_NULL;
+
+rt_err_t rt_usbh_adk_set_string(const char* manufacturer, const char* model,
+ const char* description, const char* _version, const char* uri,
+ const char* serial)
+{
+ _adk_manufacturer = manufacturer;
+ _adk_model = model;
+ _adk_description = description;
+ _adk_version = _version;
+ _adk_uri = uri;
+ _adk_serial = serial;
+
+ return RT_EOK;
+}
+
+#ifdef RT_USING_MODULE
+#include <rtm.h>
+
+RTM_EXPORT(rt_usbh_adk_set_string);
+#endif
+
+/**
+ * This function will do USB_REQ_GET_PROTOCOL request to set idle period to the usb adk device
+ *
+ * @param intf the interface instance.
+ * @duration the idle period of requesting data.
+ * @report_id the report id
+ *
+ * @return the error code, RT_EOK on successfully.
+*/
+static rt_err_t rt_usbh_adk_get_protocol(struct uintf* intf, rt_uint16_t *protocol)
+{
+ struct urequest setup;
+ uinst_t device;
+ int timeout = USB_TIMEOUT_BASIC;
+
+ /* parameter check */
+ RT_ASSERT(intf != RT_NULL);
+ RT_ASSERT(intf->device != RT_NULL);
+
+ device = intf->device;
+
+ setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_VENDOR |
+ USB_REQ_TYPE_DEVICE;
+ setup.request = USB_REQ_GET_PROTOCOL;
+ setup.index = 0;
+ setup.length = 2;
+ setup.value = 0;
+
+ if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, (void*)protocol, 2,
+ timeout) == 0) return RT_EOK;
+ else return -RT_FALSE;
+}
+
+/**
+ * This function will do USB_REQ_SEND_STRING request to set idle period to the usb adk device
+ *
+ * @param intf the interface instance.
+ * @duration the idle period of requesting data.
+ * @report_id the report id
+ *
+ * @return the error code, RT_EOK on successfully.
+*/
+static rt_err_t rt_usbh_adk_send_string(struct uintf* intf, rt_uint16_t index,
+ const char* str)
+{
+ struct urequest setup;
+ uinst_t device;
+ int timeout = USB_TIMEOUT_BASIC;
+
+ /* parameter check */
+ RT_ASSERT(intf != RT_NULL);
+ RT_ASSERT(intf->device != RT_NULL);
+
+ device = intf->device;
+
+ setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_VENDOR |
+ USB_REQ_TYPE_DEVICE;
+ setup.request = USB_REQ_SEND_STRING;
+ setup.index = index;
+ setup.length = rt_strlen(str) + 1;
+ setup.value = 0;
+
+ if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, (void*)str,
+ rt_strlen(str) + 1, timeout) == 0) return RT_EOK;
+ else return -RT_FALSE;
+}
+
+/**
+ * This function will do USB_REQ_START request to set idle period to the usb adk device
+ *
+ * @param intf the interface instance.
+ * @duration the idle period of requesting data.
+ * @report_id the report id
+ *
+ * @return the error code, RT_EOK on successfully.
+*/
+static rt_err_t rt_usbh_adk_start(struct uintf* intf)
+{
+ struct urequest setup;
+ uinst_t device;
+ int timeout = USB_TIMEOUT_BASIC;
+
+ /* parameter check */
+ RT_ASSERT(intf != RT_NULL);
+ RT_ASSERT(intf->device != RT_NULL);
+
+ device = intf->device;
+
+ setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_VENDOR |
+ USB_REQ_TYPE_DEVICE;
+ setup.request = USB_REQ_START;
+ setup.index = 0;
+ setup.length = 0;
+ setup.value = 0;
+
+ if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, RT_NULL, 0,
+ timeout) == 0) return RT_EOK;
+ else return -RT_FALSE;
+}
+
+/**
+ * This function will read data from usb adk device
+ *
+ * @param intf the interface instance.
+ *
+ * @return the error code, RT_EOK on successfully.
+*/
+static rt_ssize_t rt_usbh_adk_read(rt_device_t device, rt_off_t pos, void* buffer,
+ rt_size_t size)
+{
+ uadk_t adk;
+ rt_size_t length;
+ struct uintf* intf;
+
+ /* check parameter */
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(buffer != RT_NULL);
+
+ intf = (struct uintf*)device->user_data;
+ adk = (uadk_t)intf->user_data;
+
+ length = rt_usb_hcd_bulk_xfer(intf->device->hcd, adk->pipe_in,
+ buffer, size, 300);
+
+ return length;
+
+}
+
+/**
+ * This function will write data to usb adk device
+ *
+ * @param intf the interface instance.
+ *
+ * @return the error code, RT_EOK on successfully.
+*/
+static rt_ssize_t rt_usbh_adk_write (rt_device_t device, rt_off_t pos, const void* buffer,
+ rt_size_t size)
+{
+ uadk_t adk;
+ rt_size_t length;
+ struct uintf* intf;
+
+ RT_ASSERT(buffer != RT_NULL);
+
+ intf = (struct uintf*)device->user_data;
+ adk = (uadk_t)intf->user_data;
+
+ length = rt_usb_hcd_bulk_xfer(intf->device->hcd, adk->pipe_out,
+ (void*)buffer, size, 300);
+
+ return length;
+}
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops adk_device_ops =
+{
+ RT_NULL;
+ RT_NULL;
+ RT_NULL;
+ rt_usbh_adk_read;
+ rt_usbh_adk_write;
+ RT_NULL;
+};
+#endif
+
+/**
+ * This function will run adk class driver when usb device is detected and identified
+ * as a adk class device, it will continue the enumulate process.
+ *
+ * @param arg the argument.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+static rt_err_t rt_usbh_adk_enable(void* arg)
+{
+ int i = 0;
+ uadk_t adk;
+ struct uintf* intf = (struct uintf*)arg;
+ udev_desc_t dev_desc;
+ rt_uint16_t protocol;
+ rt_err_t ret;
+
+ /* parameter check */
+ if(intf == RT_NULL)
+ {
+ rt_kprintf("the interface is not available\n");
+ return -RT_EIO;
+ }
+
+ LOG_D("rt_usbh_adk_run");
+
+ dev_desc = &intf->device->dev_desc;
+ if(dev_desc->idVendor == USB_ACCESSORY_VENDOR_ID &&
+ (dev_desc->idProduct == USB_ACCESSORY_PRODUCT_ID ||
+ dev_desc->idProduct == USB_ACCESSORY_ADB_PRODUCT_ID))
+ {
+ if(intf->intf_desc->bInterfaceSubClass != 0xFF) return -RT_ERROR;
+
+ LOG_D("found android accessory device");
+ }
+ else
+ {
+ LOG_D("switch device");
+
+ if((ret = rt_usbh_adk_get_protocol(intf, &protocol)) != RT_EOK)
+ {
+ rt_kprintf("rt_usbh_adk_get_protocol failed\n");
+ return ret;
+ }
+
+ if(protocol != 1)
+ {
+ rt_kprintf("read protocol failed\n");
+ return -RT_ERROR;
+ }
+
+ rt_usbh_adk_send_string(intf,
+ ACCESSORY_STRING_MANUFACTURER, _adk_manufacturer);
+ rt_usbh_adk_send_string(intf,
+ ACCESSORY_STRING_MODEL, _adk_model);
+ rt_usbh_adk_send_string(intf,
+ ACCESSORY_STRING_DESCRIPTION, _adk_description);
+ rt_usbh_adk_send_string(intf,
+ ACCESSORY_STRING_VERSION, _adk_version);
+ rt_usbh_adk_send_string(intf,
+ ACCESSORY_STRING_URI, _adk_uri);
+ rt_usbh_adk_send_string(intf,
+ ACCESSORY_STRING_SERIAL, _adk_serial);
+
+ LOG_D("manufacturer %s", _adk_manufacturer);
+ LOG_D("model %s", _adk_model);
+ LOG_D("description %s", _adk_description);
+ LOG_D("version %s", _adk_version);
+ LOG_D("uri %s", _adk_uri);
+ LOG_D("serial %s", _adk_serial);
+
+ if((ret = rt_usbh_adk_start(intf)) != RT_EOK)
+ {
+ rt_kprintf("rt_usbh_adk_start failed\n");
+ return ret;
+ }
+
+ return RT_EOK;
+ }
+
+ adk = rt_malloc(sizeof(struct uadkinst));
+ RT_ASSERT(adk != RT_NULL);
+
+ /* initilize the data structure */
+ rt_memset(adk, 0, sizeof(struct uadkinst));
+ intf->user_data = (void*)adk;
+
+ for(i=0; i<intf->intf_desc->bNumEndpoints; i++)
+ {
+ uep_desc_t ep_desc;
+
+ /* get endpoint descriptor from interface descriptor */
+ rt_usbh_get_endpoint_descriptor(intf->intf_desc, i, &ep_desc);
+ if(ep_desc == RT_NULL)
+ {
+ rt_kprintf("rt_usb_get_endpoint_descriptor error\n");
+ return -RT_ERROR;
+ }
+
+ /* the endpoint type of adk class should be BULK */
+ if((ep_desc->bmAttributes & USB_EP_ATTR_TYPE_MASK) != USB_EP_ATTR_BULK)
+ continue;
+
+ /* allocate pipes according to the endpoint type */
+ if(ep_desc->bEndpointAddress & USB_DIR_IN)
+ {
+ /* allocate an in pipe for the adk instance */
+ ret = rt_usb_hcd_alloc_pipe(intf->device->hcd, &adk->pipe_in,
+ intf, ep_desc, RT_NULL);
+ if(ret != RT_EOK) return ret;
+ }
+ else
+ {
+ /* allocate an output pipe for the adk instance */
+ ret = rt_usb_hcd_alloc_pipe(intf->device->hcd, &adk->pipe_out,
+ intf, ep_desc, RT_NULL);
+ if(ret != RT_EOK) return ret;
+ }
+ }
+
+ /* check pipes infomation */
+ if(adk->pipe_in == RT_NULL || adk->pipe_out == RT_NULL)
+ {
+ rt_kprintf("pipe error, unsupported device\n");
+ return -RT_ERROR;
+ }
+
+ /* set configuration */
+ ret = rt_usbh_set_configure(intf->device, 1);
+ if(ret != RT_EOK) return ret;
+
+ /* register adk device */
+ adk->device.type = RT_Device_Class_Char;
+#ifdef RT_USING_DEVICE_OPS
+ adk->device.ops = &adk_device_ops;
+#else
+ adk->device.init = RT_NULL;
+ adk->device.open = RT_NULL;
+ adk->device.close = RT_NULL;
+ adk->device.read = rt_usbh_adk_read;
+ adk->device.write = rt_usbh_adk_write;
+ adk->device.control = RT_NULL;
+#endif
+ adk->device.user_data = (void*)intf;
+
+ rt_device_register(&adk->device, "adkdev", RT_DEVICE_FLAG_RDWR);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will be invoked when usb device plug out is detected and it would clean
+ * and release all hub class related resources.
+ *
+ * @param arg the argument.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+static rt_err_t rt_usbh_adk_disable(void* arg)
+{
+ uadk_t adk;
+ struct uintf* intf = (struct uintf*)arg;
+
+ RT_ASSERT(intf != RT_NULL);
+
+ LOG_D("rt_usbh_adk_stop");
+
+ adk = (uadk_t)intf->user_data;
+ if(adk == RT_NULL)
+ {
+ rt_free(intf);
+ return RT_EOK;
+ }
+
+ if(adk->pipe_in != RT_NULL)
+ rt_usb_hcd_free_pipe(intf->device->hcd, adk->pipe_in);
+
+ if(adk->pipe_out != RT_NULL)
+ rt_usb_hcd_free_pipe(intf->device->hcd, adk->pipe_out);
+
+ /* unregister adk device */
+ rt_device_unregister(&adk->device);
+
+ /* free adk instance */
+ if(adk != RT_NULL)
+ {
+ rt_free(adk);
+ }
+
+ /* free interface instance */
+ rt_free(intf);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will register adk class driver to the usb class driver manager.
+ * and it should be invoked in the usb system initialization.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+ucd_t rt_usbh_class_driver_adk(void)
+{
+ adk_driver.class_code = USB_CLASS_ADK;
+
+ adk_driver.enable = rt_usbh_adk_enable;
+ adk_driver.disable = rt_usbh_adk_disable;
+
+ return &adk_driver;
+}
+
+#endif
+
diff --git a/components/legacy/usb/usbhost/class/adk.h b/components/legacy/usb/usbhost/class/adk.h
new file mode 100644
index 0000000000..67c3392d7a
--- /dev/null
+++ b/components/legacy/usb/usbhost/class/adk.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2011-12-12 Yi Qiu first version
+ */
+
+#ifndef __ADK_H__
+#define __ADK_H__
+
+#include <rtthread.h>
+
+struct uadkinst
+{
+ upipe_t pipe_in;
+ upipe_t pipe_out;
+
+ struct rt_device device;
+};
+typedef struct uadkinst* uadk_t;
+
+#define USB_ACCESSORY_VENDOR_ID 0x18D1
+#define USB_ACCESSORY_PRODUCT_ID 0x2D00
+#define USB_ACCESSORY_ADB_PRODUCT_ID 0x2D01
+
+#define ACCESSORY_STRING_MANUFACTURER 0
+#define ACCESSORY_STRING_MODEL 1
+#define ACCESSORY_STRING_DESCRIPTION 2
+#define ACCESSORY_STRING_VERSION 3
+#define ACCESSORY_STRING_URI 4
+#define ACCESSORY_STRING_SERIAL 5
+
+#define USB_REQ_GET_PROTOCOL 51
+#define USB_REQ_SEND_STRING 52
+#define USB_REQ_START 53
+
+#define USB_CLASS_ADK 0xff
+
+#endif
+
diff --git a/components/legacy/usb/usbhost/class/hid.c b/components/legacy/usb/usbhost/class/hid.c
new file mode 100644
index 0000000000..5911faf1aa
--- /dev/null
+++ b/components/legacy/usb/usbhost/class/hid.c
@@ -0,0 +1,410 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2011-12-12 Yi Qiu first version
+ * 2021-02-23 Leslie Lee update with current usb api
+ */
+
+#include <rtthread.h>
+#include <drivers/usb_host.h>
+#include "hid.h"
+
+#ifdef RT_USBH_HID
+
+#define DBG_TAG "usbhost.hid"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+static struct uclass_driver hid_driver;
+static rt_list_t _protocal_list;
+
+/**
+ * This function will do USB_REQ_SET_IDLE request to set idle period to the usb hid device
+ *
+ * @param intf the interface instance.
+ * @duration the idle period of requesting data.
+ * @report_id the report id
+ *
+ * @return the error code, RT_EOK on successfully.
+*/
+rt_err_t rt_usbh_hid_set_idle(struct uhintf* intf, int duration, int report_id)
+{
+ struct urequest setup;
+ struct uinstance* device;
+ int timeout = USB_TIMEOUT_BASIC;
+
+ /* parameter check */
+ RT_ASSERT(intf != RT_NULL);
+ RT_ASSERT(intf->device != RT_NULL);
+
+ device = intf->device;
+
+ setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
+ USB_REQ_TYPE_INTERFACE;
+ setup.bRequest = USB_REQ_SET_IDLE;
+ setup.wIndex = 0;
+ setup.wLength = 0;
+ setup.wValue = (duration << 8 )| report_id;
+
+ if (rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
+ if (rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) == 0)
+ return RT_EOK;
+
+ return -RT_FALSE;
+}
+
+/**
+ * This function will do USB_REQ_GET_REPORT request to get report from the usb hid device
+ *
+ * @param intf the interface instance.
+ * @buffer the data buffer to save usb report descriptor.
+ * @param nbytes the size of buffer
+ *
+ * @return the error code, RT_EOK on successfully.
+*/
+rt_err_t rt_usbh_hid_get_report(struct uhintf* intf, rt_uint8_t type,
+ rt_uint8_t id, rt_uint8_t *buffer, rt_size_t size)
+{
+ struct urequest setup;
+ struct uinstance* device;
+ int timeout = USB_TIMEOUT_BASIC;
+
+ /* parameter check */
+ RT_ASSERT(intf != RT_NULL);
+ RT_ASSERT(intf->device != RT_NULL);
+
+ device = intf->device;
+
+ setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS |
+ USB_REQ_TYPE_INTERFACE;
+ setup.bRequest = USB_REQ_GET_REPORT;
+ setup.wIndex = intf->intf_desc->bInterfaceNumber;
+ setup.wLength = size;
+ setup.wValue = (type << 8 ) + id;
+
+ if (rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
+ {
+ if (rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, buffer, size, timeout) == size)
+ {
+ if (rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, RT_NULL, 0, timeout) == 0)
+ {
+ return RT_EOK;
+ }
+ }
+ }
+ else
+ return -RT_FALSE;
+ return -RT_FALSE;
+}
+
+/**
+ * This function will do USB_REQ_SET_REPORT request to set report to the usb hid device
+ *
+ * @param intf the interface instance.
+ * @buffer the data buffer to save usb report descriptor.
+ * @param nbytes the size of buffer
+ *
+ * @return the error code, RT_EOK on successfully.
+*/
+rt_err_t rt_usbh_hid_set_report(struct uhintf* intf, rt_uint8_t *buffer, rt_size_t size)
+{
+ struct urequest setup;
+ struct uinstance* device;
+ int timeout = USB_TIMEOUT_BASIC;
+
+ /* parameter check */
+ RT_ASSERT(intf != RT_NULL);
+ RT_ASSERT(intf->device != RT_NULL);
+
+ device = intf->device;
+
+ setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
+ USB_REQ_TYPE_INTERFACE;
+ setup.bRequest = USB_REQ_SET_REPORT;
+ setup.wIndex = intf->intf_desc->bInterfaceNumber;
+ setup.wLength = size;
+ setup.wValue = 0x02 << 8;
+
+ if (rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
+ return RT_EOK;
+ else
+ return -RT_FALSE;
+}
+
+/**
+ * This function will do USB_REQ_SET_PROTOCOL request to set protocal to the usb hid device.
+ *
+ * @param intf the interface instance.
+ * @param protocol the protocol id.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_hid_set_protocal(struct uhintf* intf, int protocol)
+{
+ struct urequest setup;
+ struct uinstance* device;
+ int timeout = USB_TIMEOUT_BASIC;
+
+ /* parameter check */
+ RT_ASSERT(intf != RT_NULL);
+ RT_ASSERT(intf->device != RT_NULL);
+
+ device = intf->device;
+
+ setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
+ USB_REQ_TYPE_INTERFACE;
+ setup.bRequest = USB_REQ_SET_PROTOCOL;
+ setup.wIndex = 0;
+ setup.wLength = 0;
+ setup.wValue = protocol;
+
+ if (rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
+ return RT_EOK;
+ else
+ return -RT_FALSE;
+}
+
+/**
+ * This function will do USB_REQ_GET_DESCRIPTOR request for the device instance
+ * to set feature of the hub port.
+ *
+ * @param intf the interface instance.
+ * @buffer the data buffer to save usb report descriptor.
+ * @param nbytes the size of buffer
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_hid_get_report_descriptor(struct uhintf* intf,
+ rt_uint8_t *buffer, rt_size_t size)
+{
+ struct urequest setup;
+ struct uinstance* device;
+ int timeout = USB_TIMEOUT_BASIC;
+
+ /* parameter check */
+ RT_ASSERT(intf != RT_NULL);
+ RT_ASSERT(intf->device != RT_NULL);
+
+ device = intf->device;
+
+ setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_STANDARD|
+ USB_REQ_TYPE_INTERFACE;
+ setup.bRequest = USB_REQ_GET_DESCRIPTOR;
+ setup.wIndex = 0;
+ setup.wLength = size;
+ setup.wValue = USB_DESC_TYPE_REPORT << 8;
+
+ if (rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
+ {
+ if (rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, buffer, size, timeout) == size)
+ {
+ if (rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, RT_NULL, 0, timeout) == 0)
+ {
+ return RT_EOK;
+ }
+ }
+ }
+ else
+ return -RT_FALSE;
+ return -RT_FALSE;
+}
+
+/**
+ * This function will register specified hid protocal to protocal list
+ *
+ * @param protocal the specified protocal.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_hid_protocal_register(uprotocal_t protocal)
+{
+ RT_ASSERT(protocal != RT_NULL);
+
+ if (protocal == RT_NULL) return -RT_ERROR;
+
+ /* insert class driver into driver list */
+ rt_list_insert_after(&_protocal_list, &(protocal->list));
+
+ return RT_EOK;
+}
+
+/**
+ * This function is the callback function of hid's int endpoint, it is invoked when data comes.
+ *
+ * @param context the context of the callback function.
+ *
+ * @return none.
+ */
+static void rt_usbh_hid_callback(void* context)
+{
+ upipe_t pipe;
+ struct uhid* hid;
+ int timeout = USB_TIMEOUT_LONG;
+
+ /* parameter check */
+ RT_ASSERT(context != RT_NULL);
+
+ pipe = (upipe_t)context;
+ hid = (struct uhid*)((struct uhintf*)pipe->inst)->user_data;
+
+ /* invoke protocal callback function */
+ hid->protocal->callback((void*)hid);
+
+ /* parameter check */
+ RT_ASSERT(((struct uhintf*)pipe->inst)->device->hcd != RT_NULL);
+
+ rt_usb_hcd_pipe_xfer(((struct uhintf*)pipe->inst)->device->hcd, pipe,
+ hid->buffer, pipe->ep.wMaxPacketSize, timeout);
+}
+
+/**
+ * This function will find specified hid protocal from protocal list
+ *
+ * @param pro_id the protocal id.
+ *
+ * @return the found protocal or RT_NULL if there is no this protocal.
+ */
+static uprotocal_t rt_usbh_hid_protocal_find(int pro_id)
+{
+ struct rt_list_node *node;
+
+ /* try to find protocal object */
+ for (node = _protocal_list.next; node != &_protocal_list; node = node->next)
+ {
+ uprotocal_t protocal =
+ (uprotocal_t)rt_list_entry(node, struct uprotocal, list);
+ if (protocal->pro_id == pro_id) return protocal;
+ }
+
+ /* not found */
+ return RT_NULL;
+}
+
+/**
+ * This function will run hid class driver when usb device is detected and identified
+ * as a hid class device, it will continue the enumulate process.
+ *
+ * @param arg the argument.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+static rt_err_t rt_usbh_hid_enable(void* arg)
+{
+ int i = 0, pro_id;
+ uprotocal_t protocal;
+ struct uhid* hid;
+ struct uhintf* intf = (struct uhintf*)arg;
+
+ /* parameter check */
+ if(intf == RT_NULL)
+ {
+ rt_kprintf("the interface is not available\n");
+ return -RT_EIO;
+ }
+
+ pro_id = intf->intf_desc->bInterfaceProtocol;
+
+ LOG_D("HID device enable, protocal id %d", pro_id);
+
+ protocal = rt_usbh_hid_protocal_find(pro_id);
+ if(protocal == RT_NULL)
+ {
+ rt_kprintf("can't find hid protocal %d\n", pro_id);
+ intf->user_data = RT_NULL;
+ return -RT_ERROR;
+ }
+
+ hid = rt_malloc(sizeof(struct uhid));
+ RT_ASSERT(hid != RT_NULL);
+
+ /* initilize the data structure */
+ rt_memset(hid, 0, sizeof(struct uhid));
+ intf->user_data = (void*)hid;
+ hid->protocal = protocal;
+
+ for(i=0; i<intf->intf_desc->bNumEndpoints; i++)
+ {
+ rt_err_t ret;
+ uep_desc_t ep_desc;
+
+ /* get endpoint descriptor */
+ rt_usbh_get_endpoint_descriptor(intf->intf_desc, i, &ep_desc);
+ if(ep_desc == RT_NULL)
+ {
+ rt_kprintf("rt_usbh_get_endpoint_descriptor error\n");
+ return -RT_ERROR;
+ }
+
+ if(USB_EP_ATTR(ep_desc->bmAttributes) != USB_EP_ATTR_INT)
+ continue;
+
+ if(!(ep_desc->bEndpointAddress & USB_DIR_IN)) continue;
+
+ ret = rt_usb_hcd_alloc_pipe(intf->device->hcd, &hid->pipe_in,
+ intf->device, ep_desc);
+ if(ret != RT_EOK) return ret;
+ }
+
+ /* initialize hid protocal */
+ hid->protocal->init((void*)intf);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will be invoked when usb device plug out is detected and it would clean
+ * and release all hub class related resources.
+ *
+ * @param arg the argument.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+static rt_err_t rt_usbh_hid_disable(void* arg)
+{
+ struct uhid* hid;
+ struct uhintf* intf = (struct uhintf*)arg;
+
+ RT_ASSERT(intf != RT_NULL);
+
+ LOG_D("rt_usbh_hid_disable");
+
+ hid = (struct uhid*)intf->user_data;
+ if(hid != RT_NULL)
+ {
+ if(hid->pipe_in != RT_NULL)
+ {
+ /* free the HID in pipe */
+ rt_usb_hcd_free_pipe(intf->device->hcd, hid->pipe_in);
+ }
+
+ /* free the hid instance */
+ rt_free(hid);
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * This function will register hid class driver to the usb class driver manager.
+ * and it should be invoked in the usb system initialization.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+ucd_t rt_usbh_class_driver_hid(void)
+{
+ rt_list_init(&_protocal_list);
+
+ hid_driver.class_code = USB_CLASS_HID;
+
+ hid_driver.enable = rt_usbh_hid_enable;
+ hid_driver.disable = rt_usbh_hid_disable;
+
+ return &hid_driver;
+}
+
+#endif
+
diff --git a/components/legacy/usb/usbhost/class/hid.h b/components/legacy/usb/usbhost/class/hid.h
new file mode 100644
index 0000000000..c7e88b66b8
--- /dev/null
+++ b/components/legacy/usb/usbhost/class/hid.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2011-12-12 Yi Qiu first version
+ */
+
+#ifndef __HID_H__
+#define __HID_H__
+
+#include <rtthread.h>
+
+struct uhid
+{
+ upipe_t pipe_in;
+ rt_uint8_t buffer[8];
+ uprotocal_t protocal;
+};
+typedef struct uhid uhid_t;
+
+#define USB_REQ_GET_REPORT 0x01
+#define USB_REQ_GET_IDLE 0x02
+#define USB_REQ_GET_PROTOCOL 0x03
+#define USB_REQ_SET_REPORT 0x09
+#define USB_REQ_SET_IDLE 0x0a
+#define USB_REQ_SET_PROTOCOL 0x0b
+
+#define USB_HID_KEYBOARD 1
+#define USB_HID_MOUSE 2
+
+rt_err_t rt_usbh_hid_set_idle(struct uhintf* intf, int duration, int report_id);
+rt_err_t rt_usbh_hid_get_report(struct uhintf* intf, rt_uint8_t type, rt_uint8_t id, rt_uint8_t *buffer, rt_size_t size);
+rt_err_t rt_usbh_hid_set_report(struct uhintf* intf, rt_uint8_t *buffer, rt_size_t size);
+rt_err_t rt_usbh_hid_set_protocal(struct uhintf* intf, int protocol);
+rt_err_t rt_usbh_hid_get_report_descriptor(struct uhintf* intf, rt_uint8_t *buffer, rt_size_t size);
+rt_err_t rt_usbh_hid_protocal_register(uprotocal_t protocal);
+
+#endif
diff --git a/components/legacy/usb/usbhost/class/mass.c b/components/legacy/usb/usbhost/class/mass.c
new file mode 100644
index 0000000000..c29cd30ee4
--- /dev/null
+++ b/components/legacy/usb/usbhost/class/mass.c
@@ -0,0 +1,647 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2011-12-12 Yi Qiu first version
+ */
+
+#include <rtthread.h>
+#include <drivers/usb_host.h>
+#include "mass.h"
+
+#ifdef RT_USBH_MSTORAGE
+
+#define DBG_TAG "usbhost.mass"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+extern rt_err_t rt_udisk_run(struct uhintf* intf);
+extern rt_err_t rt_udisk_stop(struct uhintf* intf);
+
+static struct uclass_driver storage_driver;
+
+/**
+ * This function will do USBREQ_GET_MAX_LUN request for the usb interface instance.
+ *
+ * @param intf the interface instance.
+ * @param max_lun the buffer to save max_lun.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+static rt_err_t _pipe_check(struct uhintf* intf, upipe_t pipe)
+{
+ struct uinstance* device;
+ rt_err_t ret;
+ ustor_t stor;
+ int size = 0;
+ struct ustorage_csw csw;
+
+ if(intf == RT_NULL || pipe == RT_NULL)
+ {
+ rt_kprintf("the interface is not available\n");
+ return -RT_EIO;
+ }
+
+ /* get usb device instance from the interface instance */
+ device = intf->device;
+
+ /* get storage instance from the interface instance */
+ stor = (ustor_t)intf->user_data;
+
+ /* check pipe status */
+ if(pipe->status == UPIPE_STATUS_OK) return RT_EOK;
+
+ if(pipe->status == UPIPE_STATUS_ERROR)
+ {
+ rt_kprintf("pipe status error\n");
+ return -RT_EIO;
+ }
+ if(pipe->status == UPIPE_STATUS_STALL)
+ {
+ /* clear the pipe stall status */
+ ret = rt_usbh_clear_feature(device, pipe->ep.bEndpointAddress,
+ USB_FEATURE_ENDPOINT_HALT);
+ if(ret != RT_EOK) return ret;
+ }
+
+
+ rt_thread_delay(50);
+
+ rt_kprintf("pipes1 0x%x, 0x%x\n", stor->pipe_in, stor->pipe_out);
+
+ stor->pipe_in->status = UPIPE_STATUS_OK;
+
+ LOG_D("clean storage in pipe stall");
+
+ /* it should receive csw after clear the stall feature */
+ size = rt_usb_hcd_pipe_xfer(stor->pipe_in->inst->hcd,
+ stor->pipe_in, &csw, SIZEOF_CSW, 100);
+ if(size != SIZEOF_CSW)
+ {
+ rt_kprintf("receive the csw after stall failed\n");
+ return -RT_EIO;
+ }
+
+ return -RT_ERROR;
+}
+
+/**
+ * This function will do USBREQ_GET_MAX_LUN request for the usb interface instance.
+ *
+ * @param intf the interface instance.
+ * @param max_lun the buffer to save max_lun.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+static rt_err_t rt_usb_bulk_only_xfer(struct uhintf* intf,
+ ustorage_cbw_t cmd, rt_uint8_t* buffer, int timeout)
+{
+ rt_size_t size;
+ rt_err_t ret;
+ upipe_t pipe;
+ struct ustorage_csw csw;
+ ustor_t stor;
+
+ RT_ASSERT(cmd != RT_NULL);
+
+ if(intf == RT_NULL)
+ {
+ rt_kprintf("the interface is not available\n");
+ return -RT_EIO;
+ }
+
+ /* get storage instance from the interface instance */
+ stor = (ustor_t)intf->user_data;
+
+ do
+ {
+ /* send the cbw */
+ size = rt_usb_hcd_pipe_xfer(stor->pipe_out->inst->hcd, stor->pipe_out,
+ cmd, SIZEOF_CBW, timeout);
+ if(size != SIZEOF_CBW)
+ {
+ rt_kprintf("CBW size error\n");
+ return -RT_EIO;
+ }
+ if(cmd->xfer_len != 0)
+ {
+ pipe = (cmd->dflags == CBWFLAGS_DIR_IN) ? stor->pipe_in :
+ stor->pipe_out;
+ size = rt_usb_hcd_pipe_xfer(pipe->inst->hcd, pipe, (void*)buffer,
+ cmd->xfer_len, timeout);
+ if(size != cmd->xfer_len)
+ {
+ rt_kprintf("request size %d, transfer size %d\n",
+ cmd->xfer_len, size);
+ break;
+ }
+ }
+
+ /* receive the csw */
+ size = rt_usb_hcd_pipe_xfer(stor->pipe_in->inst->hcd, stor->pipe_in,
+ &csw, SIZEOF_CSW, timeout);
+ if(size != SIZEOF_CSW)
+ {
+ rt_kprintf("csw size error\n");
+ return -RT_EIO;
+ }
+ }while(0);
+
+ /* check in pipes status */
+ ret = _pipe_check(intf, stor->pipe_in);
+ if(ret != RT_EOK)
+ {
+ rt_kprintf("in pipe error\n");
+ return ret;
+ }
+
+ /* check out pipes status */
+ ret = _pipe_check(intf, stor->pipe_out);
+ if(ret != RT_EOK)
+ {
+ rt_kprintf("out pipe error\n");
+ return ret;
+ }
+
+ /* check csw status */
+ if(csw.signature != CSW_SIGNATURE || csw.tag != CBW_TAG_VALUE)
+ {
+ rt_kprintf("csw signature error\n");
+ return -RT_EIO;
+ }
+
+ if(csw.status != 0)
+ {
+ //rt_kprintf("csw status error:%d\n",csw.status);
+ return -RT_ERROR;
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * This function will do USBREQ_GET_MAX_LUN request for the usb interface instance.
+ *
+ * @param intf the interface instance.
+ * @param max_lun the buffer to save max_lun.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_storage_get_max_lun(struct uhintf* intf, rt_uint8_t* max_lun)
+{
+ struct uinstance* device;
+ struct urequest setup;
+ int timeout = USB_TIMEOUT_BASIC;
+
+ if(intf == RT_NULL)
+ {
+ rt_kprintf("the interface is not available\n");
+ return -RT_EIO;
+ }
+
+ /* parameter check */
+ RT_ASSERT(intf->device != RT_NULL);
+ LOG_D("rt_usbh_storage_get_max_lun");
+
+ /* get usb device instance from the interface instance */
+ device = intf->device;
+
+ /* construct the request */
+ setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS |
+ USB_REQ_TYPE_INTERFACE;
+ setup.bRequest = USBREQ_GET_MAX_LUN;
+ setup.wValue = intf->intf_desc->bInterfaceNumber;
+ setup.wIndex = 0;
+ setup.wLength = 1;
+
+ /* do control transfer request */
+ if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8)
+ {
+ return -RT_EIO;
+ }
+ if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, max_lun, 1, timeout) != 1)
+ {
+ return -RT_EIO;
+ }
+ if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, RT_NULL, 0, timeout) != 0)
+ {
+ return -RT_EIO;
+ }
+ return RT_EOK;
+}
+
+/**
+ * This function will do USBREQ_MASS_STORAGE_RESET request for the usb interface instance.
+ *
+ * @param intf the interface instance.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_storage_reset(struct uhintf* intf)
+{
+ struct urequest setup;
+ struct uinstance* device;
+ int timeout = USB_TIMEOUT_BASIC;
+
+ /* parameter check */
+ if(intf == RT_NULL)
+ {
+ rt_kprintf("the interface is not available\n");
+ return -RT_EIO;
+ }
+
+ RT_ASSERT(intf->device != RT_NULL);
+ LOG_D("rt_usbh_storage_reset");
+
+ /* get usb device instance from the interface instance */
+ device = intf->device;
+
+ /* construct the request */
+ setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
+ USB_REQ_TYPE_INTERFACE;
+ setup.bRequest = USBREQ_MASS_STORAGE_RESET;
+ setup.wIndex = intf->intf_desc->bInterfaceNumber;
+ setup.wLength = 0;
+ setup.wValue = 0;
+
+ if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8)
+ {
+ return -RT_EIO;
+ }
+ if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) != 0)
+ {
+ return -RT_EIO;
+ }
+ return RT_EOK;
+}
+
+/**
+ * This function will execute SCSI_READ_10 command to read data from the usb device.
+ *
+ * @param intf the interface instance.
+ * @param buffer the data buffer to save read data
+ * @param sector the start sector address to read.
+ * @param sector the sector count to read.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_storage_read10(struct uhintf* intf, rt_uint8_t *buffer,
+ rt_uint32_t sector, rt_size_t count, int timeout)
+{
+ struct ustorage_cbw cmd;
+
+ /* parameter check */
+ if(intf == RT_NULL)
+ {
+ rt_kprintf("interface is not available\n");
+ return -RT_EIO;
+ }
+
+ RT_ASSERT(intf->device != RT_NULL);
+ LOG_D("rt_usbh_storage_read10");
+
+ /* construct the command block wrapper */
+ rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
+ cmd.signature = CBW_SIGNATURE;
+ cmd.tag = CBW_TAG_VALUE;
+ cmd.xfer_len = SECTOR_SIZE * count;
+ cmd.dflags = CBWFLAGS_DIR_IN;
+ cmd.lun = 0;
+ cmd.cb_len = 10;
+ cmd.cb[0] = SCSI_READ_10;
+ cmd.cb[1] = 0;
+ cmd.cb[2] = (rt_uint8_t)(sector >> 24);
+ cmd.cb[3] = (rt_uint8_t)(sector >> 16);
+ cmd.cb[4] = (rt_uint8_t)(sector >> 8);
+ cmd.cb[5] = (rt_uint8_t)sector;
+ cmd.cb[6] = 0;
+ cmd.cb[7] = (count & 0xff00) >> 8;
+ cmd.cb[8] = (rt_uint8_t) count & 0xff;
+
+ return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout);
+}
+
+/**
+ * This function will execute SCSI_WRITE_10 command to write data to the usb device.
+ *
+ * @param intf the interface instance.
+ * @param buffer the data buffer to save write data
+ * @param sector the start sector address to write.
+ * @param sector the sector count to write.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_storage_write10(struct uhintf* intf, rt_uint8_t *buffer,
+ rt_uint32_t sector, rt_size_t count, int timeout)
+{
+ struct ustorage_cbw cmd;
+
+ /* parameter check */
+ if(intf == RT_NULL)
+ {
+ rt_kprintf("the interface is not available\n");
+ return -RT_EIO;
+ }
+
+ RT_ASSERT(intf->device != RT_NULL);
+ LOG_D("rt_usbh_storage_write10");
+
+ /* construct the command block wrapper */
+ rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
+ cmd.signature = CBW_SIGNATURE;
+ cmd.tag = CBW_TAG_VALUE;
+ cmd.xfer_len = SECTOR_SIZE * count;
+ cmd.dflags = CBWFLAGS_DIR_OUT;
+ cmd.lun = 0;
+ cmd.cb_len = 10;
+ cmd.cb[0] = SCSI_WRITE_10;
+ cmd.cb[1] = 0;
+ cmd.cb[2] = (rt_uint8_t)(sector >> 24);
+ cmd.cb[3] = (rt_uint8_t)(sector >> 16);
+ cmd.cb[4] = (rt_uint8_t)(sector >> 8);
+ cmd.cb[5] = (rt_uint8_t)sector;
+ cmd.cb[6] = 0;
+ cmd.cb[7] = (count & 0xff00) >> 8;
+ cmd.cb[8] = (rt_uint8_t) count & 0xff;
+
+ return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout);
+}
+
+/**
+ * This function will execute SCSI_REQUEST_SENSE command to get sense data.
+ *
+ * @param intf the interface instance.
+ * @param buffer the data buffer to save sense data
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_storage_request_sense(struct uhintf* intf, rt_uint8_t* buffer)
+{
+ struct ustorage_cbw cmd;
+ int timeout = USB_TIMEOUT_LONG;
+
+ /* parameter check */
+ if(intf == RT_NULL)
+ {
+ rt_kprintf("the interface is not available\n");
+ return -RT_EIO;
+ }
+
+ RT_ASSERT(intf->device != RT_NULL);
+ LOG_D("rt_usbh_storage_request_sense");
+
+ /* construct the command block wrapper */
+ rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
+ cmd.signature = CBW_SIGNATURE;
+ cmd.tag = CBW_TAG_VALUE;
+ cmd.xfer_len = 18;
+ cmd.dflags = CBWFLAGS_DIR_IN;
+ cmd.lun = 0;
+ cmd.cb_len = 6;
+ cmd.cb[0] = SCSI_REQUEST_SENSE;
+ cmd.cb[4] = 18;
+
+ return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout);
+}
+
+/**
+ * This function will execute SCSI_TEST_UNIT_READY command to get unit ready status.
+ *
+ * @param intf the interface instance.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_storage_test_unit_ready(struct uhintf* intf)
+{
+ struct ustorage_cbw cmd;
+ int timeout = USB_TIMEOUT_LONG;
+
+ /* parameter check */
+ if(intf == RT_NULL)
+ {
+ rt_kprintf("the interface is not available\n");
+ return -RT_EIO;
+ }
+
+ RT_ASSERT(intf->device != RT_NULL);
+ LOG_D("rt_usbh_storage_test_unit_ready");
+
+ /* construct the command block wrapper */
+ rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
+ cmd.signature = CBW_SIGNATURE;
+ cmd.tag = CBW_TAG_VALUE;
+ cmd.xfer_len = 0;
+ cmd.dflags = CBWFLAGS_DIR_OUT;
+ cmd.lun = 0;
+ cmd.cb_len = 12;
+ cmd.cb[0] = SCSI_TEST_UNIT_READY;
+
+ return rt_usb_bulk_only_xfer(intf, &cmd, RT_NULL, timeout);
+}
+
+/**
+ * This function will execute SCSI_INQUIRY_CMD command to get inquiry data.
+ *
+ * @param intf the interface instance.
+ * @param buffer the data buffer to save inquiry data
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_storage_inquiry(struct uhintf* intf, rt_uint8_t* buffer)
+{
+ struct ustorage_cbw cmd;
+ int timeout = USB_TIMEOUT_LONG;
+
+ /* parameter check */
+ if(intf == RT_NULL)
+ {
+ rt_kprintf("the interface is not available\n");
+ return -RT_EIO;
+ }
+
+ RT_ASSERT(intf->device != RT_NULL);
+ LOG_D("rt_usbh_storage_inquiry");
+
+ /* construct the command block wrapper */
+ rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
+ cmd.signature = CBW_SIGNATURE;
+ cmd.tag = CBW_TAG_VALUE;
+ cmd.xfer_len = 36;
+ cmd.dflags = CBWFLAGS_DIR_IN;
+ cmd.lun = 0;
+ cmd.cb_len = 6;//12
+ cmd.cb[0] = SCSI_INQUIRY_CMD;
+ cmd.cb[4] = 36;
+
+ return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout);
+}
+
+/**
+ * This function will execute SCSI_READ_CAPACITY command to get capacity data.
+ *
+ * @param intf the interface instance.
+ * @param buffer the data buffer to save capacity data
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_storage_get_capacity(struct uhintf* intf, rt_uint8_t* buffer)
+{
+ struct ustorage_cbw cmd;
+ int timeout = USB_TIMEOUT_LONG;
+
+ /* parameter check */
+ if(intf == RT_NULL)
+ {
+ rt_kprintf("the interface is not available\n");
+ return -RT_EIO;
+ }
+
+ RT_ASSERT(intf->device != RT_NULL);
+ LOG_D("rt_usbh_storage_get_capacity");
+
+ /* construct the command block wrapper */
+ rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
+ cmd.signature = CBW_SIGNATURE;
+ cmd.tag = CBW_TAG_VALUE;
+ cmd.xfer_len = 8;
+ cmd.dflags = CBWFLAGS_DIR_IN;
+ cmd.lun = 0;
+ cmd.cb_len = 12;
+ cmd.cb[0] = SCSI_READ_CAPACITY;
+
+ return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout);
+}
+
+/**
+ * This function will run mass storage class driver when usb device is detected
+ * and identified as a mass storage class device, it will continue to do the enumulate
+ * process.
+ *
+ * @param arg the argument.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+static rt_err_t rt_usbh_storage_enable(void* arg)
+{
+ int i = 0;
+ rt_err_t ret;
+ ustor_t stor;
+ struct uhintf* intf = (struct uhintf*)arg;
+
+ /* parameter check */
+ if(intf == RT_NULL)
+ {
+ rt_kprintf("the interface is not available\n");
+ return -RT_EIO;
+ }
+
+ LOG_D("subclass %d, protocal %d",
+ intf->intf_desc->bInterfaceSubClass,
+ intf->intf_desc->bInterfaceProtocol);
+
+ LOG_D("rt_usbh_storage_run");
+
+ /* only support SCSI subclass and bulk only protocal */
+
+ stor = rt_malloc(sizeof(struct ustor));
+ RT_ASSERT(stor != RT_NULL);
+
+ /* initilize the data structure */
+ rt_memset(stor, 0, sizeof(struct ustor));
+ intf->user_data = (void*)stor;
+
+ for(i=0; i<intf->intf_desc->bNumEndpoints; i++)
+ {
+ uep_desc_t ep_desc;
+
+ /* get endpoint descriptor from interface descriptor */
+ rt_usbh_get_endpoint_descriptor(intf->intf_desc, i, &ep_desc);
+ if(ep_desc == RT_NULL)
+ {
+ rt_kprintf("rt_usb_get_endpoint_descriptor error\n");
+ return -RT_ERROR;
+ }
+
+ /* the endpoint type of mass storage class should be BULK */
+ if((ep_desc->bmAttributes & USB_EP_ATTR_TYPE_MASK) != USB_EP_ATTR_BULK)
+ continue;
+
+ /* allocate pipes according to the endpoint type */
+ if(ep_desc->bEndpointAddress & USB_DIR_IN)
+ {
+ /* alloc an in pipe for the storage instance */
+ stor->pipe_in = rt_usb_instance_find_pipe(intf->device,ep_desc->bEndpointAddress);
+ }
+ else
+ {
+ /* alloc an output pipe for the storage instance */
+ stor->pipe_out = rt_usb_instance_find_pipe(intf->device,ep_desc->bEndpointAddress);
+ }
+ }
+
+ /* check pipes infomation */
+ if(stor->pipe_in == RT_NULL || stor->pipe_out == RT_NULL)
+ {
+ rt_kprintf("pipe error, unsupported device\n");
+ return -RT_ERROR;
+ }
+
+ /* should implement as callback */
+ ret = rt_udisk_run(intf);
+ if(ret != RT_EOK) return ret;
+
+ return RT_EOK;
+}
+
+/**
+ * This function will be invoked when usb device plug out is detected and it would clean
+ * and release all mass storage class related resources.
+ *
+ * @param arg the argument.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+static rt_err_t rt_usbh_storage_disable(void* arg)
+{
+ ustor_t stor;
+ struct uhintf* intf = (struct uhintf*)arg;
+
+ /* parameter check */
+ RT_ASSERT(intf != RT_NULL);
+ RT_ASSERT(intf->user_data != RT_NULL);
+ RT_ASSERT(intf->device != RT_NULL);
+
+ LOG_D("rt_usbh_storage_stop");
+
+ /* get storage instance from interface instance */
+ stor = (ustor_t)intf->user_data;
+
+ rt_udisk_stop(intf);
+
+
+ /* free storage instance */
+ if(stor != RT_NULL) rt_free(stor);
+ return RT_EOK;
+}
+
+/**
+ * This function will register mass storage class driver to the usb class driver manager.
+ * and it should be invoked in the usb system initialization.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+ucd_t rt_usbh_class_driver_storage(void)
+{
+ storage_driver.class_code = USB_CLASS_MASS_STORAGE;
+
+ storage_driver.enable = rt_usbh_storage_enable;
+ storage_driver.disable = rt_usbh_storage_disable;
+
+ return &storage_driver;
+}
+
+#endif
+
diff --git a/components/legacy/usb/usbhost/class/mass.h b/components/legacy/usb/usbhost/class/mass.h
new file mode 100644
index 0000000000..6d54dd66a7
--- /dev/null
+++ b/components/legacy/usb/usbhost/class/mass.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2011-12-12 Yi Qiu first version
+ */
+
+#ifndef __MASS_H__
+#define __MASS_H__
+
+#include <rtthread.h>
+#include "dfs_fs.h"
+
+#define MAX_PARTITION_COUNT 4
+#define SECTOR_SIZE 512
+
+struct ustor_data
+{
+ struct dfs_partition part;
+ struct uhintf* intf;
+ int udisk_id;
+ const char path;
+};
+
+struct ustor
+{
+ upipe_t pipe_in;
+ upipe_t pipe_out;
+ rt_uint32_t capicity[2];
+
+ struct rt_device dev[MAX_PARTITION_COUNT];
+ rt_uint8_t dev_cnt;
+};
+typedef struct ustor* ustor_t;
+
+rt_err_t rt_usbh_storage_get_max_lun(struct uhintf* intf, rt_uint8_t* max_lun);
+rt_err_t rt_usbh_storage_reset(struct uhintf* intf);
+rt_err_t rt_usbh_storage_read10(struct uhintf* intf, rt_uint8_t *buffer,
+ rt_uint32_t sector, rt_size_t count, int timeout);
+rt_err_t rt_usbh_storage_write10(struct uhintf* intf, rt_uint8_t *buffer,
+ rt_uint32_t sector, rt_size_t count, int timeout);
+rt_err_t rt_usbh_storage_request_sense(struct uhintf* intf, rt_uint8_t* buffer);
+rt_err_t rt_usbh_storage_test_unit_ready(struct uhintf* intf);
+rt_err_t rt_usbh_storage_inquiry(struct uhintf* intf, rt_uint8_t* buffer);
+rt_err_t rt_usbh_storage_get_capacity(struct uhintf* intf, rt_uint8_t* buffer);
+
+#endif
diff --git a/components/legacy/usb/usbhost/class/udisk.c b/components/legacy/usb/usbhost/class/udisk.c
new file mode 100644
index 0000000000..07815e5996
--- /dev/null
+++ b/components/legacy/usb/usbhost/class/udisk.c
@@ -0,0 +1,456 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2011-12-12 Yi Qiu first version
+ */
+
+#include <rtthread.h>
+#include <dfs_fs.h>
+#include <drivers/usb_host.h>
+#include "mass.h"
+
+#define DBG_TAG "usbhost.udisk"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#ifdef RT_USBH_MSTORAGE
+
+#define UDISK_MAX_COUNT 8
+static rt_uint8_t _udisk_idset = 0;
+
+static int udisk_get_id(void)
+{
+ int i;
+
+ for(i=0; i< UDISK_MAX_COUNT; i++)
+ {
+ if((_udisk_idset & (1 << i)) != 0) continue;
+ else break;
+ }
+
+ /* it should not happen */
+ if(i == UDISK_MAX_COUNT) RT_ASSERT(0);
+
+ _udisk_idset |= (1 << i);
+ return i;
+}
+
+static void udisk_free_id(int id)
+{
+ RT_ASSERT(id < UDISK_MAX_COUNT)
+
+ _udisk_idset &= ~(1 << id);
+}
+
+/**
+ * This function will initialize the udisk device
+ *
+ * @param dev the pointer of device driver structure
+ *
+ * @return RT_EOK
+ */
+static rt_err_t rt_udisk_init(rt_device_t dev)
+{
+ return RT_EOK;
+}
+
+/**
+ * This function will read some data from a device.
+ *
+ * @param dev the pointer of device driver structure
+ * @param pos the position of reading
+ * @param buffer the data buffer to save read data
+ * @param size the size of buffer
+ *
+ * @return the actually read size on successful, otherwise negative returned.
+ */
+static rt_ssize_t rt_udisk_read(rt_device_t dev, rt_off_t pos, void* buffer,
+ rt_size_t size)
+{
+ rt_err_t ret;
+ struct uhintf* intf;
+ struct ustor_data* data;
+ int timeout = USB_TIMEOUT_LONG;
+
+ /* check parameter */
+ RT_ASSERT(dev != RT_NULL);
+ RT_ASSERT(buffer != RT_NULL);
+
+ if(size > 4096) timeout *= 2;
+
+ data = (struct ustor_data*)dev->user_data;
+ intf = data->intf;
+
+ ret = rt_usbh_storage_read10(intf, (rt_uint8_t*)buffer, pos, size, timeout);
+
+ if (ret != RT_EOK)
+ {
+ rt_kprintf("usb mass_storage read failed\n");
+ return 0;
+ }
+
+ return size;
+}
+
+/**
+ * This function will write some data to a device.
+ *
+ * @param dev the pointer of device driver structure
+ * @param pos the position of written
+ * @param buffer the data buffer to be written to device
+ * @param size the size of buffer
+ *
+ * @return the actually written size on successful, otherwise negative returned.
+ */
+static rt_ssize_t rt_udisk_write (rt_device_t dev, rt_off_t pos, const void* buffer,
+ rt_size_t size)
+{
+ rt_err_t ret;
+ struct uhintf* intf;
+ struct ustor_data* data;
+ int timeout = USB_TIMEOUT_LONG;
+
+ /* check parameter */
+ RT_ASSERT(dev != RT_NULL);
+ RT_ASSERT(buffer != RT_NULL);
+
+ if(size * SECTOR_SIZE > 4096) timeout *= 2;
+
+ data = (struct ustor_data*)dev->user_data;
+ intf = data->intf;
+
+ ret = rt_usbh_storage_write10(intf, (rt_uint8_t*)buffer, pos, size, timeout);
+ if (ret != RT_EOK)
+ {
+ rt_kprintf("usb mass_storage write %d sector failed\n", size);
+ return 0;
+ }
+
+ return size;
+}
+
+/**
+ * This function will execute SCSI_INQUIRY_CMD command to get inquiry data.
+ *
+ * @param intf the interface instance.
+ * @param buffer the data buffer to save inquiry data
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+static rt_err_t rt_udisk_control(rt_device_t dev, int cmd, void *args)
+{
+ ustor_t stor;
+ struct ustor_data* data;
+
+ /* check parameter */
+ RT_ASSERT(dev != RT_NULL);
+
+ data = (struct ustor_data*)dev->user_data;
+ stor = (ustor_t)data->intf->user_data;
+
+ if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
+ {
+ struct rt_device_blk_geometry *geometry;
+
+ geometry = (struct rt_device_blk_geometry *)args;
+ if (geometry == RT_NULL) return -RT_ERROR;
+
+ geometry->bytes_per_sector = SECTOR_SIZE;
+ geometry->block_size = stor->capicity[1];
+ geometry->sector_count = stor->capicity[0];
+ }
+
+ return RT_EOK;
+}
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops udisk_device_ops =
+{
+ rt_udisk_init,
+ RT_NULL,
+ RT_NULL,
+ rt_udisk_read,
+ rt_udisk_write,
+ rt_udisk_control
+};
+#endif
+
+/**
+ * This function will run udisk driver when usb disk is detected.
+ *
+ * @param intf the usb interface instance.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_udisk_run(struct uhintf* intf)
+{
+ int i = 0;
+ rt_err_t ret;
+ char dname[8];
+ char sname[8];
+ rt_uint8_t max_lun, *sector, sense[18], inquiry[36];
+ struct dfs_partition part[MAX_PARTITION_COUNT];
+ ustor_t stor;
+
+ /* check parameter */
+ RT_ASSERT(intf != RT_NULL);
+
+ /* set interface */
+// ret = rt_usbh_set_interface(intf->device, intf->intf_desc->bInterfaceNumber);
+// if(ret != RT_EOK)
+// rt_usbh_clear_feature(intf->device, 0, USB_FEATURE_ENDPOINT_HALT);
+ /* reset mass storage class device */
+ ret = rt_usbh_storage_reset(intf);
+ if(ret != RT_EOK) return ret;
+
+ stor = (ustor_t)intf->user_data;
+
+ /* get max logic unit number */
+ ret = rt_usbh_storage_get_max_lun(intf, &max_lun);
+ if(ret != RT_EOK)
+ rt_usbh_clear_feature(intf->device, 0, USB_FEATURE_ENDPOINT_HALT);
+
+ /* reset pipe in endpoint */
+ if(stor->pipe_in->status == UPIPE_STATUS_STALL)
+ {
+ ret = rt_usbh_clear_feature(intf->device,
+ stor->pipe_in->ep.bEndpointAddress, USB_FEATURE_ENDPOINT_HALT);
+ if(ret != RT_EOK) return ret;
+ }
+
+
+ /* reset pipe out endpoint */
+ if(stor->pipe_out->status == UPIPE_STATUS_STALL)
+ {
+ ret = rt_usbh_clear_feature(intf->device,
+ stor->pipe_out->ep.bEndpointAddress, USB_FEATURE_ENDPOINT_HALT);
+ if(ret != RT_EOK) return ret;
+ }
+
+ while((ret = rt_usbh_storage_inquiry(intf, inquiry)) != RT_EOK)
+ {
+ if(ret == -RT_EIO) return ret;
+
+ rt_thread_delay(5);
+ if(i++ < 10) continue;
+ rt_kprintf("rt_usbh_storage_inquiry error\n");
+ return -RT_ERROR;
+ }
+
+ i = 0;
+
+ /* wait device ready */
+ while((ret = rt_usbh_storage_test_unit_ready(intf)) != RT_EOK)
+ {
+ if(ret == -RT_EIO) return ret;
+
+ ret = rt_usbh_storage_request_sense(intf, sense);
+ if(ret == -RT_EIO) return ret;
+
+ rt_thread_delay(10);
+ if(i++ < 10) continue;
+
+ rt_kprintf("rt_usbh_storage_test_unit_ready error\n");
+ return -RT_ERROR;
+ }
+
+ i = 0;
+ rt_memset(stor->capicity, 0, sizeof(stor->capicity));
+
+ /* get storage capacity */
+ while((ret = rt_usbh_storage_get_capacity(intf,
+ (rt_uint8_t*)stor->capicity)) != RT_EOK)
+ {
+ if(ret == -RT_EIO) return ret;
+
+ rt_thread_delay(50);
+ if(i++ < 10) continue;
+
+ stor->capicity[0] = 2880;
+ stor->capicity[1] = 0x200;
+
+ rt_kprintf("rt_usbh_storage_get_capacity error\n");
+ break;
+ }
+
+ stor->capicity[0] = uswap_32(stor->capicity[0]);
+ stor->capicity[1] = uswap_32(stor->capicity[1]);
+ stor->capicity[0] += 1;
+
+ LOG_D("capicity %d, block size %d",
+ stor->capicity[0], stor->capicity[1]);
+
+ /* get the first sector to read partition table */
+ sector = (rt_uint8_t*) rt_malloc (SECTOR_SIZE);
+ if (sector == RT_NULL)
+ {
+ rt_kprintf("allocate partition sector buffer failed\n");
+ return -RT_ERROR;
+ }
+
+ rt_memset(sector, 0, SECTOR_SIZE);
+
+ LOG_D("read partition table");
+
+ /* get the partition table */
+ ret = rt_usbh_storage_read10(intf, sector, 0, 1, USB_TIMEOUT_LONG);
+ if(ret != RT_EOK)
+ {
+ rt_kprintf("read parition table error\n");
+
+ rt_free(sector);
+ return -RT_ERROR;
+ }
+
+ LOG_D("finished reading partition");
+
+ for(i=0; i<MAX_PARTITION_COUNT; i++)
+ {
+ /* get the first partition */
+ ret = dfs_filesystem_get_partition(&part[i], sector, i);
+ if (ret == RT_EOK)
+ {
+ struct ustor_data* data = rt_malloc(sizeof(struct ustor_data));
+ if (data == RT_NULL)
+ {
+ LOG_E("Allocate partition data buffer failed.");
+ continue;
+ }
+ rt_memset(data, 0, sizeof(struct ustor_data));
+ data->intf = intf;
+ data->udisk_id = udisk_get_id();
+ rt_snprintf(dname, 6, "ud%d-%d", data->udisk_id, i);
+ rt_snprintf(sname, 8, "sem_ud%d", i);
+ data->part.lock = rt_sem_create(sname, 1, RT_IPC_FLAG_FIFO);
+
+ /* register sdcard device */
+ stor->dev[i].type = RT_Device_Class_Block;
+#ifdef RT_USING_DEVICE_OPS
+ stor->dev[i].ops = &udisk_device_ops;
+#else
+ stor->dev[i].init = rt_udisk_init;
+ stor->dev[i].read = rt_udisk_read;
+ stor->dev[i].write = rt_udisk_write;
+ stor->dev[i].control = rt_udisk_control;
+#endif
+ stor->dev[i].user_data = (void*)data;
+
+ rt_device_register(&stor->dev[i], dname, RT_DEVICE_FLAG_RDWR |
+ RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE);
+
+ stor->dev_cnt++;
+ if (dfs_mount(stor->dev[i].parent.name, UDISK_MOUNTPOINT, "elm",
+ 0, 0) == 0)
+ {
+ LOG_D("udisk part %d mount successfully", i);
+ }
+ else
+ {
+ LOG_D("udisk part %d mount failed", i);
+ }
+ }
+ else
+ {
+ if(i == 0)
+ {
+ struct ustor_data* data = rt_malloc(sizeof(struct ustor_data));
+ if (data == RT_NULL)
+ {
+ LOG_E("Allocate partition data buffer failed.");
+ break;
+ }
+ rt_memset(data, 0, sizeof(struct ustor_data));
+ data->udisk_id = udisk_get_id();
+
+ /* there is no partition table */
+ data->part.offset = 0;
+ data->part.size = 0;
+ data->intf = intf;
+ data->part.lock = rt_sem_create("sem_ud", 1, RT_IPC_FLAG_FIFO);
+
+ rt_snprintf(dname, 7, "udisk%d", data->udisk_id);
+
+ /* register sdcard device */
+ stor->dev[0].type = RT_Device_Class_Block;
+#ifdef RT_USING_DEVICE_OPS
+ stor->dev[i].ops = &udisk_device_ops;
+#else
+ stor->dev[0].init = rt_udisk_init;
+ stor->dev[0].read = rt_udisk_read;
+ stor->dev[0].write = rt_udisk_write;
+ stor->dev[0].control = rt_udisk_control;
+#endif
+ stor->dev[0].user_data = (void*)data;
+
+ rt_device_register(&stor->dev[0], dname,
+ RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE
+ | RT_DEVICE_FLAG_STANDALONE);
+
+ stor->dev_cnt++;
+ if (dfs_mount(stor->dev[0].parent.name, UDISK_MOUNTPOINT,
+ "elm", 0, 0) == 0)
+ {
+ rt_kprintf("Mount FAT on Udisk successful.\n");
+ }
+ else
+ {
+ rt_kprintf("Mount FAT on Udisk failed.\n");
+ }
+ }
+
+ break;
+ }
+ }
+
+ rt_free(sector);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will be invoked when usb disk plug out is detected and it would clean
+ * and release all udisk related resources.
+ *
+ * @param intf the usb interface instance.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_udisk_stop(struct uhintf* intf)
+{
+ int i;
+ ustor_t stor;
+ struct ustor_data* data;
+
+ /* check parameter */
+ RT_ASSERT(intf != RT_NULL);
+ RT_ASSERT(intf->device != RT_NULL);
+
+ stor = (ustor_t)intf->user_data;
+ RT_ASSERT(stor != RT_NULL);
+
+ for(i=0; i<stor->dev_cnt; i++)
+ {
+ rt_device_t dev = &stor->dev[i];
+ data = (struct ustor_data*)dev->user_data;
+
+ /* unmount filesystem */
+ dfs_unmount(UDISK_MOUNTPOINT);
+
+ /* delete semaphore */
+ rt_sem_delete(data->part.lock);
+ udisk_free_id(data->udisk_id);
+ rt_free(data);
+
+ /* unregister device */
+ rt_device_unregister(&stor->dev[i]);
+ }
+
+ return RT_EOK;
+}
+
+#endif
+
diff --git a/components/legacy/usb/usbhost/class/ukbd.c b/components/legacy/usb/usbhost/class/ukbd.c
new file mode 100644
index 0000000000..db080ed406
--- /dev/null
+++ b/components/legacy/usb/usbhost/class/ukbd.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2012-01-03 Yi Qiu first version
+ */
+
+#include <rtthread.h>
+#include <drivers/usb_host.h>
+#include "hid.h"
+
+#if defined(RT_USBH_HID) && defined(RT_USBH_HID_KEYBOARD)
+
+#define DBG_TAG "usbhost.ukbd"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+static struct uprotocal kbd_protocal;
+
+static rt_err_t rt_usbh_hid_kbd_callback(void* arg)
+{
+ int int1, int2;
+ struct uhid* hid;
+
+ hid = (struct uhid*)arg;
+
+ int1 = *(rt_uint32_t*)hid->buffer;
+ int2 = *(rt_uint32_t*)(&hid->buffer[4]);
+
+ if(int1 != 0 || int2 != 0)
+ {
+ LOG_D("key down 0x%x, 0x%x", int1, int2);
+ }
+
+ return RT_EOK;
+}
+
+static rt_thread_t kbd_thread;
+static void kbd_task(void* param)
+{
+ struct uhintf* intf = (struct uhintf*)param;
+ while (1)
+ {
+ if (rt_usb_hcd_pipe_xfer(intf->device->hcd, ((struct uhid*)intf->user_data)->pipe_in,
+ ((struct uhid*)intf->user_data)->buffer, ((struct uhid*)intf->user_data)->pipe_in->ep.wMaxPacketSize,
+ USB_TIMEOUT_BASIC) == 0)
+ {
+ break;
+ }
+
+ rt_usbh_hid_kbd_callback(intf->user_data);
+ }
+}
+
+
+static rt_err_t rt_usbh_hid_kbd_init(void* arg)
+{
+ struct uhintf* intf = (struct uhintf*)arg;
+
+ RT_ASSERT(intf != RT_NULL);
+
+ rt_usbh_hid_set_protocal(intf, 0);
+
+ rt_usbh_hid_set_idle(intf, 10, 0);
+
+ LOG_D("start usb keyboard");
+
+ kbd_thread = rt_thread_create("kbd0", kbd_task, intf, 1024, 8, 100);
+ rt_thread_startup(kbd_thread);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will define the hid keyboard protocal, it will be register to the protocal list.
+ *
+ * @return the keyboard protocal structure.
+ */
+uprotocal_t rt_usbh_hid_protocal_kbd(void)
+{
+ kbd_protocal.pro_id = USB_HID_KEYBOARD;
+
+ kbd_protocal.init = rt_usbh_hid_kbd_init;
+ kbd_protocal.callback = rt_usbh_hid_kbd_callback;
+
+ return &kbd_protocal;
+}
+
+#endif
+
diff --git a/components/legacy/usb/usbhost/class/umouse.c b/components/legacy/usb/usbhost/class/umouse.c
new file mode 100644
index 0000000000..dfd6e9081c
--- /dev/null
+++ b/components/legacy/usb/usbhost/class/umouse.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2012-01-03 Yi Qiu first version
+ */
+
+#include <rtthread.h>
+#include <drivers/usb_host.h>
+#include "hid.h"
+
+#ifdef RT_USING_RTGUI
+#include <rtgui/event.h>
+#include <rtgui/rtgui_server.h>
+#include "drv_lcd.h"
+#endif
+
+#if defined(RT_USBH_HID) && defined(RT_USBH_HID_MOUSE)
+
+#define DBG_TAG "usbhost.umouse"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+static struct uprotocal mouse_protocal;
+
+#ifdef RT_USING_RTGUI
+#define LKEY_PRESS 0x01
+#define RKEY_PRESS 0x02
+#define MKEY_PRESS 0x04
+#define MOUSE_SCALING 0x02
+
+static rt_bool_t lkey_down=RT_FALSE;
+//static rt_bool_t rkey_down=RT_FALSE;
+//static rt_bool_t mkey_down=RT_FALSE;
+static struct rtgui_event_mouse emouse;
+#endif
+
+static rt_err_t rt_usbh_hid_mouse_callback(void* arg)
+{
+ struct uhid* hid;
+#ifdef RT_USING_RTGUI
+ rt_uint16_t xoffset=0;
+ rt_uint16_t yoffset=0;
+#endif
+ hid = (struct uhid*)arg;
+
+ LOG_D("hid 0x%x 0x%x",
+ *(rt_uint32_t*)hid->buffer,
+ *(rt_uint32_t*)(&hid->buffer[4]));
+#ifdef RT_USING_RTGUI
+ if(hid->buffer[1]!=0)
+ {
+ if(hid->buffer[1]>127)
+ {
+ xoffset=(256-hid->buffer[1])*MOUSE_SCALING;
+ if(emouse.x>xoffset)
+ {
+ emouse.x-=xoffset;
+ }
+ else
+ {
+ emouse.x=0;
+ }
+ }
+ else
+ {
+ xoffset=(hid->buffer[1])*MOUSE_SCALING;
+ if((emouse.x+xoffset)<480)
+ {
+ emouse.x+=xoffset;
+ }
+ else
+ {
+ emouse.x=480;
+ }
+ }
+ }
+ if(hid->buffer[2]!=0)
+ {
+
+ if(hid->buffer[2]>127)
+ {
+ yoffset=(256-hid->buffer[2])*MOUSE_SCALING;
+ if(emouse.y>yoffset)
+ {
+ emouse.y-=yoffset;
+ }
+ else
+ {
+ emouse.y=0;
+ }
+ }
+ else
+ {
+ yoffset=hid->buffer[2]*MOUSE_SCALING;
+ if(emouse.y+yoffset<272)
+ {
+ emouse.y+=yoffset;
+ }
+ else
+ {
+ emouse.y=272;
+ }
+ }
+ }
+ if(xoffset!=0||yoffset!=0)
+ {
+ cursor_set_position(emouse.x,emouse.y);
+ }
+ if(hid->buffer[0]&LKEY_PRESS)
+ {
+ if(lkey_down==RT_FALSE)
+ {
+ // rt_kprintf("mouse left key press down\n");
+ emouse.button = (RTGUI_MOUSE_BUTTON_LEFT | RTGUI_MOUSE_BUTTON_DOWN);
+ rtgui_server_post_event(&emouse.parent, sizeof(struct rtgui_event_mouse));
+ lkey_down=RT_TRUE;
+ }
+ }
+ else if(lkey_down==RT_TRUE)
+ {
+ // rt_kprintf("mouse left key press up\n");
+ emouse.button = (RTGUI_MOUSE_BUTTON_LEFT | RTGUI_MOUSE_BUTTON_UP);
+ rtgui_server_post_event(&emouse.parent, sizeof(struct rtgui_event_mouse));
+ lkey_down=RT_FALSE;
+ }
+#endif
+ return RT_EOK;
+}
+
+static rt_thread_t mouse_thread;
+static void mouse_task(void* param)
+{
+ struct uhintf* intf = (struct uhintf*)param;
+ while (1)
+ {
+ if (rt_usb_hcd_pipe_xfer(intf->device->hcd, ((struct uhid*)intf->user_data)->pipe_in,
+ ((struct uhid*)intf->user_data)->buffer, ((struct uhid*)intf->user_data)->pipe_in->ep.wMaxPacketSize,
+ USB_TIMEOUT_BASIC) == 0)
+ {
+ break;
+ }
+
+ rt_usbh_hid_mouse_callback(intf->user_data);
+ }
+}
+
+
+static rt_err_t rt_usbh_hid_mouse_init(void* arg)
+{
+ struct uhintf* intf = (struct uhintf*)arg;
+
+ RT_ASSERT(intf != RT_NULL);
+
+ rt_usbh_hid_set_protocal(intf, 0);
+
+ rt_usbh_hid_set_idle(intf, 0, 0);
+
+ mouse_thread = rt_thread_create("mouse0", mouse_task, intf, 1024, 8, 100);
+ rt_thread_startup(mouse_thread);
+
+ LOG_D("start usb mouse");
+#ifdef RT_USING_RTGUI
+ RTGUI_EVENT_MOUSE_BUTTON_INIT(&emouse);
+ emouse.wid = RT_NULL;
+ cursor_display(RT_TRUE);
+#endif
+ return RT_EOK;
+}
+
+/**
+ * This function will define the hid mouse protocal, it will be register to the protocal list.
+ *
+ * @return the keyboard protocal structure.
+ */
+uprotocal_t rt_usbh_hid_protocal_mouse(void)
+{
+ mouse_protocal.pro_id = USB_HID_MOUSE;
+
+ mouse_protocal.init = rt_usbh_hid_mouse_init;
+ mouse_protocal.callback = rt_usbh_hid_mouse_callback;
+
+ return &mouse_protocal;
+}
+
+#endif
+
diff --git a/components/legacy/usb/usbhost/core/driver.c b/components/legacy/usb/usbhost/core/driver.c
new file mode 100644
index 0000000000..28a79dfa7f
--- /dev/null
+++ b/components/legacy/usb/usbhost/core/driver.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2011-03-12 Yi Qiu first version
+ * 2021-02-23 Leslie Lee provide possibility for multi usb host
+ */
+
+#include <rtthread.h>
+#include <rtservice.h>
+#include <drivers/usb_host.h>
+
+static rt_list_t _driver_list;
+static rt_bool_t _driver_list_created = RT_FALSE;
+
+/**
+ * This function will initilize the usb class driver related data structure,
+ * and it should be invoked in the usb system initialization.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_class_driver_init(void)
+{
+ if (_driver_list_created == RT_FALSE)
+ {
+ rt_list_init(&_driver_list);
+ _driver_list_created = RT_TRUE;
+ }
+ return RT_EOK;
+}
+
+/**
+ * This function will register an usb class driver to the class driver manager.
+ *
+ * @param drv the pointer of the usb class driver.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+
+rt_err_t rt_usbh_class_driver_register(ucd_t drv)
+{
+ if (drv == RT_NULL) return -RT_ERROR;
+
+ if (rt_usbh_class_driver_find(drv->class_code, drv->subclass_code) == RT_NULL)
+ {
+ /* insert class driver into driver list */
+ rt_list_insert_after(&_driver_list, &(drv->list));
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * This function will removes a previously registed usb class driver.
+ *
+ * @param drv the pointer of the usb class driver structure.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_class_driver_unregister(ucd_t drv)
+{
+ RT_ASSERT(drv != RT_NULL);
+
+ /* remove class driver from driver list */
+ rt_list_remove(&(drv->list));
+
+ return RT_EOK;
+}
+
+/**
+ * This function will run an usb class driver.
+ *
+ * @param drv the pointer of usb class driver.
+ * @param args the parameter of run function.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_class_driver_enable(ucd_t drv, void* args)
+{
+ RT_ASSERT(drv != RT_NULL);
+
+ if(drv->enable != RT_NULL)
+ drv->enable(args);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will stop a usb class driver.
+ *
+ * @param drv the pointer of usb class driver structure.
+ * @param args the argument of the stop function.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_class_driver_disable(ucd_t drv, void* args)
+{
+ RT_ASSERT(drv != RT_NULL);
+
+ if(drv->disable != RT_NULL)
+ drv->disable(args);
+
+ return RT_EOK;
+}
+
+
+/**
+ * This function finds a usb class driver by specified class code and subclass code.
+ *
+ * @param class_code the usb class driver's class code.
+ * @param subclass_code the usb class driver's sub class code.
+ *
+ * @return the registered usb class driver on successful, or RT_NULL on failure.
+ */
+ucd_t rt_usbh_class_driver_find(int class_code, int subclass_code)
+{
+ struct rt_list_node *node;
+
+ /* enter critical */
+ if (rt_thread_self() != RT_NULL)
+ rt_enter_critical();
+
+ /* try to find driver object */
+ for (node = _driver_list.next; node != &_driver_list; node = node->next)
+ {
+ ucd_t drv =
+ (ucd_t)rt_list_entry(node, struct uclass_driver, list);
+ if (drv->class_code == class_code)
+ {
+ /* leave critical */
+ if (rt_thread_self() != RT_NULL)
+ rt_exit_critical();
+
+ return drv;
+ }
+ }
+
+ /* leave critical */
+ if (rt_thread_self() != RT_NULL)
+ rt_exit_critical();
+
+ /* not found */
+ return RT_NULL;
+}
diff --git a/components/legacy/usb/usbhost/core/hub.c b/components/legacy/usb/usbhost/core/hub.c
new file mode 100644
index 0000000000..d8e6716099
--- /dev/null
+++ b/components/legacy/usb/usbhost/core/hub.c
@@ -0,0 +1,727 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2011-12-12 Yi Qiu first version
+ * 2021-02-23 Leslie Lee provide possibility for multi usb host
+ */
+
+#include <rtthread.h>
+#include <drivers/usb_host.h>
+
+#define USB_THREAD_STACK_SIZE 4096
+
+#define DBG_TAG "usb.host.hub"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+
+// static struct rt_messagequeue *usb_mq;
+static struct uclass_driver hub_driver;
+// static struct uhub root_hub;
+
+static rt_err_t root_hub_ctrl(struct uhcd *hcd, rt_uint16_t port, rt_uint8_t cmd, void *args)
+{
+ switch(cmd)
+ {
+ case RH_GET_PORT_STATUS:
+ (*(rt_uint32_t *)args) = hcd->roothub->port_status[port-1];
+ break;
+ case RH_SET_PORT_STATUS:
+ hcd->roothub->port_status[port-1] = (*(rt_uint32_t *)args);
+ break;
+ case RH_CLEAR_PORT_FEATURE:
+ switch(((rt_uint32_t)args))
+ {
+ case PORT_FEAT_C_CONNECTION:
+ hcd->roothub->port_status[port-1] &= ~PORT_CCSC;
+ break;
+ case PORT_FEAT_C_ENABLE:
+ hcd->roothub->port_status[port-1] &= ~PORT_PESC;
+ break;
+ case PORT_FEAT_C_SUSPEND:
+ hcd->roothub->port_status[port-1] &= ~PORT_PSSC;
+ break;
+ case PORT_FEAT_C_OVER_CURRENT:
+ hcd->roothub->port_status[port-1] &= ~PORT_POCIC;
+ break;
+ case PORT_FEAT_C_RESET:
+ hcd->roothub->port_status[port-1] &= ~PORT_PRSC;
+ break;
+ }
+ break;
+ case RH_SET_PORT_FEATURE:
+ switch((rt_uint32_t)args)
+ {
+ case PORT_FEAT_CONNECTION:
+ hcd->roothub->port_status[port-1] |= PORT_CCSC;
+ break;
+ case PORT_FEAT_ENABLE:
+ hcd->roothub->port_status[port-1] |= PORT_PESC;
+ break;
+ case PORT_FEAT_SUSPEND:
+ hcd->roothub->port_status[port-1] |= PORT_PSSC;
+ break;
+ case PORT_FEAT_OVER_CURRENT:
+ hcd->roothub->port_status[port-1] |= PORT_POCIC;
+ break;
+ case PORT_FEAT_RESET:
+ hcd->ops->reset_port(port);
+ break;
+ case PORT_FEAT_POWER:
+ break;
+ case PORT_FEAT_LOWSPEED:
+ break;
+ case PORT_FEAT_HIGHSPEED:
+ break;
+ }
+ break;
+ default:
+ return -RT_ERROR;
+ }
+ return RT_EOK;
+}
+void rt_usbh_root_hub_connect_handler(struct uhcd *hcd, rt_uint8_t port, rt_bool_t isHS)
+{
+ struct uhost_msg msg;
+ msg.type = USB_MSG_CONNECT_CHANGE;
+ msg.content.hub = hcd->roothub;
+ hcd->roothub->port_status[port - 1] |= PORT_CCS | PORT_CCSC;
+ if(isHS)
+ {
+ hcd->roothub->port_status[port - 1] &= ~PORT_LSDA;
+ }
+ else
+ {
+ hcd->roothub->port_status[port - 1] |= PORT_LSDA;
+ }
+ rt_usbh_event_signal(hcd, &msg);
+}
+
+void rt_usbh_root_hub_disconnect_handler(struct uhcd *hcd, rt_uint8_t port)
+{
+ struct uhost_msg msg;
+ msg.type = USB_MSG_CONNECT_CHANGE;
+ msg.content.hub = hcd->roothub;
+ hcd->roothub->port_status[port - 1] |= PORT_CCSC;
+ hcd->roothub->port_status[port - 1] &= ~PORT_CCS;
+ rt_usbh_event_signal(hcd, &msg);
+}
+
+/**
+ * This function will do USB_REQ_GET_DESCRIPTOR bRequest for the device instance
+ * to get usb hub descriptor.
+ *
+ * @param intf the interface instance.
+ * @buffer the data buffer to save usb hub descriptor.
+ * @param nbytes the size of buffer
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_hub_get_descriptor(struct uinstance* device, rt_uint8_t *buffer, rt_size_t nbytes)
+{
+ struct urequest setup;
+ int timeout = USB_TIMEOUT_BASIC;
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+
+ setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_DEVICE;
+ setup.bRequest = USB_REQ_GET_DESCRIPTOR;
+ setup.wIndex = 0;
+ setup.wLength = nbytes;
+ setup.wValue = USB_DESC_TYPE_HUB << 8;
+
+ if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
+ {
+ if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, buffer, nbytes, timeout) == nbytes)
+ {
+ return RT_EOK;
+ }
+ }
+ return -RT_FALSE;
+}
+
+/**
+ * This function will do USB_REQ_GET_STATUS bRequest for the device instance
+ * to get usb hub status.
+ *
+ * @param intf the interface instance.
+ * @buffer the data buffer to save usb hub status.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_hub_get_status(struct uinstance* device, rt_uint32_t* buffer)
+{
+ struct urequest setup;
+ int timeout = USB_TIMEOUT_BASIC;
+
+ /* parameter check */
+ RT_ASSERT(device != RT_NULL);
+
+ setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_DEVICE;
+ setup.bRequest = USB_REQ_GET_STATUS;
+ setup.wIndex = 0;
+ setup.wLength = 4;
+ setup.wValue = 0;
+ if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
+ {
+ if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, buffer, 4, timeout) == 4)
+ {
+ return RT_EOK;
+ }
+ }
+ return -RT_FALSE;
+}
+
+/**
+ * This function will do USB_REQ_GET_STATUS bRequest for the device instance
+ * to get hub port status.
+ *
+ * @param intf the interface instance.
+ * @port the hub port to get status.
+ * @buffer the data buffer to save usb hub status.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_hub_get_port_status(uhub_t hub, rt_uint16_t port, rt_uint32_t* buffer)
+{
+ struct urequest setup;
+ int timeout = USB_TIMEOUT_BASIC;
+
+ /* parameter check */
+ RT_ASSERT(hub != RT_NULL);
+
+ /* get roothub port status */
+ if(hub->is_roothub)
+ {
+ root_hub_ctrl(hub->hcd, port, RH_GET_PORT_STATUS,
+ (void*)buffer);
+ return RT_EOK;
+ }
+
+ setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_OTHER;
+ setup.bRequest = USB_REQ_GET_STATUS;
+ setup.wIndex = port;
+ setup.wLength = 4;
+ setup.wValue = 0;
+
+ if(rt_usb_hcd_setup_xfer(hub->hcd, hub->self->pipe_ep0_out, &setup, timeout) == 8)
+ {
+ if(rt_usb_hcd_pipe_xfer(hub->hcd, hub->self->pipe_ep0_in, buffer, 4, timeout) == 4)
+ {
+ return RT_EOK;
+ }
+ }
+ return -RT_FALSE;
+}
+
+/**
+ * This function will do USB_REQ_CLEAR_FEATURE bRequest for the device instance
+ * to clear feature of the hub port.
+ *
+ * @param intf the interface instance.
+ * @port the hub port.
+ * @feature feature to be cleared.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_hub_clear_port_feature(uhub_t hub, rt_uint16_t port, rt_uint16_t feature)
+{
+ struct urequest setup;
+ int timeout = USB_TIMEOUT_BASIC;
+
+ /* parameter check */
+ RT_ASSERT(hub != RT_NULL);
+
+ /* clear roothub feature */
+ if(hub->is_roothub)
+ {
+ root_hub_ctrl(hub->hcd, port, RH_CLEAR_PORT_FEATURE,
+ (void*)(rt_uint32_t)feature);
+ return RT_EOK;
+ }
+
+ setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
+ USB_REQ_TYPE_OTHER;
+ setup.bRequest = USB_REQ_CLEAR_FEATURE;
+ setup.wIndex = port;
+ setup.wLength = 0;
+ setup.wValue = feature;
+
+ if(rt_usb_hcd_setup_xfer(hub->hcd, hub->self->pipe_ep0_out, &setup, timeout) == 8)
+ {
+ return RT_EOK;
+ }
+ return -RT_FALSE;
+}
+
+/**
+ * This function will do USB_REQ_SET_FEATURE bRequest for the device instance
+ * to set feature of the hub port.
+ *
+ * @param intf the interface instance.
+ * @port the hub port.
+ * @feature feature to be set.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_hub_set_port_feature(uhub_t hub, rt_uint16_t port,
+ rt_uint16_t feature)
+{
+ struct urequest setup;
+ int timeout = USB_TIMEOUT_BASIC;
+
+ /* parameter check */
+ RT_ASSERT(hub != RT_NULL);
+
+ /* clear roothub feature */
+ if(hub->is_roothub)
+ {
+ root_hub_ctrl(hub->hcd, port, RH_SET_PORT_FEATURE,
+ (void*)(rt_uint32_t)feature);
+ return RT_EOK;
+ }
+
+ setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
+ USB_REQ_TYPE_OTHER;
+ setup.bRequest = USB_REQ_SET_FEATURE;
+ setup.wIndex = port;
+ setup.wLength = 0;
+ setup.wValue = feature;
+
+ if(rt_usb_hcd_setup_xfer(hub->hcd, hub->self->pipe_ep0_out, &setup, timeout) == 8)
+ {
+ return RT_EOK;
+ }
+ else return -RT_FALSE;
+}
+
+/**
+ * This function will rest hub port, it is invoked when sub device attached to the hub port.
+ *
+ * @param intf the interface instance.
+ * @param port the hub port.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_hub_reset_port(uhub_t hub, rt_uint16_t port)
+{
+ rt_err_t ret;
+ rt_uint32_t pstatus;
+
+ /* parameter check */
+ RT_ASSERT(hub != RT_NULL);
+
+ rt_thread_delay(50);
+
+ /* reset hub port */
+ ret = rt_usbh_hub_set_port_feature(hub, port, PORT_FEAT_RESET);
+ if(ret != RT_EOK) return ret;
+
+ while(1)
+ {
+ ret = rt_usbh_hub_get_port_status(hub, port, &pstatus);
+ if(!(pstatus & PORT_PRS)) break;
+ }
+
+ /* clear port reset feature */
+ ret = rt_usbh_hub_clear_port_feature(hub, port, PORT_FEAT_C_RESET);
+ if(ret != RT_EOK) return ret;
+
+ rt_thread_delay(50);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will do debouce, it is invoked when sub device attached to the hub port.
+ *
+ * @param device the usb instance.
+ * @param port the hub port.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_hub_port_debounce(uhub_t hub, rt_uint16_t port)
+{
+ rt_err_t ret;
+ int i = 0, times = 20;
+ rt_uint32_t pstatus;
+ rt_bool_t connect = RT_TRUE;
+ int delayticks = USB_DEBOUNCE_TIME / times;
+ if (delayticks < 1)
+ delayticks = 1;
+
+ /* parameter check */
+ RT_ASSERT(hub != RT_NULL);
+
+ for(i=0; i<times; i++)
+ {
+ ret = rt_usbh_hub_get_port_status(hub, port, &pstatus);
+ if(ret != RT_EOK) return ret;
+
+ if(!(pstatus & PORT_CCS))
+ {
+ connect = RT_FALSE;
+ break;
+ }
+
+ rt_thread_delay(delayticks);
+ }
+
+ if(connect) return RT_EOK;
+ else return -RT_ERROR;
+}
+
+/**
+ * This function will poll all the hub ports to detect port status, especially connect and
+ * disconnect events.
+ *
+ * @param intf the interface instance.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+static rt_err_t rt_usbh_hub_port_change(uhub_t hub)
+{
+ int i;
+ rt_bool_t reconnect;
+
+ /* parameter check */
+ RT_ASSERT(hub != RT_NULL);
+
+ /* get usb device instance */
+ for (i = 0; i < hub->num_ports; i++)
+ {
+ rt_err_t ret;
+ struct uinstance* device;
+ rt_uint32_t pstatus = 0;
+
+ reconnect = RT_FALSE;
+
+ /* get hub port status */
+ ret = rt_usbh_hub_get_port_status(hub, i + 1, &pstatus);
+ if(ret != RT_EOK) continue;
+
+ LOG_D("port %d status 0x%x", i + 1, pstatus);
+
+ /* check port status change */
+ if (pstatus & PORT_CCSC)
+ {
+ /* clear port status change feature */
+ rt_usbh_hub_clear_port_feature(hub, i + 1, PORT_FEAT_C_CONNECTION);
+ reconnect = RT_TRUE;
+ }
+
+ if(pstatus & PORT_PESC)
+ {
+ rt_usbh_hub_clear_port_feature(hub, i + 1, PORT_FEAT_C_ENABLE);
+ reconnect = RT_TRUE;
+ }
+
+ if(reconnect)
+ {
+ if(hub->child[i] != RT_NULL && hub->child[i]->status != DEV_STATUS_IDLE)
+ {
+ rt_usbh_detach_instance(hub->child[i]);
+
+ /* Child device have been detach. Set hub->child[i] to NULL. */
+ hub->child[i] = RT_NULL;
+ }
+
+ ret = rt_usbh_hub_port_debounce(hub, i + 1);
+ if(ret != RT_EOK) continue;
+
+ /* allocate an usb instance for new connected device */
+ device = rt_usbh_alloc_instance(hub->hcd);
+ if(device == RT_NULL) break;
+
+ /* set usb device speed */
+ device->speed = (pstatus & PORT_LSDA) ? 1 : 0;
+ device->parent_hub = hub;
+ device->hcd = hub->hcd;
+ device->port = i + 1;
+ hub->child[i] = device;
+
+ /* reset usb roothub port */
+ rt_usbh_hub_reset_port(hub, i + 1);
+
+ /* attatch the usb instance to the hcd */
+ rt_usbh_attatch_instance(device);
+ }
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * This function is the callback function of hub's int endpoint, it is invoked when data comes.
+ *
+ * @param context the context of the callback function.
+ *
+ * @return none.
+ */
+static void rt_usbh_hub_irq(void* context)
+{
+ upipe_t pipe;
+ uhub_t hub;
+ int timeout = USB_TIMEOUT_BASIC;
+
+ RT_ASSERT(context != RT_NULL);
+
+ pipe = (upipe_t)context;
+ hub = (uhub_t)pipe->user_data;
+
+ if(pipe->status != UPIPE_STATUS_OK)
+ {
+ LOG_D("hub irq error");
+ return;
+ }
+
+ rt_usbh_hub_port_change(hub);
+
+ LOG_D("hub int xfer...");
+
+ /* parameter check */
+ RT_ASSERT(pipe->inst->hcd != RT_NULL);
+
+ rt_usb_hcd_pipe_xfer(hub->self->hcd, pipe, hub->buffer, pipe->ep.wMaxPacketSize, timeout);
+}
+
+/**
+ * This function will run usb hub class driver when usb hub is detected and identified
+ * as a hub class device, it will continue to do the enumulate process.
+ *
+ * @param arg the argument.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+
+static rt_err_t rt_usbh_hub_enable(void *arg)
+{
+ int i = 0;
+ rt_err_t ret = RT_EOK;
+ uep_desc_t ep_desc = RT_NULL;
+ uhub_t hub;
+ struct uinstance* device;
+ struct uhintf* intf = (struct uhintf*)arg;
+ upipe_t pipe_in = RT_NULL;
+ int timeout = USB_TIMEOUT_LONG;
+ /* paremeter check */
+ RT_ASSERT(intf != RT_NULL);
+
+ /* get usb device instance */
+ device = intf->device;
+
+ /* create a hub instance */
+ hub = rt_malloc(sizeof(struct uhub));
+ RT_ASSERT(hub != RT_NULL);
+ rt_memset(hub, 0, sizeof(struct uhub));
+
+ /* make interface instance's user data point to hub instance */
+ intf->user_data = (void*)hub;
+
+ /* get hub descriptor head */
+ ret = rt_usbh_hub_get_descriptor(device, (rt_uint8_t*)&hub->hub_desc, 8);
+ if(ret != RT_EOK)
+ {
+ rt_kprintf("get hub descriptor failed\n");
+ return -RT_ERROR;
+ }
+
+ /* get full hub descriptor */
+ ret = rt_usbh_hub_get_descriptor(device, (rt_uint8_t*)&hub->hub_desc,
+ hub->hub_desc.length);
+ if(ret != RT_EOK)
+ {
+ rt_kprintf("get hub descriptor again failed\n");
+ return -RT_ERROR;
+ }
+
+ /* get hub ports number */
+ /* If hub device supported ports over USB_HUB_PORT_NUM(Ex: 8 port hub). Set hub->num_ports to USB_HUB_PORT_NUM */
+ if(hub->hub_desc.num_ports > USB_HUB_PORT_NUM)
+ hub->num_ports = USB_HUB_PORT_NUM;
+ else
+ hub->num_ports = hub->hub_desc.num_ports;
+
+ hub->hcd = device->hcd;
+ hub->self = device;
+
+ /* reset all hub ports */
+ for (i = 0; i < hub->num_ports; i++)
+ {
+ rt_usbh_hub_set_port_feature(hub, i + 1, PORT_FEAT_POWER);
+ rt_thread_delay(hub->hub_desc.pwron_to_good
+ * 2 * RT_TICK_PER_SECOND / 1000 );
+ }
+
+ if(intf->intf_desc->bNumEndpoints != 1)
+ return -RT_ERROR;
+
+ /* get endpoint descriptor from interface descriptor */
+ rt_usbh_get_endpoint_descriptor(intf->intf_desc, 0, &ep_desc);
+ if(ep_desc == RT_NULL)
+ {
+ rt_kprintf("rt_usb_get_endpoint_descriptor error\n");
+ return -RT_ERROR;
+ }
+
+ /* the endpoint type of hub class should be interrupt */
+ if( USB_EP_ATTR(ep_desc->bmAttributes) == USB_EP_ATTR_INT)
+ {
+ /* the endpoint direction of hub class should be in */
+ if(ep_desc->bEndpointAddress & USB_DIR_IN)
+ {
+ /* allocate a pipe according to the endpoint type */
+ pipe_in = rt_usb_instance_find_pipe(device,ep_desc->bEndpointAddress);
+ if(pipe_in == RT_NULL)
+ {
+ return -RT_ERROR;
+ }
+ rt_usb_pipe_add_callback(pipe_in,rt_usbh_hub_irq);
+ }
+ else return -RT_ERROR;
+ }
+
+ /* parameter check */
+ RT_ASSERT(device->hcd != RT_NULL);
+ pipe_in->user_data = hub;
+ rt_usb_hcd_pipe_xfer(hub->hcd, pipe_in, hub->buffer,
+ pipe_in->ep.wMaxPacketSize, timeout);
+ return RT_EOK;
+}
+
+/**
+ * This function will be invoked when usb hub plug out is detected and it would clean
+ * and release all hub class related resources.
+ *
+ * @param arg the argument.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+static rt_err_t rt_usbh_hub_disable(void* arg)
+{
+ int i;
+ uhub_t hub;
+ struct uhintf* intf = (struct uhintf*)arg;
+
+ /* paremeter check */
+ RT_ASSERT(intf != RT_NULL);
+
+ LOG_D("rt_usbh_hub_stop");
+ hub = (uhub_t)intf->user_data;
+
+ for(i=0; i<hub->num_ports; i++)
+ {
+ if(hub->child[i] != RT_NULL)
+ rt_usbh_detach_instance(hub->child[i]);
+ }
+
+ if(hub != RT_NULL) rt_free(hub);
+
+ return RT_EOK;
+}
+
+/**
+ * This function will register hub class driver to the usb class driver manager.
+ * and it should be invoked in the usb system initialization.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+ucd_t rt_usbh_class_driver_hub(void)
+{
+ hub_driver.class_code = USB_CLASS_HUB;
+
+ hub_driver.enable = rt_usbh_hub_enable;
+ hub_driver.disable = rt_usbh_hub_disable;
+
+ return &hub_driver;
+}
+
+/**
+ * This function is the main entry of usb hub thread, it is in charge of
+ * processing all messages received from the usb message buffer.
+ *
+ * @param parameter the parameter of the usb host thread.
+ *
+ * @return none.
+ */
+static void rt_usbh_hub_thread_entry(void* parameter)
+{
+ uhcd_t hcd = (uhcd_t)parameter;
+ while(1)
+ {
+ struct uhost_msg msg;
+
+ /* receive message */
+ if (rt_mq_recv(hcd->usb_mq, &msg, sizeof(struct uhost_msg), RT_WAITING_FOREVER) < 0)
+ continue;
+
+ switch (msg.type)
+ {
+ case USB_MSG_CONNECT_CHANGE:
+ rt_usbh_hub_port_change(msg.content.hub);
+ break;
+ case USB_MSG_CALLBACK:
+ /* invoke callback */
+ msg.content.cb.function(msg.content.cb.context);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/**
+ * This function will post an message to the usb message queue,
+ *
+ * @param msg the message to be posted
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_event_signal(uhcd_t hcd, struct uhost_msg* msg)
+{
+ RT_ASSERT(msg != RT_NULL);
+
+ /* send message to usb message queue */
+ rt_mq_send(hcd->usb_mq, (void*)msg, sizeof(struct uhost_msg));
+
+ return RT_EOK;
+}
+
+/**
+ * This function will initialize usb hub thread.
+ *
+ * @return none.
+ *
+ */
+void rt_usbh_hub_init(uhcd_t hcd)
+{
+ rt_thread_t thread;
+ /* create root hub for hcd */
+ hcd->roothub = rt_malloc(sizeof(struct uhub));
+ if(hcd->roothub == RT_NULL)
+ {
+ LOG_E("hcd->roothub: allocate buffer failed.");
+ return;
+ }
+ rt_memset(hcd->roothub, 0, sizeof(struct uhub));
+ hcd->roothub->is_roothub = RT_TRUE;
+ hcd->roothub->hcd = hcd;
+ hcd->roothub->num_ports = hcd->num_ports;
+ /* create usb message queue */
+
+ hcd->usb_mq = rt_mq_create(hcd->parent.parent.name, 32, 16, RT_IPC_FLAG_FIFO);
+
+ /* create usb hub thread */
+ thread = rt_thread_create(hcd->parent.parent.name, rt_usbh_hub_thread_entry, hcd,
+ USB_THREAD_STACK_SIZE, 8, 20);
+ if(thread != RT_NULL)
+ {
+ /* startup usb host thread */
+ rt_thread_startup(thread);
+ }
+}
diff --git a/components/legacy/usb/usbhost/core/usbhost.c b/components/legacy/usb/usbhost/core/usbhost.c
new file mode 100644
index 0000000000..a4cdc12e5e
--- /dev/null
+++ b/components/legacy/usb/usbhost/core/usbhost.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2011-12-12 Yi Qiu first version
+ * 2021-02-23 Leslie Lee provide possibility for multi usb host
+ */
+#include <rtthread.h>
+#include <drivers/usb_host.h>
+
+#define USB_HOST_CONTROLLER_NAME "usbh"
+
+#if defined(RT_USBH_HID_KEYBOARD) || defined(RT_USBH_HID_MOUSE)
+#include <hid.h>
+#endif
+
+/**
+ * This function will initialize the usb host stack, all the usb class driver and
+ * host controller driver are also be initialized here.
+ *
+ * @return none.
+ */
+rt_err_t rt_usb_host_init(const char *name)
+{
+ ucd_t drv;
+ rt_device_t uhc;
+
+ uhc = rt_device_find(name);
+ if(uhc == RT_NULL)
+ {
+ rt_kprintf("can't find usb host controller %s\n", name);
+ return -RT_ERROR;
+ }
+
+ /* initialize usb hub */
+ rt_usbh_hub_init((uhcd_t)uhc);
+
+ /* initialize class driver */
+ rt_usbh_class_driver_init();
+
+#ifdef RT_USBH_MSTORAGE
+ /* register mass storage class driver */
+ drv = rt_usbh_class_driver_storage();
+ rt_usbh_class_driver_register(drv);
+#endif
+#ifdef RT_USBH_HID
+ extern ucd_t rt_usbh_class_driver_hid(void);
+ /* register mass storage class driver */
+ drv = rt_usbh_class_driver_hid();
+ rt_usbh_class_driver_register(drv);
+#ifdef RT_USBH_HID_MOUSE
+ {
+ extern uprotocal_t rt_usbh_hid_protocal_mouse(void);
+ rt_usbh_hid_protocal_register(rt_usbh_hid_protocal_mouse());
+ }
+#endif
+#ifdef RT_USBH_HID_KEYBOARD
+ {
+ extern uprotocal_t rt_usbh_hid_protocal_kbd(void);
+ rt_usbh_hid_protocal_register(rt_usbh_hid_protocal_kbd());
+ }
+#endif
+#endif
+
+ /* register hub class driver */
+ drv = rt_usbh_class_driver_hub();
+ rt_usbh_class_driver_register(drv);
+
+ /* initialize usb host controller */
+ rt_device_init(uhc);
+
+ return RT_EOK;
+}
diff --git a/components/legacy/usb/usbhost/core/usbhost_core.c b/components/legacy/usb/usbhost/core/usbhost_core.c
new file mode 100644
index 0000000000..fae5ba75fb
--- /dev/null
+++ b/components/legacy/usb/usbhost/core/usbhost_core.c
@@ -0,0 +1,586 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2011-12-12 Yi Qiu first version
+ */
+
+#include <rtthread.h>
+#include <drivers/usb_host.h>
+
+#define DBG_TAG "usbhost.core"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+static struct uinstance dev[USB_MAX_DEVICE];
+
+/**
+ * This function will allocate an usb device instance from system.
+ *
+ * @param parent the hub instance to which the new allocated device attached.
+ * @param port the hub port.
+ *
+ * @return the allocate instance on successful, or RT_NULL on failure.
+ */
+uinst_t rt_usbh_alloc_instance(uhcd_t uhcd)
+{
+ int i;
+
+ /* lock scheduler */
+ rt_enter_critical();
+
+ for(i=0; i<USB_MAX_DEVICE; i++)
+ {
+ /* to find an idle instance handle */
+ if(dev[i].status != DEV_STATUS_IDLE) continue;
+
+ /* initialize the usb device instance */
+ rt_memset(&dev[i], 0, sizeof(struct uinstance));
+
+ dev[i].status = DEV_STATUS_BUSY;
+ dev[i].index = i + 1;
+ dev[i].address = 0;
+ dev[i].max_packet_size = 0x8;
+ rt_list_init(&dev[i].pipe);
+ dev[i].hcd = uhcd;
+ /* unlock scheduler */
+ rt_exit_critical();
+ return &dev[i];
+ }
+
+ /* unlock scheduler */
+ rt_exit_critical();
+
+ return RT_NULL;
+}
+
+/**
+ * This function will attatch an usb device instance to a host controller,
+ * and do device enumunation process.
+ *
+ * @param hcd the host controller driver.
+ * @param device the usb device instance.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+static struct uendpoint_descriptor ep0_out_desc =
+{
+ /*endpoint descriptor*/
+ USB_DESC_LENGTH_ENDPOINT,
+ USB_DESC_TYPE_ENDPOINT,
+ 0x00 | USB_DIR_OUT,
+ USB_EP_ATTR_CONTROL,
+ 0x00,
+ 0x00,
+};
+static struct uendpoint_descriptor ep0_in_desc =
+{
+ /*endpoint descriptor*/
+ USB_DESC_LENGTH_ENDPOINT,
+ USB_DESC_TYPE_ENDPOINT,
+ 0x00 | USB_DIR_IN,
+ USB_EP_ATTR_CONTROL,
+ 0x00,
+ 0x00,
+};
+rt_err_t rt_usbh_attatch_instance(uinst_t device)
+{
+ int i = 0;
+ rt_err_t ret = RT_EOK;
+ struct uconfig_descriptor cfg_desc;
+ udev_desc_t dev_desc;
+ uintf_desc_t intf_desc;
+ uep_desc_t ep_desc;
+ rt_uint8_t ep_index;
+ upipe_t pipe;
+ ucd_t drv;
+
+ RT_ASSERT(device != RT_NULL);
+
+ rt_memset(&cfg_desc, 0, sizeof(struct uconfig_descriptor));
+ dev_desc = &device->dev_desc;
+
+ /* alloc address 0 ep0 pipe*/
+ ep0_out_desc.wMaxPacketSize = 8;
+ ep0_in_desc.wMaxPacketSize = 8;
+ rt_usb_hcd_alloc_pipe(device->hcd, &device->pipe_ep0_out, device, &ep0_out_desc);
+ rt_usb_hcd_alloc_pipe(device->hcd, &device->pipe_ep0_in, device, &ep0_in_desc);
+
+ LOG_D("start enumnation");
+
+ /* get device descriptor head */
+ ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_DEVICE, (void*)dev_desc, 8);
+ if(ret != RT_EOK)
+ {
+ rt_kprintf("get device descriptor head failed\n");
+ return ret;
+ }
+
+ /* reset bus */
+ rt_usbh_hub_reset_port(device->parent_hub, device->port);
+ rt_thread_delay(2);
+ rt_usbh_hub_clear_port_feature(device->parent_hub, i + 1, PORT_FEAT_C_CONNECTION);
+ /* set device address */
+ ret = rt_usbh_set_address(device);
+ if(ret != RT_EOK)
+ {
+ rt_kprintf("set device address failed\n");
+ return ret;
+ }
+ /* free address 0 ep0 pipe*/
+
+ rt_usb_hcd_free_pipe(device->hcd,device->pipe_ep0_out);
+ rt_usb_hcd_free_pipe(device->hcd,device->pipe_ep0_in);
+
+ /* set device max packet size */
+ ep0_out_desc.wMaxPacketSize = device->dev_desc.bMaxPacketSize0;
+ ep0_in_desc.wMaxPacketSize = device->dev_desc.bMaxPacketSize0;
+
+ /* alloc true address ep0 pipe*/
+ rt_usb_hcd_alloc_pipe(device->hcd, &device->pipe_ep0_out, device, &ep0_out_desc);
+ rt_usb_hcd_alloc_pipe(device->hcd, &device->pipe_ep0_in, device, &ep0_in_desc);
+ LOG_D("get device descriptor length %d",
+ dev_desc->bLength);
+
+ /* get full device descriptor again */
+ ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_DEVICE, (void*)dev_desc, dev_desc->bLength);
+ if(ret != RT_EOK)
+ {
+ rt_kprintf("get full device descriptor failed\n");
+ return ret;
+ }
+
+ LOG_D("Vendor ID 0x%x", dev_desc->idVendor);
+ LOG_D("Product ID 0x%x", dev_desc->idProduct);
+
+ /* get configuration descriptor head */
+ ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_CONFIGURATION, &cfg_desc, 18);
+ if(ret != RT_EOK)
+ {
+ rt_kprintf("get configuration descriptor head failed\n");
+ return ret;
+ }
+
+ /* alloc memory for configuration descriptor */
+ device->cfg_desc = (ucfg_desc_t)rt_malloc(cfg_desc.wTotalLength);
+ if(device->cfg_desc == RT_NULL)
+ {
+ return -RT_ENOMEM;
+ }
+ rt_memset(device->cfg_desc, 0, cfg_desc.wTotalLength);
+
+ /* get full configuration descriptor */
+ ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_CONFIGURATION,
+ device->cfg_desc, cfg_desc.wTotalLength);
+ if(ret != RT_EOK)
+ {
+ rt_kprintf("get full configuration descriptor failed\n");
+ return ret;
+ }
+
+ /* set configuration */
+ ret = rt_usbh_set_configure(device, 1);
+ if(ret != RT_EOK)
+ {
+ return ret;
+ }
+ for(i=0; i<device->cfg_desc->bNumInterfaces; i++)
+ {
+ /* get interface descriptor through configuration descriptor */
+ ret = rt_usbh_get_interface_descriptor(device->cfg_desc, i, &intf_desc);
+ if(ret != RT_EOK)
+ {
+ rt_kprintf("rt_usb_get_interface_descriptor error\n");
+ return -RT_ERROR;
+ }
+
+ LOG_D("interface class 0x%x, subclass 0x%x",
+ intf_desc->bInterfaceClass,
+ intf_desc->bInterfaceSubClass);
+ /* alloc pipe*/
+ for(ep_index = 0; ep_index < intf_desc->bNumEndpoints; ep_index++)
+ {
+ rt_usbh_get_endpoint_descriptor(intf_desc, ep_index, &ep_desc);
+ if(ep_desc != RT_NULL)
+ {
+ if(rt_usb_hcd_alloc_pipe(device->hcd, &pipe, device, ep_desc) != RT_EOK)
+ {
+ rt_kprintf("alloc pipe failed\n");
+ return -RT_ERROR;
+ }
+ rt_usb_instance_add_pipe(device,pipe);
+ }
+ else
+ {
+ rt_kprintf("get endpoint desc failed\n");
+ return -RT_ERROR;
+ }
+ }
+ /* find driver by class code found in interface descriptor */
+ drv = rt_usbh_class_driver_find(intf_desc->bInterfaceClass,
+ intf_desc->bInterfaceSubClass);
+
+ if(drv != RT_NULL)
+ {
+ /* allocate memory for interface device */
+ device->intf[i] = (struct uhintf*)rt_malloc(sizeof(struct uhintf));
+ if(device->intf[i] == RT_NULL)
+ {
+ return -RT_ENOMEM;
+ }
+ device->intf[i]->drv = drv;
+ device->intf[i]->device = device;
+ device->intf[i]->intf_desc = intf_desc;
+ device->intf[i]->user_data = RT_NULL;
+
+ /* open usb class driver */
+ ret = rt_usbh_class_driver_enable(drv, (void*)device->intf[i]);
+ if(ret != RT_EOK)
+ {
+ rt_kprintf("interface %d run class driver error\n", i);
+ }
+ }
+ else
+ {
+ rt_kprintf("find usb device driver failed\n");
+ continue;
+ }
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * This function will detach an usb device instance from its host controller,
+ * and release all resource.
+ *
+ * @param device the usb device instance.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_detach_instance(uinst_t device)
+{
+ int i = 0;
+ rt_list_t * l;
+ if(device == RT_NULL)
+ {
+ rt_kprintf("no usb instance to detach\n");
+ return -RT_ERROR;
+ }
+
+ /* free configration descriptor */
+ if (device->cfg_desc) {
+ for (i = 0; i < device->cfg_desc->bNumInterfaces; i++)
+ {
+ if (device->intf[i] == RT_NULL) continue;
+ if (device->intf[i]->drv == RT_NULL) continue;
+
+ RT_ASSERT(device->intf[i]->device == device);
+
+ LOG_D("free interface instance %d", i);
+ rt_usbh_class_driver_disable(device->intf[i]->drv, (void*)device->intf[i]);
+ rt_free(device->intf[i]);
+ }
+ rt_free(device->cfg_desc);
+ }
+
+ rt_usb_hcd_free_pipe(device->hcd,device->pipe_ep0_out);
+ rt_usb_hcd_free_pipe(device->hcd,device->pipe_ep0_in);
+
+ while(device->pipe.next!= &device->pipe)
+ {
+ l = device->pipe.next;
+ rt_list_remove(l);
+ rt_usb_hcd_free_pipe(device->hcd,rt_list_entry(l,struct upipe,list));
+ }
+ rt_memset(device, 0, sizeof(struct uinstance));
+
+ return RT_EOK;
+}
+
+/**
+ * This function will do USB_REQ_GET_DESCRIPTO' bRequest for the usb device instance,
+ *
+ * @param device the usb device instance.
+ * @param type the type of descriptor bRequest.
+ * @param buffer the data buffer to save requested data
+ * @param nbytes the size of buffer
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_get_descriptor(uinst_t device, rt_uint8_t type, void* buffer,
+ int nbytes)
+{
+ struct urequest setup;
+ int timeout = USB_TIMEOUT_BASIC;
+
+ RT_ASSERT(device != RT_NULL);
+
+ setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_STANDARD |
+ USB_REQ_TYPE_DEVICE;
+ setup.bRequest = USB_REQ_GET_DESCRIPTOR;
+ setup.wIndex = 0;
+ setup.wLength = nbytes;
+ setup.wValue = type << 8;
+
+ if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
+ {
+ if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, buffer, nbytes, timeout) == nbytes)
+ {
+ if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, RT_NULL, 0, timeout) == 0)
+ {
+ return RT_EOK;
+ }
+ }
+ }
+ return -RT_ERROR;
+}
+
+/**
+ * This function will set an address to the usb device.
+ *
+ * @param device the usb device instance.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_set_address(uinst_t device)
+{
+ struct urequest setup;
+ int timeout = USB_TIMEOUT_BASIC;
+
+ RT_ASSERT(device != RT_NULL);
+
+ LOG_D("rt_usb_set_address");
+
+ setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD |
+ USB_REQ_TYPE_DEVICE;
+ setup.bRequest = USB_REQ_SET_ADDRESS;
+ setup.wIndex = 0;
+ setup.wLength = 0;
+ setup.wValue = device->index;
+
+ if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8)
+ {
+ return -RT_ERROR;
+ }
+ if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) == 0)
+ {
+ device->address = device->index;
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * This function will set a configuration to the usb device.
+ *
+ * @param device the usb device instance.
+ * @param config the configuration number.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_set_configure(uinst_t device, int config)
+{
+ struct urequest setup;
+ int timeout = USB_TIMEOUT_BASIC;
+
+ /* check parameter */
+ RT_ASSERT(device != RT_NULL);
+
+ setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD |
+ USB_REQ_TYPE_DEVICE;
+ setup.bRequest = USB_REQ_SET_CONFIGURATION;
+ setup.wIndex = 0;
+ setup.wLength = 0;
+ setup.wValue = config;
+
+ if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8)
+ {
+ return -RT_ERROR;
+ }
+ if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) != 0)
+ {
+ return -RT_ERROR;
+ }
+ return RT_EOK;
+}
+
+/**
+ * This function will set an interface to the usb device.
+ *
+ * @param device the usb device instance.
+ * @param intf the interface number.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_set_interface(uinst_t device, int intf)
+{
+ struct urequest setup;
+ int timeout = USB_TIMEOUT_BASIC;
+
+ /* check parameter */
+ RT_ASSERT(device != RT_NULL);
+
+ setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD |
+ USB_REQ_TYPE_INTERFACE;
+ setup.bRequest = USB_REQ_SET_INTERFACE;
+ setup.wIndex = 0;
+ setup.wLength = 0;
+ setup.wValue = intf;
+
+ if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8)
+ {
+ return -RT_ERROR;
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * This function will clear feature for the endpoint of the usb device.
+ *
+ * @param device the usb device instance.
+ * @param endpoint the endpoint number of the usb device.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_clear_feature(uinst_t device, int endpoint, int feature)
+{
+ struct urequest setup;
+ int timeout = USB_TIMEOUT_BASIC;
+
+ /* check parameter */
+ RT_ASSERT(device != RT_NULL);
+
+ setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD |
+ USB_REQ_TYPE_ENDPOINT;
+ setup.bRequest = USB_REQ_CLEAR_FEATURE;
+ setup.wIndex = endpoint;
+ setup.wLength = 0;
+ setup.wValue = feature;
+
+ if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8)
+ {
+ return -RT_ERROR;
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * This function will get an interface descriptor from the configuration descriptor.
+ *
+ * @param cfg_desc the point of configuration descriptor structure.
+ * @param num the number of interface descriptor.
+ * @intf_desc the point of interface descriptor point.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_get_interface_descriptor(ucfg_desc_t cfg_desc, int num,
+ uintf_desc_t* intf_desc)
+{
+ rt_uint32_t ptr, depth = 0;
+ udesc_t desc;
+
+ /* check parameter */
+ RT_ASSERT(cfg_desc != RT_NULL);
+
+ ptr = (rt_uint32_t)cfg_desc + cfg_desc->bLength;
+ while(ptr < (rt_uint32_t)cfg_desc + cfg_desc->wTotalLength)
+ {
+ if(depth++ > 0x20)
+ {
+ *intf_desc = RT_NULL;
+ return -RT_EIO;
+ }
+ desc = (udesc_t)ptr;
+ if(desc->type == USB_DESC_TYPE_INTERFACE)
+ {
+ if(((uintf_desc_t)desc)->bInterfaceNumber == num)
+ {
+ *intf_desc = (uintf_desc_t)desc;
+
+ LOG_D("rt_usb_get_interface_descriptor: %d", num);
+ return RT_EOK;
+ }
+ }
+ ptr = (rt_uint32_t)desc + desc->bLength;
+ }
+
+ rt_kprintf("rt_usb_get_interface_descriptor %d failed\n", num);
+ return -RT_EIO;
+}
+
+/**
+ * This function will get an endpoint descriptor from the interface descriptor.
+ *
+ * @param intf_desc the point of interface descriptor structure.
+ * @param num the number of endpoint descriptor.
+ * @param ep_desc the point of endpoint descriptor point.
+ *
+ * @return the error code, RT_EOK on successfully.
+ */
+rt_err_t rt_usbh_get_endpoint_descriptor(uintf_desc_t intf_desc, int num,
+ uep_desc_t* ep_desc)
+{
+ int count = 0, depth = 0;
+ rt_uint32_t ptr;
+ udesc_t desc;
+
+ /* check parameter */
+ RT_ASSERT(intf_desc != RT_NULL);
+ RT_ASSERT(num < intf_desc->bNumEndpoints);
+ *ep_desc = RT_NULL;
+
+ ptr = (rt_uint32_t)intf_desc + intf_desc->bLength;
+ while(count < intf_desc->bNumEndpoints)
+ {
+ if(depth++ > 0x20)
+ {
+ *ep_desc = RT_NULL;
+ return -RT_EIO;
+ }
+ desc = (udesc_t)ptr;
+ if(desc->type == USB_DESC_TYPE_ENDPOINT)
+ {
+ if(num == count)
+ {
+ *ep_desc = (uep_desc_t)desc;
+
+ LOG_D("rt_usb_get_endpoint_descriptor: %d", num);
+ return RT_EOK;
+ }
+ else count++;
+ }
+ ptr = (rt_uint32_t)desc + desc->bLength;
+ }
+
+ rt_kprintf("rt_usb_get_endpoint_descriptor %d failed\n", num);
+ return -RT_EIO;
+}
+
+int rt_usb_hcd_pipe_xfer(uhcd_t hcd, upipe_t pipe, void* buffer, int nbytes, int timeout)
+{
+ rt_size_t remain_size;
+ rt_size_t send_size;
+ remain_size = nbytes;
+ rt_uint8_t * pbuffer = (rt_uint8_t *)buffer;
+ do
+ {
+ LOG_D("pipe transform remain size,: %d", remain_size);
+ send_size = (remain_size > pipe->ep.wMaxPacketSize) ? pipe->ep.wMaxPacketSize : remain_size;
+ if(hcd->ops->pipe_xfer(pipe, USBH_PID_DATA, pbuffer, send_size, timeout) == send_size)
+ {
+ remain_size -= send_size;
+ pbuffer += send_size;
+ }
+ else
+ {
+ return 0;
+ }
+ }while(remain_size > 0);
+ return nbytes;
+}