[update][cherryusb] sync from cherryusb master

This commit is contained in:
jzlv 2023-01-11 20:35:55 +08:00
parent daef36c40e
commit 240594aa20
28 changed files with 939 additions and 514 deletions

View File

@ -1,4 +1,4 @@
sdk_generate_library()
sdk_generate_library()
sdk_add_include_directories(common)
sdk_add_include_directories(osal)
sdk_add_include_directories(core)

View File

@ -6,6 +6,8 @@
#ifndef CHERRYUSB_CONFIG_H
#define CHERRYUSB_CONFIG_H
#define CHERRYUSB_VERSION 0x000700
/* ================ USB common Configuration ================ */
#define CONFIG_USB_PRINTF(...) printf(__VA_ARGS__)
@ -42,6 +44,17 @@
/* Enable test mode */
// #define CONFIG_USBDEV_TEST_MODE
//#define CONFIG_USBDEV_TX_RX_THREAD
#ifdef CONFIG_USBDEV_TX_RX_THREAD
#ifndef CONFIG_USBDEV_TX_RX_PRIO
#define CONFIG_USBDEV_TX_RX_PRIO 4
#endif
#ifndef CONFIG_USBDEV_TX_RX_STACKSIZE
#define CONFIG_USBDEV_TX_RX_STACKSIZE 2048
#endif
#endif
#ifndef CONFIG_USBDEV_MSC_BLOCK_SIZE
#define CONFIG_USBDEV_MSC_BLOCK_SIZE 512
#endif
@ -58,18 +71,6 @@
#define CONFIG_USBDEV_MSC_VERSION_STRING "0.01"
#endif
// #define CONFIG_USBDEV_MSC_THREAD
#ifdef CONFIG_USBDEV_MSC_THREAD
#ifndef CONFIG_USBDEV_MSC_STACKSIZE
#define CONFIG_USBDEV_MSC_STACKSIZE 2048
#endif
#ifndef CONFIG_USBDEV_MSC_PRIO
#define CONFIG_USBDEV_MSC_PRIO 4
#endif
#endif
#ifndef CONFIG_USBDEV_AUDIO_VERSION
#define CONFIG_USBDEV_AUDIO_VERSION 0x0100
#endif
@ -78,13 +79,31 @@
#define CONFIG_USBDEV_AUDIO_MAX_CHANNEL 8
#endif
#ifndef CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE
#define CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE 128
#endif
#ifndef CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE
#define CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE 1536
#endif
#ifndef CONFIG_USBDEV_RNDIS_VENDOR_ID
#define CONFIG_USBDEV_RNDIS_VENDOR_ID 0x0000ffff
#endif
#ifndef CONFIG_USBDEV_RNDIS_VENDOR_DESC
#define CONFIG_USBDEV_RNDIS_VENDOR_DESC "CherryUSB"
#endif
#define CONFIG_USBDEV_RNDIS_USING_LWIP
/* ================ USB HOST Stack Configuration ================== */
#define CONFIG_USBHOST_MAX_RHPORTS 1
#define CONFIG_USBHOST_MAX_EXTHUBS 1
#define CONFIG_USBHOST_MAX_EHPORTS 4
#define CONFIG_USBHOST_MAX_INTERFACES 6
#define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 8
#define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 1
#define CONFIG_USBHOST_MAX_ENDPOINTS 4
#define CONFIG_USBHOST_DEV_NAMELEN 16
@ -121,8 +140,8 @@
/* ================ EHCI Configuration ================ */
#define CONFIG_USB_EHCI_HCCR_BASE (0x20072000)
#define CONFIG_USB_EHCI_HCOR_BASE (0x20072000 + 0x10)
#define CONFIG_USB_EHCI_HCCR_BASE (0x20072000)
#define CONFIG_USB_EHCI_HCOR_BASE (0x20072000 + 0x10)
#define CONFIG_USB_EHCI_FRAME_LIST_SIZE 1024
// #define CONFIG_USB_EHCI_INFO_ENABLE
// #define CONFIG_USB_ECHI_HCOR_RESERVED_DISABLE

View File

@ -146,6 +146,7 @@ static int usbh_cdc_acm_connect(struct usbh_hubport *hport, uint8_t intf)
USB_LOG_INFO("Register CDC ACM Class:%s\r\n", hport->config.intf[intf].devname);
usbh_cdc_acm_run(cdc_acm_class);
return ret;
}
@ -166,6 +167,7 @@ static int usbh_cdc_acm_disconnect(struct usbh_hubport *hport, uint8_t intf)
usbh_pipe_free(cdc_acm_class->bulkout);
}
usbh_cdc_acm_stop(cdc_acm_class);
memset(cdc_acm_class, 0, sizeof(struct usbh_cdc_acm));
usb_free(cdc_acm_class);
@ -176,12 +178,38 @@ static int usbh_cdc_acm_disconnect(struct usbh_hubport *hport, uint8_t intf)
return ret;
}
static int usbh_cdc_data_connect(struct usbh_hubport *hport, uint8_t intf)
{
return 0;
}
static int usbh_cdc_data_disconnect(struct usbh_hubport *hport, uint8_t intf)
{
return 0;
}
__WEAK void usbh_cdc_acm_run(struct usbh_cdc_acm *cdc_acm_class)
{
}
__WEAK void usbh_cdc_acm_stop(struct usbh_cdc_acm *cdc_acm_class)
{
}
const struct usbh_class_driver cdc_acm_class_driver = {
.driver_name = "cdc_acm",
.connect = usbh_cdc_acm_connect,
.disconnect = usbh_cdc_acm_disconnect
};
const struct usbh_class_driver cdc_data_class_driver = {
.driver_name = "cdc_data",
.connect = usbh_cdc_data_connect,
.disconnect = usbh_cdc_data_disconnect
};
CLASS_INFO_DEFINE const struct usbh_class_info cdc_acm_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
.class = USB_DEVICE_CLASS_CDC,
@ -191,3 +219,13 @@ CLASS_INFO_DEFINE const struct usbh_class_info cdc_acm_class_info = {
.pid = 0x00,
.class_driver = &cdc_acm_class_driver
};
CLASS_INFO_DEFINE const struct usbh_class_info cdc_data_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS,
.class = USB_DEVICE_CLASS_CDC_DATA,
.subclass = 0x00,
.protocol = 0x00,
.vid = 0x00,
.pid = 0x00,
.class_driver = &cdc_data_class_driver
};

View File

@ -32,6 +32,8 @@ int usbh_cdc_acm_set_line_coding(struct usbh_cdc_acm *cdc_acm_class, struct cdc_
int usbh_cdc_acm_get_line_coding(struct usbh_cdc_acm *cdc_acm_class, struct cdc_line_coding *line_coding);
int usbh_cdc_acm_set_line_state(struct usbh_cdc_acm *cdc_acm_class, bool dtr, bool rts);
void usbh_cdc_acm_run(struct usbh_cdc_acm *cdc_acm_class);
void usbh_cdc_acm_stop(struct usbh_cdc_acm *cdc_acm_class);
#ifdef __cplusplus
}
#endif

View File

@ -148,7 +148,8 @@ int usbh_hid_connect(struct usbh_hubport *hport, uint8_t intf)
USB_LOG_INFO("Register HID Class:%s\r\n", hport->config.intf[intf].devname);
return 0;
usbh_hid_run(hid_class);
return ret;
}
int usbh_hid_disconnect(struct usbh_hubport *hport, uint8_t intf)
@ -168,6 +169,7 @@ int usbh_hid_disconnect(struct usbh_hubport *hport, uint8_t intf)
usbh_pipe_free(hid_class->intout);
}
usbh_hid_stop(hid_class);
memset(hid_class, 0, sizeof(struct usbh_hid));
usb_free(hid_class);
@ -178,27 +180,27 @@ int usbh_hid_disconnect(struct usbh_hubport *hport, uint8_t intf)
return ret;
}
__WEAK void usbh_hid_run(struct usbh_hid *hid_class)
{
}
__WEAK void usbh_hid_stop(struct usbh_hid *hid_class)
{
}
const struct usbh_class_driver hid_class_driver = {
.driver_name = "hid",
.connect = usbh_hid_connect,
.disconnect = usbh_hid_disconnect
};
CLASS_INFO_DEFINE const struct usbh_class_info hid_keyboard_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
CLASS_INFO_DEFINE const struct usbh_class_info hid_custom_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS,
.class = USB_DEVICE_CLASS_HID,
.subclass = HID_SUBCLASS_BOOTIF,
.protocol = HID_PROTOCOL_KEYBOARD,
.vid = 0x00,
.pid = 0x00,
.class_driver = &hid_class_driver
};
CLASS_INFO_DEFINE const struct usbh_class_info hid_mouse_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
.class = USB_DEVICE_CLASS_HID,
.subclass = HID_SUBCLASS_BOOTIF,
.protocol = HID_PROTOCOL_MOUSE,
.subclass = 0x00,
.protocol = 0x00,
.vid = 0x00,
.pid = 0x00,
.class_driver = &hid_class_driver

View File

@ -25,6 +25,8 @@ extern "C" {
int usbh_hid_set_idle(struct usbh_hid *hid_class, uint8_t report_id, uint8_t duration);
int usbh_hid_get_idle(struct usbh_hid *hid_class, uint8_t *buffer);
void usbh_hid_run(struct usbh_hid *hid_class);
void usbh_hid_stop(struct usbh_hid *hid_class);
#ifdef __cplusplus
}
#endif

View File

