forked from xuos/xiuos
First commit XiUOS
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
SRC_DIR := third_party_usb
|
||||
SRC_FILES += dev_usb.c drv_usb.c bus_usb.c
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file bus_usb.c
|
||||
* @brief register usb bus function using bus driver framework
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-24
|
||||
*/
|
||||
|
||||
#include <bus_usb.h>
|
||||
#include <dev_usb.h>
|
||||
|
||||
/*Register the USB BUS*/
|
||||
int UsbBusInit(struct UsbBus *usb_bus, const char *bus_name)
|
||||
{
|
||||
NULL_PARAM_CHECK(usb_bus);
|
||||
NULL_PARAM_CHECK(bus_name);
|
||||
|
||||
x_err_t ret = EOK;
|
||||
|
||||
if (BUS_INSTALL != usb_bus->bus.bus_state) {
|
||||
strncpy(usb_bus->bus.bus_name, bus_name, NAME_NUM_MAX);
|
||||
|
||||
usb_bus->bus.bus_type = TYPE_USB_BUS;
|
||||
usb_bus->bus.bus_state = BUS_INSTALL;
|
||||
usb_bus->bus.private_data = usb_bus->private_data;
|
||||
|
||||
ret = BusRegister(&usb_bus->bus);
|
||||
if (EOK != ret) {
|
||||
KPrintf("UsbBusInit BusRegister error %u\n", ret);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
KPrintf("UsbBusInit BusRegister bus has been register state%u\n", usb_bus->bus.bus_state);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*Register the USB Driver*/
|
||||
int UsbDriverInit(struct UsbDriver *usb_driver, const char *driver_name)
|
||||
{
|
||||
NULL_PARAM_CHECK(usb_driver);
|
||||
NULL_PARAM_CHECK(driver_name);
|
||||
|
||||
x_err_t ret = EOK;
|
||||
|
||||
if (DRV_INSTALL != usb_driver->driver.driver_state) {
|
||||
usb_driver->driver.driver_type = TYPE_USB_DRV;
|
||||
usb_driver->driver.driver_state = DRV_INSTALL;
|
||||
|
||||
strncpy(usb_driver->driver.drv_name, driver_name, NAME_NUM_MAX);
|
||||
|
||||
usb_driver->driver.configure = usb_driver->configure;
|
||||
|
||||
usb_driver->driver.private_data = usb_driver->private_data;
|
||||
|
||||
ret = UsbDriverRegister(&usb_driver->driver);
|
||||
if (EOK != ret) {
|
||||
KPrintf("UsbDriverInit DriverRegister error %u\n", ret);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
KPrintf("UsbDriverInit DriverRegister driver has been register state%u\n", usb_driver->driver.driver_state);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*Release the USB device*/
|
||||
int UsbReleaseBus(struct UsbBus *usb_bus)
|
||||
{
|
||||
NULL_PARAM_CHECK(usb_bus);
|
||||
|
||||
return BusRelease(&usb_bus->bus);
|
||||
}
|
||||
|
||||
/*Register the USB Driver to the USB BUS*/
|
||||
int UsbDriverAttachToBus(const char *drv_name, const char *bus_name)
|
||||
{
|
||||
NULL_PARAM_CHECK(drv_name);
|
||||
NULL_PARAM_CHECK(bus_name);
|
||||
|
||||
x_err_t ret = EOK;
|
||||
|
||||
struct Bus *bus;
|
||||
struct Driver *driver;
|
||||
|
||||
bus = BusFind(bus_name);
|
||||
if (NONE == bus) {
|
||||
KPrintf("UsbDriverAttachToBus find usb bus error!name %s\n", bus_name);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
if (TYPE_USB_BUS == bus->bus_type) {
|
||||
driver = UsbDriverFind(drv_name, TYPE_USB_DRV);
|
||||
if (NONE == driver) {
|
||||
KPrintf("UsbDriverAttachToBus find usb driver error!name %s\n", drv_name);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
if (TYPE_USB_DRV == driver->driver_type) {
|
||||
ret = DriverRegisterToBus(bus, driver);
|
||||
if (EOK != ret) {
|
||||
KPrintf("UsbDriverAttachToBus DriverRegisterToBus error %u\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file dev_usb.c
|
||||
* @brief register usb dev function using bus driver framework
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-24
|
||||
*/
|
||||
|
||||
#include <bus_usb.h>
|
||||
#include <dev_usb.h>
|
||||
|
||||
static DoubleLinklistType usbdev_linklist;
|
||||
|
||||
/*Create the usb device linklist*/
|
||||
static void USBDeviceLinkInit()
|
||||
{
|
||||
InitDoubleLinkList(&usbdev_linklist);
|
||||
}
|
||||
|
||||
/*Find the register USB device*/
|
||||
HardwareDevType USBDeviceFind(const char *dev_name, enum DevType dev_type)
|
||||
{
|
||||
NULL_PARAM_CHECK(dev_name);
|
||||
|
||||
struct HardwareDev *device = NONE;
|
||||
|
||||
DoubleLinklistType *node = NONE;
|
||||
DoubleLinklistType *head = &usbdev_linklist;
|
||||
|
||||
for (node = head->node_next; node != head; node = node->node_next) {
|
||||
device = SYS_DOUBLE_LINKLIST_ENTRY(node, struct HardwareDev, dev_link);
|
||||
if ((!strcmp(device->dev_name, dev_name)) && (dev_type == device->dev_type)) {
|
||||
return device;
|
||||
}
|
||||
}
|
||||
|
||||
KPrintf("USBDeviceFind cannot find the %s device.return NULL\n", dev_name);
|
||||
return NONE;
|
||||
}
|
||||
|
||||
/*Register the USB device*/
|
||||
int USBDeviceRegister(struct UsbHardwareDevice *usb_device, void *usb_param, const char *device_name)
|
||||
{
|
||||
NULL_PARAM_CHECK(usb_device);
|
||||
NULL_PARAM_CHECK(device_name);
|
||||
|
||||
x_err_t ret = EOK;
|
||||
static x_bool dev_link_flag = RET_FALSE;
|
||||
|
||||
if (dev_link_flag) {
|
||||
USBDeviceLinkInit();
|
||||
dev_link_flag = RET_TRUE;
|
||||
}
|
||||
|
||||
if (DEV_INSTALL != usb_device->haldev.dev_state) {
|
||||
strncpy(usb_device->haldev.dev_name, device_name, NAME_NUM_MAX);
|
||||
usb_device->haldev.dev_type = TYPE_USB_DEV;
|
||||
usb_device->haldev.dev_state = DEV_INSTALL;
|
||||
|
||||
usb_device->haldev.dev_done = (struct HalDevDone *)usb_device->dev_done;
|
||||
|
||||
usb_device->haldev.private_data = usb_param;
|
||||
|
||||
DoubleLinkListInsertNodeAfter(&usbdev_linklist, &(usb_device->haldev.dev_link));
|
||||
} else {
|
||||
KPrintf("USBDeviceRegister device has been register state%u\n", usb_device->haldev.dev_state);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*Register the USB Device to the USB BUS*/
|
||||
int USBDeviceAttachToBus(const char *dev_name, const char *bus_name)
|
||||
{
|
||||
NULL_PARAM_CHECK(dev_name);
|
||||
NULL_PARAM_CHECK(bus_name);
|
||||
|
||||
x_err_t ret = EOK;
|
||||
|
||||
struct Bus *bus;
|
||||
struct HardwareDev *device;
|
||||
|
||||
bus = BusFind(bus_name);
|
||||
if (NONE == bus) {
|
||||
KPrintf("USBDeviceAttachToBus find usb bus error!name %s\n", bus_name);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
if (TYPE_USB_BUS == bus->bus_type) {
|
||||
device = USBDeviceFind(dev_name, TYPE_USB_DEV);
|
||||
if (NONE == device) {
|
||||
KPrintf("USBDeviceAttachToBus find usb device error!name %s\n", dev_name);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
if (TYPE_USB_DEV == device->dev_type) {
|
||||
ret = DeviceRegisterToBus(bus, device);
|
||||
if (EOK != ret) {
|
||||
KPrintf("usbDeviceAttachToBus DeviceRegisterToBus error %u\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return EOK;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file drv_usb.c
|
||||
* @brief register usb drv function using bus driver framework
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-24
|
||||
*/
|
||||
|
||||
#include <bus_usb.h>
|
||||
#include <dev_usb.h>
|
||||
|
||||
static DoubleLinklistType usbdrv_linklist;
|
||||
|
||||
/*Create the driver linklist*/
|
||||
static void UsbDrvLinkInit()
|
||||
{
|
||||
InitDoubleLinkList(&usbdrv_linklist);
|
||||
}
|
||||
|
||||
/*Find the regiter driver*/
|
||||
DriverType UsbDriverFind(const char *drv_name, enum DriverType drv_type)
|
||||
{
|
||||
NULL_PARAM_CHECK(drv_name);
|
||||
|
||||
struct Driver *driver = NONE;
|
||||
|
||||
DoubleLinklistType *node = NONE;
|
||||
DoubleLinklistType *head = &usbdrv_linklist;
|
||||
|
||||
for (node = head->node_next; node != head; node = node->node_next) {
|
||||
driver = SYS_DOUBLE_LINKLIST_ENTRY(node, struct Driver, driver_link);
|
||||
if ((!strcmp(driver->drv_name, drv_name)) && (drv_type == driver->driver_type)) {
|
||||
return driver;
|
||||
}
|
||||
}
|
||||
|
||||
KPrintf("UsbDriverFind cannot find the %s driver.return NULL\n", drv_name);
|
||||
return NONE;
|
||||
}
|
||||
|
||||
/*Register the Driver, manage with the double linklist*/
|
||||
int UsbDriverRegister(struct Driver *driver)
|
||||
{
|
||||
NULL_PARAM_CHECK(driver);
|
||||
|
||||
x_err_t ret = EOK;
|
||||
static x_bool driver_link_flag = RET_FALSE;
|
||||
|
||||
if (!driver_link_flag) {
|
||||
UsbDrvLinkInit();
|
||||
driver_link_flag = RET_TRUE;
|
||||
}
|
||||
|
||||
DoubleLinkListInsertNodeAfter(&usbdrv_linklist, &(driver->driver_link));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
SRC_DIR := usbhost
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,4 @@
|
||||
SRC_DIR := core class
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
SRC_FILES += mass.c
|
||||
SRC_FILES += udisk.c
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,571 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-12-12 Yi Qiu first version
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file mass.c
|
||||
* @brief support usb storage function
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-25
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: mass.c
|
||||
Description: support usb storage function
|
||||
Others: take RT-Thread v4.0.2/components/drivers/usb/usbhost/class/mass.c for references
|
||||
https://github.com/RT-Thread/rt-thread/tree/v4.0.2
|
||||
History:
|
||||
1. Date: 2021-04-25
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. support usb storage configure, function and struct
|
||||
2. support usb bus driver framework
|
||||
*************************************************/
|
||||
|
||||
#include <xiuos.h>
|
||||
#include <usb_host.h>
|
||||
#include "mass.h"
|
||||
|
||||
#ifdef USBH_MSTORAGE
|
||||
|
||||
extern x_err_t UdiskRun(struct uhintf* intf);
|
||||
extern x_err_t UdiskStop(struct uhintf* intf);
|
||||
|
||||
static struct UclassDriver StorageDriver;
|
||||
|
||||
|
||||
static x_err_t PipeCheck(struct uhintf* intf, upipe_t pipe)
|
||||
{
|
||||
struct uinstance* device;
|
||||
x_err_t ret;
|
||||
UstorPointer stor;
|
||||
int size = 0;
|
||||
struct UstorageCsw csw;
|
||||
|
||||
if(intf == NONE || pipe == NONE)
|
||||
{
|
||||
KPrintf("the interface is not available\n");
|
||||
return -EPIO;
|
||||
}
|
||||
|
||||
|
||||
device = intf->device;
|
||||
|
||||
|
||||
stor = (UstorPointer)intf->UserData;
|
||||
|
||||
|
||||
if(pipe->status == UPIPE_STATUS_OK) return EOK;
|
||||
|
||||
if(pipe->status == UPIPE_STATUS_ERROR)
|
||||
{
|
||||
KPrintf("pipe status error\n");
|
||||
return -EPIO;
|
||||
}
|
||||
if(pipe->status == UPIPE_STATUS_STALL)
|
||||
{
|
||||
|
||||
ret = UsbhClearFeature(device, pipe->ep.bEndpointAddress,
|
||||
USB_FEATURE_ENDPOINT_HALT);
|
||||
if(ret != EOK) return ret;
|
||||
}
|
||||
|
||||
|
||||
DelayKTask(50);
|
||||
|
||||
KPrintf("pipes1 0x%x, 0x%x\n", stor->pipe_in, stor->pipe_out);
|
||||
|
||||
stor->pipe_in->status = UPIPE_STATUS_OK;
|
||||
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("clean storage in pipe stall\n"));
|
||||
|
||||
|
||||
size = UsbHcdPipeXfer(stor->pipe_in->inst->hcd,
|
||||
stor->pipe_in, &csw, SIZEOF_CSW, 100);
|
||||
if(size != SIZEOF_CSW)
|
||||
{
|
||||
KPrintf("receive the csw after stall failed\n");
|
||||
return -EPIO;
|
||||
}
|
||||
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
|
||||
static x_err_t UsbBulkOnlyXfer(struct uhintf* intf,
|
||||
UstorageCbwPointer cmd, uint8* buffer, int timeout)
|
||||
{
|
||||
x_size_t size;
|
||||
x_err_t ret;
|
||||
upipe_t pipe;
|
||||
struct UstorageCsw csw;
|
||||
UstorPointer stor;
|
||||
|
||||
NULL_PARAM_CHECK(cmd);
|
||||
|
||||
if(intf == NONE)
|
||||
{
|
||||
KPrintf("the interface is not available\n");
|
||||
return -EPIO;
|
||||
}
|
||||
|
||||
|
||||
stor = (UstorPointer)intf->UserData;
|
||||
|
||||
do
|
||||
{
|
||||
|
||||
size = UsbHcdPipeXfer(stor->pipe_out->inst->hcd, stor->pipe_out,
|
||||
cmd, SIZEOF_CBW, timeout);
|
||||
if(size != SIZEOF_CBW)
|
||||
{
|
||||
KPrintf("CBW size error\n");
|
||||
return -EPIO;
|
||||
}
|
||||
if(cmd->XferLen != 0)
|
||||
{
|
||||
pipe = (cmd->dflags == CBWFLAGS_DIR_IN) ? stor->pipe_in :
|
||||
stor->pipe_out;
|
||||
size = UsbHcdPipeXfer(pipe->inst->hcd, pipe, (void*)buffer,
|
||||
cmd->XferLen, timeout);
|
||||
if(size != cmd->XferLen)
|
||||
{
|
||||
KPrintf("request size %d, transfer size %d\n",
|
||||
cmd->XferLen, size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
size = UsbHcdPipeXfer(stor->pipe_in->inst->hcd, stor->pipe_in,
|
||||
&csw, SIZEOF_CSW, timeout);
|
||||
if(size != SIZEOF_CSW)
|
||||
{
|
||||
KPrintf("csw size error\n");
|
||||
return -EPIO;
|
||||
}
|
||||
}while(0);
|
||||
|
||||
|
||||
ret = PipeCheck(intf, stor->pipe_in);
|
||||
if(ret != EOK)
|
||||
{
|
||||
KPrintf("in pipe error\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
ret = PipeCheck(intf, stor->pipe_out);
|
||||
if(ret != EOK)
|
||||
{
|
||||
KPrintf("out pipe error\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
if(csw.signature != CSW_SIGNATURE || csw.tag != CBW_TAG_VALUE)
|
||||
{
|
||||
KPrintf("csw signature error\n");
|
||||
return -EPIO;
|
||||
}
|
||||
|
||||
if(csw.status != 0)
|
||||
{
|
||||
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
|
||||
x_err_t UsbhStorageGetMaxLun(struct uhintf* intf, uint8* MaxLun)
|
||||
{
|
||||
struct uinstance* device;
|
||||
struct urequest setup;
|
||||
int timeout = USB_TIMEOUT_BASIC;
|
||||
|
||||
if(intf == NONE)
|
||||
{
|
||||
KPrintf("the interface is not available\n");
|
||||
return -EPIO;
|
||||
}
|
||||
|
||||
|
||||
NULL_PARAM_CHECK(intf->device);
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("UsbhStorageGetMaxLun\n"));
|
||||
|
||||
|
||||
device = intf->device;
|
||||
|
||||
|
||||
setup.RequestType = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS |
|
||||
USB_REQ_TYPE_INTERFACE;
|
||||
setup.bRequest = USBREQ_GET_MAX_LUN;
|
||||
setup.wValue = intf->IntfDesc->bInterfaceNumber;
|
||||
setup.wIndex = 0;
|
||||
setup.wLength = 1;
|
||||
|
||||
|
||||
if(UsbHcdSetupXfer(device->hcd, device->PipeEp0Out, &setup, timeout) != 8)
|
||||
{
|
||||
return -EPIO;
|
||||
}
|
||||
if(UsbHcdPipeXfer(device->hcd, device->PipeEp0In, MaxLun, 1, timeout) != 1)
|
||||
{
|
||||
return -EPIO;
|
||||
}
|
||||
if(UsbHcdPipeXfer(device->hcd, device->PipeEp0Out, NONE, 0, timeout) != 0)
|
||||
{
|
||||
return -EPIO;
|
||||
}
|
||||
return EOK;
|
||||
}
|
||||
|
||||
|
||||
x_err_t UsbhStorageReset(struct uhintf* intf)
|
||||
{
|
||||
struct urequest setup;
|
||||
struct uinstance* device;
|
||||
int timeout = USB_TIMEOUT_BASIC;
|
||||
|
||||
|
||||
if(intf == NONE)
|
||||
{
|
||||
KPrintf("the interface is not available\n");
|
||||
return -EPIO;
|
||||
}
|
||||
|
||||
NULL_PARAM_CHECK(intf->device);
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("UsbhStorageReset\n"));
|
||||
|
||||
|
||||
device = intf->device;
|
||||
|
||||
|
||||
setup.RequestType = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
|
||||
USB_REQ_TYPE_INTERFACE;
|
||||
setup.bRequest = USBREQ_MASS_STORAGE_RESET;
|
||||
setup.wIndex = intf->IntfDesc->bInterfaceNumber;
|
||||
setup.wLength = 0;
|
||||
setup.wValue = 0;
|
||||
|
||||
if(UsbHcdSetupXfer(device->hcd, device->PipeEp0Out, &setup, timeout) != 8)
|
||||
{
|
||||
return -EPIO;
|
||||
}
|
||||
if(UsbHcdPipeXfer(device->hcd, device->PipeEp0In, NONE, 0, timeout) != 0)
|
||||
{
|
||||
return -EPIO;
|
||||
}
|
||||
return EOK;
|
||||
}
|
||||
|
||||
|
||||
x_err_t UsbhStorageRead10(struct uhintf* intf, uint8 *buffer,
|
||||
uint32 sector, x_size_t count, int timeout)
|
||||
{
|
||||
struct UstorageCbw cmd;
|
||||
|
||||
|
||||
if(intf == NONE)
|
||||
{
|
||||
KPrintf("interface is not available\n");
|
||||
return -EPIO;
|
||||
}
|
||||
|
||||
NULL_PARAM_CHECK(intf->device);
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("UsbhStorageRead10\n"));
|
||||
|
||||
|
||||
memset(&cmd, 0, sizeof(struct UstorageCbw));
|
||||
cmd.signature = CBW_SIGNATURE;
|
||||
cmd.tag = CBW_TAG_VALUE;
|
||||
cmd.XferLen = SECTOR_SIZE * count;
|
||||
cmd.dflags = CBWFLAGS_DIR_IN;
|
||||
cmd.lun = 0;
|
||||
cmd.CbLen = 10;
|
||||
cmd.cb[0] = SCSI_READ_10;
|
||||
cmd.cb[1] = 0;
|
||||
cmd.cb[2] = (uint8)(sector >> 24);
|
||||
cmd.cb[3] = (uint8)(sector >> 16);
|
||||
cmd.cb[4] = (uint8)(sector >> 8);
|
||||
cmd.cb[5] = (uint8)sector;
|
||||
cmd.cb[6] = 0;
|
||||
cmd.cb[7] = (count & 0xff00) >> 8;
|
||||
cmd.cb[8] = (uint8) count & 0xff;
|
||||
|
||||
return UsbBulkOnlyXfer(intf, &cmd, buffer, timeout);
|
||||
}
|
||||
|
||||
|
||||
x_err_t UsbhStorageWrite10(struct uhintf* intf, uint8 *buffer,
|
||||
uint32 sector, x_size_t count, int timeout)
|
||||
{
|
||||
struct UstorageCbw cmd;
|
||||
|
||||
|
||||
if(intf == NONE)
|
||||
{
|
||||
KPrintf("the interface is not available\n");
|
||||
return -EPIO;
|
||||
}
|
||||
|
||||
NULL_PARAM_CHECK(intf->device);
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("UsbhStorageWrite10\n"));
|
||||
|
||||
|
||||
memset(&cmd, 0, sizeof(struct UstorageCbw));
|
||||
cmd.signature = CBW_SIGNATURE;
|
||||
cmd.tag = CBW_TAG_VALUE;
|
||||
cmd.XferLen = SECTOR_SIZE * count;
|
||||
cmd.dflags = CBWFLAGS_DIR_OUT;
|
||||
cmd.lun = 0;
|
||||
cmd.CbLen = 10;
|
||||
cmd.cb[0] = SCSI_WRITE_10;
|
||||
cmd.cb[1] = 0;
|
||||
cmd.cb[2] = (uint8)(sector >> 24);
|
||||
cmd.cb[3] = (uint8)(sector >> 16);
|
||||
cmd.cb[4] = (uint8)(sector >> 8);
|
||||
cmd.cb[5] = (uint8)sector;
|
||||
cmd.cb[6] = 0;
|
||||
cmd.cb[7] = (count & 0xff00) >> 8;
|
||||
cmd.cb[8] = (uint8) count & 0xff;
|
||||
|
||||
return UsbBulkOnlyXfer(intf, &cmd, buffer, timeout);
|
||||
}
|
||||
|
||||
|
||||
x_err_t UsbhStorageRequestSense(struct uhintf* intf, uint8* buffer)
|
||||
{
|
||||
struct UstorageCbw cmd;
|
||||
int timeout = USB_TIMEOUT_LONG;
|
||||
|
||||
|
||||
if(intf == NONE)
|
||||
{
|
||||
KPrintf("the interface is not available\n");
|
||||
return -EPIO;
|
||||
}
|
||||
|
||||
NULL_PARAM_CHECK(intf->device);
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("UsbhStorageRequestSense\n"));
|
||||
|
||||
|
||||
memset(&cmd, 0, sizeof(struct UstorageCbw));
|
||||
cmd.signature = CBW_SIGNATURE;
|
||||
cmd.tag = CBW_TAG_VALUE;
|
||||
cmd.XferLen = 18;
|
||||
cmd.dflags = CBWFLAGS_DIR_IN;
|
||||
cmd.lun = 0;
|
||||
cmd.CbLen = 6;
|
||||
cmd.cb[0] = SCSI_REQUEST_SENSE;
|
||||
cmd.cb[4] = 18;
|
||||
|
||||
return UsbBulkOnlyXfer(intf, &cmd, buffer, timeout);
|
||||
}
|
||||
|
||||
|
||||
x_err_t UsbhStorageTestUnitReady(struct uhintf* intf)
|
||||
{
|
||||
struct UstorageCbw cmd;
|
||||
int timeout = USB_TIMEOUT_LONG;
|
||||
|
||||
|
||||
if(intf == NONE)
|
||||
{
|
||||
KPrintf("the interface is not available\n");
|
||||
return -EPIO;
|
||||
}
|
||||
|
||||
NULL_PARAM_CHECK(intf->device);
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("UsbhStorageTestUnitReady\n"));
|
||||
|
||||
|
||||
memset(&cmd, 0, sizeof(struct UstorageCbw));
|
||||
cmd.signature = CBW_SIGNATURE;
|
||||
cmd.tag = CBW_TAG_VALUE;
|
||||
cmd.XferLen = 0;
|
||||
cmd.dflags = CBWFLAGS_DIR_OUT;
|
||||
cmd.lun = 0;
|
||||
cmd.CbLen = 12;
|
||||
cmd.cb[0] = SCSI_TEST_UNIT_READY;
|
||||
|
||||
return UsbBulkOnlyXfer(intf, &cmd, NONE, timeout);
|
||||
}
|
||||
|
||||
|
||||
x_err_t UsbhStorageInquiry(struct uhintf* intf, uint8* buffer)
|
||||
{
|
||||
struct UstorageCbw cmd;
|
||||
int timeout = USB_TIMEOUT_LONG;
|
||||
|
||||
|
||||
if(intf == NONE)
|
||||
{
|
||||
KPrintf("the interface is not available\n");
|
||||
return -EPIO;
|
||||
}
|
||||
|
||||
NULL_PARAM_CHECK(intf->device);
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("UsbhStorageInquiry\n"));
|
||||
|
||||
|
||||
memset(&cmd, 0, sizeof(struct UstorageCbw));
|
||||
cmd.signature = CBW_SIGNATURE;
|
||||
cmd.tag = CBW_TAG_VALUE;
|
||||
cmd.XferLen = 36;
|
||||
cmd.dflags = CBWFLAGS_DIR_IN;
|
||||
cmd.lun = 0;
|
||||
cmd.CbLen = 6;
|
||||
cmd.cb[0] = SCSI_INQUIRY_CMD;
|
||||
cmd.cb[4] = 36;
|
||||
|
||||
return UsbBulkOnlyXfer(intf, &cmd, buffer, timeout);
|
||||
}
|
||||
|
||||
|
||||
x_err_t UsbhStorageGetCapacity(struct uhintf* intf, uint8* buffer)
|
||||
{
|
||||
struct UstorageCbw cmd;
|
||||
int timeout = USB_TIMEOUT_LONG;
|
||||
|
||||
|
||||
if(intf == NONE)
|
||||
{
|
||||
KPrintf("the interface is not available\n");
|
||||
return -EPIO;
|
||||
}
|
||||
|
||||
NULL_PARAM_CHECK(intf->device);
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("UsbhStorageGetCapacity\n"));
|
||||
|
||||
|
||||
memset(&cmd, 0, sizeof(struct UstorageCbw));
|
||||
cmd.signature = CBW_SIGNATURE;
|
||||
cmd.tag = CBW_TAG_VALUE;
|
||||
cmd.XferLen = 8;
|
||||
cmd.dflags = CBWFLAGS_DIR_IN;
|
||||
cmd.lun = 0;
|
||||
cmd.CbLen = 12;
|
||||
cmd.cb[0] = SCSI_READ_CAPACITY;
|
||||
|
||||
return UsbBulkOnlyXfer(intf, &cmd, buffer, timeout);
|
||||
}
|
||||
|
||||
|
||||
static x_err_t UsbhStorageEnable(void* arg)
|
||||
{
|
||||
int i = 0;
|
||||
x_err_t ret;
|
||||
UstorPointer stor;
|
||||
struct uhintf* intf = (struct uhintf*)arg;
|
||||
|
||||
|
||||
if(intf == NONE)
|
||||
{
|
||||
KPrintf("the interface is not available\n");
|
||||
return -EPIO;
|
||||
}
|
||||
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("subclass %d, protocal %d\n",
|
||||
intf->IntfDesc->bInterfaceSubClass,
|
||||
intf->IntfDesc->bInterfaceProtocol));
|
||||
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("usbh_storage_run\n"));
|
||||
|
||||
|
||||
|
||||
stor = x_malloc(sizeof(struct ustor));
|
||||
NULL_PARAM_CHECK(stor);
|
||||
|
||||
|
||||
memset(stor, 0, sizeof(struct ustor));
|
||||
intf->UserData = (void*)stor;
|
||||
|
||||
for(i=0; i<intf->IntfDesc->bNumEndpoints; i++)
|
||||
{
|
||||
UepDescPointer EpDesc;
|
||||
|
||||
|
||||
UsbhGetEndpointDescriptor(intf->IntfDesc, i, &EpDesc);
|
||||
if(EpDesc == NONE)
|
||||
{
|
||||
KPrintf("usb_get_endpoint_descriptor error\n");
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
|
||||
if((EpDesc->bmAttributes & USB_EP_ATTR_TYPE_MASK) != USB_EP_ATTR_BULK)
|
||||
continue;
|
||||
|
||||
|
||||
if(EpDesc->bEndpointAddress & USB_DIR_IN)
|
||||
{
|
||||
|
||||
stor->pipe_in = UsbInstanceFindPipe(intf->device,EpDesc->bEndpointAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
stor->pipe_out = UsbInstanceFindPipe(intf->device,EpDesc->bEndpointAddress);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(stor->pipe_in == NONE || stor->pipe_out == NONE)
|
||||
{
|
||||
KPrintf("pipe error, unsupported device\n");
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
|
||||
ret = UdiskRun(intf);
|
||||
if(ret != EOK) return ret;
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
|
||||
static x_err_t UsbhStorageDisable(void* arg)
|
||||
{
|
||||
UstorPointer stor;
|
||||
struct uhintf* intf = (struct uhintf*)arg;
|
||||
|
||||
|
||||
NULL_PARAM_CHECK(intf);
|
||||
NULL_PARAM_CHECK(intf->UserData);
|
||||
NULL_PARAM_CHECK(intf->device );
|
||||
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("usbh_storage_stop\n"));
|
||||
|
||||
|
||||
stor = (UstorPointer)intf->UserData;
|
||||
|
||||
UdiskStop(intf);
|
||||
|
||||
|
||||
|
||||
if(stor != NONE) x_free(stor);
|
||||
return EOK;
|
||||
}
|
||||
|
||||
|
||||
UcdPointer UsbhClassDriverStorage(void)
|
||||
{
|
||||
StorageDriver.ClassCode = USB_CLASS_MASS_STORAGE;
|
||||
|
||||
StorageDriver.enable = UsbhStorageEnable;
|
||||
StorageDriver.disable = UsbhStorageDisable;
|
||||
|
||||
return &StorageDriver;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-12-12 Yi Qiu first version
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file mass.h
|
||||
* @brief define usb storage function and struct
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-25
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: mass.h
|
||||
Description: define usb storage function and struct
|
||||
Others: take RT-Thread v4.0.2/components/drivers/usb/usbhost/class/mass.h for references
|
||||
https://github.com/RT-Thread/rt-thread/tree/v4.0.2
|
||||
History:
|
||||
1. Date: 2021-04-25
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. support define usb storage configure, function and struct
|
||||
2. support usb bus driver framework
|
||||
*************************************************/
|
||||
|
||||
#ifndef __MASS_H__
|
||||
#define __MASS_H__
|
||||
|
||||
#include <xiuos.h>
|
||||
|
||||
|
||||
#define MAX_PARTITION_COUNT 4
|
||||
#define SECTOR_SIZE 512
|
||||
|
||||
struct UstorData
|
||||
{
|
||||
|
||||
struct uhintf* intf;
|
||||
int UdiskId;
|
||||
const char path;
|
||||
};
|
||||
|
||||
struct ustor
|
||||
{
|
||||
upipe_t pipe_in;
|
||||
upipe_t pipe_out;
|
||||
uint32 capicity[2];
|
||||
|
||||
uint8 DevCnt;
|
||||
};
|
||||
typedef struct ustor* UstorPointer;
|
||||
|
||||
x_err_t UsbhStorageGetMaxLun(struct uhintf* intf, uint8* MaxLun);
|
||||
x_err_t UsbhStorageReset(struct uhintf* intf);
|
||||
x_err_t UsbhStorageRead10(struct uhintf* intf, uint8 *buffer,
|
||||
uint32 sector, x_size_t count, int timeout);
|
||||
x_err_t UsbhStorageWrite10(struct uhintf* intf, uint8 *buffer,
|
||||
uint32 sector, x_size_t count, int timeout);
|
||||
x_err_t UsbhStorageRequestSense(struct uhintf* intf, uint8* buffer);
|
||||
x_err_t UsbhStorageTestUnitReady(struct uhintf* intf);
|
||||
x_err_t UsbhStorageInquiry(struct uhintf* intf, uint8* buffer);
|
||||
x_err_t UsbhStorageGetCapacity(struct uhintf* intf, uint8* buffer);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,398 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-12-12 Yi Qiu first version
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file udisk.c
|
||||
* @brief support usb udisk function , write and read
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-25
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: udisk.c
|
||||
Description: support usb udisk function , write and read
|
||||
Others: take RT-Thread v4.0.2/components/drivers/usb/usbhost/class/udisk.c for references
|
||||
https://github.com/RT-Thread/rt-thread/tree/v4.0.2
|
||||
History:
|
||||
1. Date: 2021-04-25
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. support usb udisk configure, function and struct
|
||||
2. support usb bus driver framework
|
||||
*************************************************/
|
||||
|
||||
#include <xiuos.h>
|
||||
|
||||
#include <usb_host.h>
|
||||
#include "mass.h"
|
||||
|
||||
#if defined(FS_VFS)
|
||||
#include <iot-vfs.h>
|
||||
#endif
|
||||
|
||||
#ifdef USBH_MSTORAGE
|
||||
#include <bus.h>
|
||||
#include <bus_usb.h>
|
||||
#include <dev_usb.h>
|
||||
|
||||
|
||||
#define UDISK_MAX_COUNT 8
|
||||
static uint8 UdiskIdset = 0;
|
||||
|
||||
static int UdiskGetId(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i< UDISK_MAX_COUNT; i++)
|
||||
{
|
||||
if((UdiskIdset & (1 << i)) != 0) continue;
|
||||
else break;
|
||||
}
|
||||
|
||||
|
||||
if(i == UDISK_MAX_COUNT) CHECK(0);
|
||||
|
||||
UdiskIdset |= (1 << i);
|
||||
return i;
|
||||
}
|
||||
|
||||
static void UdiskFreeId(int id)
|
||||
{
|
||||
CHECK(id < UDISK_MAX_COUNT);
|
||||
|
||||
UdiskIdset &= ~(1 << id);
|
||||
}
|
||||
|
||||
static x_size_t UdiskRead_new(struct UstorData* data, x_OffPos pos, void* buffer,
|
||||
x_size_t size)
|
||||
{
|
||||
x_err_t ret;
|
||||
struct uhintf* intf;
|
||||
int timeout = USB_TIMEOUT_LONG;
|
||||
|
||||
|
||||
NULL_PARAM_CHECK(buffer);
|
||||
|
||||
if(size > 4096) timeout *= 2;
|
||||
|
||||
intf = data->intf;
|
||||
|
||||
ret = UsbhStorageRead10(intf, (uint8*)buffer, pos, size, timeout);
|
||||
|
||||
if (ret != EOK)
|
||||
{
|
||||
KPrintf("usb mass_storage read failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static x_size_t UdiskWrite_new (struct UstorData* data, x_OffPos pos, const void* buffer,
|
||||
x_size_t size)
|
||||
{
|
||||
x_err_t ret;
|
||||
struct uhintf* intf;
|
||||
int timeout = USB_TIMEOUT_LONG;
|
||||
|
||||
|
||||
NULL_PARAM_CHECK(buffer);
|
||||
|
||||
if(size * SECTOR_SIZE > 4096) timeout *= 2;
|
||||
|
||||
intf = data->intf;
|
||||
|
||||
ret = UsbhStorageWrite10(intf, (uint8*)buffer, pos, size, timeout);
|
||||
if (ret != EOK)
|
||||
{
|
||||
KPrintf("usb mass_storage write %d sector failed\n", size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
uint32 UdiskRead_new_api(void *dev, struct BusBlockReadParam *read_param)
|
||||
{
|
||||
struct UsbHardwareDevice* usb_dev = (struct UsbHardwareDevice*)dev;
|
||||
|
||||
return UdiskRead_new(usb_dev->private_data, read_param->pos, read_param->buffer, read_param->size);
|
||||
}
|
||||
|
||||
uint32 UdiskWirte_new_api(void *dev, struct BusBlockWriteParam *write_param)
|
||||
{
|
||||
struct UsbHardwareDevice* usb_dev = (struct UsbHardwareDevice*)dev;
|
||||
|
||||
return UdiskWrite_new(usb_dev->private_data, write_param->pos, write_param->buffer, write_param->size);
|
||||
}
|
||||
|
||||
x_err_t UdiskRun(struct uhintf* intf)
|
||||
{
|
||||
int i = 0;
|
||||
x_err_t ret;
|
||||
char dname[8];
|
||||
char sname[8];
|
||||
uint8 MaxLun, *sector, sense[18], inquiry[36];
|
||||
|
||||
UstorPointer stor;
|
||||
|
||||
|
||||
NULL_PARAM_CHECK(intf );
|
||||
|
||||
|
||||
ret = UsbhStorageReset(intf);
|
||||
if(ret != EOK) return ret;
|
||||
|
||||
stor = (UstorPointer)intf->UserData;
|
||||
|
||||
|
||||
ret = UsbhStorageGetMaxLun(intf, &MaxLun);
|
||||
if(ret != EOK)
|
||||
UsbhClearFeature(intf->device, 0, USB_FEATURE_ENDPOINT_HALT);
|
||||
|
||||
|
||||
if(stor->pipe_in->status == UPIPE_STATUS_STALL)
|
||||
{
|
||||
ret = UsbhClearFeature(intf->device,
|
||||
stor->pipe_in->ep.bEndpointAddress, USB_FEATURE_ENDPOINT_HALT);
|
||||
if(ret != EOK) return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(stor->pipe_out->status == UPIPE_STATUS_STALL)
|
||||
{
|
||||
ret = UsbhClearFeature(intf->device,
|
||||
stor->pipe_out->ep.bEndpointAddress, USB_FEATURE_ENDPOINT_HALT);
|
||||
if(ret != EOK) return ret;
|
||||
}
|
||||
|
||||
while((ret = UsbhStorageInquiry(intf, inquiry)) != EOK)
|
||||
{
|
||||
if(ret == -EPIO) return ret;
|
||||
|
||||
DelayKTask(5);
|
||||
if(i++ < 10) continue;
|
||||
KPrintf("UsbhStorageInquiry error\n");
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
|
||||
|
||||
while((ret = UsbhStorageTestUnitReady(intf)) != EOK)
|
||||
{
|
||||
if(ret == -EPIO) return ret;
|
||||
|
||||
ret = UsbhStorageRequestSense(intf, sense);
|
||||
if(ret == -EPIO) return ret;
|
||||
|
||||
DelayKTask(10);
|
||||
if(i++ < 10) continue;
|
||||
|
||||
KPrintf("UsbhStorageTestUnitReady error\n");
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
memset(stor->capicity, 0, sizeof(stor->capicity));
|
||||
|
||||
|
||||
while((ret = UsbhStorageGetCapacity(intf,
|
||||
(uint8*)stor->capicity)) != EOK)
|
||||
{
|
||||
if(ret == -EPIO) return ret;
|
||||
|
||||
DelayKTask(50);
|
||||
if(i++ < 10) continue;
|
||||
|
||||
stor->capicity[0] = 2880;
|
||||
stor->capicity[1] = 0x200;
|
||||
|
||||
KPrintf("UsbhStorageGetCapacity error\n");
|
||||
break;
|
||||
}
|
||||
|
||||
stor->capicity[0] = uswap_32(stor->capicity[0]);
|
||||
stor->capicity[1] = uswap_32(stor->capicity[1]);
|
||||
stor->capicity[0] += 1;
|
||||
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("capicity %d, block size %d\n",
|
||||
stor->capicity[0], stor->capicity[1]));
|
||||
|
||||
|
||||
sector = (uint8*) x_malloc (SECTOR_SIZE);
|
||||
if (sector == NONE)
|
||||
{
|
||||
KPrintf("allocate partition sector buffer failed\n");
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
memset(sector, 0, SECTOR_SIZE);
|
||||
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("read partition table\n"));
|
||||
|
||||
|
||||
ret = UsbhStorageRead10(intf, sector, 0, 1, USB_TIMEOUT_LONG);
|
||||
if(ret != EOK)
|
||||
{
|
||||
KPrintf("read parition table error\n");
|
||||
|
||||
x_free(sector);
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("finished reading partition\n"));
|
||||
|
||||
struct UstorData* data = x_malloc(sizeof(struct UstorData));
|
||||
memset(data, 0, sizeof(struct UstorData));
|
||||
data->UdiskId = UdiskGetId();
|
||||
|
||||
|
||||
data->intf = intf;
|
||||
|
||||
|
||||
snprintf(dname, sizeof(dname), "udisk%d", data->UdiskId);
|
||||
|
||||
struct Bus* usb_bus = BusFind(UDISK_USB_BUS_NAME);
|
||||
struct UsbHardwareDevice* usb_dev = (struct UsbHardwareDevice*)BusFindDevice(usb_bus, UDISK_USB_DEVICE_NAME);
|
||||
if (usb_dev)
|
||||
{
|
||||
KPrintf("udisk.c find usb dev seccess\n");
|
||||
usb_dev->private_data = (void*)data;
|
||||
}
|
||||
else
|
||||
{
|
||||
KPrintf("udisk.c find usb dev fail \n");
|
||||
}
|
||||
|
||||
data->intf = intf;
|
||||
|
||||
NULL_PARAM_CHECK(data);
|
||||
NULL_PARAM_CHECK(intf );
|
||||
CHECK(data->intf == intf);
|
||||
|
||||
stor->DevCnt++;
|
||||
|
||||
if (MountFilesystem(UDISK_USB_BUS_NAME, UDISK_USB_DEVICE_NAME,USB_DRIVER_NAME, FSTYPE_FATFS, UDISK_MOUNTPOINT) == 0)
|
||||
KPrintf("Mount FAT on Udisk successful.\n");
|
||||
else
|
||||
KPrintf("Mount FAT on Udisk failed.\n");
|
||||
|
||||
// for(i=0; i<MAX_PARTITION_COUNT; i++)
|
||||
// {
|
||||
// /* get the first partition */
|
||||
// ret = dfs_filesystem_get_partition(&part[i], sector, i);
|
||||
// if (ret == EOK)
|
||||
// {
|
||||
// struct ustor_data* data = x_malloc(sizeof(struct ustor_data));
|
||||
// memset(data, 0, sizeof(struct ustor_data));
|
||||
// data->intf = intf;
|
||||
// data->udisk_id = udisk_get_id();
|
||||
// snprintf(dname, 6, "ud%d-%d", data->udisk_id, i);
|
||||
// snprintf(sname, 8, "sem_ud%d", i);
|
||||
// data->part.lock = KSemaphoreCreate( 1);
|
||||
|
||||
// /* register sdcard device */
|
||||
// stor->dev[i].type = Dev_TYPE_Block;
|
||||
|
||||
// stor->dev[i].init = udisk_init;
|
||||
// stor->dev[i].read = udisk_read;
|
||||
// stor->dev[i].write = udisk_write;
|
||||
// stor->dev[i].control = udisk_control;
|
||||
|
||||
// stor->dev[i].UserData = (void*)data;
|
||||
|
||||
// DeviceRegister(&stor->dev[i], dname, SIGN_OPER_RDWR |
|
||||
// SIGN_OPER_REMOVABLE |SIGN_OPER_STANDALONE);
|
||||
|
||||
// stor->dev_cnt++;
|
||||
// if (dfs_mount(stor->dev[i].parent.name, UDISK_MOUNTPOINT, "elm",
|
||||
// 0, 0) == 0)
|
||||
// {
|
||||
// SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("udisk part %d mount successfully\n", i));
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("udisk part %d mount failed\n", i));
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if(i == 0)
|
||||
// {
|
||||
// struct ustor_data* data = x_malloc(sizeof(struct ustor_data));
|
||||
// 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 = KSemaphoreCreate( 1);
|
||||
|
||||
// snprintf(dname, 7, "udisk%d", data->udisk_id);
|
||||
|
||||
// /* register sdcard device */
|
||||
// stor->dev[0].type = Dev_TYPE_Block;
|
||||
|
||||
// stor->dev[0].init = udisk_init;
|
||||
// stor->dev[0].read = udisk_read;
|
||||
// stor->dev[0].write = udisk_write;
|
||||
// stor->dev[0].control = udisk_control;
|
||||
|
||||
// stor->dev[0].UserData = (void*)data;
|
||||
|
||||
// DeviceRegister(&stor->dev[0], dname,
|
||||
// SIGN_OPER_RDWR |SIGN_OPER_REMOVABLE
|
||||
// |SIGN_OPER_STANDALONE);
|
||||
|
||||
// stor->dev_cnt++;
|
||||
// if (dfs_mount(stor->dev[0].parent.name, UDISK_MOUNTPOINT,
|
||||
// "elm", 0, 0) == 0)
|
||||
// {
|
||||
// KPrintf("Mount FAT on Udisk successful.\n");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// KPrintf("Mount FAT on Udisk failed.\n");
|
||||
// }
|
||||
// }
|
||||
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
x_free(sector);
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
x_err_t UdiskStop(struct uhintf* intf)
|
||||
{
|
||||
int i;
|
||||
UstorPointer stor;
|
||||
|
||||
NULL_PARAM_CHECK(intf);
|
||||
NULL_PARAM_CHECK(intf->device);
|
||||
|
||||
stor = (UstorPointer)intf->UserData;
|
||||
NULL_PARAM_CHECK(stor);
|
||||
|
||||
for(i=0; i<stor->DevCnt; i++)
|
||||
{
|
||||
UnmountFileSystem(UDISK_MOUNTPOINT);
|
||||
}
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,5 @@
|
||||
SRC_FILES +=core.c driver.c usbhost.c hub.c
|
||||
|
||||
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,609 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-03-12 Yi Qiu first version
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file core.c
|
||||
* @brief support usb host function and configure
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-25
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: core.c
|
||||
Description: support usb host function and configure
|
||||
Others: take RT-Thread v4.0.2/components/drivers/usb/usbhost/core/usbhost_core.c for references
|
||||
https://github.com/RT-Thread/rt-thread/tree/v4.0.2
|
||||
History:
|
||||
1. Date: 2021-04-25
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. support usb host configure, function and struct
|
||||
2. support usb bus driver framework
|
||||
*************************************************/
|
||||
|
||||
#include <xiuos.h>
|
||||
#include <usb_host.h>
|
||||
|
||||
static struct uinstance dev[USB_MAX_DEVICE];
|
||||
|
||||
|
||||
/**
|
||||
* Allocate a usb host instance
|
||||
*
|
||||
* @param uhcd pointer to a uhcd object
|
||||
*
|
||||
* @return pointer to a uinstance object (NULL on failure)
|
||||
*/
|
||||
UinstPointer UsbhAllocInstance(UhcdPointer uhcd)
|
||||
{
|
||||
int i;
|
||||
x_base lock;
|
||||
|
||||
for(i=0; i<USB_MAX_DEVICE; i++)
|
||||
{
|
||||
lock = CriticalAreaLock();
|
||||
if(dev[i].status != DEV_STATUS_IDLE) continue;
|
||||
|
||||
memset(&dev[i], 0, sizeof(struct uinstance));
|
||||
|
||||
dev[i].status = DEV_STATUS_BUSY;
|
||||
dev[i].index = i + 1;
|
||||
dev[i].address = 0;
|
||||
dev[i].MaxPacketSize = 0x8;
|
||||
InitDoubleLinkList(&dev[i].pipe);
|
||||
dev[i].hcd = uhcd;
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
return &dev[i];
|
||||
}
|
||||
|
||||
return NONE;
|
||||
}
|
||||
|
||||
|
||||
static struct UendpointDescriptor Ep0OutDesc =
|
||||
{
|
||||
|
||||
USB_DESC_LENGTH_ENDPOINT,
|
||||
USB_DESC_TYPE_ENDPOINT,
|
||||
0x00 | USB_DIR_OUT,
|
||||
USB_EP_ATTR_CONTROL,
|
||||
0x00,
|
||||
0x00,
|
||||
};
|
||||
static struct UendpointDescriptor Ep0InDesc =
|
||||
{
|
||||
|
||||
USB_DESC_LENGTH_ENDPOINT,
|
||||
USB_DESC_TYPE_ENDPOINT,
|
||||
0x00 | USB_DIR_IN,
|
||||
USB_EP_ATTR_CONTROL,
|
||||
0x00,
|
||||
0x00,
|
||||
};
|
||||
|
||||
/**
|
||||
* Enumerate and invoke class driver when a usb device is connected
|
||||
*
|
||||
* @param device pointer to a uinstance object
|
||||
*/
|
||||
x_err_t UsbhAttatchInstance(UinstPointer device)
|
||||
{
|
||||
int i = 0;
|
||||
x_err_t ret = EOK;
|
||||
struct UconfigDescriptor CfgDesc;
|
||||
UdevDescPointer DevDesc;
|
||||
UintfDescPointer IntfDesc;
|
||||
UepDescPointer EpDesc;
|
||||
uint8 EpIndex;
|
||||
upipe_t pipe;
|
||||
UcdPointer drv;
|
||||
|
||||
NULL_PARAM_CHECK(device);
|
||||
|
||||
memset(&CfgDesc, 0, sizeof(struct UconfigDescriptor));
|
||||
DevDesc = &device->DevDesc;
|
||||
|
||||
|
||||
Ep0OutDesc.wMaxPacketSize = 8;
|
||||
Ep0InDesc.wMaxPacketSize = 8;
|
||||
UsbHcdAllocPipe(device->hcd, &device->PipeEp0Out, device, &Ep0OutDesc);
|
||||
UsbHcdAllocPipe(device->hcd, &device->PipeEp0In, device, &Ep0InDesc);
|
||||
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("start enumnation\n"));
|
||||
|
||||
|
||||
ret = UsbhGetDescriptor(device, USB_DESC_TYPE_DEVICE, (void*)DevDesc, 8);
|
||||
if(ret != EOK)
|
||||
{
|
||||
KPrintf("get device descriptor head failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
UsbhHubResetPort(device->parent_hub, device->port);
|
||||
DelayKTask(2);
|
||||
UsbhHubClearPortFeature(device->parent_hub, i + 1, PORT_FEAT_C_CONNECTION);
|
||||
|
||||
ret = UsbhSetAddress(device);
|
||||
|
||||
if(ret != EOK)
|
||||
{
|
||||
KPrintf("set device address failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
UsbHcdFreePipe(device->hcd,device->PipeEp0Out);
|
||||
UsbHcdFreePipe(device->hcd,device->PipeEp0In);
|
||||
|
||||
|
||||
Ep0OutDesc.wMaxPacketSize = device->DevDesc.bMaxPacketSize0;
|
||||
Ep0InDesc.wMaxPacketSize = device->DevDesc.bMaxPacketSize0;
|
||||
|
||||
|
||||
UsbHcdAllocPipe(device->hcd, &device->PipeEp0Out, device, &Ep0OutDesc);
|
||||
UsbHcdAllocPipe(device->hcd, &device->PipeEp0In, device, &Ep0InDesc);
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("get device descriptor length %d\n",
|
||||
DevDesc->bLength));
|
||||
|
||||
|
||||
ret = UsbhGetDescriptor(device, USB_DESC_TYPE_DEVICE, (void*)DevDesc, DevDesc->bLength);
|
||||
if(ret != EOK)
|
||||
{
|
||||
KPrintf("get full device descriptor failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("Vendor ID 0x%x\n", DevDesc->idVendor));
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("Product ID 0x%x\n", DevDesc->idProduct));
|
||||
|
||||
|
||||
ret = UsbhGetDescriptor(device, USB_DESC_TYPE_CONFIGURATION, &CfgDesc, 18);
|
||||
if(ret != EOK)
|
||||
{
|
||||
KPrintf("get configuration descriptor head failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
device->CfgDesc = (UcfgDescPointer)x_malloc(CfgDesc.wTotalLength);
|
||||
memset(device->CfgDesc, 0, CfgDesc.wTotalLength);
|
||||
|
||||
|
||||
ret = UsbhGetDescriptor(device, USB_DESC_TYPE_CONFIGURATION,
|
||||
device->CfgDesc, CfgDesc.wTotalLength);
|
||||
if(ret != EOK)
|
||||
{
|
||||
KPrintf("get full configuration descriptor failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
ret = UsbhSetConfigure(device, 1);
|
||||
if(ret != EOK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
for(i=0; i<device->CfgDesc->bNumInterfaces; i++)
|
||||
{
|
||||
|
||||
ret = UsbhGetInterfaceDescriptor(device->CfgDesc, i, &IntfDesc);
|
||||
if(ret != EOK)
|
||||
{
|
||||
KPrintf("usb_get_interface_descriptor error\n");
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("interface class 0x%x, subclass 0x%x\n",
|
||||
IntfDesc->bInterfaceClass,
|
||||
IntfDesc->bInterfaceSubClass));
|
||||
|
||||
for(EpIndex = 0; EpIndex < IntfDesc->bNumEndpoints; EpIndex++)
|
||||
{
|
||||
UsbhGetEndpointDescriptor(IntfDesc, EpIndex, &EpDesc);
|
||||
if(EpDesc != NONE)
|
||||
{
|
||||
if(UsbHcdAllocPipe(device->hcd, &pipe, device, EpDesc) != EOK)
|
||||
{
|
||||
KPrintf("alloc pipe failed\n");
|
||||
return ERROR;
|
||||
}
|
||||
usb_instance_add_pipe(device,pipe);
|
||||
}
|
||||
else
|
||||
{
|
||||
KPrintf("get endpoint desc failed\n");
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
drv = UsbhClassDriverFind(IntfDesc->bInterfaceClass,
|
||||
IntfDesc->bInterfaceSubClass);
|
||||
|
||||
if(drv != NONE)
|
||||
{
|
||||
|
||||
device->intf[i] = (struct uhintf*)x_malloc(sizeof(struct uhintf));
|
||||
device->intf[i]->drv = drv;
|
||||
device->intf[i]->device = device;
|
||||
device->intf[i]->IntfDesc = IntfDesc;
|
||||
device->intf[i]->UserData = NONE;
|
||||
|
||||
|
||||
ret = UsbhClassDriverEnable(drv, (void*)device->intf[i]);
|
||||
if(ret != EOK)
|
||||
{
|
||||
KPrintf("interface %d run class driver error\n", i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
KPrintf("find usb device driver failed\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Detach a connected device
|
||||
*
|
||||
* @param device pointer to a uinstance object
|
||||
*
|
||||
* @return 0 on success, error code on failure
|
||||
*/
|
||||
x_err_t UsbhDetachInstance(UinstPointer device)
|
||||
{
|
||||
int i = 0;
|
||||
DoubleLinklistType * l;
|
||||
if(device == NONE)
|
||||
{
|
||||
KPrintf("no usb instance to detach\n");
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
|
||||
if (device->CfgDesc) {
|
||||
for (i = 0; i < device->CfgDesc->bNumInterfaces; i++)
|
||||
{
|
||||
if (device->intf[i] == NONE) continue;
|
||||
if (device->intf[i]->drv == NONE) continue;
|
||||
|
||||
CHECK(device->intf[i]->device == device);
|
||||
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("free interface instance %d\n", i));
|
||||
UsbhClassDriverDisable(device->intf[i]->drv, (void*)device->intf[i]);
|
||||
x_free(device->intf[i]);
|
||||
}
|
||||
x_free(device->CfgDesc);
|
||||
}
|
||||
|
||||
UsbHcdFreePipe(device->hcd,device->PipeEp0Out);
|
||||
UsbHcdFreePipe(device->hcd,device->PipeEp0In);
|
||||
|
||||
while(device->pipe.node_next!= &device->pipe)
|
||||
{
|
||||
l = device->pipe.node_next;
|
||||
DoubleLinkListRmNode(l);
|
||||
UsbHcdFreePipe(device->hcd,SYS_DOUBLE_LINKLIST_ENTRY(l,struct upipe,list));
|
||||
}
|
||||
memset(device, 0, sizeof(struct uinstance));
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get device descriptor of a connected device
|
||||
*
|
||||
* @param device pointer to a uinstance object
|
||||
* @param type device type
|
||||
* @param buffer buffer to store the descriptor
|
||||
*
|
||||
* @return 0 on success, error code on failure
|
||||
*/
|
||||
x_err_t UsbhGetDescriptor(UinstPointer device, uint8 type, void* buffer,
|
||||
int nbytes)
|
||||
{
|
||||
struct urequest setup;
|
||||
int timeout = USB_TIMEOUT_BASIC;
|
||||
|
||||
NULL_PARAM_CHECK(device);
|
||||
|
||||
setup.RequestType = 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(UsbHcdSetupXfer(device->hcd, device->PipeEp0Out, &setup, timeout) == 8)
|
||||
{
|
||||
if(UsbHcdPipeXfer(device->hcd, device->PipeEp0In, buffer, nbytes, timeout) == nbytes)
|
||||
{
|
||||
if(UsbHcdPipeXfer(device->hcd, device->PipeEp0Out, NONE, 0, timeout) == 0)
|
||||
{
|
||||
return EOK;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set address of a connected device
|
||||
*
|
||||
* @param device pointer to a uinstance object
|
||||
*
|
||||
* @return 0 on success, error code on failure
|
||||
*/
|
||||
x_err_t UsbhSetAddress(UinstPointer device)
|
||||
{
|
||||
struct urequest setup;
|
||||
int timeout = USB_TIMEOUT_BASIC;
|
||||
|
||||
NULL_PARAM_CHECK(device);
|
||||
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("usb_set_address\n"));
|
||||
|
||||
setup.RequestType = 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(UsbHcdSetupXfer(device->hcd, device->PipeEp0Out, &setup, timeout) != 8)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
if(UsbHcdPipeXfer(device->hcd, device->PipeEp0In, NONE, 0, timeout) == 0)
|
||||
{
|
||||
device->address = device->index;
|
||||
}
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set configuration of a connected device
|
||||
*
|
||||
* @param device pointer to a uinstance object
|
||||
* @param config value of configuration
|
||||
*
|
||||
* @return 0 on success, error code on failure
|
||||
*/
|
||||
x_err_t UsbhSetConfigure(UinstPointer device, int config)
|
||||
{
|
||||
struct urequest setup;
|
||||
int timeout = USB_TIMEOUT_BASIC;
|
||||
|
||||
|
||||
NULL_PARAM_CHECK(device);
|
||||
|
||||
setup.RequestType = 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(UsbHcdSetupXfer(device->hcd, device->PipeEp0Out, &setup, timeout) != 8)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
if(UsbHcdPipeXfer(device->hcd, device->PipeEp0In, NONE, 0, timeout) != 0)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
return EOK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set interface of a connected device
|
||||
*
|
||||
* @param device pointer to a uinstance object
|
||||
* @param intf interface number
|
||||
*
|
||||
* @return 0 on success, error code on failure
|
||||
*/
|
||||
x_err_t UsbhSetInterface(UinstPointer device, int intf)
|
||||
{
|
||||
struct urequest setup;
|
||||
int timeout = USB_TIMEOUT_BASIC;
|
||||
|
||||
|
||||
NULL_PARAM_CHECK(device);
|
||||
|
||||
setup.RequestType = 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(UsbHcdSetupXfer(device->hcd, device->PipeEp0Out, &setup, timeout) != 8)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clear feature of a given endpoint
|
||||
*
|
||||
* @param device pointer to a uinstance object
|
||||
* @param endpoint endpoint number
|
||||
* @param feature feature number
|
||||
*
|
||||
* @return 0 on success, error code on failure
|
||||
*/
|
||||
x_err_t UsbhClearFeature(UinstPointer device, int endpoint, int feature)
|
||||
{
|
||||
struct urequest setup;
|
||||
int timeout = USB_TIMEOUT_BASIC;
|
||||
|
||||
|
||||
NULL_PARAM_CHECK(device);
|
||||
|
||||
setup.RequestType = 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(UsbHcdSetupXfer(device->hcd, device->PipeEp0Out, &setup, timeout) != 8)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get interface descriptor of a connected device
|
||||
*
|
||||
* @param CfgDesc pointer to a UconfigDescriptor object
|
||||
* @param num interface number
|
||||
* @param IntfDesc pointer to a UinterfaceDescriptor object
|
||||
*
|
||||
* @return 0 on success, error code on failure
|
||||
*/
|
||||
x_err_t UsbhGetInterfaceDescriptor(UcfgDescPointer CfgDesc, int num,
|
||||
UintfDescPointer* IntfDesc)
|
||||
{
|
||||
uint64 ptr, depth = 0;
|
||||
UdescPointer desc;
|
||||
|
||||
|
||||
NULL_PARAM_CHECK(CfgDesc);
|
||||
|
||||
ptr = (uint64)CfgDesc + CfgDesc->bLength;
|
||||
while(ptr < (uint64)CfgDesc + CfgDesc->wTotalLength)
|
||||
{
|
||||
if(depth++ > 0x20)
|
||||
{
|
||||
*IntfDesc = NONE;
|
||||
return -EPIO;
|
||||
}
|
||||
desc = (UdescPointer)ptr;
|
||||
if(desc->type == USB_DESC_TYPE_INTERFACE)
|
||||
{
|
||||
if(((UintfDescPointer)desc)->bInterfaceNumber == num)
|
||||
{
|
||||
*IntfDesc = (UintfDescPointer)desc;
|
||||
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB,
|
||||
("usb_get_interface_descriptor: %d\n", num));
|
||||
return EOK;
|
||||
}
|
||||
}
|
||||
ptr = (uint64)desc + desc->bLength;
|
||||
}
|
||||
|
||||
KPrintf("usb_get_interface_descriptor %d failed\n", num);
|
||||
return -EPIO;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get descriptor of an interface endpoint
|
||||
*
|
||||
* @param IntfDesc pointer to an UinterfaceDescriptor object
|
||||
* @param num endpoint number
|
||||
* @param EpDesc pointer to an UendpointDescriptor object pointer
|
||||
*
|
||||
* @return 0 on success, error code on failure
|
||||
*/
|
||||
x_err_t UsbhGetEndpointDescriptor(UintfDescPointer IntfDesc, int num,
|
||||
UepDescPointer* EpDesc)
|
||||
{
|
||||
int count = 0, depth = 0;
|
||||
uint64 ptr;
|
||||
UdescPointer desc;
|
||||
|
||||
|
||||
NULL_PARAM_CHECK(IntfDesc);
|
||||
CHECK(num < IntfDesc->bNumEndpoints);
|
||||
*EpDesc = NONE;
|
||||
|
||||
ptr = (uint64)IntfDesc + IntfDesc->bLength;
|
||||
while(count < IntfDesc->bNumEndpoints)
|
||||
{
|
||||
if(depth++ > 0x20)
|
||||
{
|
||||
*EpDesc = NONE;
|
||||
return -EPIO;
|
||||
}
|
||||
desc = (UdescPointer)ptr;
|
||||
if(desc->type == USB_DESC_TYPE_ENDPOINT)
|
||||
{
|
||||
if(num == count)
|
||||
{
|
||||
*EpDesc = (UepDescPointer)desc;
|
||||
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB,
|
||||
("usb_get_endpoint_descriptor: %d\n", num));
|
||||
return EOK;
|
||||
}
|
||||
else count++;
|
||||
}
|
||||
ptr = (uint64)desc + desc->bLength;
|
||||
}
|
||||
|
||||
KPrintf("usb_get_endpoint_descriptor %d failed\n", num);
|
||||
return -EPIO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfer data on a specified endpoint (pipe)
|
||||
*
|
||||
* @param hcd pointer to a uhcd object
|
||||
* @param pipe pointer to a upipe object
|
||||
* @param buffer buffer to store data to be sent/received
|
||||
* @param nbytes number of bytes to be sent/received
|
||||
* @param timeout maximum timeout
|
||||
*
|
||||
* @return number of bytes sent/received
|
||||
*/
|
||||
int UsbHcdPipeXfer(UhcdPointer hcd, upipe_t pipe, void* buffer, int nbytes, int timeout)
|
||||
{
|
||||
x_size_t RemainSize;
|
||||
x_size_t SendSize;
|
||||
RemainSize = nbytes;
|
||||
uint8 * pbuffer = (uint8 *)buffer;
|
||||
do
|
||||
{
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB,("pipe transform remain size,: %d\n", RemainSize));
|
||||
SendSize = (RemainSize > pipe->ep.wMaxPacketSize) ? pipe->ep.wMaxPacketSize : RemainSize;
|
||||
if(hcd->ops->pipe_xfer(pipe, USBH_PID_DATA, pbuffer, SendSize, timeout) == SendSize)
|
||||
{
|
||||
RemainSize -= SendSize;
|
||||
pbuffer += SendSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}while(RemainSize > 0);
|
||||
return nbytes;
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-03-12 Yi Qiu first version
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file driver.c
|
||||
* @brief support usb host driver function and register configure
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-25
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: driver.c
|
||||
Description: support usb host driver function , init and register
|
||||
Others: take RT-Thread v4.0.2/components/drivers/usb/usbhost/core/driver.c for references
|
||||
https://github.com/RT-Thread/rt-thread/tree/v4.0.2
|
||||
History:
|
||||
1. Date: 2021-04-25
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. support usb host driver configure, function and struct
|
||||
2. support usb bus driver framework
|
||||
*************************************************/
|
||||
|
||||
#include <xiuos.h>
|
||||
#include <xs_klist.h>
|
||||
#include <usb_host.h>
|
||||
|
||||
static DoubleLinklistType DriverList;
|
||||
|
||||
|
||||
x_err_t UsbhClassDriverInit(void)
|
||||
{
|
||||
InitDoubleLinkList(&DriverList);
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
x_err_t UsbhClassDriverRegister(UcdPointer drv)
|
||||
{
|
||||
if (drv == NONE) return -ERROR;
|
||||
|
||||
|
||||
DoubleLinkListInsertNodeAfter(&DriverList, &(drv->list));
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
|
||||
x_err_t UsbhClassDriverUnregister(UcdPointer drv)
|
||||
{
|
||||
NULL_PARAM_CHECK(drv);
|
||||
|
||||
|
||||
DoubleLinkListRmNode(&(drv->list));
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
|
||||
x_err_t UsbhClassDriverEnable(UcdPointer drv, void* args)
|
||||
{
|
||||
NULL_PARAM_CHECK(drv);
|
||||
|
||||
if(drv->enable != NONE)
|
||||
drv->enable(args);
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
|
||||
x_err_t UsbhClassDriverDisable(UcdPointer drv, void* args)
|
||||
{
|
||||
NULL_PARAM_CHECK(drv);
|
||||
|
||||
if(drv->disable != NONE)
|
||||
drv->disable(args);
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
UcdPointer UsbhClassDriverFind(int ClassCode, int subclass_code)
|
||||
{
|
||||
struct SysDoubleLinklistNode *node;
|
||||
x_base lock;
|
||||
|
||||
if (GetKTaskDescriptor() != NONE)
|
||||
lock = CriticalAreaLock();
|
||||
|
||||
for (node = DriverList.node_next; node != &DriverList; node = node->node_next)
|
||||
{
|
||||
UcdPointer drv =
|
||||
(UcdPointer)SYS_DOUBLE_LINKLIST_ENTRY(node, struct UclassDriver, list);
|
||||
if (drv->ClassCode == ClassCode)
|
||||
{
|
||||
if (GetKTaskDescriptor() != NONE)
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
return drv;
|
||||
}
|
||||
}
|
||||
|
||||
if (GetKTaskDescriptor() != NONE)
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
return NONE;
|
||||
}
|
||||
@@ -0,0 +1,631 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-12-12 Yi Qiu first version
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file hub.c
|
||||
* @brief support usb hub driver function and configure
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-25
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: hub.c
|
||||
Description: support usb hub driver function , init and irq configure
|
||||
Others: take RT-Thread v4.0.2/components/drivers/usb/usbhost/core/hub.c for references
|
||||
https://github.com/RT-Thread/rt-thread/tree/v4.0.2
|
||||
History:
|
||||
1. Date: 2021-04-25
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. support usb hub driver configure, function and struct
|
||||
2. support usb bus driver framework
|
||||
*************************************************/
|
||||
|
||||
#include <xiuos.h>
|
||||
#include <usb_host.h>
|
||||
|
||||
#define USB_THREAD_STACK_SIZE 4096
|
||||
|
||||
static int32 UsbMq;
|
||||
static struct UclassDriver HubDriver;
|
||||
static struct uhub RootHub;
|
||||
|
||||
static x_err_t RootHubCtrl(struct uhcd *hcd, uint16 port, uint8 cmd, void *args)
|
||||
{
|
||||
switch(cmd)
|
||||
{
|
||||
case RH_GET_PORT_STATUS:
|
||||
(*(uint32 *)args) = hcd->roothub->PortStatus[port-1];
|
||||
break;
|
||||
case RH_SET_PORT_STATUS:
|
||||
hcd->roothub->PortStatus[port-1] = (*(uint32 *)args);
|
||||
break;
|
||||
case RH_CLEAR_PORT_FEATURE:
|
||||
switch(((uint64)args))
|
||||
{
|
||||
case PORT_FEAT_C_CONNECTION:
|
||||
hcd->roothub->PortStatus[port-1] &= ~PORT_CCSC;
|
||||
break;
|
||||
case PORT_FEAT_C_ENABLE:
|
||||
hcd->roothub->PortStatus[port-1] &= ~PORT_PESC;
|
||||
break;
|
||||
case PORT_FEAT_C_SUSPEND:
|
||||
hcd->roothub->PortStatus[port-1] &= ~PORT_PSSC;
|
||||
break;
|
||||
case PORT_FEAT_C_OVER_CURRENT:
|
||||
hcd->roothub->PortStatus[port-1] &= ~PORT_POCIC;
|
||||
break;
|
||||
case PORT_FEAT_C_RESET:
|
||||
hcd->roothub->PortStatus[port-1] &= ~PORT_PRSC;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case RH_SET_PORT_FEATURE:
|
||||
switch((uint64)args)
|
||||
{
|
||||
case PORT_FEAT_CONNECTION:
|
||||
hcd->roothub->PortStatus[port-1] |= PORT_CCSC;
|
||||
break;
|
||||
case PORT_FEAT_ENABLE:
|
||||
hcd->roothub->PortStatus[port-1] |= PORT_PESC;
|
||||
break;
|
||||
case PORT_FEAT_SUSPEND:
|
||||
hcd->roothub->PortStatus[port-1] |= PORT_PSSC;
|
||||
break;
|
||||
case PORT_FEAT_OVER_CURRENT:
|
||||
hcd->roothub->PortStatus[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 ERROR;
|
||||
}
|
||||
return EOK;
|
||||
}
|
||||
void UsbhRootHubConnectHandler(struct uhcd *hcd, uint8 port, x_bool isHS)
|
||||
{
|
||||
struct UhostMsg msg;
|
||||
msg.type = USB_MSG_CONNECT_CHANGE;
|
||||
msg.content.hub = hcd->roothub;
|
||||
hcd->roothub->PortStatus[port - 1] |= PORT_CCS | PORT_CCSC;
|
||||
if(isHS)
|
||||
{
|
||||
hcd->roothub->PortStatus[port - 1] &= ~PORT_LSDA;
|
||||
}
|
||||
else
|
||||
{
|
||||
hcd->roothub->PortStatus[port - 1] |= PORT_LSDA;
|
||||
}
|
||||
UsbhEventSignal(&msg);
|
||||
}
|
||||
|
||||
void UsbhRootHubDisconnectHandler(struct uhcd *hcd, uint8 port)
|
||||
{
|
||||
struct UhostMsg msg;
|
||||
msg.type = USB_MSG_CONNECT_CHANGE;
|
||||
msg.content.hub = hcd->roothub;
|
||||
hcd->roothub->PortStatus[port - 1] |= PORT_CCSC;
|
||||
hcd->roothub->PortStatus[port - 1] &= ~PORT_CCS;
|
||||
UsbhEventSignal(&msg);
|
||||
}
|
||||
|
||||
|
||||
x_err_t UsbhHubGetDescriptor(struct uinstance* device, uint8 *buffer, x_size_t nbytes)
|
||||
{
|
||||
struct urequest setup;
|
||||
int timeout = USB_TIMEOUT_BASIC;
|
||||
|
||||
|
||||
NULL_PARAM_CHECK(device);
|
||||
|
||||
setup.RequestType = 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(UsbHcdSetupXfer(device->hcd, device->PipeEp0Out, &setup, timeout) == 8)
|
||||
{
|
||||
if(UsbHcdPipeXfer(device->hcd, device->PipeEp0In, buffer, nbytes, timeout) == nbytes)
|
||||
{
|
||||
return EOK;
|
||||
}
|
||||
}
|
||||
return -RET_FALSE;
|
||||
}
|
||||
|
||||
|
||||
x_err_t UsbhHubGetStatus(struct uinstance* device, uint32* buffer)
|
||||
{
|
||||
struct urequest setup;
|
||||
int timeout = USB_TIMEOUT_BASIC;
|
||||
|
||||
|
||||
NULL_PARAM_CHECK(device);
|
||||
|
||||
setup.RequestType = 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(UsbHcdSetupXfer(device->hcd, device->PipeEp0Out, &setup, timeout) == 8)
|
||||
{
|
||||
if(UsbHcdPipeXfer(device->hcd, device->PipeEp0In, buffer, 4, timeout) == 4)
|
||||
{
|
||||
return EOK;
|
||||
}
|
||||
}
|
||||
return -RET_FALSE;
|
||||
}
|
||||
|
||||
|
||||
x_err_t UsbhHubGetPortStatus(UhubPointer hub, uint16 port, uint32* buffer)
|
||||
{
|
||||
struct urequest setup;
|
||||
int timeout = USB_TIMEOUT_BASIC;
|
||||
|
||||
|
||||
NULL_PARAM_CHECK(hub);
|
||||
|
||||
|
||||
if(hub->IsRoothub)
|
||||
{
|
||||
RootHubCtrl(hub->hcd, port, RH_GET_PORT_STATUS,
|
||||
(void*)buffer);
|
||||
return EOK;
|
||||
}
|
||||
|
||||
setup.RequestType = 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(UsbHcdSetupXfer(hub->hcd, hub->self->PipeEp0Out, &setup, timeout) == 8)
|
||||
{
|
||||
if(UsbHcdPipeXfer(hub->hcd, hub->self->PipeEp0In, buffer, 4, timeout) == 4)
|
||||
{
|
||||
return EOK;
|
||||
}
|
||||
}
|
||||
return -RET_FALSE;
|
||||
}
|
||||
|
||||
|
||||
x_err_t UsbhHubClearPortFeature(UhubPointer hub, uint16 port, uint16 feature)
|
||||
{
|
||||
struct urequest setup;
|
||||
int timeout = USB_TIMEOUT_BASIC;
|
||||
|
||||
|
||||
NULL_PARAM_CHECK(hub);
|
||||
|
||||
|
||||
|
||||
if(hub->IsRoothub)
|
||||
{
|
||||
RootHubCtrl(hub->hcd, port, RH_CLEAR_PORT_FEATURE,
|
||||
(void*)(uint64)feature);
|
||||
return EOK;
|
||||
}
|
||||
|
||||
setup.RequestType = 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(UsbHcdSetupXfer(hub->hcd, hub->self->PipeEp0Out, &setup, timeout) == 8)
|
||||
{
|
||||
return EOK;
|
||||
}
|
||||
return -RET_FALSE;
|
||||
}
|
||||
|
||||
|
||||
x_err_t UsbhHubSetPortFeature(UhubPointer hub, uint16 port,
|
||||
uint16 feature)
|
||||
{
|
||||
struct urequest setup;
|
||||
int timeout = USB_TIMEOUT_BASIC;
|
||||
|
||||
|
||||
NULL_PARAM_CHECK(hub);
|
||||
|
||||
|
||||
if(hub->IsRoothub)
|
||||
{
|
||||
RootHubCtrl(hub->hcd, port, RH_SET_PORT_FEATURE,
|
||||
(void*)(uint64)feature);
|
||||
return EOK;
|
||||
}
|
||||
|
||||
setup.RequestType = 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(UsbHcdSetupXfer(hub->hcd, hub->self->PipeEp0Out, &setup, timeout) == 8)
|
||||
{
|
||||
return EOK;
|
||||
}
|
||||
else return -RET_FALSE;
|
||||
}
|
||||
|
||||
|
||||
x_err_t UsbhHubResetPort(UhubPointer hub, uint16 port)
|
||||
{
|
||||
x_err_t ret;
|
||||
uint32 pstatus;
|
||||
|
||||
|
||||
NULL_PARAM_CHECK(hub);
|
||||
|
||||
DelayKTask(50);
|
||||
|
||||
|
||||
ret = UsbhHubSetPortFeature(hub, port, PORT_FEAT_RESET);
|
||||
if(ret != EOK) return ret;
|
||||
|
||||
while(RET_TRUE)
|
||||
{
|
||||
ret = UsbhHubGetPortStatus(hub, port, &pstatus);
|
||||
if(!(pstatus & PORT_PRS)) break;
|
||||
}
|
||||
|
||||
|
||||
ret = UsbhHubClearPortFeature(hub, port, PORT_FEAT_C_RESET);
|
||||
if(ret != EOK) return ret;
|
||||
|
||||
DelayKTask(50);
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
|
||||
x_err_t UsbhHubPortDebounce(UhubPointer hub, uint16 port)
|
||||
{
|
||||
x_err_t ret;
|
||||
int i = 0, times = 20;
|
||||
uint32 pstatus;
|
||||
x_bool connect = RET_TRUE;
|
||||
int delayticks = USB_DEBOUNCE_TIME / times;
|
||||
if (delayticks < 1)
|
||||
delayticks = 1;
|
||||
|
||||
|
||||
NULL_PARAM_CHECK(hub);
|
||||
|
||||
for(i=0; i<times; i++)
|
||||
{
|
||||
ret = UsbhHubGetPortStatus(hub, port, &pstatus);
|
||||
if(ret != EOK) return ret;
|
||||
|
||||
if(!(pstatus & PORT_CCS))
|
||||
{
|
||||
connect = RET_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
DelayKTask(delayticks);
|
||||
}
|
||||
|
||||
if(connect) return EOK;
|
||||
else return -ERROR;
|
||||
}
|
||||
|
||||
|
||||
static x_err_t UsbhHubPortChange(UhubPointer hub)
|
||||
{
|
||||
int i;
|
||||
x_bool reconnect;
|
||||
|
||||
|
||||
NULL_PARAM_CHECK(hub);
|
||||
|
||||
|
||||
for (i = 0; i < hub->NumPorts; i++)
|
||||
{
|
||||
x_err_t ret;
|
||||
struct uinstance* device;
|
||||
uint32 pstatus = 0;
|
||||
|
||||
reconnect = RET_FALSE;
|
||||
|
||||
|
||||
ret = UsbhHubGetPortStatus(hub, i + 1, &pstatus);
|
||||
if(ret != EOK) continue;
|
||||
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("port %d status 0x%x\n", i + 1, pstatus));
|
||||
|
||||
|
||||
if (pstatus & PORT_CCSC)
|
||||
{
|
||||
|
||||
UsbhHubClearPortFeature(hub, i + 1, PORT_FEAT_C_CONNECTION);
|
||||
reconnect = RET_TRUE;
|
||||
}
|
||||
|
||||
if(pstatus & PORT_PESC)
|
||||
{
|
||||
UsbhHubClearPortFeature(hub, i + 1, PORT_FEAT_C_ENABLE);
|
||||
reconnect = RET_TRUE;
|
||||
}
|
||||
|
||||
if(reconnect)
|
||||
{
|
||||
if(hub->child[i] != NONE && hub->child[i]->status != DEV_STATUS_IDLE)
|
||||
UsbhDetachInstance(hub->child[i]);
|
||||
|
||||
ret = UsbhHubPortDebounce(hub, i + 1);
|
||||
if(ret != EOK) continue;
|
||||
|
||||
|
||||
device = UsbhAllocInstance(hub->hcd);
|
||||
if(device == NONE) break;
|
||||
|
||||
|
||||
device->speed = (pstatus & PORT_LSDA) ? 1 : 0;
|
||||
device->parent_hub = hub;
|
||||
device->hcd = hub->hcd;
|
||||
device->port = i + 1;
|
||||
hub->child[i] = device;
|
||||
|
||||
|
||||
UsbhHubResetPort(hub, i + 1);
|
||||
|
||||
|
||||
UsbhAttatchInstance(device);
|
||||
}
|
||||
}
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
|
||||
static void UsbhHubIrq(void* context)
|
||||
{
|
||||
upipe_t pipe;
|
||||
UhubPointer hub;
|
||||
int timeout = USB_TIMEOUT_BASIC;
|
||||
|
||||
if(NONE == context) {
|
||||
KPrintf("PARAM CHECK FAILED ...%s %d contex is NULL.\n",__FUNCTION__,__LINE__);
|
||||
return;
|
||||
}
|
||||
|
||||
pipe = (upipe_t)context;
|
||||
hub = (UhubPointer)pipe->UserData;
|
||||
|
||||
if(pipe->status != UPIPE_STATUS_OK)
|
||||
{
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB,("hub irq error\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
UsbhHubPortChange(hub);
|
||||
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB,("hub int xfer...\n"));
|
||||
|
||||
|
||||
CHECK(pipe->inst->hcd);
|
||||
|
||||
UsbHcdPipeXfer(hub->self->hcd, pipe, hub->buffer, pipe->ep.wMaxPacketSize, timeout);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static x_err_t UsbhHubEnable(void *arg)
|
||||
{
|
||||
int i = 0;
|
||||
x_err_t ret = EOK;
|
||||
UepDescPointer EpDesc = NONE;
|
||||
UhubPointer hub;
|
||||
struct uinstance* device;
|
||||
struct uhintf* intf = (struct uhintf*)arg;
|
||||
upipe_t pipe_in = NONE;
|
||||
int timeout = USB_TIMEOUT_LONG;
|
||||
|
||||
NULL_PARAM_CHECK(intf);
|
||||
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("usbh_hub_run\n"));
|
||||
|
||||
|
||||
device = intf->device;
|
||||
|
||||
|
||||
hub = x_malloc(sizeof(struct uhub));
|
||||
memset(hub, 0, sizeof(struct uhub));
|
||||
|
||||
|
||||
intf->UserData = (void*)hub;
|
||||
|
||||
|
||||
ret = UsbhHubGetDescriptor(device, (uint8*)&hub->HubDesc, 8);
|
||||
if(ret != EOK)
|
||||
{
|
||||
KPrintf("get hub descriptor failed\n");
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
|
||||
ret = UsbhHubGetDescriptor(device, (uint8*)&hub->HubDesc,
|
||||
hub->HubDesc.length);
|
||||
if(ret != EOK)
|
||||
{
|
||||
KPrintf("get hub descriptor again failed\n");
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
|
||||
hub->NumPorts = hub->HubDesc.NumPorts;
|
||||
hub->hcd = device->hcd;
|
||||
hub->self = device;
|
||||
|
||||
|
||||
for (i = 0; i < hub->NumPorts; i++)
|
||||
{
|
||||
|
||||
UsbhHubSetPortFeature(hub, i + 1, PORT_FEAT_POWER);
|
||||
DelayKTask(hub->HubDesc.PwronToGood
|
||||
|
||||
* 2 * TICK_PER_SECOND / 1000 );
|
||||
}
|
||||
|
||||
if(intf->IntfDesc->bNumEndpoints != 1)
|
||||
return -ERROR;
|
||||
|
||||
|
||||
UsbhGetEndpointDescriptor(intf->IntfDesc, 0, &EpDesc);
|
||||
if(EpDesc == NONE)
|
||||
{
|
||||
KPrintf("usb_get_endpoint_descriptor error\n");
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
|
||||
if( USB_EP_ATTR(EpDesc->bmAttributes) == USB_EP_ATTR_INT)
|
||||
{
|
||||
|
||||
if(EpDesc->bEndpointAddress & USB_DIR_IN)
|
||||
{
|
||||
|
||||
pipe_in = UsbInstanceFindPipe(device,EpDesc->bEndpointAddress);
|
||||
if(pipe_in == NONE)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
UsbPipeAddCallback(pipe_in,UsbhHubIrq);
|
||||
}
|
||||
else return -ERROR;
|
||||
}
|
||||
|
||||
|
||||
NULL_PARAM_CHECK(device->hcd);
|
||||
pipe_in->UserData = hub;
|
||||
UsbHcdPipeXfer(hub->hcd, pipe_in, hub->buffer,
|
||||
pipe_in->ep.wMaxPacketSize, timeout);
|
||||
return EOK;
|
||||
}
|
||||
|
||||
|
||||
static x_err_t UsbhHubDisable(void* arg)
|
||||
{
|
||||
int i;
|
||||
UhubPointer hub;
|
||||
struct uhintf* intf = (struct uhintf*)arg;
|
||||
|
||||
|
||||
NULL_PARAM_CHECK(intf);
|
||||
|
||||
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("usbh_hub_stop\n"));
|
||||
hub = (UhubPointer)intf->UserData;
|
||||
|
||||
for(i=0; i<hub->NumPorts; i++)
|
||||
{
|
||||
if(hub->child[i] != NONE)
|
||||
UsbhDetachInstance(hub->child[i]);
|
||||
}
|
||||
|
||||
if(hub != NONE) x_free(hub);
|
||||
if(intf != NONE) x_free(intf);
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
|
||||
UcdPointer UsbhClassDriverHub(void)
|
||||
{
|
||||
HubDriver.ClassCode = USB_CLASS_HUB;
|
||||
|
||||
HubDriver.enable = UsbhHubEnable;
|
||||
HubDriver.disable = UsbhHubDisable;
|
||||
|
||||
return &HubDriver;
|
||||
}
|
||||
|
||||
|
||||
static void UsbhHubThreadEntry(void* parameter)
|
||||
{
|
||||
while(RET_TRUE)
|
||||
{
|
||||
struct UhostMsg msg;
|
||||
|
||||
|
||||
|
||||
if(KMsgQueueRecv(UsbMq, &msg, sizeof(struct UhostMsg), WAITING_FOREVER)
|
||||
|
||||
!= EOK ) continue;
|
||||
|
||||
|
||||
switch (msg.type)
|
||||
{
|
||||
case USB_MSG_CONNECT_CHANGE:
|
||||
UsbhHubPortChange(msg.content.hub);
|
||||
break;
|
||||
case USB_MSG_CALLBACK:
|
||||
|
||||
msg.content.cb.function(msg.content.cb.context);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
x_err_t UsbhEventSignal(struct UhostMsg* msg)
|
||||
{
|
||||
NULL_PARAM_CHECK(msg);
|
||||
|
||||
|
||||
|
||||
KMsgQueueSend(UsbMq, (void*)msg, sizeof(struct UhostMsg));
|
||||
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
|
||||
void UsbhHubInit(UhcdPointer hcd)
|
||||
{
|
||||
|
||||
int32 thread;
|
||||
|
||||
RootHub.IsRoothub = RET_TRUE;
|
||||
hcd->roothub = &RootHub;
|
||||
RootHub.hcd = hcd;
|
||||
RootHub.NumPorts = hcd->NumPorts;
|
||||
|
||||
UsbMq = KCreateMsgQueue( 32, 16);
|
||||
|
||||
|
||||
thread = KTaskCreate("usbh", UsbhHubThreadEntry, NONE,
|
||||
USB_THREAD_STACK_SIZE, 8);
|
||||
if(thread >= 0)
|
||||
{
|
||||
|
||||
StartupKTask(thread);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-12-12 Yi Qiu first version
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file usbhost.c
|
||||
* @brief support usb host function init
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-25
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: usbhost.c
|
||||
Description: support usb host function init
|
||||
Others: take RT-Thread v4.0.2/components/drivers/usb/usbhost/core/usbhost.c for references
|
||||
https://github.com/RT-Thread/rt-thread/tree/v4.0.2
|
||||
History:
|
||||
1. Date: 2021-04-25
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. support usb host driver init
|
||||
2. support usb bus driver framework
|
||||
*************************************************/
|
||||
|
||||
#include <xiuos.h>
|
||||
#include <usb_host.h>
|
||||
|
||||
#define USB_HOST_CONTROLLER_NAME "usbh"
|
||||
|
||||
x_err_t UsbHostInit(struct uhcd *hcd)
|
||||
{
|
||||
UcdPointer drv;
|
||||
|
||||
UsbhHubInit((UhcdPointer)hcd);
|
||||
|
||||
UsbhClassDriverInit();
|
||||
|
||||
#ifdef USBH_MSTORAGE
|
||||
|
||||
drv = UsbhClassDriverStorage();
|
||||
UsbhClassDriverRegister(drv);
|
||||
#endif
|
||||
|
||||
|
||||
drv = UsbhClassDriverHub();
|
||||
UsbhClassDriverRegister(drv);
|
||||
|
||||
return EOK;
|
||||
}
|
||||
Reference in New Issue
Block a user