提交 070e54a1 编写于 作者: qiuyiuestc's avatar qiuyiuestc

add usbhost stack

git-svn-id: https://rt-thread.googlecode.com/svn/trunk@2154 bbd45198-f89e-11dd-88c7-29a3b14d5316
上级 4b670b08
Import('RTT_ROOT')
from building import *
cwd = GetCurrentDir()
src = Split("""
core/core.c
core/driver.c
core/usbhost.c
core/hub.c
""")
if GetDepend('RT_USB_CLASS_ADK'):
src += Glob('class/adk.c')
src += Glob('udev/adkapp.c')
if GetDepend('RT_USB_CLASS_MASS_STORAGE'):
src += Glob('class/mass.c')
src += Glob('udev/udisk.c')
if GetDepend('RT_USING_CLASS_HID'):
src += Glob('class/hid.c')
if GetDepend('RT_USING_HID_MOUSE'):
src += Glob('udev/umouse.c')
if GetDepend('RT_USB_HID_KEYBOARD'):
src += Glob('udev/ukbd.c')
CPPPATH = [cwd, cwd + '/class', cwd + '/core', \
cwd + '/include', cwd + '../../../include']
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_USB_HOST'], CPPPATH = CPPPATH)
Return('group')
/*
* File : adk.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2011, RT-Thread Development Team
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rt-thread.org/license/LICENSE
*
* Change Logs:
* Date Author Notes
* 2011-12-12 Yi Qiu first version
*/
#include <rtthread.h>
#include <rtdevice.h>
#include "driver.h"
#include "core.h"
#include "hcd.h"
#include "adk.h"
#ifdef RT_USB_CLASS_ADK
static struct uclass_driver adk_driver;
rt_err_t rt_usb_adk_read(uifinst_t ifinst, rt_uint8_t *buffer,
rt_size_t size)
{
uadkinst_t adkinst;
rt_size_t length;
RT_ASSERT(buffer != RT_NULL);
if(ifinst == RT_NULL)
{
rt_kprintf("the interface is not available\n");
return -RT_EIO;
}
/* get storage instance from the interface instance */
adkinst = (uadkinst_t)ifinst->user_data;
/* send the cbw */
length = rt_usb_hcd_bulk_xfer(ifinst->uinst->hcd, adkinst->pipe_in,
buffer, size, 300);
return length;
}
rt_err_t rt_usb_adk_write(uifinst_t ifinst, rt_uint8_t *buffer,
rt_size_t size)
{
uadkinst_t adkinst;
rt_size_t length;
RT_ASSERT(buffer != RT_NULL);
if(ifinst == RT_NULL)
{
rt_kprintf("the interface is not available\n");
return -RT_EIO;
}
/* get storage instance from the interface instance */
adkinst = (uadkinst_t)ifinst->user_data;
/* send the cbw */
length = rt_usb_hcd_bulk_xfer(ifinst->uinst->hcd, adkinst->pipe_out,
buffer, size, 300);
return length;
}
/**
* This function will run adk class driver when usb device is detected and identified
* as a adk class device, it will continue the enumulate process.
*
* @param arg the argument.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usb_adk_run(void* arg)
{
int i = 0;
uadkinst_t adkinst;
uifinst_t ifinst = (uifinst_t)arg;
rt_err_t ret;
/* parameter check */
if(ifinst == RT_NULL)
{
rt_kprintf("the interface is not available\n");
return -RT_EIO;
}
RT_DEBUG_LOG(RT_DEBUG_USB,("rt_usb_adk_run\n"));
adkinst = rt_malloc(sizeof(struct uadkinst));
RT_ASSERT(adkinst != RT_NULL);
/* initilize the data structure */
rt_memset(adkinst, 0, sizeof(struct uadkinst));
ifinst->user_data = (void*)adkinst;
for(i=0; i<ifinst->intf_desc->bNumEndpoints; i++)
{
uep_desc_t ep_desc;
/* get endpoint descriptor from interface descriptor */
rt_usb_get_endpoint_descriptor(ifinst->intf_desc, i, &ep_desc);
if(ep_desc == RT_NULL)
{
rt_kprintf("rt_usb_get_endpoint_descriptor error\n");
return -RT_ERROR;
}
/* the endpoint type of adk class should be BULK */
if((ep_desc->bmAttributes & USB_EP_ATTR_TYPE_MASK) != USB_EP_ATTR_BULK)
continue;
/* allocate pipes according to the endpoint type */
if(ep_desc->bEndpointAddress & USB_DIR_IN)
{
/* allocate an in pipe for the adk instance */
ret = rt_usb_hcd_alloc_pipe(ifinst->uinst->hcd, &adkinst->pipe_in,
ifinst, ep_desc, RT_NULL);
if(ret != RT_EOK) return ret;
}
else
{
/* allocate an output pipe for the adk instance */
ret = rt_usb_hcd_alloc_pipe(ifinst->uinst->hcd, &adkinst->pipe_out,
ifinst, ep_desc, RT_NULL);
if(ret != RT_EOK) return ret;
}
}
/* check pipes infomation */
if(adkinst->pipe_in == RT_NULL || adkinst->pipe_out == RT_NULL)
{
rt_kprintf("pipe error, unsupported device\n");
return -RT_ERROR;
}
return RT_EOK;
}
/**
* This function will be invoked when usb device plug out is detected and it would clean
* and release all hub class related resources.
*
* @param arg the argument.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usb_adk_stop(void* arg)
{
uadkinst_t adkinst;
uifinst_t ifinst = (uifinst_t)arg;
RT_ASSERT(ifinst != RT_NULL);
RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usb_adk_stop\n"));
adkinst = (uadkinst_t)ifinst->user_data;
if(adkinst->pipe_in != RT_NULL)
rt_usb_hcd_free_pipe(ifinst->uinst->hcd, adkinst->pipe_in);
/* free adk instance */
if(adkinst != RT_NULL) rt_free(adkinst);
/* free interface instance */
if(ifinst != RT_NULL) rt_free(ifinst);
return RT_EOK;
}
/**
* This function will register adk class driver to the usb class driver manager.
* and it should be invoked in the usb system initialization.
*
* @return the error code, RT_EOK on successfully.
*/
ucd_t rt_usb_class_driver_adk(void)
{
adk_driver.class_code = USB_CLASS_ADK;
adk_driver.run = rt_usb_adk_run;
adk_driver.stop = rt_usb_adk_stop;
return &adk_driver;
}
#endif
/*
* File : adk.h
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2011, RT-Thread Development Team
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rt-thread.org/license/LICENSE
*
* Change Logs:
* Date Author Notes
* 2011-12-12 Yi Qiu first version
*/
#ifndef __HID_H__
#define __HID_H__
#include <rtthread.h>
struct uadkinst
{
upipe_t pipe_in;
upipe_t pipe_out;
};
typedef struct uadkinst* uadkinst_t;
#define USB_CLASS_ADK 0xff
#endif
/*
* File : core.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2011, RT-Thread Development Team
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rt-thread.org/license/LICENSE
*
* Change Logs:
* Date Author Notes
* 2011-12-12 Yi Qiu first version
*/
#include <rtthread.h>
#include "usbhost.h"
#include "core.h"
#include "driver.h"
#include "hcd.h"
#include "hub.h"
static struct uinstance uinst[USB_MAX_DEVICE];
/**
* This function will allocate an usb device instance from system.
*
* @param parent the hub instance to which the new allocated device attached.
* @param port the hub port.
*
* @return the allocate instance on successful, or RT_NULL on failure.
*/
uinst_t rt_usb_alloc_instance(void)
{
int i;
/* lock scheduler */
rt_enter_critical();
for(i=0; i<USB_MAX_DEVICE; i++)
{
/* to find an idle instance handle */
if(uinst[i].status != UINST_STATUS_IDLE) continue;
/* initialize the usb device instance */
rt_memset(&uinst[i], 0, sizeof(struct uinstance));
uinst[i].status = UINST_STATUS_BUSY;
uinst[i].index = i + 1;
uinst[i].address = 0;
uinst[i].max_packet_size = 0x8;
/* unlock scheduler */
rt_exit_critical();
return &uinst[i];
}
/* unlock scheduler */
rt_exit_critical();
return RT_NULL;
}
/**
* This function will attatch an usb device instance to a host controller,
* and do device enumunation process.
*
* @param hcd the host controller driver.
* @param uinst the usb device instance.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usb_attatch_instance(uinst_t uinst)
{
int i = 0;
rt_err_t ret = RT_EOK;
struct uconfig_descriptor cfg_desc;
udev_desc_t dev_desc;
uintf_desc_t intf_desc;
ucd_t drv;
RT_ASSERT(uinst != RT_NULL);
rt_memset(&cfg_desc, 0, sizeof(struct uconfig_descriptor));
dev_desc = &uinst->dev_desc;
/* get device descriptor head */
ret = rt_usb_get_descriptor(uinst, USB_DESC_TYPE_DEVICE, (void*)dev_desc, 8);
if(ret != RT_EOK)
{
rt_kprintf("get device descriptor head failed\n");
return ret;
}
/* set device address */
ret = rt_usb_set_address(uinst);
if(ret != RT_EOK)
{
rt_kprintf("set device address failed\n");
return ret;
}
/* set device max packet size */
uinst->max_packet_size = uinst->dev_desc.bMaxPacketSize0;
RT_DEBUG_LOG(RT_DEBUG_USB, ("get device descriptor length %d\n",
dev_desc->bLength));
/* get full device descriptor again */
ret = rt_usb_get_descriptor
(uinst, USB_DESC_TYPE_DEVICE, (void*)dev_desc, dev_desc->bLength);
if(ret != RT_EOK)
{
rt_kprintf("get full device descriptor failed\n");
return ret;
}
/* get configuration descriptor head */
ret = rt_usb_get_descriptor(uinst, USB_DESC_TYPE_CONFIGURATION, &cfg_desc,
sizeof(struct uconfig_descriptor));
if(ret != RT_EOK)
{
rt_kprintf("get configuration descriptor head failed\n");
return ret;
}
/* alloc memory for configuration descriptor */
uinst->cfg_desc = (ucfg_desc_t)rt_malloc(cfg_desc.wTotalLength);
rt_memset(uinst->cfg_desc, 0, cfg_desc.wTotalLength);
/* get full configuration descriptor */
ret = rt_usb_get_descriptor(uinst, USB_DESC_TYPE_CONFIGURATION,
uinst->cfg_desc, cfg_desc.wTotalLength);
if(ret != RT_EOK)
{
rt_kprintf("get full configuration descriptor failed\n");
return ret;
}
/* set configuration */
ret = rt_usb_set_configure(uinst, 1);
if(ret != RT_EOK) return ret;
//for(i=0; i<uinst->cfg_desc->bNumInterfaces; i++)
{
/* get interface descriptor through configuration descriptor */
ret = rt_usb_get_interface_descriptor(uinst->cfg_desc, i, &intf_desc);
if(ret != RT_EOK)
{
rt_kprintf("rt_usb_get_interface_descriptor error\n");
return -RT_ERROR;
}
/* find driver by class code found in interface descriptor */
drv = rt_usb_class_driver_find(intf_desc->bInterfaceClass,
intf_desc->bInterfaceSubClass);
if(drv != RT_NULL)
{
/* allocate memory for interface uinst */
uinst->ifinst[i] =
(uifinst_t)rt_malloc(sizeof(struct uifinst));
uinst->ifinst[i]->drv = drv;
uinst->ifinst[i]->uinst = uinst;
uinst->ifinst[i]->intf_desc = intf_desc;
/* open usb class driver */
ret = rt_usb_class_driver_run(drv, (void*)uinst->ifinst[i]);
if(ret != RT_EOK)
{
rt_kprintf("interface %d run class driver error\n", i);
}
}
else
{
rt_kprintf("find usb device driver failed\n");
return -RT_ERROR;
}
}
return RT_EOK;
}
/**
* This function will detach an usb device instance from its host controller,
* and release all resource.
*
* @param uinst the usb device instance.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usb_detach_instance(uinst_t uinst)
{
int i = 0;
if(uinst == RT_NULL)
{
rt_kprintf("no usb instance to detach\n");
return -RT_ERROR;
}
/* free configration descriptor */
if(uinst->cfg_desc) rt_free(uinst->cfg_desc);
for(i=0; i<uinst->cfg_desc->bNumInterfaces; i++)
{
if(uinst->ifinst[i] == RT_NULL) continue;
if(uinst->ifinst[i]->drv == RT_NULL) continue;
RT_ASSERT(uinst->ifinst[i]->uinst == uinst);
RT_DEBUG_LOG(RT_DEBUG_USB, ("free interface instance %d\n", i));
rt_usb_class_driver_stop(uinst->ifinst[i]->drv, (void*)uinst->ifinst[i]);
}
rt_memset(uinst, 0, sizeof(struct uinstance));
return RT_EOK;
}
/**
* This function will do USB_REQ_GET_DESCRIPTO' request for the usb device instance,
*
* @param uinst the usb device instance.
* @param type the type of descriptor request.
* @param buffer the data buffer to save requested data
* @param nbytes the size of buffer
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usb_get_descriptor(uinst_t uinst, rt_uint8_t type, void* buffer,
int nbytes)
{
struct ureqest setup;
int timeout = 100;
RT_ASSERT(uinst != RT_NULL);
setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_STANDARD |
USB_REQ_TYPE_DEVICE;
setup.request = USB_REQ_GET_DESCRIPTOR;
setup.index = 0;
setup.length = nbytes;
setup.value = type << 8;
if(rt_usb_hcd_control_xfer(uinst->hcd, uinst, &setup, buffer, nbytes,
timeout) != nbytes) return -RT_EIO;
else return RT_EOK;
}
/**
* This function will set an address to the usb device.
*
* @param uinst the usb device instance.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usb_set_address(uinst_t uinst)
{
struct ureqest setup;
int timeout = 100;
RT_ASSERT(uinst != RT_NULL);
RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usb_set_address\n"));
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD |
USB_REQ_TYPE_DEVICE;
setup.request = USB_REQ_SET_ADDRESS;
setup.index = 0;
setup.length = 0;
setup.value = uinst->index;
if(rt_usb_hcd_control_xfer(uinst->hcd, uinst, &setup, RT_NULL, 0,
timeout) != 0) return -RT_EIO;
rt_thread_delay(50);
uinst->address = uinst->index;
return RT_EOK;
}
/**
* This function will set a configuration to the usb device.
*
* @param uinst the usb device instance.
* @param config the configuration number.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usb_set_configure(uinst_t uinst, int config)
{
struct ureqest setup;
int timeout = 100;
/* check parameter */
RT_ASSERT(uinst != RT_NULL);
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD |
USB_REQ_TYPE_DEVICE;
setup.request = USB_REQ_SET_CONFIGURATION;
setup.index = 0;
setup.length = 0;
setup.value = config;
if(rt_usb_hcd_control_xfer(uinst->hcd, uinst, &setup, RT_NULL, 0,
timeout) != 0) return -RT_EIO;
return RT_EOK;
}
/**
* This function will set an interface to the usb device.
*
* @param uinst the usb device instance.
* @param intf the interface number.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usb_set_interface(uinst_t uinst, int intf)
{
struct ureqest setup;
int timeout = 100;
/* check parameter */
RT_ASSERT(uinst != RT_NULL);
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD |
USB_REQ_TYPE_INTERFACE;
setup.request = USB_REQ_SET_INTERFACE;
setup.index = 0;
setup.length = 0;
setup.value = intf;
if(rt_usb_hcd_control_xfer(uinst->hcd, uinst, &setup, RT_NULL, 0,
timeout) != 0) return -RT_EIO;
return RT_EOK;
}
/**
* This function will clear feature for the endpoint of the usb device.
*
* @param uinst the usb device instance.
* @param endpoint the endpoint number of the usb device.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usb_clear_feature(uinst_t uinst, int endpoint, int feature)
{
struct ureqest setup;
int timeout = 100;
/* check parameter */
RT_ASSERT(uinst != RT_NULL);
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD |
USB_REQ_TYPE_ENDPOINT;
setup.request = USB_REQ_CLEAR_FEATURE;
setup.index = endpoint;
setup.length = 0;
setup.value = feature;
if(rt_usb_hcd_control_xfer(uinst->hcd, uinst, &setup, RT_NULL, 0,
timeout) != 0) return -RT_EIO;
return RT_EOK;
}
/**
* This function will get an interface descriptor from the configuration descriptor.
*
* @param cfg_desc the point of configuration descriptor structure.
* @param num the number of interface descriptor.
* @intf_desc the point of interface descriptor point.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usb_get_interface_descriptor(ucfg_desc_t cfg_desc, int num,
uintf_desc_t* intf_desc)
{
rt_uint32_t ptr, depth = 0;
udesc_t desc;
/* check parameter */
RT_ASSERT(cfg_desc != RT_NULL);
ptr = (rt_uint32_t)cfg_desc + cfg_desc->bLength;
while(ptr < (rt_uint32_t)cfg_desc + cfg_desc->wTotalLength)
{
if(depth++ > 0x20)
{
*intf_desc = RT_NULL;
return -RT_EIO;
}
desc = (udesc_t)ptr;
if(desc->type == USB_DESC_TYPE_INTERFACE)
{
if(((uintf_desc_t)desc)->bInterfaceNumber == num)
{
*intf_desc = (uintf_desc_t)desc;
RT_DEBUG_LOG(RT_DEBUG_USB,
("rt_usb_get_interface_descriptor: %d\n", num));
return RT_EOK;
}
}
ptr = (rt_uint32_t)desc + desc->bLength;
}
rt_kprintf("rt_usb_get_interface_descriptor %d failed\n", num);
return -RT_EIO;
}
/**
* This function will get an endpoint descriptor from the interface descriptor.
*
* @param intf_desc the point of interface descriptor structure.
* @param num the number of endpoint descriptor.
* @param ep_desc the point of endpoint descriptor point.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usb_get_endpoint_descriptor(uintf_desc_t intf_desc, int num,
uep_desc_t* ep_desc)
{
int count = 0, depth = 0;
rt_uint32_t ptr;
udesc_t desc;
/* check parameter */
RT_ASSERT(intf_desc != RT_NULL);
RT_ASSERT(num < intf_desc->bNumEndpoints);
ptr = (rt_uint32_t)intf_desc + intf_desc->bLength;
while(count < intf_desc->bNumEndpoints)
{
if(depth++ > 0x20)
{
*ep_desc = RT_NULL;
return -RT_EIO;
}
desc = (udesc_t)ptr;
if(desc->type == USB_DESC_TYPE_ENDPOINT)
{
if(num == count)
{
*ep_desc = (uep_desc_t)desc;
RT_DEBUG_LOG(RT_DEBUG_USB,
("rt_usb_get_endpoint_descriptor: %d\n", num));
return RT_EOK;
}
else count++;
}
ptr = (rt_uint32_t)desc + desc->bLength;
}
rt_kprintf("rt_usb_get_endpoint_descriptor %d failed\n", num);
return -RT_EIO;
}
/*
* File : core.h
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2011, RT-Thread Development Team
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rt-thread.org/license/LICENSE
*
* Change Logs:
* Date Author Notes
* 2011-12-12 Yi Qiu first version
*/
#ifndef __CORE_H__
#define __CORE_H__
#include <rtthread.h>
#include "usbspec.h"
#include "usbhost.h"
#define USB_MAX_DEVICE 32
#define USB_MAX_INTERFACE 8
#define PORT_NUM 4
#define SIZEOF_USB_REQUEST 8
struct uhcd;
struct uifinst;
struct uhubinst;
typedef void (*func_callback)(void *context);
enum umsg_type
{
USB_MSG_CONNECT_CHANGE,
USB_MSG_CALLBACK,
};
typedef enum umsg_type umsg_type;
#define UINST_STATUS_IDLE 0
#define UINST_STATUS_BUSY 1
#define UINST_STATUS_ERROR 2
struct uinstance
{
struct udevice_descriptor dev_desc;
ucfg_desc_t cfg_desc;
struct uhcd *hcd;
rt_uint8_t status;
rt_uint8_t type;
rt_uint8_t index;
rt_uint8_t address;
rt_uint8_t speed;
rt_uint8_t max_packet_size;
rt_uint8_t port;
struct uhubinst* parent;
struct uifinst* ifinst[USB_MAX_INTERFACE];
};
typedef struct uinstance* uinst_t;
struct uifinst
{
uinst_t uinst;
uintf_desc_t intf_desc;
ucd_t drv;
void *user_data;
};
typedef struct uifinst* uifinst_t;
#define UPIPE_STATUS_OK 0
#define UPIPE_STATUS_STALL 1
#define UPIPE_STATUS_ERROR 2
struct upipe
{
rt_uint32_t status;
struct uendpoint_descriptor ep;
uifinst_t ifinst;
func_callback callback;
void* user_data;
};
typedef struct upipe* upipe_t;
struct umsg
{
umsg_type type;
union
{
struct uhubinst* uhub;
struct
{
func_callback function;
void *context;
}cb;
}content;
};
typedef struct umsg* umsg_t;
uinst_t rt_usb_alloc_instance(void);
rt_err_t rt_usb_attatch_instance(uinst_t uinst);
rt_err_t rt_usb_detach_instance(uinst_t uinst);
rt_err_t rt_usb_get_descriptor(uinst_t uinst, rt_uint8_t type, void* buffer,
int nbytes);
rt_err_t rt_usb_set_configure(uinst_t uinst, int config);
rt_err_t rt_usb_set_address(uinst_t uinst);
rt_err_t rt_usb_set_interface(uinst_t uinst, int intf);
rt_err_t rt_usb_clear_feature(uinst_t uinst, int endpoint, int feature);
rt_err_t rt_usb_get_interface_descriptor(ucfg_desc_t cfg_desc, int num,
uintf_desc_t* intf_desc);
rt_err_t rt_usb_get_endpoint_descriptor(uintf_desc_t intf_desc, int num,
uep_desc_t* ep_desc);
#endif
/*
* File : driver.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2011, RT-Thread Development Team
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rt-thread.org/license/LICENSE
*
* Change Logs:
* Date Author Notes
* 2011-03-12 Yi Qiu first version
*/
#include <rtthread.h>
#include <rtdevice.h>
#include "driver.h"
static rt_list_t _driver_list;
/**
* This function will initilize the usb class driver related data structure,
* and it should be invoked in the usb system initialization.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usb_class_driver_init(void)
{
rt_list_init(&_driver_list);
return RT_EOK;
}
/**
* This function will register an usb class driver to the class driver manager.
*
* @param drv the pointer of the usb class driver.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usb_class_driver_register(ucd_t drv)
{
RT_ASSERT(drv != RT_NULL);
if (drv == RT_NULL) return -RT_ERROR;
/* insert class driver into driver list */
rt_list_insert_after(&_driver_list, &(drv->list));
return RT_EOK;
}
/**
* This function will removes a previously registed usb class driver.
*
* @param drv the pointer of the usb class driver structure.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usb_class_driver_unregister(ucd_t drv)
{
RT_ASSERT(drv != RT_NULL);
/* remove class driver from driver list */
rt_list_remove(&(drv->list));
return RT_EOK;
}
/**
* This function will run an usb class driver.
*
* @param drv the pointer of usb class driver.
* @param args the parameter of run function.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usb_class_driver_run(ucd_t drv, void* args)
{
RT_ASSERT(drv != RT_NULL);
if(drv->run != RT_NULL)
drv->run(args);
return RT_EOK;
}
/**
* This function will stop a usb class driver.
*
* @param drv the pointer of usb class driver structure.
* @param args the argument of the stop function.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usb_class_driver_stop(ucd_t drv, void* args)
{
RT_ASSERT(drv != RT_NULL);
if(drv->stop != RT_NULL)
drv->stop(args);
return RT_EOK;
}
/**
* This function finds a usb class driver by specified class code and subclass code.
*
* @param class_code the usb class driver's class code.
* @param subclass_code the usb class driver's sub class code.
*
* @return the registered usb class driver on successful, or RT_NULL on failure.
*/
ucd_t rt_usb_class_driver_find(int class_code, int subclass_code)
{
struct rt_list_node *node;
/* enter critical */
if (rt_thread_self() != RT_NULL)
rt_enter_critical();
/* try to find driver object */
for (node = _driver_list.next; node != &_driver_list; node = node->next)
{
ucd_t drv =
(ucd_t)rt_list_entry(node, struct uclass_driver, list);
if (drv->class_code == class_code)
{
/* leave critical */
if (rt_thread_self() != RT_NULL)
rt_exit_critical();
return drv;
}
}
/* leave critical */
if (rt_thread_self() != RT_NULL)
rt_exit_critical();
/* not found */
return RT_NULL;
}
/*
* File : hub.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2011, RT-Thread Development Team
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rt-thread.org/license/LICENSE
*
* Change Logs:
* Date Author Notes
* 2011-12-12 Yi Qiu first version
*/
#include <rtthread.h>
#include "core.h"
#include "hcd.h"
#include "hub.h"
#define USB_THREAD_STACK_SIZE 2048
static struct rt_messagequeue *usb_mq;
static struct uclass_driver hub_driver;
/**
* This function will do USB_REQ_GET_DESCRIPTOR request for the device instance
* to get usb hub descriptor.
*
* @param ifinst the interface instance.
* @buffer the data buffer to save usb hub descriptor.
* @param nbytes the size of buffer
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usb_hub_get_descriptor(uinst_t uinst, rt_uint8_t *buffer,
rt_size_t nbytes)
{
struct ureqest setup;
int timeout = 100;
/* parameter check */
RT_ASSERT(uinst != RT_NULL);
setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS |
USB_REQ_TYPE_DEVICE;
setup.request = USB_REQ_GET_DESCRIPTOR;
setup.index = 0;
setup.length = nbytes;
setup.value = USB_DESC_TYPE_HUB << 8;
if(rt_usb_hcd_control_xfer(uinst->hcd, uinst, &setup, buffer, nbytes,
timeout) == nbytes) return RT_EOK;
else return -RT_FALSE;
}
/**
* This function will do USB_REQ_GET_STATUS request for the device instance
* to get usb hub status.
*
* @param ifinst the interface instance.
* @buffer the data buffer to save usb hub status.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usb_hub_get_status(uinst_t uinst, rt_uint8_t* buffer)
{
struct ureqest setup;
int timeout = 100;
int length = 4;
/* parameter check */
RT_ASSERT(uinst != RT_NULL);
setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS |
USB_REQ_TYPE_DEVICE;
setup.request = USB_REQ_GET_STATUS;
setup.index = 0;
setup.length = length;
setup.value = 0;
if(rt_usb_hcd_control_xfer(uinst->hcd, uinst, &setup, buffer, length,
timeout) == length) return RT_EOK;
else return -RT_FALSE;
}
/**
* This function will do USB_REQ_GET_STATUS request for the device instance
* to get hub port status.
*
* @param ifinst the interface instance.
* @port the hub port to get status.
* @buffer the data buffer to save usb hub status.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usb_hub_get_port_status(uhubinst_t uhub, rt_uint16_t port,
rt_uint8_t* buffer)
{
struct ureqest setup;
int timeout = 100;
int length = 4;
/* parameter check */
RT_ASSERT(uhub != RT_NULL);
/* get roothub port status */
if(uhub->is_roothub)
{
rt_usb_hcd_hub_control(uhub->hcd, port, RH_GET_PORT_STATUS,
(void*)buffer);
return RT_EOK;
}
setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS |
USB_REQ_TYPE_OTHER;
setup.request = USB_REQ_GET_STATUS;
setup.index = port;
setup.length = 4;
setup.value = 0;
if(rt_usb_hcd_control_xfer(uhub->hcd, uhub->self, &setup, buffer,
length, timeout) == timeout) return RT_EOK;
else return -RT_FALSE;
}
/**
* This function will do USB_REQ_CLEAR_FEATURE request for the device instance
* to clear feature of the hub port.
*
* @param ifinst the interface instance.
* @port the hub port.
* @feature feature to be cleared.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usb_hub_clear_port_feature(uhubinst_t uhub, rt_uint16_t port,
rt_uint16_t feature)
{
struct ureqest setup;
int timeout = 100;
/* parameter check */
RT_ASSERT(uhub != RT_NULL);
/* clear roothub feature */
if(uhub->is_roothub)
{
rt_usb_hcd_hub_control(uhub->hcd, port, RH_CLEAR_PORT_FEATURE,
(void*)feature);
return RT_EOK;
}
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
USB_REQ_TYPE_OTHER;
setup.request = USB_REQ_CLEAR_FEATURE;
setup.index = port;
setup.length = 0;
setup.value = feature;
if(rt_usb_hcd_control_xfer(uhub->hcd, uhub->self, &setup, RT_NULL, 0,
timeout) == 0) return RT_EOK;
else return -RT_FALSE;
}
/**
* This function will do USB_REQ_SET_FEATURE request for the device instance
* to set feature of the hub port.
*
* @param ifinst the interface instance.
* @port the hub port.
* @feature feature to be set.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usb_hub_set_port_feature(uhubinst_t uhub, rt_uint16_t port,
rt_uint16_t feature)
{
struct ureqest setup;
int timeout = 100;
/* parameter check */
RT_ASSERT(uhub != RT_NULL);
/* clear roothub feature */
if(uhub->is_roothub)
{
rt_usb_hcd_hub_control(uhub->hcd, port, RH_SET_PORT_FEATURE,
(void*)feature);
return RT_EOK;
}
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
USB_REQ_TYPE_OTHER;
setup.request = USB_REQ_SET_FEATURE;
setup.index = port;
setup.length = 0;
setup.value = feature;
if(rt_usb_hcd_control_xfer(uhub->hcd, uhub->self, &setup, RT_NULL, 0,
timeout) == 0) return RT_EOK;
else return -RT_FALSE;
}
/**
* This function will rest hub port, it is invoked when sub device attached to the hub port.
*
* @param ifinst the interface instance.
* @param port the hub port.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usb_hub_reset_port(uhubinst_t uhub, rt_uint16_t port)
{
rt_err_t ret;
rt_uint32_t pstatus;
/* parameter check */
RT_ASSERT(uhub != RT_NULL);
rt_thread_delay(50);
/* reset hub port */
ret = rt_usb_hub_set_port_feature(uhub, port, PORT_FEAT_RESET);
if(ret != RT_EOK) return ret;
while(1)
{
ret = rt_usb_hub_get_port_status(uhub, port, (rt_uint8_t*)&pstatus);
if(!(pstatus & PORT_PRS)) break;
}
/* clear port reset feature */
ret = rt_usb_hub_clear_port_feature(uhub, port, PORT_FEAT_C_RESET);
if(ret != RT_EOK) return ret;
rt_thread_delay(50);
return RT_EOK;
}
/**
* This function will do debouce, it is invoked when sub device attached to the hub port.
*
* @param uinst the usb instance.
* @param port the hub port.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usb_hub_port_debounce(uhubinst_t uhub, rt_uint16_t port)
{
rt_err_t ret;
int i = 0, times = 20;
rt_uint32_t pstatus;
rt_bool_t connect = RT_TRUE;
/* parameter check */
RT_ASSERT(uhub != RT_NULL);
for(i=0; i<times; i++)
{
ret = rt_usb_hub_get_port_status(uhub, port, (rt_uint8_t*)&pstatus);
if(ret != RT_EOK) return ret;
if(!(pstatus & PORT_CCS))
{
connect = RT_FALSE;
break;
}
rt_thread_delay(1);
}
if(connect) return RT_EOK;
else return -RT_ERROR;
}
/**
* This function will poll all the hub ports to detect port status, especially connect and
* disconnect events.
*
* @param ifinst the interface instance.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usb_hub_port_change(uhubinst_t uhub)
{
int i;
rt_bool_t reconnect;
/* parameter check */
RT_ASSERT(uhub != RT_NULL);
/* get usb device instance */
for (i = 0; i < uhub->num_ports; i++)
{
rt_err_t ret;
uinst_t uinst;
rt_uint32_t pstatus = 0;
reconnect = RT_FALSE;
/* get hub port status */
ret = rt_usb_hub_get_port_status(uhub, i + 1, (rt_uint8_t*)&pstatus);
if(ret != RT_EOK) continue;
RT_DEBUG_LOG(RT_DEBUG_USB, ("port_status 0x%x\n", pstatus));
/* check port status change */
if ((pstatus & PORT_CCSC))
{
/* clear port status change feature */
rt_usb_hub_clear_port_feature(uhub, i + 1, PORT_FEAT_C_CONNECTION);
reconnect = RT_TRUE;
}
if(pstatus & PORT_PESC)
{
rt_usb_hub_clear_port_feature(uhub, i + 1, PORT_FEAT_C_ENABLE);
reconnect = RT_TRUE;
}
if(reconnect)
{
if(uhub->child[i])
rt_usb_detach_instance(uhub->child[i]);
ret = rt_usb_hub_port_debounce(uhub, i + 1);
if(ret != RT_EOK) continue;
/* allocate an usb instance for new connected device */
uinst = rt_usb_alloc_instance();
if(uinst == RT_NULL) break;
/* set usb device speed */
uinst->speed = (pstatus & PORT_LSDA) ? 1 : 0;
uinst->parent = uhub;
uinst->hcd = uhub->hcd;
uhub->child[i] = uinst;
/* reset usb roothub port */
rt_usb_hub_reset_port(uhub, i + 1);
/* attatch the usb instance to the hcd */
rt_usb_attatch_instance(uinst);
}
}
return RT_EOK;
}
/**
* This function is the callback function of hub's int endpoint, it is invoked when data comes.
*
* @param context the context of the callback function.
*
* @return none.
*/
static void rt_usb_hub_irq(void* context)
{
upipe_t pipe;
uifinst_t ifinst;
uhubinst_t uhub;
int timeout = 100;
RT_ASSERT(context != RT_NULL);
pipe = (upipe_t)context;
ifinst = pipe->ifinst;
uhub = (uhubinst_t)ifinst->user_data;
if(pipe->status != UPIPE_STATUS_OK)
{
rt_kprintf("hub irq error\n");
return;
}
rt_usb_hub_port_change(uhub);
rt_kprintf("hub int xfer...\n");
/* parameter check */
RT_ASSERT(pipe->ifinst->uinst->hcd != RT_NULL);
rt_usb_hcd_int_xfer(ifinst->uinst->hcd, pipe, uhub->buffer,
pipe->ep.wMaxPacketSize, timeout);
}
/**
* This function will run usb hub class driver when usb hub is detected and identified
* as a hub class device, it will continue to do the enumulate process.
*
* @param arg the argument.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usb_hub_run(void *arg)
{
int i = 0;
rt_err_t ret = RT_EOK;
uep_desc_t ep_desc;
uhubinst_t uhub;
uinst_t uinst;
uifinst_t ifinst = (uifinst_t)arg;
int timeout = 300;
/* paremeter check */
RT_ASSERT(ifinst != RT_NULL);
RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usb_hub_run\n"));
/* get usb device instance */
uinst = ifinst->uinst;
/* create a hub instance */
uhub = rt_malloc(sizeof(struct uhubinst));
rt_memset(uhub, 0, sizeof(struct uhubinst));
/* make interface instance's user data point to hub instance */
ifinst->user_data = (void*)uhub;
/* get hub descriptor head */
ret = rt_usb_hub_get_descriptor(uinst, (rt_uint8_t*)&uhub->hub_desc, 8);
if(ret != RT_EOK)
{
rt_kprintf("get hub descriptor failed\n");
return -RT_ERROR;
}
/* get full hub descriptor */
ret = rt_usb_hub_get_descriptor(uinst, (rt_uint8_t*)&uhub->hub_desc,
uhub->hub_desc.length);
if(ret != RT_EOK)
{
rt_kprintf("get hub descriptor again failed\n");
return -RT_ERROR;
}
/* get hub ports number */
uhub->num_ports = uhub->hub_desc.num_ports;
uhub->hcd = uinst->hcd;
uhub->self = uinst;
/* reset all hub ports */
for (i = 0; i < uhub->num_ports; i++)
{
rt_usb_hub_set_port_feature(uhub, i + 1, PORT_FEAT_POWER);
rt_thread_delay(uhub->hub_desc.pwron_to_good
* 2 * RT_TICK_PER_SECOND / 1000 );
}
if(ifinst->intf_desc->bNumEndpoints != 1)
return -RT_ERROR;
/* get endpoint descriptor from interface descriptor */
rt_usb_get_endpoint_descriptor(ifinst->intf_desc, 0, &ep_desc);
if(ep_desc == RT_NULL)
{
rt_kprintf("rt_usb_get_endpoint_descriptor error\n");
return -RT_ERROR;
}
/* the endpoint type of hub class should be interrupt */
if( USB_EP_ATTR(ep_desc->bmAttributes) == USB_EP_ATTR_INT)
{
/* the endpoint direction of hub class should be in */
if(ep_desc->bEndpointAddress & USB_DIR_IN)
{
/* allocate a pipe according to the endpoint type */
rt_usb_hcd_alloc_pipe(uinst->hcd, &uhub->pipe_in, ifinst,
ep_desc, rt_usb_hub_irq);
}
else return -RT_ERROR;
}
/* parameter check */
RT_ASSERT(uinst->hcd != RT_NULL);
rt_usb_hcd_int_xfer(uinst->hcd, uhub->pipe_in, uhub->buffer,
uhub->pipe_in->ep.wMaxPacketSize, timeout);
return RT_EOK;
}
/**
* This function will be invoked when usb hub plug out is detected and it would clean
* and release all hub class related resources.
*
* @param arg the argument.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usb_hub_stop(void* arg)
{
int i;
uhubinst_t uhub;
uinst_t uinst;
uifinst_t ifinst = (uifinst_t)arg;
/* paremeter check */
RT_ASSERT(ifinst != RT_NULL);
RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usb_hub_stop\n"));
uinst = ifinst->uinst;
uhub = (uhubinst_t)ifinst->user_data;
if(uhub->pipe_in != RT_NULL)
rt_usb_hcd_free_pipe(uinst->hcd, uhub->pipe_in);
for(i=0; i<uhub->num_ports; i++)
{
if(uhub->child[i] != RT_NULL)
rt_usb_detach_instance(uhub->child[i]);
}
if(uhub != RT_NULL) rt_free(uhub);
if(ifinst != RT_NULL) rt_free(ifinst);
return RT_EOK;
}
/**
* This function will register hub class driver to the usb class driver manager.
* and it should be invoked in the usb system initialization.
*
* @return the error code, RT_EOK on successfully.
*/
ucd_t rt_usb_class_driver_hub(void)
{
hub_driver.class_code = USB_CLASS_HUB;
hub_driver.run = rt_usb_hub_run;
hub_driver.stop = rt_usb_hub_stop;
return &hub_driver;
}
/**
* This function is the main entry of usb hub thread, it is in charge of
* processing all messages received from the usb message buffer.
*
* @param parameter the parameter of the usb host thread.
*
* @return none.
*/
static void rt_usb_hub_thread_entry(void* parameter)
{
while(1)
{
struct umsg msg;
/* receive message */
if(rt_mq_recv(usb_mq, &msg, sizeof(struct umsg), RT_WAITING_FOREVER)
!= RT_EOK ) continue;
RT_DEBUG_LOG(RT_DEBUG_USB, ("msg type %d\n", msg.type));
switch (msg.type)
{
case USB_MSG_CONNECT_CHANGE:
rt_usb_hub_port_change(msg.content.uhub);
break;
case USB_MSG_CALLBACK:
/* invoke callback */
msg.content.cb.function(msg.content.cb.context);
break;
default:
break;
}
}
}
/**
* This function will post an message to the usb message queue,
*
* @param msg the message to be posted
* @param size the size of the message .
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usb_post_event(struct umsg* msg, rt_size_t size)
{
RT_ASSERT(msg != RT_NULL);
/* send message to usb message queue */
rt_mq_send(usb_mq, (void*)msg, size);
return RT_EOK;
}
/**
* This function will initialize usb system.
*
* @return none.
*
*/
void rt_usb_system_init(void)
{
rt_thread_t thread;
/* create usb message queue */
usb_mq = rt_mq_create("usbh", 32, 16, RT_IPC_FLAG_FIFO);
/* create usb hub thread */
thread = rt_thread_create("usbh", rt_usb_hub_thread_entry, RT_NULL,
USB_THREAD_STACK_SIZE, 8, 20);
if(thread != RT_NULL)
{
/* startup usb host thread */
rt_thread_startup(thread);
}
}
/*
* File : hub.h
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2011, RT-Thread Development Team
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rt-thread.org/license/LICENSE
*
* Change Logs:
* Date Author Notes
* 2011-12-12 Yi Qiu first version
*/
#ifndef __HUB_H__
#define __HUB_H__
#include <rtthread.h>
typedef struct uhubinst* uhubinst_t;
struct uhubinst
{
struct uhub_descriptor hub_desc;
rt_uint8_t num_ports;
rt_uint32_t port_status[PORT_NUM];
struct uinstance* child[PORT_NUM];
rt_bool_t is_roothub;
upipe_t pipe_in;
rt_uint8_t buffer[8];
struct uinstance* self;
struct uhcd *hcd;
};
#define RH_GET_PORT_STATUS 0
#define RH_SET_PORT_STATUS 1
#define RH_CLEAR_PORT_FEATURE 2
#define RH_SET_PORT_FEATURE 3
/*
* Port feature numbers
*/
#define PORT_FEAT_CONNECTION 0
#define PORT_FEAT_ENABLE 1
#define PORT_FEAT_SUSPEND 2
#define PORT_FEAT_OVER_CURRENT 3
#define PORT_FEAT_RESET 4
#define PORT_FEAT_POWER 8
#define PORT_FEAT_LOWSPEED 9
#define PORT_FEAT_HIGHSPEED 10
#define PORT_FEAT_C_CONNECTION 16
#define PORT_FEAT_C_ENABLE 17
#define PORT_FEAT_C_SUSPEND 18
#define PORT_FEAT_C_OVER_CURRENT 19
#define PORT_FEAT_C_RESET 20
/*
The HcRhPortStatus[1:NDP] register is used to control and report port events on a per-port
basis. NumberDownstreamPorts represents the number of HcRhPortStatus registers that are
implemented in hardware. The lower word is used to reflect the port status, whereas the upper
word reflects the status change bits. Some status bits are implemented with special write behavior
(see below). If a transaction (token through handshake) is in progress when a write to change
port status occurs, the resulting port status change must be postponed until the transaction
completes. Reserved bits should always be written '0'.
*/
#define PORT_CCS 0x00000001UL /* R:CurrentConnectStatus - W:ClearPortEnable */
#define PORT_PES 0x00000002UL /* R:PortEnableStatus - W:SetPortEnable */
#define PORT_PSS 0x00000004UL /* R:PortSuspendStatus - W:SetPortSuspend */
#define PORT_POCI 0x00000008UL /* R:PortOverCurrentIndicator - W:ClearSuspendStatus */
#define PORT_PRS 0x00000010UL /* R:PortResetStatus - W: SetPortReset */
#define PORT_PPS 0x00000100UL /* R:PortPowerStatus - W: SetPortPower */
#define PORT_LSDA 0x00000200UL /* R:LowSpeedDeviceAttached - W:ClearPortPower */
#define PORT_CCSC 0x00010000UL
#define PORT_PESC 0x00020000UL
#define PORT_PSSC 0x00040000UL
#define PORT_POCIC 0x00080000UL
#define PORT_PRSC 0x00100000UL
/*
*Hub Status & Hub Change bit masks
*/
#define HUB_STATUS_LOCAL_POWER 0x0001
#define HUB_STATUS_OVERCURRENT 0x0002
#define HUB_CHANGE_LOCAL_POWER 0x0001
#define HUB_CHANGE_OVERCURRENT 0x0002
rt_err_t rt_usb_hub_get_descriptor(uinst_t uinst, rt_uint8_t *buffer,
rt_size_t size);
rt_err_t rt_usb_hub_get_status(uinst_t uinst, rt_uint8_t* buffer);
rt_err_t rt_usb_hub_get_port_status(uhubinst_t uhub, rt_uint16_t port,
rt_uint8_t* buffer);
rt_err_t rt_usb_hub_clear_port_feature(uhubinst_t uhub, rt_uint16_t port,
rt_uint16_t feature);
rt_err_t rt_usb_hub_set_port_feature(uhubinst_t uhub, rt_uint16_t port,
rt_uint16_t feature);
rt_err_t rt_usb_hub_reset_port(uhubinst_t uhub, rt_uint16_t port);
rt_err_t rt_usb_post_event(struct umsg* msg, rt_size_t size);
#endif
/*
* File : usbhost.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2011, RT-Thread Development Team
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rt-thread.org/license/LICENSE
*
* Change Logs:
* Date Author Notes
* 2011-3-12 Yi Qiu first version
*/
#include <rtthread.h>
#include "usbhost.h"
#include "core.h"
#include "hub.h"
#if defined(RT_USB_HID_KEYBOARD) || defined(RT_USB_HID_MOUSE)
#include <hid.h>
#endif
/**
* This function will initialize the usb host stack, all the usb class driver and
* host controller driver are also be initialized here.
*
* @return none.
*/
void rt_usbhost_init(void)
{
ucd_t drv;
rt_device_t dev;
#ifdef RT_USB_CLASS_HID
uprotocal_t protocal;
#endif
/* initialize usb hub */
rt_usb_system_init();
/* initialize class driver */
rt_usb_class_driver_init();
#ifdef RT_USB_CLASS_MASS_STORAGE
/* register mass storage class driver */
drv = rt_usb_class_driver_storage();
rt_usb_class_driver_register(drv);
#endif
#ifdef RT_USB_CLASS_HID
/* register hid class driver */
drv = rt_usb_class_driver_hid();
rt_usb_class_driver_register(drv);
#ifdef RT_USB_HID_KEYBOARD
/* register hid keyboard protocal */
protocal = rt_usb_hid_protocal_kbd();
rt_usb_hid_protocal_register(protocal);
#endif
#ifdef RT_USB_HID_MOUSE
/* register hid mouse protocal */
protocal = rt_usb_hid_protocal_mouse();
rt_usb_hid_protocal_register(protocal);
#endif
#endif
#ifdef RT_USB_CLASS_ADK
/* register adk class driver */
drv = rt_usb_class_driver_adk();
rt_usb_class_driver_register(drv);
#endif
/* register hub class driver */
drv = rt_usb_class_driver_hub();
rt_usb_class_driver_register(drv);
#ifdef RT_USB_HCD_MUSB
/* register musb host controller driver */
dev = rt_usb_hcd_musb();
rt_device_register(dev, "musb", 0);
rt_device_init(dev);
#endif
#ifdef RT_USB_HCD_OHCI
/* register ohci host controller driver */
dev = rt_usb_hcd_ohci();
rt_device_register(dev, "ohci", 0);
rt_device_init(dev);
#endif
#ifdef RT_USB_HCD_STM32
/* register ohci host controller driver */
dev = rt_usb_hcd_susb();
rt_device_register(dev, "susb", 0);
rt_device_init(dev);
#endif
}
#ifndef __DRIVER_H__
#define __DRIVER_H__
#include <rtthread.h>
enum uclass_type
{
rt_usb_Class_MassStor = 0,
rt_usb_Class_Hid,
rt_usb_Class_Hub,
};
struct uclass_driver
{
rt_list_t list;
int class_code;
int subclass_code;
rt_err_t (*run)(void* arg);
rt_err_t (*stop)(void* arg);
void* user_data;
};
typedef struct uclass_driver* ucd_t;
struct uprotocal
{
rt_list_t list;
int pro_id;
rt_err_t (*init)(void* arg);
rt_err_t (*callback)(void* arg);
};
typedef struct uprotocal* uprotocal_t;
rt_err_t rt_usb_class_driver_init(void);
rt_err_t rt_usb_class_driver_register(ucd_t drv);
rt_err_t rt_usb_class_driver_unregister(ucd_t drv);
rt_err_t rt_usb_class_driver_run(ucd_t drv, void* args);
rt_err_t rt_usb_class_driver_stop(ucd_t drv, void* args);
ucd_t rt_usb_class_driver_find(int class_code, int subclass_code);
#endif
/*
* File : hcd.h
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2011, RT-Thread Development Team
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rt-thread.org/license/LICENSE
*
* Change Logs:
* Date Author Notes
* 2011-12-12 Yi Qiu first version
*/
#ifndef __HCD_H__
#define __HCD_H__
#include <rtthread.h>
#include "usbspec.h"
struct uhcd_ops
{
int (*ctl_xfer)(uinst_t inst, ureq_t setup, void* buffer, int nbytes,
int timeout);
int (*bulk_xfer)(upipe_t pipe, void* buffer, int nbytes, int timeout);
int (*int_xfer)(upipe_t pipe, void* buffer, int nbytes, int timeout);
int (*iso_xfer)(upipe_t pipe, void* buffer, int nbytes, int timeout);
rt_err_t (*alloc_pipe)(struct upipe** pipe, uifinst_t ifinst, uep_desc_t ep,
func_callback callback);
rt_err_t (*free_pipe)(upipe_t pipe);
rt_err_t (*hub_ctrl)(rt_uint16_t port, rt_uint8_t cmd, void *args);
};
struct uhcd
{
struct rt_device parent;
struct uhcd_ops* ops;
};
typedef struct uhcd* uhcd_t;
rt_inline rt_err_t rt_usb_hcd_alloc_pipe(uhcd_t hcd, upipe_t* pipe,
uifinst_t ifinst, uep_desc_t ep, func_callback callback)
{
if(ifinst == RT_NULL) return -RT_EIO;
/* parameter check */
RT_ASSERT(hcd != RT_NULL);
RT_ASSERT(hcd->ops != RT_NULL);
RT_ASSERT(hcd->ops->alloc_pipe!= RT_NULL);
return hcd->ops->alloc_pipe(pipe, ifinst, ep, callback);
}
rt_inline rt_err_t rt_usb_hcd_free_pipe(uhcd_t hcd, upipe_t pipe)
{
RT_ASSERT(pipe != RT_NULL);
/* parameter check */
RT_ASSERT(hcd != RT_NULL);
RT_ASSERT(hcd->ops != RT_NULL);
RT_ASSERT(hcd->ops->free_pipe!= RT_NULL);
return hcd->ops->free_pipe(pipe);
}
rt_inline int rt_usb_hcd_bulk_xfer(uhcd_t hcd, upipe_t pipe, void* buffer,
int nbytes, int timeout)
{
if(pipe == RT_NULL) return -1;
if(pipe->ifinst == RT_NULL) return -1;
if(pipe->ifinst->uinst == RT_NULL) return -1;
if(pipe->ifinst->uinst->status == UINST_STATUS_IDLE)
return -1;
/* parameter check */
RT_ASSERT(hcd != RT_NULL);
RT_ASSERT(hcd->ops != RT_NULL);
RT_ASSERT(hcd->ops->bulk_xfer!= RT_NULL);
return hcd->ops->bulk_xfer(pipe, buffer, nbytes, timeout);
}
rt_inline int rt_usb_hcd_control_xfer(uhcd_t hcd, uinst_t uinst, ureq_t setup,
void* buffer, int nbytes, int timeout)
{
if(uinst->status == UINST_STATUS_IDLE) return -1;
/* parameter check */
RT_ASSERT(hcd != RT_NULL);
RT_ASSERT(hcd->ops != RT_NULL);
RT_ASSERT(hcd->ops->ctl_xfer!= RT_NULL);
return hcd->ops->ctl_xfer(uinst, setup, buffer, nbytes, timeout);
}
rt_inline int rt_usb_hcd_int_xfer(uhcd_t hcd, upipe_t pipe, void* buffer,
int nbytes, int timeout)
{
if(pipe == RT_NULL) return -1;
if(pipe->ifinst == RT_NULL) return -1;
if(pipe->ifinst->uinst == RT_NULL) return -1;
if(pipe->ifinst->uinst->status == UINST_STATUS_IDLE)
return -1;
RT_ASSERT(hcd != RT_NULL);
RT_ASSERT(hcd->ops != RT_NULL);
RT_ASSERT(hcd->ops->int_xfer!= RT_NULL);
return hcd->ops->int_xfer(pipe, buffer, nbytes, timeout);
}
rt_inline rt_err_t rt_usb_hcd_hub_control(uhcd_t hcd, rt_uint16_t port,
rt_uint8_t cmd, void *args)
{
RT_ASSERT(hcd != RT_NULL);
RT_ASSERT(hcd->ops != RT_NULL);
RT_ASSERT(hcd->ops->hub_ctrl != RT_NULL);
return hcd->ops->hub_ctrl(port, cmd, args);
}
#endif
/*
* File : usbhost.h
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2011, RT-Thread Development Team
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rt-thread.org/license/LICENSE
*
* Change Logs:
* Date Author Notes
* 2011-3-12 Yi Qiu first version
*/
#ifndef __RT_USB_HOST_INIT_H__
#define __RT_USB_HOST_INIT_H__
#include <rtthread.h>
#include "driver.h"
#define RT_DEBUG_USB 1
void rt_usbhost_init(void);
void rt_usb_system_init(void);
/* usb class driver definition */
ucd_t rt_usb_class_driver_hid(void);
ucd_t rt_usb_class_driver_hub(void);
ucd_t rt_usb_class_driver_storage(void);
ucd_t rt_usb_class_driver_adk(void);
/* usb hid protocal definition */
uprotocal_t rt_usb_hid_protocal_kbd(void);
uprotocal_t rt_usb_hid_protocal_mouse(void);
/* usb host controller driver definition */
rt_device_t rt_usb_hcd_musb(void);
rt_device_t rt_usb_hcd_ohci(void);
rt_device_t rt_usb_hcd_susb(void);
#endif
/*
* File : core.h
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2011, RT-Thread Development Team
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rt-thread.org/license/LICENSE
*
* Change Logs:
* Date Author Notes
* 2011-12-12 Yi Qiu first version
*/
#ifndef __USB_SPEC_H__
#define __USB_SPEC_H__
#include <rtthread.h>
struct usb_descriptor
{
rt_uint8_t bLength;
rt_uint8_t type;
};
typedef struct usb_descriptor* udesc_t;
struct udevice_descriptor
{
rt_uint8_t bLength;
rt_uint8_t type;
rt_uint16_t bcdUSB;
rt_uint8_t bDeviceClass;
rt_uint8_t bDeviceSubClass;
rt_uint8_t bDeviceProtocol;
rt_uint8_t bMaxPacketSize0;
rt_uint16_t idVendor;
rt_uint16_t idProduct;
rt_uint16_t bcdDevice;
rt_uint8_t iManufacturer;
rt_uint8_t iProduct;
rt_uint8_t iSerialNumber;
rt_uint8_t bNumConfigurations;
};
typedef struct udevice_descriptor* udev_desc_t;
struct uconfig_descriptor
{
rt_uint8_t bLength;
rt_uint8_t type;
rt_uint16_t wTotalLength;
rt_uint8_t bNumInterfaces;
rt_uint8_t bConfigurationValue;
rt_uint8_t iConfiguration;
rt_uint8_t bmAttributes;
rt_uint8_t MaxPower;
};
typedef struct uconfig_descriptor* ucfg_desc_t;
struct uinterface_descriptor
{
rt_uint8_t bLength;
rt_uint8_t type;
rt_uint8_t bInterfaceNumber;
rt_uint8_t bAlternateSetting;
rt_uint8_t bNumEndpoints;
rt_uint8_t bInterfaceClass;
rt_uint8_t bInterfaceSubClass;
rt_uint8_t bInterfaceProtocol;
rt_uint8_t iInterface;
};
typedef struct uinterface_descriptor* uintf_desc_t;
struct uendpoint_descriptor
{
rt_uint8_t bLength;
rt_uint8_t type;
rt_uint8_t bEndpointAddress;
rt_uint8_t bmAttributes;
rt_uint16_t wMaxPacketSize;
rt_uint8_t bInterval;
};
typedef struct uendpoint_descriptor* uep_desc_t;
struct ustring_descriptor
{
rt_uint8_t bLength;
rt_uint8_t type;
rt_uint8_t* String;
};
typedef struct ustring_descriptor* ustr_desc_t;
struct uhub_descriptor
{
rt_uint8_t length;
rt_uint8_t type;
rt_uint8_t num_ports;
rt_uint16_t characteristics;
rt_uint8_t pwron_to_good; /* power on to power good */
rt_uint8_t current;
rt_uint8_t removable[8];
rt_uint8_t pwr_ctl[8];
};
typedef struct uhub_descriptor* uhub_desc_t;
struct ureqest
{
rt_uint8_t request_type;
rt_uint8_t request;
rt_uint16_t value;
rt_uint16_t index;
rt_uint16_t length;
};
typedef struct ureqest* ureq_t;
#define uswap_32(x) \
((((x) & 0xff000000) >> 24) | \
(((x) & 0x00ff0000) >> 8) | \
(((x) & 0x0000ff00) << 8) | \
(((x) & 0x000000ff) << 24))
#define USB_CLASS_DEVICE 0x00
#define USB_CLASS_AUDIO 0x01
#define USB_CLASS_CDC 0x02
#define USB_CLASS_HID 0x03
#define USB_CLASS_PHYSICAL 0x05
#define USB_CLASS_IMAGE 0x06
#define USB_CLASS_PRINTER 0x07
#define USB_CLASS_MASS_STORAGE 0x08
#define USB_CLASS_HUB 0x09
#define USB_CLASS_CDC_DATA 0x0a
#define USB_CLASS_SMART_CARD 0x0b
#define USB_CLASS_SECURITY 0x0d
#define USB_CLASS_VIDEO 0x0e
#define USB_CLASS_HEALTHCARE 0x0f
#define USB_CLASS_DIAG_DEVICE 0xdc
#define USB_CLASS_WIRELESS 0xe0
#define USB_CLASS_MISC 0xef
#define USB_CLASS_APP_SPECIFIC 0xfe
#define USB_CLASS_VEND_SPECIFIC 0xff
#define USB_DESC_TYPE_DEVICE 0x01
#define USB_DESC_TYPE_CONFIGURATION 0x02
#define USB_DESC_TYPE_STRING 0x03
#define USB_DESC_TYPE_INTERFACE 0x04
#define USB_DESC_TYPE_ENDPOINT 0x05
#define USB_DESC_TYPE_DEVICEQUALIFIER 0x06
#define USB_DESC_TYPE_OTHERSPEED 0x07
#define USB_DESC_TYPE_HID 0x21
#define USB_DESC_TYPE_REPORT 0x22
#define USB_DESC_TYPE_PHYSICAL 0x23
#define USB_DESC_TYPE_HUB 0x29
#define USB_REQ_TYPE_STANDARD 0x00
#define USB_REQ_TYPE_CLASS 0x20
#define USB_REQ_TYPE_VENDOR 0x40
#define USB_REQ_TYPE_TYPE_MASK 0x60
#define USB_REQ_TYPE_DIR_OUT 0x00
#define USB_REQ_TYPE_DIR_IN 0x80
#define USB_REQ_TYPE_DEVICE 0x00
#define USB_REQ_TYPE_INTERFACE 0x01
#define USB_REQ_TYPE_ENDPOINT 0x02
#define USB_REQ_TYPE_OTHER 0x03
#define USB_REQ_TYPE_RECIPIENT_MASK 0x1f
#define USB_FEATURE_ENDPOINT_HALT 0x00
#define USB_FEATURE_DEV_REMOTE_WAKEUP 0x01
#define USB_FEATURE_TEST_MODE 0x02
#define USB_REQ_GET_STATUS 0x00
#define USB_REQ_CLEAR_FEATURE 0x01
#define USB_REQ_SET_FEATURE 0x03
#define USB_REQ_SET_ADDRESS 0x05
#define USB_REQ_GET_DESCRIPTOR 0x06
#define USB_REQ_SET_DESCRIPTOR 0x07
#define USB_REQ_GET_CONFIGURATION 0x08
#define USB_REQ_SET_CONFIGURATION 0x09
#define USB_REQ_GET_INTERFACE 0x0A
#define USB_REQ_SET_INTERFACE 0x0B
#define USB_REQ_SYNCH_FRAME 0x0C
#define USB_REQ_SET_ENCRYPTION 0x0D
#define USB_REQ_GET_ENCRYPTION 0x0E
#define USB_REQ_RPIPE_ABORT 0x0E
#define USB_REQ_SET_HANDSHAKE 0x0F
#define USB_REQ_RPIPE_RESET 0x0F
#define USB_REQ_GET_HANDSHAKE 0x10
#define USB_REQ_SET_CONNECTION 0x11
#define USB_REQ_SET_SECURITY_DATA 0x12
#define USB_REQ_GET_SECURITY_DATA 0x13
#define USB_REQ_SET_WUSB_DATA 0x14
#define USB_REQ_LOOPBACK_DATA_WRITE 0x15
#define USB_REQ_LOOPBACK_DATA_READ 0x16
#define USB_REQ_SET_INTERFACE_DS 0x17
#define USB_PID_OUT 0x01
#define USB_PID_ACK 0x02
#define USB_PID_DATA0 0x03
#define USB_PID_SOF 0x05
#define USB_PID_IN 0x09
#define USB_PID_NACK 0x0A
#define USB_PID_DATA1 0x0B
#define USB_PID_PRE 0x0C
#define USB_PID_SETUP 0x0D
#define USB_PID_STALL 0x0E
#define USB_EP_DESC_OUT 0x00
#define USB_EP_DESC_IN 0x80
#define USB_EP_DESC_NUM_MASK 0x0f
#define USB_EP_ATTR_CONTROL 0x00
#define USB_EP_ATTR_ISOC 0x01
#define USB_EP_ATTR_BULK 0x02
#define USB_EP_ATTR_INT 0x03
#define USB_EP_ATTR_TYPE_MASK 0x03
#define USB_EPNO_MASK 0x7f
#define USB_DIR_OUT 0x00
#define USB_DIR_IN 0x80
#define USB_DIR_MASK 0x80
#define USB_EP_ATTR(attr) (attr & USB_EP_ATTR_TYPE_MASK)
#define USB_EP_DESC_NUM(addr) (addr & USB_EP_DESC_NUM_MASK)
#endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册