@ -5,35 +5,37 @@
*/
#include "usbh_hub.h"
#define DEV_FORMAT "/dev/hub%d"
#define DEV_FORMAT "/dev/hub%d"
#define DEBOUNCE_TIMEOUT 400
#define DEBOUNCE_TIME_STEP 25
#define HUB_DEBOUNCE_TIMEOUT 1500
#define HUB_DEBOUNCE_STEP 25
#define HUB_DEBOUNCE_STABLE 100
#define DELAY_TIME_AFTER_RESET 200
#define EXTHUB_FIRST_INDEX 2
#define EXTHUB_FIRST_INDEX 2
static uint32_t g_devinuse = 0;
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_hub_buf[32];
usb_slist_t hub_event_head = USB_SLIST_OBJECT_INIT(hub_event_head);
usb_slist_t hub_class_head = USB_SLIST_OBJECT_INIT(hub_class_head);
usb_osal_sem_t hub_event_wait;
usb_osal_thread_t hub_thread;
usb_osal_mq_t hub_mq;
USB_NOCACHE_RAM_SECTION struct usbh_hub roothub;
struct usbh_hubport roothub_parent_port;
#if CONFIG_USBHOST_MAX_EXTHUBS > 0
USB_NOCACHE_RAM_SECTION struct usbh_hub exthub[CONFIG_USBHOST_MAX_EXTHUBS];
#endif
extern int usbh_hport_activate_ep0(struct usbh_hubport *hport);
extern int usbh_hport_deactivate_ep0(struct usbh_hubport *hport);
extern int usbh_enumerate(struct usbh_hubport *hport);
static void usbh_hub_thread_wakeup(struct usbh_hub *hub);
static const char *speed_table[] = { "error-speed", "low-speed", "full-speed", "high-speed", "wireless-speed", "super-speed", "superplus-speed" };
#if CONFIG_USBHOST_MAX_EXTHUBS > 0
static int usbh_hub_devno_alloc(void)
{
int devno;
@ -55,6 +57,17 @@ static void usbh_hub_devno_free(uint8_t devno)
g_devinuse &= ~(1 << devno);
}
}
#endif
static void usbh_hub_register(struct usbh_hub *hub)
{
usb_slist_add_tail(&hub_class_head, &hub->list);
}
static void usbh_hub_unregister(struct usbh_hub *hub)
{
usb_slist_remove(&hub_class_head, &hub->list);
}
static int _usbh_hub_get_hub_descriptor(struct usbh_hub *hub, uint8_t *buffer)
{
@ -225,12 +238,7 @@ static int usbh_hub_clear_feature(struct usbh_hub *hub, uint8_t port, uint8_t fe
}
}
static void usbh_hub_thread_wakeup(struct usbh_hub *hub)
{
usb_slist_add_tail(&hub_event_head, &hub->hub_event_list);
usb_osal_sem_give(hub_event_wait);
}
#if CONFIG_USBHOST_MAX_EXTHUBS > 0
static void hub_int_complete_callback(void *arg, int nbytes)
{
struct usbh_hub *hub = (struct usbh_hub *)arg;
@ -326,7 +334,7 @@ static int usbh_hub_disconnect(struct usbh_hubport *hport, uint8_t intf)
usbh_hport_deactivate_ep0(child);
for (uint8_t i = 0; i < child->config.config_desc.bNumInterfaces; i++) {
if (child->config.intf[i].class_driver && child->config.intf[i].class_driver->disconnect) {
ret = CLASS_DISCONNECT(child, i);
CLASS_DISCONNECT(child, i);
}
}
@ -342,20 +350,20 @@ static int usbh_hub_disconnect(struct usbh_hubport *hport, uint8_t intf)
}
return ret;
}
#endif
static void usbh_roothub_register(void)
static void usbh_hubport_release(struct usbh_hubport *child)
{
memset(&roothub, 0, sizeof(struct usbh_hub));
memset(&roothub_parent_port, 0, sizeof(struct usbh_hubport));
roothub_parent_port.port = 1;
roothub_parent_port.dev_addr = 1;
roothub.connected = true;
roothub.index = 1;
roothub.is_roothub = true;
roothub.parent = &roothub_parent_port;
roothub.hub_addr = roothub_parent_port.dev_addr;
roothub.hub_desc.bNbrPorts = CONFIG_USBHOST_MAX_RHPORTS;
usbh_hub_register(&roothub);
if (child->connected) {
child->connected = false;
usbh_hport_deactivate_ep0(child);
for (uint8_t i = 0; i < child->config.config_desc.bNumInterfaces; i++) {
if (child->config.intf[i].class_driver && child->config.intf[i].class_driver->disconnect) {
CLASS_DISCONNECT(child, i);
}
}
child->config.config_desc.bNumInterfaces = 0;
}
}
static void usbh_hub_events(struct usbh_hub *hub)
@ -419,8 +427,7 @@ static void usbh_hub_events(struct usbh_hub *hub)
if (portchange & HUB_PORT_STATUS_C_CONNECTION) {
uint16_t connection = 0;
uint16_t debouncestable = 0;
for (uint32_t debouncetime = 0; debouncetime < DEBOUNCE_TIMEOUT; debouncetime += DEBOUNCE_TIME_STEP) {
usb_osal_msleep(DEBOUNCE_TIME_STEP);
for (uint32_t debouncetime = 0; debouncetime < HUB_DEBOUNCE_TIMEOUT; debouncetime += HUB_DEBOUNCE_STEP) {
/* Read hub port status */
ret = usbh_hub_get_portstatus(hub, port + 1, &port_status);
if (ret < 0) {
@ -432,21 +439,29 @@ static void usbh_hub_events(struct usbh_hub *hub)
portchange = port_status.wPortChange;
USB_LOG_DBG("Port %u, status:0x%02x, change:0x%02x\r\n", port + 1, portstatus, portchange);
if ((portstatus & HUB_PORT_STATUS_CONNECTION) == connection) {
if (connection) {
if (++debouncestable == 4) {
break;
}
if (!(portchange & HUB_PORT_STATUS_C_CONNECTION) &&
((portstatus & HUB_PORT_STATUS_CONNECTION) == connection)) {
debouncestable += HUB_DEBOUNCE_STEP;
if (debouncestable >= HUB_DEBOUNCE_STABLE) {
break;
}
} else {
debouncestable = 0;
connection = portstatus & HUB_PORT_STATUS_CONNECTION;
}
connection = portstatus & HUB_PORT_STATUS_CONNECTION;
if (portchange & HUB_PORT_STATUS_C_CONNECTION) {
usbh_hub_clear_feature(hub, port + 1, HUB_PORT_FEATURE_C_CONNECTION);
}
usb_osal_msleep(HUB_DEBOUNCE_STEP);
}
/** check if debounce ok */
if (debouncestable < HUB_DEBOUNCE_STABLE) {
USB_LOG_ERR("Failed to debounce port %u\r\n", port + 1);
break;
}
/* Last, check connect status */
@ -484,6 +499,8 @@ static void usbh_hub_events(struct usbh_hub *hub)
}
child = &hub->child[port];
/** release child sources first */
usbh_hubport_release(child);
memset(child, 0, sizeof(struct usbh_hubport));
child->parent = hub;
@ -498,25 +515,22 @@ static void usbh_hub_events(struct usbh_hub *hub)
}
} else {
USB_LOG_ERR("Failed to enable port %u\r\n", port + 1);
child = &hub->child[port];
/** release child sources */
usbh_hubport_release(child);
continue;
}
} else {
child = &hub->child[port];
child->connected = false;
usbh_hport_deactivate_ep0(child);
for (uint8_t i = 0; i < child->config.config_desc.bNumInterfaces; i++) {
if (child->config.intf[i].class_driver && child->config.intf[i].class_driver->disconnect) {
CLASS_DISCONNECT(child, i);
}
}
USB_LOG_INFO("Device on Hub %u, Port %u disconnected\r\n", hub->index, port + 1);
usbh_device_unmount_done_callback(child);
child->config.config_desc.bNumInterfaces = 0;
/** release child sources */
usbh_hubport_release(child);
}
}
}
hub->int_buffer[0] = 0;
/* Start next hub int transfer */
if (!hub->is_roothub && hub->connected) {
usbh_submit_urb(&hub->intin_urb);
@ -525,48 +539,49 @@ static void usbh_hub_events(struct usbh_hub *hub)
static void usbh_hub_thread(void *argument)
{
size_t flags;
struct usbh_hub *hub;
int ret = 0;
usb_hc_init();
while (1) {
ret = usb_osal_sem_take(hub_event_wait, 0xffffffff);
ret = usb_osal_mq_recv(hub_mq, (uint32_t *)&hub, 0xffffffff);
if (ret < 0) {
continue;
}
while (!usb_slist_isempty(&hub_event_head)) {
struct usbh_hub *hub = usb_slist_first_entry(&hub_event_head, struct usbh_hub, hub_event_list);
flags = usb_osal_enter_critical_section();
usb_slist_remove(&hub_event_head, &hub->hub_event_list);
usb_osal_leave_critical_section(flags);
usbh_hub_events(hub);
}
usbh_hub_events(hub);
}
}
static void usbh_roothub_register(void)
{
memset(&roothub, 0, sizeof(struct usbh_hub));
roothub.connected = true;
roothub.index = 1;
roothub.is_roothub = true;
roothub.parent = NULL;
roothub.hub_addr = 1;
roothub.hub_desc.bNbrPorts = CONFIG_USBHOST_MAX_RHPORTS;
usbh_hub_register(&roothub);
}
static void usbh_hub_thread_wakeup(struct usbh_hub *hub)
{
usb_osal_mq_send(hub_mq, (uint32_t)hub);
}
void usbh_roothub_thread_wakeup(uint8_t port)
{
roothub.int_buffer[0] |= (1 << port);
usbh_hub_thread_wakeup(&roothub);
}
void usbh_hub_register(struct usbh_hub *hub)
{
usb_slist_add_tail(&hub_class_head, &hub->list);
}
void usbh_hub_unregister(struct usbh_hub *hub)
{
usb_slist_remove(&hub_class_head, &hub->list);
}
int usbh_hub_initialize(void)
{
usbh_roothub_register();
hub_event_wait = usb_osal_sem_create(0);
if (hub_event_wait == NULL) {
hub_mq = usb_osal_mq_create(7);
if (hub_mq == NULL) {
return -1;
}
@ -576,19 +591,20 @@ int usbh_hub_initialize(void)
}
return 0;
}
const struct usbh_class_driver hub_driver = {
#if CONFIG_USBHOST_MAX_EXTHUBS > 0
const struct usbh_class_driver hub_class_driver = {
.driver_name = "hub",
.connect = usbh_hub_connect,
.disconnect = usbh_hub_disconnect
};
CLASS_INFO_DEFINE const struct usbh_class_info hub_info = {
CLASS_INFO_DEFINE const struct usbh_class_info hub_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS,
.class = USB_DEVICE_CLASS_HUB,
.subclass = 0,
.protocol = 0,
.vid = 0x00,
.pid = 0x00,
.class_driver = &hub_driver
.class_driver = &hub_class_driver
};
#endif

View File

@ -19,8 +19,6 @@ extern usb_slist_t hub_class_head;
extern "C" {
#endif
void usbh_roothub_thread_wakeup(uint8_t port);
void usbh_hub_register(struct usbh_hub *hub);
void usbh_hub_unregister(struct usbh_hub *hub);
int usbh_hub_initialize(void);
#ifdef __cplusplus
}

View File

@ -6,13 +6,6 @@
#include "usbd_core.h"
#include "usbd_msc.h"
#include "usb_scsi.h"
#ifdef CONFIG_USBDEV_MSC_THREAD
#include "usb_osal.h"
#endif
#define MSC_THREAD_OP_READ_MEM 1
#define MSC_THREAD_OP_WRITE_MEM 2
#define MSC_THREAD_OP_WRITE_DONE 3
#define MSD_OUT_EP_IDX 0
#define MSD_IN_EP_IDX 1
@ -49,13 +42,6 @@ USB_NOCACHE_RAM_SECTION struct usbd_msc_cfg_priv {
uint8_t block_buffer[CONFIG_USBDEV_MSC_BLOCK_SIZE];
} usbd_msc_cfg;
#ifdef CONFIG_USBDEV_MSC_THREAD
static volatile uint8_t thread_op;
static usb_osal_sem_t msc_sem;
static usb_osal_thread_t msc_thread;
static volatile uint32_t current_byte_read;
#endif
static void usbd_msc_reset(void)
{
usbd_msc_cfg.stage = MSC_READ_CBW;
@ -635,17 +621,11 @@ static bool SCSI_processRead(void)
transfer_len = MIN(usbd_msc_cfg.nsectors * usbd_msc_cfg.scsi_blk_size, CONFIG_USBDEV_MSC_BLOCK_SIZE);
/* Start reading one sector */
#ifdef CONFIG_USBDEV_MSC_THREAD
thread_op = MSC_THREAD_OP_READ_MEM;
usb_osal_sem_give(msc_sem);
return true;
#else
if (usbd_msc_sector_read(usbd_msc_cfg.start_sector, usbd_msc_cfg.block_buffer, transfer_len) != 0) {
SCSI_SetSenseData(SCSI_KCQHE_UREINRESERVEDAREA);
return false;
}
#endif
usbd_ep_start_write(mass_ep_data[MSD_IN_EP_IDX].ep_addr, usbd_msc_cfg.block_buffer, transfer_len);
usbd_msc_cfg.start_sector += (transfer_len / usbd_msc_cfg.scsi_blk_size);
@ -659,47 +639,15 @@ static bool SCSI_processRead(void)
return true;
}
#ifdef CONFIG_USBDEV_MSC_THREAD
static void usbd_msc_thread_memory_read_done(void)
{
size_t flags;
uint32_t transfer_len;
flags = usb_osal_enter_critical_section();
transfer_len = MIN(usbd_msc_cfg.nsectors * usbd_msc_cfg.scsi_blk_size, CONFIG_USBDEV_MSC_BLOCK_SIZE);
usbd_ep_start_write(mass_ep_data[MSD_IN_EP_IDX].ep_addr,
usbd_msc_cfg.block_buffer, transfer_len);
usbd_msc_cfg.start_sector += (transfer_len / usbd_msc_cfg.scsi_blk_size);
usbd_msc_cfg.nsectors -= (transfer_len / usbd_msc_cfg.scsi_blk_size);
usbd_msc_cfg.csw.dDataResidue -= transfer_len;
if (usbd_msc_cfg.nsectors == 0) {
usbd_msc_cfg.stage = MSC_SEND_CSW;
}
usb_osal_leave_critical_section(flags);
}
#endif
static bool SCSI_processWrite(uint32_t nbytes)
{
uint32_t data_len = 0;
USB_LOG_DBG("write lba:%d\r\n", usbd_msc_cfg.start_sector);
/* Start writing one sector */
#ifdef CONFIG_USBDEV_MSC_THREAD
thread_op = MSC_THREAD_OP_WRITE_MEM;
current_byte_read = nbytes;
usb_osal_sem_give(msc_sem);
return true;
#else
if (usbd_msc_sector_write(usbd_msc_cfg.start_sector, usbd_msc_cfg.block_buffer, nbytes) != 0) {
SCSI_SetSenseData(SCSI_KCQHE_WRITEFAULT);
return false;
}
#endif
usbd_msc_cfg.start_sector += (nbytes / usbd_msc_cfg.scsi_blk_size);
usbd_msc_cfg.nsectors -= (nbytes / usbd_msc_cfg.scsi_blk_size);
@ -715,29 +663,6 @@ static bool SCSI_processWrite(uint32_t nbytes)
return true;
}
#ifdef CONFIG_USBDEV_MSC_THREAD
static void usbd_msc_thread_memory_write_done()
{
size_t flags;
uint32_t data_len = 0;
flags = usb_osal_enter_critical_section();
usbd_msc_cfg.start_sector += (current_byte_read / usbd_msc_cfg.scsi_blk_size);
usbd_msc_cfg.nsectors -= (current_byte_read / usbd_msc_cfg.scsi_blk_size);
usbd_msc_cfg.csw.dDataResidue -= current_byte_read;
if (usbd_msc_cfg.nsectors == 0) {
usbd_msc_send_csw(CSW_STATUS_CMD_PASSED);
} else {
data_len = MIN(usbd_msc_cfg.nsectors * usbd_msc_cfg.scsi_blk_size, CONFIG_USBDEV_MSC_BLOCK_SIZE);
usbd_ep_start_read(mass_ep_data[MSD_OUT_EP_IDX].ep_addr, usbd_msc_cfg.block_buffer, data_len);
}
usb_osal_leave_critical_section(flags);
}
#endif
static bool SCSI_CBWDecode(uint32_t nbytes)
{
uint8_t *buf2send = usbd_msc_cfg.block_buffer;
@ -883,35 +808,6 @@ void mass_storage_bulk_in(uint8_t ep, uint32_t nbytes)
}
}
#ifdef CONFIG_USBDEV_MSC_THREAD
static void usbd_msc_thread(void *argument)
{
uint32_t data_len = 0;
while (1) {
usb_osal_sem_take(msc_sem, 0xffffffff);
switch (thread_op) {
case MSC_THREAD_OP_READ_MEM:
data_len = MIN(usbd_msc_cfg.nsectors * usbd_msc_cfg.scsi_blk_size, CONFIG_USBDEV_MSC_BLOCK_SIZE);
if (usbd_msc_sector_read(usbd_msc_cfg.start_sector, usbd_msc_cfg.block_buffer, data_len) != 0) {
SCSI_SetSenseData(SCSI_KCQHE_UREINRESERVEDAREA);
}
usbd_msc_thread_memory_read_done();
break;
case MSC_THREAD_OP_WRITE_MEM:
data_len = MIN(usbd_msc_cfg.nsectors * usbd_msc_cfg.scsi_blk_size, CONFIG_USBDEV_MSC_BLOCK_SIZE);
if (usbd_msc_sector_write(usbd_msc_cfg.start_sector, usbd_msc_cfg.block_buffer, data_len) != 0) {
SCSI_SetSenseData(SCSI_KCQHE_WRITEFAULT);
}
usbd_msc_thread_memory_write_done();
break;
default:
break;
}
}
}
#endif
struct usbd_interface *usbd_msc_init_intf(struct usbd_interface *intf, const uint8_t out_ep, const uint8_t in_ep)
{
intf->class_interface_handler = msc_storage_class_interface_request_handler;
@ -935,14 +831,6 @@ struct usbd_interface *usbd_msc_init_intf(struct usbd_interface *intf, const uin
USB_LOG_ERR("msc block buffer overflow\r\n");
return NULL;
}
#ifdef CONFIG_USBDEV_MSC_THREAD
msc_sem = usb_osal_sem_create(1);
msc_thread = usb_osal_thread_create("usbd_msc", CONFIG_USBDEV_MSC_STACKSIZE, CONFIG_USBDEV_MSC_PRIO, usbd_msc_thread, NULL);
if (msc_thread == NULL) {
USB_LOG_ERR("no enough memory to alloc msc thread\r\n");
return NULL;
}
#endif
return intf;
}
@ -950,4 +838,4 @@ struct usbd_interface *usbd_msc_init_intf(struct usbd_interface *intf, const uin
void usbd_msc_set_readonly(bool readonly)
{
usbd_msc_cfg.readonly = readonly;
}
}

View File

@ -13,7 +13,9 @@ extern "C" {
#endif
/* Init msc interface driver */
struct usbd_interface *usbd_msc_init_intf(struct usbd_interface *intf, const uint8_t out_ep, const uint8_t in_ep);
struct usbd_interface *usbd_msc_init_intf(struct usbd_interface *intf,
const uint8_t out_ep,
const uint8_t in_ep);
void usbd_msc_get_cap(uint8_t lun, uint32_t *block_num, uint16_t *block_size);
int usbd_msc_sector_read(uint32_t sector, uint8_t *buffer, uint32_t length);

View File

@ -371,6 +371,7 @@ static int usbh_msc_connect(struct usbh_hubport *hport, uint8_t intf)
USB_LOG_INFO("Register MSC Class:%s\r\n", hport->config.intf[intf].devname);
usbh_msc_run(msc_class);
return ret;
}
@ -391,6 +392,7 @@ static int usbh_msc_disconnect(struct usbh_hubport *hport, uint8_t intf)
usbh_pipe_free(msc_class->bulkout);
}
usbh_msc_stop(msc_class);
memset(msc_class, 0, sizeof(struct usbh_msc));
usb_free(msc_class);
@ -401,6 +403,16 @@ static int usbh_msc_disconnect(struct usbh_hubport *hport, uint8_t intf)
return ret;
}
__WEAK void usbh_msc_run(struct usbh_msc *msc_class)
{
}
__WEAK void usbh_msc_stop(struct usbh_msc *msc_class)
{
}
const struct usbh_class_driver msc_class_driver = {
.driver_name = "msc",
.connect = usbh_msc_connect,

View File

@ -25,6 +25,8 @@ struct usbh_msc {
int usbh_msc_scsi_write10(struct usbh_msc *msc_class, uint32_t start_sector, const uint8_t *buffer, uint32_t nsectors);
int usbh_msc_scsi_read10(struct usbh_msc *msc_class, uint32_t start_sector, const uint8_t *buffer, uint32_t nsectors);
void usbh_msc_run(struct usbh_msc *msc_class);
void usbh_msc_stop(struct usbh_msc *msc_class);
#ifdef __cplusplus
extern "C" {
#endif

View File

@ -742,7 +742,10 @@ void usbd_video_probe_and_commit_controls_init(uint32_t dwFrameInterval, uint32_
usbd_video_cfg.commit.bMaxVersion = 0;
}
struct usbd_interface *usbd_video_init_intf(struct usbd_interface *intf, uint32_t dwFrameInterval, uint32_t dwMaxVideoFrameSize, uint32_t dwMaxPayloadTransferSize)
struct usbd_interface *usbd_video_init_intf(struct usbd_interface *intf,
uint32_t dwFrameInterval,
uint32_t dwMaxVideoFrameSize,
uint32_t dwMaxPayloadTransferSize)
{
intf->class_interface_handler = video_class_interface_request_handler;
intf->class_endpoint_handler = NULL;

View File

@ -6,16 +6,16 @@
#include "usbh_core.h"
#include "usbh_video.h"
#define DEV_FORMAT "/dev/video%d"
#define DEV_FORMAT "/dev/video%d"
/* general descriptor field offsets */
#define DESC_bLength 0 /** Length offset */
#define DESC_bDescriptorType 1 /** Descriptor type offset */
#define DESC_bDescriptorSubType 2 /** Descriptor subtype offset */
#define DESC_bNumFormats 3 /** Descriptor numformat offset */
#define DESC_bNumFrameDescriptors 4 /** Descriptor numframe offset */
#define DESC_bFormatIndex 3 /** Descriptor format index offset */
#define DESC_bFrameIndex 3 /** Descriptor frame index offset */
#define DESC_bLength 0 /** Length offset */
#define DESC_bDescriptorType 1 /** Descriptor type offset */
#define DESC_bDescriptorSubType 2 /** Descriptor subtype offset */
#define DESC_bNumFormats 3 /** Descriptor numformat offset */
#define DESC_bNumFrameDescriptors 4 /** Descriptor numframe offset */
#define DESC_bFormatIndex 3 /** Descriptor format index offset */
#define DESC_bFrameIndex 3 /** Descriptor frame index offset */
/* interface descriptor field offsets */
#define INTF_DESC_bInterfaceNumber 2 /** Interface number offset */
@ -32,7 +32,7 @@ static int __s_b_1732446u[256] = { 0 };
static int __s_g_337633u[256] = { 0 };
static int __s_g_698001v[256] = { 0 };
static void inityuyv2rgb_table(void)
void usbh_video_inityuyv2rgb_table(void)
{
for (int i = 0; i < 256; i++) {
__s_r_1370705v[i] = (1.370705 * (i - 128));
@ -42,7 +42,7 @@ static void inityuyv2rgb_table(void)
}
}
static void yuyv2rgb565(void *input, void *output, uint32_t len)
void usbh_video_yuyv2rgb565(void *input, void *output, uint32_t len)
{
int y0, u, y1, v;
uint8_t r, g, b;
@ -134,47 +134,84 @@ int usbh_videostreaming_get_cur_probe(struct usbh_video *video_class)
return usbh_video_get_cur(video_class, video_class->data_intf, 0x00, VIDEO_VS_PROBE_CONTROL, (uint8_t *)&video_class->probe, 26);
}
int usbh_videostreaming_set_cur_probe(struct usbh_video *video_class, uint8_t formatindex, uint8_t frameindex, uint32_t dwMaxVideoFrameSize, uint32_t dwMaxPayloadTransferSize)
int usbh_videostreaming_set_cur_probe(struct usbh_video *video_class, uint8_t formatindex, uint8_t frameindex)
{
video_class->probe.bFormatIndex = formatindex;
video_class->probe.bFrameIndex = frameindex;
video_class->probe.dwMaxVideoFrameSize = dwMaxVideoFrameSize;
video_class->probe.dwMaxPayloadTransferSize = dwMaxPayloadTransferSize;
video_class->probe.dwMaxPayloadTransferSize = 0;
return usbh_video_set_cur(video_class, video_class->data_intf, 0x00, VIDEO_VS_PROBE_CONTROL, (uint8_t *)&video_class->probe, 26);
}
int usbh_videostreaming_set_cur_commit(struct usbh_video *video_class, uint8_t formatindex, uint8_t frameindex, uint32_t dwMaxVideoFrameSize, uint32_t dwMaxPayloadTransferSize)
int usbh_videostreaming_set_cur_commit(struct usbh_video *video_class, uint8_t formatindex, uint8_t frameindex)
{
memcpy(&video_class->commit, &video_class->probe, sizeof(struct video_probe_and_commit_controls));
video_class->commit.bFormatIndex = formatindex;
video_class->commit.bFrameIndex = frameindex;
video_class->commit.dwMaxVideoFrameSize = dwMaxVideoFrameSize;
video_class->commit.dwMaxPayloadTransferSize = dwMaxPayloadTransferSize;
return usbh_video_set_cur(video_class, video_class->data_intf, 0x00, VIDEO_VS_COMMIT_CONTROL, (uint8_t *)&video_class->commit, 26);
}
int usbh_video_open(struct usbh_video *video_class, uint8_t altsetting)
int usbh_video_open(struct usbh_video *video_class,
uint8_t format_type,
uint16_t wWidth,
uint16_t wHeight,
uint8_t altsetting)
{
struct usb_setup_packet *setup = &video_class->hport->setup;
struct usb_endpoint_descriptor *ep_desc;
uint8_t mult;
uint16_t mps;
int ret;
bool found = false;
uint8_t formatidx = 0;
uint8_t frameidx = 0;
if (video_class->is_opened) {
return -EMFILE;
}
for (uint8_t i = 0; i < video_class->num_of_formats; i++) {
if (format_type == video_class->format[i].format_type) {
formatidx = i + 1;
for (uint8_t j = 0; j < video_class->format[i].num_of_frames; j++) {
if ((wWidth == video_class->format[i].frame[j].wWidth) &&
(wHeight == video_class->format[i].frame[j].wHeight)) {
frameidx = j + 1;
found = true;
break;
}
}
}
}
if (found == false) {
return -ENODEV;
}
if (altsetting > (video_class->num_of_intf_altsettings - 1)) {
return -EINVAL;
}
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = USB_REQUEST_SET_INTERFACE;
setup->wValue = altsetting;
setup->wIndex = video_class->data_intf;
setup->wLength = 0;
ret = usbh_control_transfer(video_class->hport->ep0, setup, NULL);
ret = usbh_videostreaming_get_cur_probe(video_class);
if (ret < 0) {
return ret;
}
ret = usbh_videostreaming_set_cur_probe(video_class, formatidx, frameidx);
if (ret < 0) {
return ret;
}
ret = usbh_videostreaming_get_cur_probe(video_class);
if (ret < 0) {
return ret;
}
ret = usbh_videostreaming_set_cur_probe(video_class, formatidx, frameidx);
if (ret < 0) {
return ret;
}
ret = usbh_videostreaming_get_cur_probe(video_class);
if (ret < 0) {
return ret;
}
ret = usbh_videostreaming_set_cur_commit(video_class, formatidx, frameidx);
if (ret < 0) {
return ret;
}
@ -189,15 +226,46 @@ int usbh_video_open(struct usbh_video *video_class, uint8_t altsetting)
video_class->isoout_mps = mps * (mult + 1);
usbh_hport_activate_epx(&video_class->isoout, video_class->hport, ep_desc);
}
USB_LOG_INFO("Open video and select altsetting:%u\r\n", altsetting);
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = USB_REQUEST_SET_INTERFACE;
setup->wValue = altsetting;
setup->wIndex = video_class->data_intf;
setup->wLength = 0;
ret = usbh_control_transfer(video_class->hport->ep0, setup, NULL);
if (ret < 0) {
return ret;
}
USB_LOG_INFO("Open video and select formatidx:%u, frameidx:%u, altsetting:%u\r\n", formatidx, frameidx, altsetting);
video_class->is_opened = true;
video_class->current_format = format_type;
return ret;
}
int usbh_video_close(struct usbh_video *video_class)
{
struct usb_setup_packet *setup = &video_class->hport->setup;
int ret;
int ret = 0;
USB_LOG_INFO("Close video device\r\n");
if (video_class->is_opened == false) {
return 0;
}
video_class->is_opened = false;
if (video_class->isoin) {
usbh_pipe_free(video_class->isoin);
video_class->isoin = NULL;
}
if (video_class->isoout) {
usbh_pipe_free(video_class->isoout);
video_class->isoout = NULL;
}
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = USB_REQUEST_SET_INTERFACE;
@ -209,24 +277,11 @@ int usbh_video_close(struct usbh_video *video_class)
if (ret < 0) {
return ret;
}
if (video_class->isoin) {
usbh_pipe_free(video_class->isoin);
video_class->isoin = NULL;
}
if (video_class->isoout) {
usbh_pipe_free(video_class->isoout);
video_class->isoout = NULL;
}
USB_LOG_INFO("Close video device\r\n");
video_class->is_opened = false;
return ret;
}
void usbh_video_list_info(struct usbh_video *video_class)
{
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *ep_desc;
uint8_t mult;
uint16_t mps;
@ -235,8 +290,6 @@ void usbh_video_list_info(struct usbh_video *video_class)
USB_LOG_INFO("bcdVDC:%04x\r\n", video_class->bcdVDC);
USB_LOG_INFO("Num of altsettings:%02x\r\n", video_class->num_of_intf_altsettings);
hport = video_class->hport;
for (uint8_t i = 1; i < video_class->num_of_intf_altsettings; i++) {
ep_desc = &video_class->hport->config.intf[video_class->data_intf].altsetting[i].ep[0].ep_desc;
@ -266,18 +319,14 @@ void usbh_video_list_info(struct usbh_video *video_class)
}
}
usbh_videostreaming_get_cur_probe(video_class);
USB_LOG_INFO("dwMaxVideoFrameSize:%u,dwMaxPayloadTransferSize:%u\r\n", (int)video_class->probe.dwMaxVideoFrameSize, (int)video_class->probe.dwMaxPayloadTransferSize);
USB_LOG_INFO("============= Video device information ===================\r\n");
}
static int usbh_video_ctrl_intf_connect(struct usbh_hubport *hport, uint8_t intf)
static int usbh_video_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
{
int ret;
uint8_t cur_iface = 0xff;
uint8_t cur_alt_setting = 0xff;
// uint8_t cur_alt_setting = 0xff;
uint8_t frame_index = 0xff;
uint8_t format_index = 0xff;
uint8_t num_of_frames = 0xff;
@ -378,14 +427,16 @@ static int usbh_video_ctrl_intf_connect(struct usbh_hubport *hport, uint8_t intf
usbh_video_list_info(video_class);
snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, video_class->minor);
#ifdef CONFIG_USBHOST_UVC_YUV2RGB
inityuyv2rgb_table();
#endif
USB_LOG_INFO("Register Video Class:%s\r\n", hport->config.intf[intf].devname);
return 0;
usbh_video_run(video_class);
return ret;
}
static int usbh_video_ctrl_intf_disconnect(struct usbh_hubport *hport, uint8_t intf)
static int usbh_video_ctrl_disconnect(struct usbh_hubport *hport, uint8_t intf)
{
int ret = 0;
@ -402,6 +453,7 @@ static int usbh_video_ctrl_intf_disconnect(struct usbh_hubport *hport, uint8_t i
usbh_pipe_free(video_class->isoout);
}
usbh_video_stop(video_class);
memset(video_class, 0, sizeof(struct usbh_video));
usb_free(video_class);
@ -412,13 +464,12 @@ static int usbh_video_ctrl_intf_disconnect(struct usbh_hubport *hport, uint8_t i
return ret;
}
static int usbh_video_data_intf_connect(struct usbh_hubport *hport, uint8_t intf)
static int usbh_video_streaming_connect(struct usbh_hubport *hport, uint8_t intf)
{
USB_LOG_WRN("Ignore video data intf\r\n");
return 0;
}
static int usbh_video_data_intf_disconnect(struct usbh_hubport *hport, uint8_t intf)
static int usbh_video_streaming_disconnect(struct usbh_hubport *hport, uint8_t intf)
{
return 0;
}
@ -427,9 +478,9 @@ void usbh_videostreaming_parse_mjpeg(struct usbh_urb *urb, struct usbh_videostre
{
struct usbh_iso_frame_packet *iso_packet;
uint32_t num_of_iso_packets;
uint8_t *tmp_buf;
uint8_t data_offset;
uint32_t data_len;
uint8_t header_len = 0;
num_of_iso_packets = urb->num_of_iso_packets;
iso_packet = urb->iso_packet;
@ -448,11 +499,10 @@ void usbh_videostreaming_parse_mjpeg(struct usbh_urb *urb, struct usbh_videostre
if (iso_packet[i].actual_length == 0) { /* skip no data */
continue;
}
if (iso_packet[i].actual_length < iso_packet[i].transfer_buffer[0]) { /* do not be illegal */
while (1) {
}
}
if ((iso_packet[i].transfer_buffer[0] > 12) || (iso_packet[i].transfer_buffer[0] == 0)) { /* do not be illegal */
header_len = iso_packet[i].transfer_buffer[0];
if ((header_len > 12) || (header_len == 0)) { /* do not be illegal */
while (1) {
}
}
@ -461,20 +511,20 @@ void usbh_videostreaming_parse_mjpeg(struct usbh_urb *urb, struct usbh_videostre
continue;
}
data_offset = iso_packet[i].transfer_buffer[0];
data_len = iso_packet[i].actual_length - iso_packet[i].transfer_buffer[0];
tmp_buf = stream->bufbase + stream->bufoffset;
stream->bufoffset += data_len;
memcpy(tmp_buf, &iso_packet[i].transfer_buffer[data_offset], data_len);
if ((stream->bufbase[0] != 0xff) && (stream->bufbase[1] != 0xd8)) {
if ((stream->bufoffset == 0) && (iso_packet[i].transfer_buffer[header_len] != 0xff) && (iso_packet[i].transfer_buffer[header_len + 1] != 0xd8)) {
stream->bufoffset = 0;
continue;
}
data_offset = iso_packet[i].transfer_buffer[0];
data_len = iso_packet[i].actual_length - iso_packet[i].transfer_buffer[0];
usbh_videostreaming_output(&iso_packet[i].transfer_buffer[data_offset], data_len);
stream->bufoffset += data_len;
if (iso_packet[i].transfer_buffer[1] & (1 << 1)) {
if ((stream->bufbase[stream->bufoffset - 2] != 0xff) && (stream->bufbase[stream->bufoffset - 1] != 0xd9)) {
if ((iso_packet[i].transfer_buffer[iso_packet[i].actual_length - 2] != 0xff) && (iso_packet[i].transfer_buffer[iso_packet[i].actual_length - 1] != 0xd9)) {
stream->bufoffset = 0;
continue;
}
@ -486,13 +536,13 @@ void usbh_videostreaming_parse_mjpeg(struct usbh_urb *urb, struct usbh_videostre
}
}
void usbh_videostreaming_parse_yuyv2rgb565(struct usbh_urb *urb, struct usbh_videostreaming *stream)
void usbh_videostreaming_parse_yuyv2(struct usbh_urb *urb, struct usbh_videostreaming *stream)
{
struct usbh_iso_frame_packet *iso_packet;
uint32_t num_of_iso_packets;
uint8_t *tmp_buf;
uint8_t data_offset;
uint32_t data_len;
uint8_t header_len = 0;
num_of_iso_packets = urb->num_of_iso_packets;
iso_packet = urb->iso_packet;
@ -512,11 +562,10 @@ void usbh_videostreaming_parse_yuyv2rgb565(struct usbh_urb *urb, struct usbh_vid
if (iso_packet[i].actual_length == 0) { /* skip no data */
continue;
}
if (iso_packet[i].actual_length < iso_packet[i].transfer_buffer[0]) { /* do not be illegal */
while (1) {
}
}
if ((iso_packet[i].transfer_buffer[0] > 12) || (iso_packet[i].transfer_buffer[0] == 0)) { /* do not be illegal */
header_len = iso_packet[i].transfer_buffer[0];
if ((header_len > 12) || (header_len == 0)) { /* do not be illegal */
while (1) {
}
}
@ -528,10 +577,9 @@ void usbh_videostreaming_parse_yuyv2rgb565(struct usbh_urb *urb, struct usbh_vid
data_offset = iso_packet[i].transfer_buffer[0];
data_len = iso_packet[i].actual_length - iso_packet[i].transfer_buffer[0];
tmp_buf = stream->bufbase + stream->bufoffset;
usbh_videostreaming_output(&iso_packet[i].transfer_buffer[data_offset], data_len);
stream->bufoffset += data_len;
yuyv2rgb565(&iso_packet[i].transfer_buffer[data_offset], tmp_buf, data_len);
if (iso_packet[i].transfer_buffer[1] & (1 << 1)) {
if (stream->video_one_frame_callback) {
stream->video_one_frame_callback(stream);
@ -541,34 +589,46 @@ void usbh_videostreaming_parse_yuyv2rgb565(struct usbh_urb *urb, struct usbh_vid
}
}
const struct usbh_class_driver video_class_ctrl_intf_driver = {
.driver_name = "video",
.connect = usbh_video_ctrl_intf_connect,
.disconnect = usbh_video_ctrl_intf_disconnect
__WEAK void usbh_video_run(struct usbh_video *video_class)
{
}
__WEAK void usbh_video_stop(struct usbh_video *video_class)
{
}
__WEAK void usbh_videostreaming_output(uint8_t *input, uint32_t input_len)
{
}
const struct usbh_class_driver video_ctrl_class_driver = {
.driver_name = "video_ctrl",
.connect = usbh_video_ctrl_connect,
.disconnect = usbh_video_ctrl_disconnect
};
const struct usbh_class_driver video_class_data_intf_driver = {
.driver_name = "video",
.connect = usbh_video_data_intf_connect,
.disconnect = usbh_video_data_intf_disconnect
const struct usbh_class_driver video_streaming_class_driver = {
.driver_name = "video_streaming",
.connect = usbh_video_streaming_connect,
.disconnect = usbh_video_streaming_disconnect
};
CLASS_INFO_DEFINE const struct usbh_class_info video_ctrl_intf_class_info = {
CLASS_INFO_DEFINE const struct usbh_class_info video_ctrl_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
.class = USB_DEVICE_CLASS_VIDEO,
.subclass = VIDEO_SC_VIDEOCONTROL,
.protocol = VIDEO_PC_PROTOCOL_UNDEFINED,
.vid = 0x00,
.pid = 0x00,
.class_driver = &video_class_ctrl_intf_driver
.class_driver = &video_ctrl_class_driver
};
CLASS_INFO_DEFINE const struct usbh_class_info video_data_intf_class_info = {
CLASS_INFO_DEFINE const struct usbh_class_info video_streaming_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
.class = USB_DEVICE_CLASS_VIDEO,
.subclass = VIDEO_SC_VIDEOSTREAMING,
.protocol = VIDEO_PC_PROTOCOL_UNDEFINED,
.vid = 0x00,
.pid = 0x00,
.class_driver = &video_class_data_intf_driver
.class_driver = &video_streaming_class_driver
};

View File

@ -41,6 +41,7 @@ struct usbh_video {
uint16_t isoin_mps;
uint16_t isoout_mps;
bool is_opened;
uint8_t current_format;
uint16_t bcdVDC;
uint8_t num_of_intf_altsettings;
uint8_t num_of_formats;
@ -51,19 +52,30 @@ struct usbh_video {
extern "C" {
#endif
void usbh_video_inityuyv2rgb_table(void);
void usbh_video_yuyv2rgb565(void *input, void *output, uint32_t len);
int usbh_video_get_cur(struct usbh_video *video_class, uint8_t intf, uint8_t entity_id, uint8_t cs, uint8_t *buf, uint16_t len);
int usbh_video_set_cur(struct usbh_video *video_class, uint8_t intf, uint8_t entity_id, uint8_t cs, uint8_t *buf, uint16_t len);
int usbh_videostreaming_get_cur_probe(struct usbh_video *video_class);
int usbh_videostreaming_set_cur_probe(struct usbh_video *video_class, uint8_t formatindex, uint8_t frameindex, uint32_t dwMaxVideoFrameSize, uint32_t dwMaxPayloadTransferSize);
int usbh_videostreaming_set_cur_commit(struct usbh_video *video_class, uint8_t formatindex, uint8_t frameindex, uint32_t dwMaxVideoFrameSize, uint32_t dwMaxPayloadTransferSize);
int usbh_videostreaming_set_cur_probe(struct usbh_video *video_class, uint8_t formatindex, uint8_t frameindex);
int usbh_videostreaming_set_cur_commit(struct usbh_video *video_class, uint8_t formatindex, uint8_t frameindex);
int usbh_video_open(struct usbh_video *video_class, uint8_t altsetting);
int usbh_video_open(struct usbh_video *video_class,
uint8_t format_type,
uint16_t wWidth,
uint16_t wHeight,
uint8_t altsetting);
int usbh_video_close(struct usbh_video *video_class);
void usbh_video_list_info(struct usbh_video *video_class);
void usbh_videostreaming_parse_mjpeg(struct usbh_urb *urb, struct usbh_videostreaming *stream);
void usbh_videostreaming_parse_yuyv2rgb565(struct usbh_urb *urb, struct usbh_videostreaming *stream);
void usbh_videostreaming_parse_yuyv2(struct usbh_urb *urb, struct usbh_videostreaming *stream);
void usbh_videostreaming_output(uint8_t *input, uint32_t input_len);
void usbh_video_run(struct usbh_video *video_class);
void usbh_video_stop(struct usbh_video *video_class);
#ifdef __cplusplus
}

View File

@ -21,6 +21,7 @@ struct usbd_endpoint_cfg {
uint8_t ep_addr; /* Endpoint addr with direction */
uint8_t ep_type; /* Endpoint type */
uint16_t ep_mps; /* Endpoint max packet size */
uint8_t ep_mult; /* Endpoint additional transcations in micro frame */
};
/**
@ -44,6 +45,15 @@ int usb_dc_deinit(void);
*/
int usbd_set_address(const uint8_t addr);
/**
* @brief Get USB device speed
*
* @param[in] port port index
*
* @return port speed, USB_SPEED_LOW or USB_SPEED_FULL or USB_SPEED_HIGH
*/
uint8_t usbd_get_port_speed(const uint8_t port);
/**
* @brief configure and enable endpoint.
*

View File

@ -548,6 +548,14 @@ struct usb_bos_header_descriptor {
uint8_t bNumDeviceCaps;
} __PACKED;
/* BOS Capability extension Descriptor*/
struct usb_bos_capability_extension_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bDevCapabilityType;
uint32_t bmAttributes;
} __PACKED;
/* BOS Capability platform Descriptor */
struct usb_bos_capability_platform_descriptor {
uint8_t bLength;
@ -557,6 +565,18 @@ struct usb_bos_capability_platform_descriptor {
uint8_t PlatformCapabilityUUID[16];
} __PACKED;
/* BOS Capability superspeed Descriptor */
struct usb_bos_capability_superspeed_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bDevCapabilityType;
uint8_t bmAttributes;
uint16_t wSpeedsSupported;
uint8_t bFunctionalitySupport;
uint8_t bU1DevExitLat;
uint16_t wU2DevExitLat;
} __PACKED;
/* BOS Capability MS OS Descriptors version 2 */
struct usb_bos_capability_msosv2_descriptor {
uint32_t dwWindowsVersion;
@ -572,14 +592,6 @@ struct usb_bos_capability_webusb_descriptor {
uint8_t iLandingPage;
} __PACKED;
/* BOS Capability extension Descriptor*/
struct usb_bos_capability_extension_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bDevCapabilityType;
uint32_t bmAttributes;
} __PACKED;
/* Microsoft OS 2.0 Platform Capability Descriptor
* See https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/
* microsoft-defined-usb-descriptors

View File

@ -56,6 +56,7 @@ struct usbh_urb {
uint32_t timeout;
int errorcode;
uint32_t num_of_iso_packets;
uint32_t start_frame;
usbh_complete_callback_t complete;
void *arg;
struct usbh_iso_frame_packet iso_packet[0];
@ -68,6 +69,12 @@ struct usbh_urb {
*/
int usb_hc_init(void);
/**
* @brief Get frame number.
*
* @return frame number.
*/
uint16_t usbh_get_frame_number(void);
/**
* @brief control roothub.
*

View File

@ -44,12 +44,12 @@
#ifndef __ALIGNED
#define __ALIGNED(x) __attribute__((aligned(x)))
#endif
#elif defined(__ICCARM__)
#elif defined(__ICCARM__) || defined(__ICCRX__)
#ifndef __USED
#if __ICCARM_V8
#define __USED __attribute__((used))
#else
#define __USED _Pragma("__root")
#define __USED __root
#endif
#endif

View File

@ -6,6 +6,9 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbd_core.h"
#ifdef CONFIG_USBDEV_TX_RX_THREAD
#include "usb_osal.h"
#endif
/* general descriptor field offsets */
#define DESC_bLength 0 /** Length offset */
@ -23,6 +26,12 @@
#define USB_EP_OUT_NUM 8
#define USB_EP_IN_NUM 8
struct usbd_tx_rx_msg {
uint8_t ep;
uint32_t nbytes;
usbd_endpoint_callback cb;
};
USB_NOCACHE_RAM_SECTION struct usbd_core_cfg_priv {
/** Setup packet */
USB_MEM_ALIGNX struct usb_setup_packet setup;
@ -35,17 +44,19 @@ USB_NOCACHE_RAM_SECTION struct usbd_core_cfg_priv {
/** Zero length packet flag of control transfer */
bool zlp_flag;
/** Pointer to registered descriptors */
#if defined(CHERRYUSB_VERSION) && (CHERRYUSB_VERSION > 0x000700)
struct usb_descriptor *descriptors;
#else
const uint8_t *descriptors;
#endif
/* Buffer used for storing standard, class and vendor request data */
USB_MEM_ALIGNX uint8_t req_data[CONFIG_USBDEV_REQUEST_BUFFER_LEN];
usbd_endpoint_callback in_ep_cb[USB_EP_IN_NUM];
usbd_endpoint_callback out_ep_cb[USB_EP_OUT_NUM];
/** Variable to check whether the usb has been configured */
bool configured;
/** Currently selected configuration */
uint8_t configuration;
uint8_t speed;
#ifdef CONFIG_USBDEV_TEST_MODE
bool test_mode;
#endif
@ -58,6 +69,14 @@ static struct usb_msosv1_descriptor *msosv1_desc;
static struct usb_msosv2_descriptor *msosv2_desc;
static struct usb_bos_descriptor *bos_desc;
struct usbd_tx_rx_msg tx_msg[USB_EP_IN_NUM];
struct usbd_tx_rx_msg rx_msg[USB_EP_OUT_NUM];
#ifdef CONFIG_USBDEV_TX_RX_THREAD
usb_osal_mq_t usbd_tx_rx_mq;
usb_osal_thread_t usbd_tx_rx_thread;
#endif
static void usbd_class_event_notify_handler(uint8_t event, void *arg);
static void usbd_print_setup(struct usb_setup_packet *setup)
@ -135,6 +154,119 @@ static bool usbd_reset_endpoint(const struct usb_endpoint_descriptor *ep_desc)
*
* @return true if the descriptor was found, false otherwise
*/
#if defined(CHERRYUSB_VERSION) && (CHERRYUSB_VERSION > 0x000700)
static bool usbd_get_descriptor(uint16_t type_index, uint8_t **data, uint32_t *len)
{
uint8_t type = 0U;
uint8_t index = 0U;
bool found = true;
uint8_t str_len = 0;
type = HI_BYTE(type_index);
index = LO_BYTE(type_index);
switch (type) {
case USB_DESCRIPTOR_TYPE_DEVICE:
*data = (uint8_t *)usbd_core_cfg.descriptors->device_descriptor;
*len = usbd_core_cfg.descriptors->device_descriptor[0];
break;
case USB_DESCRIPTOR_TYPE_CONFIGURATION:
usbd_core_cfg.speed = usbd_get_port_speed(0);
if (usbd_core_cfg.speed == USB_SPEED_HIGH) {
if (usbd_core_cfg.descriptors->hs_config_descriptor[index]) {
*data = (uint8_t *)usbd_core_cfg.descriptors->hs_config_descriptor[index];
*len = (usbd_core_cfg.descriptors->hs_config_descriptor[index][CONF_DESC_wTotalLength] |
(usbd_core_cfg.descriptors->hs_config_descriptor[index][CONF_DESC_wTotalLength + 1] << 8));
} else {
found = false;
}
} else {
if (usbd_core_cfg.descriptors->fs_config_descriptor[index]) {
*data = (uint8_t *)usbd_core_cfg.descriptors->fs_config_descriptor[index];
*len = (usbd_core_cfg.descriptors->fs_config_descriptor[index][CONF_DESC_wTotalLength] |
(usbd_core_cfg.descriptors->fs_config_descriptor[index][CONF_DESC_wTotalLength + 1] << 8));
} else {
found = false;
}
}
break;
case USB_DESCRIPTOR_TYPE_STRING:
if (index == USB_STRING_LANGID_INDEX) {
(*data)[0] = 0x04;
(*data)[1] = 0x03;
(*data)[2] = 0x09;
(*data)[3] = 0x04;
*len = 4;
} else if (index == USB_OSDESC_STRING_DESC_INDEX) {
if (usbd_core_cfg.descriptors->msosv1_descriptor) {
USB_LOG_INFO("read MS OS 1.0 descriptor string\r\n");
*data = usbd_core_cfg.descriptors->msosv1_descriptor->string;
*len = usbd_core_cfg.descriptors->msosv1_descriptor->string_len;
} else {
}
} else {
if (usbd_core_cfg.descriptors->string_descriptor[index - 1]) {
str_len = strlen((const char *)usbd_core_cfg.descriptors->string_descriptor[index - 1]);
(*data)[0] = str_len * 2 + 2;
(*data)[1] = 0x03;
for (uint16_t i = 0; i < str_len; i++) {
(*data)[i * 2 + 2] = usbd_core_cfg.descriptors->string_descriptor[index - 1][i];
(*data)[i * 2 + 3] = 0;
}
*len = str_len * 2 + 2;
} else {
found = false;
}
}
break;
case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER:
if (usbd_core_cfg.descriptors->device_quality_descriptor) {
*data = (uint8_t *)usbd_core_cfg.descriptors->device_quality_descriptor;
*len = usbd_core_cfg.descriptors->device_quality_descriptor[0];
} else {
found = false;
}
break;
case USB_DESCRIPTOR_TYPE_OTHER_SPEED:
if (usbd_core_cfg.speed == USB_SPEED_HIGH) {
if (usbd_core_cfg.descriptors->fs_other_speed_descriptor) {
*data = (uint8_t *)usbd_core_cfg.descriptors->fs_other_speed_descriptor;
*len = (usbd_core_cfg.descriptors->fs_other_speed_descriptor[CONF_DESC_wTotalLength] |
(usbd_core_cfg.descriptors->fs_other_speed_descriptor[CONF_DESC_wTotalLength] << 8));
} else {
found = false;
}
} else {
if (usbd_core_cfg.descriptors->hs_other_speed_descriptor) {
*data = (uint8_t *)usbd_core_cfg.descriptors->hs_other_speed_descriptor;
*len = (usbd_core_cfg.descriptors->hs_other_speed_descriptor[CONF_DESC_wTotalLength] |
(usbd_core_cfg.descriptors->hs_other_speed_descriptor[CONF_DESC_wTotalLength] << 8));
} else {
found = false;
}
}
break;
case USB_DESCRIPTOR_TYPE_BINARY_OBJECT_STORE:
USB_LOG_INFO("read BOS descriptor string\r\n");
break;
default:
found = false;
break;
}
if (found == false) {
/* nothing found */
USB_LOG_ERR("descriptor <type:%x,index:%x> not found!\r\n", type, index);
}
return found;
}
#else
static bool usbd_get_descriptor(uint16_t type_index, uint8_t **data, uint32_t *len)
{
uint8_t type = 0U;
@ -220,6 +352,7 @@ static bool usbd_get_descriptor(uint16_t type_index, uint8_t **data, uint32_t *l
return found;
}
#endif
/**
* @brief set USB configuration
@ -235,11 +368,19 @@ static bool usbd_get_descriptor(uint16_t type_index, uint8_t **data, uint32_t *l
*/
static bool usbd_set_configuration(uint8_t config_index, uint8_t alt_setting)
{
uint8_t *p = (uint8_t *)usbd_core_cfg.descriptors;
uint8_t cur_alt_setting = 0xFF;
uint8_t cur_config = 0xFF;
bool found = false;
uint8_t *p;
#if defined(CHERRYUSB_VERSION) && (CHERRYUSB_VERSION > 0x000700)
if (usbd_core_cfg.speed == USB_SPEED_HIGH) {
p = (uint8_t *)usbd_core_cfg.descriptors->hs_config_descriptor[0];
} else {
p = (uint8_t *)usbd_core_cfg.descriptors->fs_config_descriptor[0];
}
#else
p = (uint8_t *)usbd_core_cfg.descriptors;
#endif
/* configure endpoints for this configuration/altsetting */
while (p[DESC_bLength] != 0U) {
switch (p[DESC_bDescriptorType]) {
@ -289,13 +430,21 @@ static bool usbd_set_configuration(uint8_t config_index, uint8_t alt_setting)
*/
static bool usbd_set_interface(uint8_t iface, uint8_t alt_setting)
{
const uint8_t *p = usbd_core_cfg.descriptors;
const uint8_t *if_desc = NULL;
struct usb_endpoint_descriptor *ep_desc;
uint8_t cur_alt_setting = 0xFF;
uint8_t cur_iface = 0xFF;
bool ret = false;
uint8_t *p;
#if defined(CHERRYUSB_VERSION) && (CHERRYUSB_VERSION > 0x000700)
if (usbd_core_cfg.speed == USB_SPEED_HIGH) {
p = (uint8_t *)usbd_core_cfg.descriptors->hs_config_descriptor[0];
} else {
p = (uint8_t *)usbd_core_cfg.descriptors->fs_config_descriptor[0];
}
#else
p = (uint8_t *)usbd_core_cfg.descriptors;
#endif
USB_LOG_DBG("iface %u alt_setting %u\r\n", iface, alt_setting);
while (p[DESC_bLength] != 0U) {
@ -638,6 +787,40 @@ static int usbd_class_request_handler(struct usb_setup_packet *setup, uint8_t **
*/
static int usbd_vendor_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
{
#if defined(CHERRYUSB_VERSION) && (CHERRYUSB_VERSION > 0x000700)
if (usbd_core_cfg.descriptors->msosv1_descriptor) {
if (setup->bRequest == usbd_core_cfg.descriptors->msosv1_descriptor->vendor_code) {
switch (setup->wIndex) {
case 0x04:
USB_LOG_INFO("get Compat ID\r\n");
*data = (uint8_t *)usbd_core_cfg.descriptors->msosv1_descriptor->compat_id;
*len = usbd_core_cfg.descriptors->msosv1_descriptor->compat_id_len;
return 0;
case 0x05:
USB_LOG_INFO("get Compat id properties\r\n");
*data = (uint8_t *)usbd_core_cfg.descriptors->msosv1_descriptor->comp_id_property;
*len = usbd_core_cfg.descriptors->msosv1_descriptor->comp_id_property_len;
return 0;
default:
USB_LOG_ERR("unknown vendor code\r\n");
return -1;
}
}
} else if (usbd_core_cfg.descriptors->msosv2_descriptor) {
if (setup->bRequest == usbd_core_cfg.descriptors->msosv2_descriptor->vendor_code) {
switch (setup->wIndex) {
case WINUSB_REQUEST_GET_DESCRIPTOR_SET:
USB_LOG_INFO("GET MS OS 2.0 Descriptor\r\n");
*data = (uint8_t *)usbd_core_cfg.descriptors->msosv2_descriptor->compat_id;
*len = usbd_core_cfg.descriptors->msosv2_descriptor->compat_id_len;
return 0;
default:
USB_LOG_ERR("unknown vendor code\r\n");
return -1;
}
}
}
#else
if (msosv1_desc) {
if (setup->bRequest == msosv1_desc->vendor_code) {
switch (setup->wIndex) {
@ -672,7 +855,7 @@ static int usbd_vendor_request_handler(struct usb_setup_packet *setup, uint8_t *
}
}
}
#endif
usb_slist_t *i;
usb_slist_for_each(i, &usbd_intf_head)
@ -766,6 +949,7 @@ void usbd_event_reset_handler(void)
usbd_set_address(0);
usbd_core_cfg.configured = 0;
usbd_core_cfg.configuration = 0;
#ifdef CONFIG_USBDEV_TEST_MODE
usbd_core_cfg.test_mode = false;
#endif
@ -823,9 +1007,10 @@ void usbd_event_ep0_setup_complete_handler(uint8_t *psetup)
}
#endif
/* Send smallest of requested and offered length */
usbd_core_cfg.ep0_data_buf_residue = MIN(usbd_core_cfg.ep0_data_buf_len,
setup->wLength);
usbd_core_cfg.ep0_data_buf_residue = MIN(usbd_core_cfg.ep0_data_buf_len, setup->wLength);
#if defined(CHERRYUSB_VERSION) && (CHERRYUSB_VERSION > 0x000700)
#else
/* check if the data buf addr matches align size,if not, copy into align buf */
#ifndef CONFIG_USBDEV_ALIGN_CHECK_DISABLE
if (((unsigned long)usbd_core_cfg.ep0_data_buf) & (CONFIG_USB_ALIGN_SIZE - 1)) {
@ -837,12 +1022,14 @@ void usbd_event_ep0_setup_complete_handler(uint8_t *psetup)
memcpy(usbd_core_cfg.req_data, usbd_core_cfg.ep0_data_buf, usbd_core_cfg.ep0_data_buf_residue);
usbd_core_cfg.ep0_data_buf = usbd_core_cfg.req_data;
}
#endif
#endif
/* Send data or status to host */
usbd_ep_start_write(USB_CONTROL_IN_EP0, usbd_core_cfg.ep0_data_buf, usbd_core_cfg.ep0_data_buf_residue);
/*
* Set ZLP flag when host asks for a bigger length and the data size is multiplier of USB_CTRL_EP_MPS,
* to indicate the transfer done after zlp sent.
* Set ZLP flag when host asks for a bigger length and the data size is
* multiplier of USB_CTRL_EP_MPS, to indicate the transfer done after zlp
* sent.
*/
if ((setup->wLength > usbd_core_cfg.ep0_data_buf_len) && (!(usbd_core_cfg.ep0_data_buf_len % USB_CTRL_EP_MPS))) {
usbd_core_cfg.zlp_flag = true;
@ -850,84 +1037,130 @@ void usbd_event_ep0_setup_complete_handler(uint8_t *psetup)
}
}
void usbd_event_ep_in_complete_handler(uint8_t ep, uint32_t nbytes)
void usbd_event_ep0_in_complete_handler(uint8_t ep, uint32_t nbytes)
{
if (ep == USB_CONTROL_IN_EP0) {
struct usb_setup_packet *setup = &usbd_core_cfg.setup;
struct usb_setup_packet *setup = &usbd_core_cfg.setup;
usbd_core_cfg.ep0_data_buf += nbytes;
usbd_core_cfg.ep0_data_buf_residue -= nbytes;
usbd_core_cfg.ep0_data_buf += nbytes;
usbd_core_cfg.ep0_data_buf_residue -= nbytes;
USB_LOG_DBG("EP0 send %d bytes, %d remained\r\n", nbytes, usbd_core_cfg.ep0_data_buf_residue);
USB_LOG_DBG("EP0 send %d bytes, %d remained\r\n", nbytes, usbd_core_cfg.ep0_data_buf_residue);
if (usbd_core_cfg.ep0_data_buf_residue != 0) {
/* Start sending the remain data */
usbd_ep_start_write(USB_CONTROL_IN_EP0, usbd_core_cfg.ep0_data_buf, usbd_core_cfg.ep0_data_buf_residue);
if (usbd_core_cfg.ep0_data_buf_residue != 0) {
/* Start sending the remain data */
usbd_ep_start_write(USB_CONTROL_IN_EP0, usbd_core_cfg.ep0_data_buf, usbd_core_cfg.ep0_data_buf_residue);
} else {
if (usbd_core_cfg.zlp_flag == true) {
usbd_core_cfg.zlp_flag = false;
/* Send zlp to host */
USB_LOG_DBG("EP0 Send zlp\r\n");
usbd_ep_start_write(USB_CONTROL_IN_EP0, NULL, 0);
} else {
if (usbd_core_cfg.zlp_flag == true) {
usbd_core_cfg.zlp_flag = false;
/* Send zlp to host */
USB_LOG_DBG("EP0 Send zlp\r\n");
usbd_ep_start_write(USB_CONTROL_IN_EP0, NULL, 0);
} else {
/* Satisfying three conditions will jump here.
/* Satisfying three conditions will jump here.
* 1. send status completely
* 2. send zlp completely
* 3. send last data completely.
*/
if (setup->wLength && ((setup->bmRequestType & USB_REQUEST_DIR_MASK) == USB_REQUEST_DIR_IN)) {
/* if all data has sent completely, start reading out status */
usbd_ep_start_read(USB_CONTROL_OUT_EP0, NULL, 0);
}
if (setup->wLength && ((setup->bmRequestType & USB_REQUEST_DIR_MASK) == USB_REQUEST_DIR_IN)) {
/* if all data has sent completely, start reading out status */
usbd_ep_start_read(USB_CONTROL_OUT_EP0, NULL, 0);
}
}
} else {
if (usbd_core_cfg.in_ep_cb[ep & 0x7f]) {
usbd_core_cfg.in_ep_cb[ep & 0x7f](ep, nbytes);
}
}
}
void usbd_event_ep0_out_complete_handler(uint8_t ep, uint32_t nbytes)
{
struct usb_setup_packet *setup = &usbd_core_cfg.setup;
if (nbytes > 0) {
usbd_core_cfg.ep0_data_buf += nbytes;
usbd_core_cfg.ep0_data_buf_residue -= nbytes;
USB_LOG_DBG("EP0 recv %d bytes, %d remained\r\n", nbytes, usbd_core_cfg.ep0_data_buf_residue);
if (usbd_core_cfg.ep0_data_buf_residue == 0) {
/* Received all, send data to handler */
usbd_core_cfg.ep0_data_buf = usbd_core_cfg.req_data;
if (!usbd_setup_request_handler(setup, &usbd_core_cfg.ep0_data_buf, &usbd_core_cfg.ep0_data_buf_len)) {
usbd_ep_set_stall(USB_CONTROL_IN_EP0);
return;
}
/*Send status to host*/
usbd_ep_start_write(USB_CONTROL_IN_EP0, NULL, 0);
} else {
/* Start reading the remain data */
usbd_ep_start_read(USB_CONTROL_OUT_EP0, usbd_core_cfg.ep0_data_buf, usbd_core_cfg.ep0_data_buf_residue);
}
} else {
/* Read out status completely, do nothing */
USB_LOG_DBG("EP0 recv out status\r\n");
}
}
void usbd_event_ep_in_complete_handler(uint8_t ep, uint32_t nbytes)
{
#ifndef CONFIG_USBDEV_TX_RX_THREAD
if (tx_msg[ep & 0x7f].cb) {
tx_msg[ep & 0x7f].cb(ep, nbytes);
}
#else
tx_msg[ep & 0x7f].nbytes = nbytes;
usb_osal_mq_send(usbd_tx_rx_mq, (uint32_t)&tx_msg[ep & 0x7f]);
#endif
}
void usbd_event_ep_out_complete_handler(uint8_t ep, uint32_t nbytes)
{
if (ep == USB_CONTROL_OUT_EP0) {
struct usb_setup_packet *setup = &usbd_core_cfg.setup;
#ifndef CONFIG_USBDEV_TX_RX_THREAD
if (rx_msg[ep & 0x7f].cb) {
rx_msg[ep & 0x7f].cb(ep, nbytes);
}
#else
rx_msg[ep & 0x7f].nbytes = nbytes;
usb_osal_mq_send(usbd_tx_rx_mq, (uint32_t)&rx_msg[ep & 0x7f]);
#endif
}
if (nbytes > 0) {
usbd_core_cfg.ep0_data_buf += nbytes;
usbd_core_cfg.ep0_data_buf_residue -= nbytes;
#ifdef CONFIG_USBDEV_TX_RX_THREAD
static void usbdev_tx_rx_thread(void *argument)
{
struct usbd_tx_rx_msg *msg;
int ret;
USB_LOG_DBG("EP0 recv %d bytes, %d remained\r\n", nbytes, usbd_core_cfg.ep0_data_buf_residue);
if (usbd_core_cfg.ep0_data_buf_residue == 0) {
/* Received all, send data to handler */
usbd_core_cfg.ep0_data_buf = usbd_core_cfg.req_data;
if (!usbd_setup_request_handler(setup, &usbd_core_cfg.ep0_data_buf, &usbd_core_cfg.ep0_data_buf_len)) {
usbd_ep_set_stall(USB_CONTROL_IN_EP0);
return;
}
/*Send status to host*/
usbd_ep_start_write(USB_CONTROL_IN_EP0, NULL, 0);
} else {
/* Start reading the remain data */
usbd_ep_start_read(USB_CONTROL_OUT_EP0, usbd_core_cfg.ep0_data_buf, usbd_core_cfg.ep0_data_buf_residue);
}
} else {
/* Read out status completely, do nothing */
USB_LOG_DBG("EP0 recv out status\r\n");
while (1) {
ret = usb_osal_mq_recv(usbd_tx_rx_mq, (uint32_t *)&msg, 0xffffffff);
if (ret < 0) {
continue;
}
} else {
if (usbd_core_cfg.out_ep_cb[ep & 0x7f]) {
usbd_core_cfg.out_ep_cb[ep & 0x7f](ep, nbytes);
if (msg->cb) {
msg->cb(msg->ep, msg->nbytes);
}
}
}
#endif
#if defined(CHERRYUSB_VERSION) && (CHERRYUSB_VERSION > 0x000700)
void usbd_desc_register(struct usb_descriptor *desc)
{
usbd_core_cfg.descriptors = desc;
usbd_core_cfg.intf_offset = 0;
tx_msg[0].ep = 0x80;
tx_msg[0].cb = usbd_event_ep0_in_complete_handler;
rx_msg[0].ep = 0x00;
rx_msg[0].cb = usbd_event_ep0_out_complete_handler;
}
#else
void usbd_desc_register(const uint8_t *desc)
{
usbd_core_cfg.descriptors = desc;
usbd_core_cfg.intf_offset = 0;
tx_msg[0].ep = 0x80;
tx_msg[0].cb = usbd_event_ep0_in_complete_handler;
rx_msg[0].ep = 0x00;
rx_msg[0].cb = usbd_event_ep0_out_complete_handler;
}
/* Register MS OS Descriptors version 1 */
@ -946,6 +1179,7 @@ void usbd_bos_desc_register(struct usb_bos_descriptor *desc)
{
bos_desc = desc;
}
#endif
void usbd_add_interface(struct usbd_interface *intf)
{
@ -957,9 +1191,11 @@ void usbd_add_interface(struct usbd_interface *intf)
void usbd_add_endpoint(struct usbd_endpoint *ep)
{
if (ep->ep_addr & 0x80) {
usbd_core_cfg.in_ep_cb[ep->ep_addr & 0x7f] = ep->ep_cb;
tx_msg[ep->ep_addr & 0x7f].ep = ep->ep_addr;
tx_msg[ep->ep_addr & 0x7f].cb = ep->ep_cb;
} else {
usbd_core_cfg.out_ep_cb[ep->ep_addr & 0x7f] = ep->ep_cb;
rx_msg[ep->ep_addr & 0x7f].ep = ep->ep_addr;
rx_msg[ep->ep_addr & 0x7f].cb = ep->ep_cb;
}
}
@ -970,6 +1206,16 @@ bool usb_device_is_configured(void)
int usbd_initialize(void)
{
#ifdef CONFIG_USBDEV_TX_RX_THREAD
usbd_tx_rx_mq = usb_osal_mq_create(32);
if (usbd_tx_rx_mq == NULL) {
return -1;
}
usbd_tx_rx_thread = usb_osal_thread_create("usbd_tx_rx", CONFIG_USBDEV_TX_RX_STACKSIZE, CONFIG_USBDEV_TX_RX_PRIO, usbdev_tx_rx_thread, NULL);
if (usbd_tx_rx_thread == NULL) {
return -1;
}
#endif
return usb_dc_init();
}
@ -978,5 +1224,7 @@ int usbd_deinitialize(void)
usbd_core_cfg.intf_offset = 0;
usb_slist_init(&usbd_intf_head);
usb_dc_deinit();
#ifdef CONFIG_USBDEV_TX_RX_THREAD
#endif
return 0;
}

View File

@ -62,10 +62,25 @@ struct usbd_interface {
uint8_t intf_num;
};
struct usb_descriptor {
const uint8_t *device_descriptor;
const uint8_t **fs_config_descriptor;
const uint8_t **hs_config_descriptor;
const uint8_t *device_quality_descriptor;
const uint8_t *other_speed_descriptor;
const char **string_descriptor;
struct usb_msosv1_descriptor *msosv1_descriptor;
struct usb_msosv2_descriptor *msosv2_descriptor;
struct usb_bos_descriptor *bos_descriptor;
};
#if defined(CHERRYUSB_VERSION) && (CHERRYUSB_VERSION > 0x000700)
void usbd_desc_register(struct usb_descriptor *desc);
#else
void usbd_desc_register(const uint8_t *desc);
void usbd_msosv1_desc_register(struct usb_msosv1_descriptor *desc);
void usbd_msosv2_desc_register(struct usb_msosv2_descriptor *desc);
void usbd_bos_desc_register(struct usb_bos_descriptor *desc);
#endif
void usbd_add_interface(struct usbd_interface *intf);
void usbd_add_endpoint(struct usbd_endpoint *ep);

View File

@ -12,8 +12,8 @@ struct usbh_class_info *usbh_class_info_table_end = NULL;
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t ep0_request_buffer[CONFIG_USBHOST_REQUEST_BUFFER_LEN];
/* general descriptor field offsets */
#define DESC_bLength 0 /** Length offset */
#define DESC_bDescriptorType 1 /** Descriptor type offset */
#define DESC_bLength 0 /** Length offset */
#define DESC_bDescriptorType 1 /** Descriptor type offset */
#define USB_DEV_ADDR_MAX 0x7f
#define USB_DEV_ADDR_MARK_OFFSET 5
@ -109,7 +109,11 @@ static const struct usbh_class_driver *usbh_find_class_driver(uint8_t class, uin
if (index->vid == vid && index->pid == pid && index->class == class) {
return index->class_driver;
}
} else if (index->match_flags & (USB_CLASS_MATCH_INTF_CLASS)) {
} else if ((index->match_flags & (USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS)) == (USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS)) {
if (index->class == class && index->subclass == subclass) {
return index->class_driver;
}
} else if ((index->match_flags & (USB_CLASS_MATCH_INTF_CLASS)) == USB_CLASS_MATCH_INTF_CLASS) {
if (index->class == class) {
return index->class_driver;
}
@ -618,14 +622,14 @@ int usbh_enumerate(struct usbh_hubport *hport)
USB_LOG_INFO("Loading %s class driver\r\n", class_driver->driver_name);
ret = CLASS_CONNECT(hport, i);
if (ret < 0) {
ret = CLASS_DISCONNECT(hport, i);
CLASS_DISCONNECT(hport, i);
goto errout;
}
}
usbh_device_mount_done_callback(hport);
errout:
if (ret < 0) {
hport->config.config_desc.bNumInterfaces = 0;
usbh_hport_deactivate_ep0(hport);
}
if (hport->raw_config_desc) {
@ -689,6 +693,9 @@ int usbh_initialize(void)
extern uint32_t __usbh_class_info_end__;
usbh_class_info_table_begin = (struct usbh_class_info *)&__usbh_class_info_start__;
usbh_class_info_table_end = (struct usbh_class_info *)&__usbh_class_info_end__;
#elif defined(__ICCARM__) || defined(__ICCRX__)
usbh_class_info_table_begin = (struct usbh_class_info *)__section_begin("usbh_class_info");
usbh_class_info_table_end = (struct usbh_class_info *)__section_end("usbh_class_info");
#endif
/* devaddr 1 is for roothub */
@ -794,12 +801,4 @@ int lsusb(int argc, char **argv)
}
return 0;
}
__WEAK void usbh_device_mount_done_callback(struct usbh_hubport *hport)
{
}
__WEAK void usbh_device_unmount_done_callback(struct usbh_hubport *hport)
{
}
}

View File

@ -39,6 +39,9 @@ extern "C" {
#define CLASS_INFO_DEFINE __attribute__((section("usbh_class_info"))) __USED __ALIGNED(1)
#elif defined(__GNUC__)
#define CLASS_INFO_DEFINE __attribute__((section(".usbh_class_info"))) __USED __ALIGNED(1)
#elif defined(__ICCARM__) || defined(__ICCRX__)
#pragma section="usbh_class_info"
#define CLASS_INFO_DEFINE __attribute__((section("usbh_class_info"))) __USED __ALIGNED(1)
#endif
static inline void usbh_control_urb_fill(struct usbh_urb *urb,
@ -160,7 +163,6 @@ struct usbh_hub {
struct usb_hub_descriptor hub_desc;
struct usbh_hubport child[CONFIG_USBHOST_MAX_EHPORTS];
struct usbh_hubport *parent;
usb_slist_t hub_event_list;
};
int usbh_hport_activate_epx(usbh_pipe_t *pipe, struct usbh_hubport *hport, struct usb_endpoint_descriptor *ep_desc);
@ -181,8 +183,6 @@ int usbh_initialize(void);
struct usbh_hubport *usbh_find_hubport(uint8_t dev_addr);
void *usbh_find_class_instance(const char *devname);
void usbh_device_mount_done_callback(struct usbh_hubport *hport);
void usbh_device_unmount_done_callback(struct usbh_hubport *hport);
int lsusb(int argc, char **argv);
#ifdef __cplusplus

View File

@ -12,12 +12,11 @@
typedef void *usb_osal_thread_t;
typedef void *usb_osal_sem_t;
typedef void *usb_osal_mutex_t;
typedef void *usb_osal_mq_t;
typedef void (*usb_thread_entry_t)(void *argument);
usb_osal_thread_t usb_osal_thread_create(const char *name, uint32_t stack_size, uint32_t prio, usb_thread_entry_t entry, void *args);
void usb_osal_timer_init(uint32_t poll_ms, void (*hub_poll_callback)(void));
usb_osal_sem_t usb_osal_sem_create(uint32_t initial_count);
void usb_osal_sem_delete(usb_osal_sem_t sem);
int usb_osal_sem_take(usb_osal_sem_t sem, uint32_t timeout);
@ -28,10 +27,13 @@ void usb_osal_mutex_delete(usb_osal_mutex_t mutex);
int usb_osal_mutex_take(usb_osal_mutex_t mutex);
int usb_osal_mutex_give(usb_osal_mutex_t mutex);
usb_osal_mq_t usb_osal_mq_create(uint32_t max_msgs);
int usb_osal_mq_send(usb_osal_mq_t mq, uint32_t addr);
int usb_osal_mq_recv(usb_osal_mq_t mq, uint32_t *addr, uint32_t timeout);
size_t usb_osal_enter_critical_section(void);
void usb_osal_leave_critical_section(size_t flag);
void usb_osal_msleep(uint32_t delay);
#endif /* USB_OSAL_H */

View File

@ -8,6 +8,7 @@
#include <FreeRTOS.h>
#include "semphr.h"
#include "timers.h"
#include "event_groups.h"
usb_osal_thread_t usb_osal_thread_create(const char *name, uint32_t stack_size, uint32_t prio, usb_thread_entry_t entry, void *args)
{
@ -17,13 +18,6 @@ usb_osal_thread_t usb_osal_thread_create(const char *name, uint32_t stack_size,
return (usb_osal_thread_t)htask;
}
void usb_osal_timer_init(uint32_t poll_ms, void (*hub_poll_callback)(void))
{
TimerHandle_t handle = xTimerCreate("usbh_hub_poll", poll_ms, pdTRUE, 0, (TimerCallbackFunction_t)hub_poll_callback);
xTimerStart(handle, 1000);
}
usb_osal_sem_t usb_osal_sem_create(uint32_t initial_count)
{
return (usb_osal_sem_t)xSemaphoreCreateCounting(1, initial_count);
@ -49,7 +43,7 @@ int usb_osal_sem_give(usb_osal_sem_t sem)
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
return (ret == pdPASS) ? 0 : -EINVAL;
return (ret == pdPASS) ? 0 : -ETIMEDOUT;
}
usb_osal_mutex_t usb_osal_mutex_create(void)
@ -69,7 +63,30 @@ int usb_osal_mutex_take(usb_osal_mutex_t mutex)
int usb_osal_mutex_give(usb_osal_mutex_t mutex)
{
return (xSemaphoreGive((SemaphoreHandle_t)mutex) == pdPASS) ? 0 : -EINVAL;
return (xSemaphoreGive((SemaphoreHandle_t)mutex) == pdPASS) ? 0 : -ETIMEDOUT;
}
usb_osal_mq_t usb_osal_mq_create(uint32_t max_msgs)
{
return (usb_osal_mq_t)xQueueCreate(max_msgs, 4);
}
int usb_osal_mq_send(usb_osal_mq_t mq, uint32_t addr)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
int ret;
ret = xQueueSendFromISR((usb_osal_mq_t)mq, &addr, &xHigherPriorityTaskWoken);
if (ret == pdPASS) {
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
return (ret == pdPASS) ? 0 : -ETIMEDOUT;
}
int usb_osal_mq_recv(usb_osal_mq_t mq, uint32_t *addr, uint32_t timeout)
{
return (xQueueReceive((usb_osal_mq_t)mq, addr, timeout) == pdPASS) ? 0 : -ETIMEDOUT;
}
size_t usb_osal_enter_critical_section(void)

View File

@ -32,9 +32,9 @@ int usb_osal_sem_take(usb_osal_sem_t sem, uint32_t timeout)
rt_err_t result = RT_EOK;
result = rt_sem_take((rt_sem_t)sem, rt_tick_from_millisecond(timeout));
if (result == RT_ETIMEOUT) {
if (result == -RT_ETIMEOUT) {
ret = -ETIMEDOUT;
} else if (result == RT_ERROR) {
} else if (result == -RT_ERROR) {
ret = -EINVAL;
} else {
ret = 0;
@ -68,6 +68,33 @@ int usb_osal_mutex_give(usb_osal_mutex_t mutex)
return (int)rt_mutex_release((rt_mutex_t)mutex);
}
usb_osal_mq_t usb_osal_mq_create(uint32_t max_msgs)
{
return (usb_osal_mq_t)rt_mq_create("usbh_mq", 4, max_msgs, RT_IPC_FLAG_FIFO);
}
int usb_osal_mq_send(usb_osal_mq_t mq, uint32_t addr)
{
return rt_mq_send((rt_mq_t)mq, &addr, 4);
}
int usb_osal_mq_recv(usb_osal_mq_t mq, uint32_t *addr, uint32_t timeout)
{
int ret = 0;
rt_err_t result = RT_EOK;
result = rt_mq_recv((rt_mq_t)mq, addr, 4, rt_tick_from_millisecond(timeout));
if (result == -RT_ETIMEOUT) {
ret = -ETIMEDOUT;
} else if (result == -RT_ERROR) {
ret = -EINVAL;
} else {
ret = 0;
}
return (int)ret;
}
size_t usb_osal_enter_critical_section(void)
{
return rt_hw_interrupt_disable();

View File

@ -11,8 +11,8 @@
#define USBH_IRQHandler USBH_IRQHandler
#endif
#define EHCI_HCCR ((struct ehci_hccr *)CONFIG_USB_EHCI_HCCR_BASE)
#define EHCI_HCOR ((struct ehci_hcor *)CONFIG_USB_EHCI_HCOR_BASE)
#define EHCI_HCCR ((struct ehci_hccr *)CONFIG_USB_EHCI_HCCR_BASE)
#define EHCI_HCOR ((struct ehci_hcor *)CONFIG_USB_EHCI_HCOR_BASE)
#define EHCI_PTR2ADDR(x) ((uint32_t)x)
#define EHCI_ADDRALIGN32(x) ((uint32_t)(x) & ~0x1F)
@ -31,7 +31,7 @@
#define CONFIG_USB_EHCI_QH_NUM CONFIG_USBHOST_PIPE_NUM
#define CONFIG_USB_EHCI_QTD_NUM (CONFIG_USBHOST_PIPE_NUM * 3)
#define CONFIG_USB_EHCI_ITD_NUM 256
#define CONFIG_USB_EHCI_ITD_NUM 10
extern uint8_t usbh_get_port_speed(const uint8_t port);
@ -53,9 +53,9 @@ struct ehci_pipe {
struct usbh_hubport *hport;
struct ehci_qh_hw *qh;
struct usbh_urb *urb;
struct ehci_itd_hw *itdpool;
uint32_t itd_num;
uint32_t used_itd_num;
uint16_t current_itd;
uint16_t used_itd_num;
uint16_t start_frame;
usb_slist_t iso_list;
};
@ -71,14 +71,12 @@ struct ehci_qtd_hw {
struct ehci_itd_hw {
struct ehci_itd hw;
struct usbh_iso_frame_packet *iso_packet;
uint32_t start_frame;
usb_slist_t list;
} __attribute__((aligned(32)));
struct ehci_hcd {
bool ehci_qh_used[CONFIG_USB_EHCI_QH_NUM];
bool ehci_qtd_used[CONFIG_USB_EHCI_QTD_NUM];
bool ehci_itd_used[CONFIG_USB_EHCI_ITD_NUM];
struct ehci_pipe pipe_pool[CONFIG_USB_EHCI_QH_NUM];
} g_ehci_hcd;
@ -155,7 +153,31 @@ static void ehci_qtd_free(struct ehci_qtd_hw *qtd)
}
}
}
#if 0
static struct ehci_itd_hw *ehci_itd_alloc(void)
{
struct ehci_itd_hw *itd;
for (uint32_t i = 0; i < CONFIG_USB_EHCI_ITD_NUM; i++) {
if (!g_ehci_hcd.ehci_itd_used[i]) {
g_ehci_hcd.ehci_itd_used[i] = true;
itd = &ehci_itd_pool[i];
memset(itd, 0, sizeof(struct ehci_itd_hw));
return itd;
}
}
return NULL;
}
static void ehci_itd_free(struct ehci_itd_hw *itd)
{
for (uint32_t i = 0; i < CONFIG_USB_EHCI_ITD_NUM; i++) {
if (&ehci_itd_pool[i] == itd) {
g_ehci_hcd.ehci_itd_used[i] = false;
return;
}
}
}
#endif
static struct ehci_pipe *ehci_pipe_alloc(void)
{
int pipe;
@ -203,18 +225,18 @@ static inline void ehci_qh_remove(struct ehci_qh_hw *head, struct ehci_qh_hw *n)
}
}
static inline void ehci_itd_add_head(struct ehci_itd_hw *itd)
static inline void ehci_itd_add_head(struct ehci_itd_hw *itd, uint32_t sched_frame)
{
itd->hw.nlp = g_framelist[itd->start_frame];
g_framelist[itd->start_frame] = ITD_NLP_ITD(itd);
itd->hw.nlp = g_framelist[sched_frame];
g_framelist[sched_frame] = ITD_NLP_ITD(itd);
}
static inline void ehci_itd_remove(struct ehci_itd_hw *itd)
static inline void ehci_itd_remove(struct ehci_itd_hw *itd, uint32_t sched_frame)
{
if (g_framelist[itd->start_frame] == ITD_NLP_ITD(itd)) {
g_framelist[itd->start_frame] = itd->hw.nlp;
if (g_framelist[sched_frame] == ITD_NLP_ITD(itd)) {
g_framelist[sched_frame] = itd->hw.nlp;
} else {
struct ehci_itd_hw *tmp_itd = EHCI_ADDR2ITD(g_framelist[itd->start_frame]);
struct ehci_itd_hw *tmp_itd = EHCI_ADDR2ITD(g_framelist[sched_frame]);
while ((EHCI_ADDR2ITD(tmp_itd->hw.nlp) != itd) && tmp_itd) {
tmp_itd = EHCI_ADDR2ITD(tmp_itd->hw.nlp);
}
@ -405,11 +427,6 @@ static void ehci_itd_tscl_fill(struct ehci_itd_hw *itd,
ITD_TSCL_STATUS_ACTIVE; /* Status */
}
static uint16_t ehci_get_frame_id(void)
{
return (EHCI_HCOR->frindex & EHCI_FRINDEX_MASK) >> 3;
}
static struct ehci_qh_hw *ehci_control_pipe_init(struct ehci_pipe *pipe, struct usb_setup_packet *setup, uint8_t *buffer, uint32_t buflen)
{
struct ehci_qh_hw *qh = NULL;
@ -678,59 +695,53 @@ static struct ehci_qh_hw *ehci_intr_pipe_init(struct ehci_pipe *pipe, uint8_t *b
static int ehci_iso_pipe_init(struct ehci_pipe *pipe, struct usbh_iso_frame_packet *iso_packet, uint32_t num_of_iso_packets)
{
struct ehci_itd_hw *itd;
struct usbh_urb *urb;
uint32_t start_addr;
uint16_t next_frame;
uint16_t sched_frame;
uint32_t bufaddr_in_uframe;
uint32_t buflen_in_uframe;
uint32_t itd_nums;
uint32_t num_of_used_iso_packets = 0;
size_t flags;
uint32_t used_iso_packets;
//EHCI_HCOR->usbcmd &= ~EHCI_USBCMD_PSEN;
if (pipe->speed == USB_SPEED_HIGH) {
itd_nums = (num_of_iso_packets + 7) / 8;
next_frame = (ehci_get_frame_id() + 2) & 0x3ff;
used_iso_packets = 0;
if (itd_nums > pipe->itd_num) {
return -ENOMEM;
}
urb = pipe->urb;
sched_frame = urb->start_frame;
pipe->current_itd = 0;
pipe->used_itd_num = itd_nums;
ehci_iso_pipe_add_tail(pipe);
for (uint32_t i = 0; i < itd_nums; i++) {
itd = &pipe->itdpool[i];
itd = &ehci_itd_pool[i];
memset(itd, 0, sizeof(struct ehci_itd_hw));
start_addr = ((uint32_t)iso_packet[used_iso_packets].transfer_buffer);
/* fill itd bpl */
start_addr = ((uint32_t)iso_packet[num_of_used_iso_packets].transfer_buffer);
itd->iso_packet = &iso_packet[num_of_used_iso_packets];
ehci_itd_bpl_fill(itd, pipe, start_addr);
/* fill itd tscl for micro-frame */
for (uint8_t mf = 0; mf < 8; mf++) {
bufaddr_in_uframe = ((uint32_t)iso_packet[num_of_used_iso_packets].transfer_buffer);
buflen_in_uframe = iso_packet[num_of_used_iso_packets].transfer_buffer_length;
bufaddr_in_uframe = ((uint32_t)iso_packet[used_iso_packets].transfer_buffer);
buflen_in_uframe = iso_packet[used_iso_packets].transfer_buffer_length;
ehci_itd_tscl_fill(itd, pipe, mf, start_addr, bufaddr_in_uframe, buflen_in_uframe);
num_of_used_iso_packets++;
if (num_of_used_iso_packets == num_of_iso_packets) {
used_iso_packets++;
if (used_iso_packets == num_of_iso_packets) {
itd->hw.tscl[mf] |= ITD_TSCL_IOC;
break;
}
}
flags = usb_osal_enter_critical_section();
itd->start_frame = next_frame;
ehci_itd_add_head(itd);
next_frame = (next_frame + 1) & 0x3ff;
usb_osal_leave_critical_section(flags);
ehci_itd_add_head(itd, sched_frame);
sched_frame = (sched_frame + 1) & 0x3ff;
}
ehci_iso_pipe_add_tail(pipe);
} else {
}
//EHCI_HCOR->usbcmd |= EHCI_USBCMD_PSEN;
return 0;
}
@ -837,27 +848,18 @@ static void ehci_kill_qh(struct ehci_qh_hw *qhead, struct ehci_qh_hw *qh)
ehci_qh_free(qh);
}
static void ehci_check_itd(struct ehci_itd_hw *itd)
static int ehci_check_itd(struct ehci_itd_hw *itd, struct usbh_iso_frame_packet *iso_packet)
{
struct usbh_iso_frame_packet *iso_packet;
iso_packet = itd->iso_packet;
for (uint8_t mf = 0; mf < 8; mf++) {
if (itd->hw.tscl[mf] & ITD_TSCL_STATUS_MASK) {
if (itd->hw.tscl[mf] & ITD_TSCL_STATUS_XACTERR) {
iso_packet[mf].errorcode = -EIO;
} else if (itd->hw.tscl[mf] & ITD_TSCL_STATUS_BABBLE) {
iso_packet[mf].errorcode = -EPERM;
} else if (itd->hw.tscl[mf] & ITD_TSCL_STATUS_DBERROR) {
iso_packet[mf].errorcode = -EIO;
} else if (itd->hw.tscl[mf] & ITD_TSCL_STATUS_ACTIVE) {
}
iso_packet[mf].errorcode = -EIO;
return -EIO;
} else {
iso_packet[mf].actual_length = ((itd->hw.tscl[mf] & ITD_TSCL_LENGTH_MASK) >> ITD_TSCL_LENGTH_SHIFT);
iso_packet[mf].errorcode = 0;
}
}
return 0;
}
static int usbh_reset_port(const uint8_t port)
@ -992,7 +994,7 @@ int usb_hc_init(void)
#error Unsupported frame size list size
#endif
regval |= EHCI_USBCMD_ITHRE_1MF;
regval |= EHCI_USBCMD_ITHRE_8MF;
regval |= EHCI_USBCMD_ASEN;
regval |= EHCI_USBCMD_PSEN;
regval |= EHCI_USBCMD_RUN;
@ -1023,6 +1025,11 @@ int usb_hc_init(void)
return 0;
}
uint16_t usbh_get_frame_number(void)
{
return (((EHCI_HCOR->frindex & EHCI_FRINDEX_MASK) >> 3) & 0x3ff);
}
int usbh_roothub_control(struct usb_setup_packet *setup, uint8_t *buf)
{
uint8_t nports;
@ -1202,11 +1209,6 @@ int usbh_pipe_alloc(usbh_pipe_t *pipe, const struct usbh_endpoint_cfg *ep_cfg)
ppipe->dev_addr = ep_cfg->hport->dev_addr;
ppipe->hport = ep_cfg->hport;
if (ppipe->ep_type == USB_ENDPOINT_TYPE_ISOCHRONOUS) {
ppipe->itdpool = ehci_itd_pool;
ppipe->itd_num = CONFIG_USB_EHCI_ITD_NUM;
}
/* restore variable */
ppipe->inuse = true;
ppipe->waitsem = waitsem;
@ -1257,8 +1259,6 @@ int usbh_submit_urb(struct usbh_urb *urb)
return -EINVAL;
}
flags = usb_osal_enter_critical_section();
if (!pipe->hport->connected) {
return -ENODEV;
}
@ -1267,6 +1267,8 @@ int usbh_submit_urb(struct usbh_urb *urb)
return -EBUSY;
}
flags = usb_osal_enter_critical_section();
pipe->waiter = false;
pipe->xfrd = 0;
pipe->qh = NULL;
@ -1298,12 +1300,7 @@ int usbh_submit_urb(struct usbh_urb *urb)
}
break;
case USB_ENDPOINT_TYPE_ISOCHRONOUS:
ret = ehci_iso_pipe_init(pipe, urb->iso_packet, urb->num_of_iso_packets);
if (ret < 0) {
pipe->urb = NULL;
pipe->waiter = false;
return ret;
}
ehci_iso_pipe_init(pipe, urb->iso_packet, urb->num_of_iso_packets);
break;
default:
break;
@ -1315,9 +1312,7 @@ int usbh_submit_urb(struct usbh_urb *urb)
if (ret < 0) {
goto errout_timeout;
}
if (pipe->ep_type != USB_ENDPOINT_TYPE_ISOCHRONOUS) {
ret = urb->errorcode;
}
ret = urb->errorcode;
}
return ret;
errout_timeout:
@ -1333,6 +1328,7 @@ int usbh_kill_urb(struct usbh_urb *urb)
struct ehci_pipe *iso_pipe;
struct ehci_qh_hw *qh = NULL;
struct ehci_itd_hw *itd;
uint32_t sched_frame;
usb_slist_t *i;
size_t flags;
@ -1378,11 +1374,12 @@ int usbh_kill_urb(struct usbh_urb *urb)
iso_pipe = usb_slist_entry(i, struct ehci_pipe, iso_list);
if (pipe == iso_pipe) {
sched_frame = urb->start_frame;
for (uint32_t j = 0; j < pipe->used_itd_num; j++) {
itd = &pipe->itdpool[j];
ehci_check_itd(itd);
itd = &ehci_itd_pool[j];
/* remove itd from list */
ehci_itd_remove(itd);
ehci_itd_remove(itd, sched_frame);
urb->start_frame = (sched_frame + 1) & 0x3ff;
}
pipe->used_itd_num = 0;
ehci_iso_pipe_remove(pipe);
@ -1437,19 +1434,27 @@ static void ehci_scan_isochronous_list(void)
{
struct ehci_itd_hw *itd;
struct ehci_pipe *pipe;
struct usbh_urb *urb;
uint32_t sched_frame;
usb_slist_t *i;
int errorcode = 0;
usb_slist_for_each(i, &iso_pipe_list_head)
{
pipe = usb_slist_entry(i, struct ehci_pipe, iso_list);
urb = pipe->urb;
sched_frame = urb->start_frame;
for (uint32_t j = 0; j < pipe->used_itd_num; j++) {
itd = &pipe->itdpool[j];
ehci_check_itd(itd);
itd = &ehci_itd_pool[j];
errorcode = ehci_check_itd(itd, &urb->iso_packet[j * 8]);
/* remove itd from list */
ehci_itd_remove(itd);
ehci_itd_remove(itd, sched_frame);
urb->start_frame = (sched_frame + 1) & 0x3ff;
urb->errorcode = errorcode;
}
pipe->used_itd_num = 0;
ehci_iso_pipe_remove(pipe);
ehci_pipe_waitup(pipe);
}
@ -1490,6 +1495,16 @@ void USBH_IRQHandler(void)
usb_osal_sem_give(pipe->waitsem);
}
}
for (uint8_t index = 0; index < CONFIG_USB_EHCI_QH_NUM; index++) {
g_ehci_hcd.ehci_qh_used[index] = false;
}
for (uint8_t index = 0; index < CONFIG_USB_EHCI_QTD_NUM; index++) {
g_ehci_hcd.ehci_qtd_used[index] = false;
}
for (uint8_t index = 0; index < CONFIG_USB_EHCI_ITD_NUM; index++) {
g_ehci_hcd.ehci_itd_used[index] = false;
}
}
usbh_roothub_thread_wakeup(port + 1);
}

View File

@ -195,25 +195,42 @@ int hid_test(void)
return ret;
}
void usbh_device_mount_done_callback(struct usbh_hubport *hport)
{
}
void usbh_device_unmount_done_callback(struct usbh_hubport *hport)
{
}
static void usbh_class_test_thread(void *argument)
{
while (1) {
printf("helloworld\r\n");
//printf("helloworld\r\n");
usb_osal_msleep(1000);
cdc_acm_test();
msc_test();
hid_test();
//video_test();
}
}
void usbh_cdc_acm_run(struct usbh_cdc_acm *cdc_acm_class)
{
}
void usbh_cdc_acm_stop(struct usbh_cdc_acm *cdc_acm_class)
{
}
void usbh_hid_run(struct usbh_hid *hid_class)
{
}
void usbh_hid_stop(struct usbh_hid *hid_class)
{
}
void usbh_msc_run(struct usbh_msc *msc_class)
{
}
void usbh_msc_stop(struct usbh_msc *msc_class)
{
}
void usbh_class_test(void)
{
usb_osal_thread_create("usbh_test", 4096, CONFIG_USBHOST_PSC_PRIO + 1, usbh_class_test_thread, NULL);