620 lines
15 KiB
C
620 lines
15 KiB
C
#include "usb_os_adapter.h"
|
|
#include "trace.h"
|
|
#include <asm/dma-mapping.h>
|
|
#include <linux/usb/ch9.h>
|
|
#include <linux/usb/gadget.h>
|
|
#include "core.h"
|
|
#include "hcd.h"
|
|
#include "ark_dwc2.h"
|
|
#include "usbroothubdes.h"
|
|
#include "sysctl.h"
|
|
|
|
struct dwc2_host_data {
|
|
struct dwc2_hsotg *host;
|
|
struct usb_hcd hcd;
|
|
enum usb_device_speed host_speed;
|
|
int root_hub_devnum;
|
|
//struct usb_host_endpoint hep;
|
|
struct urb urb_in[16];
|
|
struct urb urb_out[16];
|
|
struct usb_host_endpoint hep_in[16];
|
|
struct usb_host_endpoint hep_out[16];
|
|
struct hc_driver *dw2_hc_driver;
|
|
List_t free_urb_list;
|
|
spinlock_t lock;
|
|
};
|
|
|
|
int dwc2_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
|
|
int dwc2_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
|
|
extern int dwc2_driver_init(struct dwc2_hsotg **dev, struct usb_hcd *hcd);
|
|
extern int dwc2_driver_uninit(struct dwc2_hsotg *hsotg);
|
|
extern struct hc_driver* dwc2_get_driver();
|
|
static int dwc_otg_submit_rh_msg(struct usb_device *dev,
|
|
unsigned long pipe, void *buffer, int txlen,
|
|
struct devrequest *cmd);
|
|
|
|
|
|
|
|
struct dwc2_host_data dwc2_host;
|
|
|
|
static void dwc2_host_complete_urb(struct urb *urb)
|
|
{
|
|
urb->dev->status &= ~USB_ST_NOT_PROC;
|
|
urb->dev->act_len = urb->actual_length;
|
|
//printf("actual_length:%d\r\n", urb->actual_length);
|
|
urb->urb_complete = 1;
|
|
}
|
|
|
|
static void usb_urb_release(struct urb *urb)
|
|
{
|
|
if (NULL == urb)
|
|
return;
|
|
spin_lock(&dwc2_host.lock);
|
|
list_add_tail(&urb->urb_list, &dwc2_host.free_urb_list);
|
|
spin_unlock(&dwc2_host.lock);
|
|
}
|
|
|
|
static struct urb *usb_urb_alloc(struct dwc2_host_data *ctx,
|
|
int iso_desc_count,
|
|
gfp_t mem_flags)
|
|
{
|
|
struct urb *urb = NULL;
|
|
u32 size = sizeof(*urb);
|
|
|
|
ListItem_t *pxListItem = NULL;
|
|
int found = 0, flags;
|
|
spin_lock_irqsave(&ctx->lock, flags);
|
|
list_for_each_entry(pxListItem, urb, &ctx->free_urb_list) {
|
|
if (urb->number_of_packets == iso_desc_count) {
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (found) {
|
|
list_del_init(&urb->urb_list);
|
|
spin_unlock_irqrestore(&ctx->lock, flags);
|
|
memset(urb, 0, sizeof(struct urb));
|
|
INIT_LIST_ITEM(&urb->urb_list);
|
|
listSET_LIST_ITEM_OWNER(&urb->urb_list, urb);
|
|
urb->urb_complete = 0;
|
|
return urb;
|
|
}
|
|
spin_unlock_irqrestore(&ctx->lock, flags);
|
|
|
|
urb = (struct urb *)kzalloc(size, mem_flags);
|
|
if (urb) {
|
|
urb->number_of_packets = iso_desc_count;
|
|
INIT_LIST_ITEM(&urb->urb_list);
|
|
listSET_LIST_ITEM_OWNER(&urb->urb_list, urb);
|
|
urb->urb_complete = 0;
|
|
}
|
|
|
|
return urb;
|
|
}
|
|
|
|
|
|
static void construct_urb(struct urb *urb, struct usb_host_endpoint *hep,
|
|
struct usb_device *dev, int endpoint_type,
|
|
unsigned long pipe, void *buffer, int len,
|
|
struct devrequest *setup, int interval)
|
|
{
|
|
int epnum = usb_pipeendpoint(pipe);
|
|
int is_in = usb_pipein(pipe);
|
|
|
|
INIT_LIST_HEAD(&hep->urb_list);
|
|
INIT_LIST_ITEM(&urb->urb_list);
|
|
urb->urb_list.pvOwner = (void *)urb;
|
|
urb->ep = hep;
|
|
urb->complete = dwc2_host_complete_urb;
|
|
urb->status = -EINPROGRESS;
|
|
urb->dev = dev;
|
|
urb->pipe = pipe;
|
|
urb->transfer_buffer = buffer;
|
|
urb->transfer_dma = (dma_addr_t)buffer;
|
|
urb->transfer_buffer_length = len;
|
|
urb->setup_packet = (unsigned char *)setup;
|
|
urb->setup_dma = (dma_addr_t)setup;
|
|
urb->transfer_flags &= ~(URB_DIR_MASK | URB_DMA_MAP_SINGLE |
|
|
URB_DMA_MAP_PAGE | URB_DMA_MAP_SG | URB_MAP_LOCAL |
|
|
URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL |
|
|
URB_DMA_SG_COMBINED);
|
|
urb->transfer_flags |= (is_in ? URB_DIR_IN : URB_DIR_OUT);
|
|
|
|
urb->ep->desc.wMaxPacketSize =
|
|
__cpu_to_le16(is_in ? dev->epmaxpacketin[epnum] :
|
|
dev->epmaxpacketout[epnum]);
|
|
urb->ep->desc.bmAttributes = endpoint_type;
|
|
urb->ep->desc.bEndpointAddress =
|
|
(is_in ? USB_DIR_IN : USB_DIR_OUT) | epnum;
|
|
urb->ep->desc.bInterval = interval;
|
|
}
|
|
|
|
static int submit_urb(struct usb_hcd *hcd, struct urb *urb)
|
|
{
|
|
int ret;
|
|
|
|
ret = dwc2_urb_enqueue(hcd, urb, 0);
|
|
if (ret < 0) {
|
|
PrintVariableValueHex("Failed to enqueue URB to controller ret", ret);
|
|
return ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int _dwc2_submit_control_msg(struct dwc2_host_data *host,
|
|
struct usb_device *dev, unsigned long pipe,
|
|
void *buffer, int len, struct devrequest *setup, int timeout)
|
|
{
|
|
struct urb *urb = NULL;
|
|
struct usb_host_endpoint *hep = NULL;
|
|
int epnum = usb_pipeendpoint(pipe);
|
|
int is_in = usb_pipein(pipe);
|
|
int ret = 0;
|
|
unsigned int start_time;
|
|
|
|
if (epnum > 8 || epnum < 0)
|
|
return -EINVAL;
|
|
|
|
if (is_in) {
|
|
hep = &host->hep_in[epnum];
|
|
} else {
|
|
hep = &host->hep_out[epnum];
|
|
}
|
|
urb = usb_urb_alloc(host, 0, IRQ_NONE);
|
|
if (urb == NULL)
|
|
return -ENOMEM;
|
|
|
|
construct_urb(urb, hep, dev, USB_ENDPOINT_XFER_CONTROL,
|
|
pipe, buffer, len, setup, 0);
|
|
|
|
/* Fix speed for non hub-attached devices */
|
|
if (!usb_dev_get_parent(dev))
|
|
dev->speed = host->host_speed;
|
|
//unsigned char *a = urb->setup_packet;
|
|
//if (a)
|
|
//printf("setup-->%02x %02x %02x %02x %02x %02x %02x %02x\r\n", a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
|
|
ret = submit_urb(&host->hcd, urb);
|
|
if (ret < 0) {
|
|
dwc2_urb_dequeue(&host->hcd, urb, 0);
|
|
goto exit;
|
|
}
|
|
|
|
start_time = get_timer(0);
|
|
ret = pdTRUE;
|
|
do {
|
|
if (get_timer(start_time) > timeout) {
|
|
ret = pdFALSE;
|
|
break;
|
|
}
|
|
} while(!urb->urb_complete);
|
|
if (ret != pdTRUE || 0 != urb->status) {//timeout
|
|
dwc2_urb_dequeue(&host->hcd, urb, 0);
|
|
if (0 != urb->status)
|
|
PrintVariableValueHex("usb control urb error", urb->status);
|
|
ret = urb->status;
|
|
} else {
|
|
ret = urb->actual_length;
|
|
}
|
|
exit:
|
|
usb_urb_release(urb);
|
|
return ret;
|
|
}
|
|
|
|
int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int transfer_len, int *actual_length, int timeout)
|
|
{
|
|
struct urb *urb = NULL;
|
|
struct usb_host_endpoint *hep = NULL;
|
|
int epnum = usb_pipeendpoint(pipe);
|
|
int is_in = usb_pipein(pipe);
|
|
int ret = 0;
|
|
struct dwc2_host_data *host = &dwc2_host;
|
|
unsigned int start_time;
|
|
|
|
if (epnum > 8 || epnum < 0)
|
|
return -EINVAL;
|
|
if (is_in) {
|
|
hep = &host->hep_in[epnum];
|
|
} else {
|
|
hep = &host->hep_out[epnum];
|
|
}
|
|
|
|
urb = usb_urb_alloc(host, 0, IRQ_NONE);
|
|
if (urb == NULL)
|
|
return -ENOMEM;
|
|
|
|
construct_urb(urb, hep, dev, USB_ENDPOINT_XFER_BULK,
|
|
pipe, buffer, transfer_len, NULL, 0);
|
|
ret = submit_urb(&host->hcd, urb);
|
|
if (ret < 0) {
|
|
dwc2_urb_dequeue(&host->hcd, urb, 0);
|
|
goto exit;
|
|
}
|
|
|
|
start_time = get_timer(0);
|
|
ret = pdTRUE;
|
|
do {
|
|
if (get_timer(start_time) > timeout) {
|
|
ret = pdFALSE;
|
|
break;
|
|
}
|
|
} while(!urb->urb_complete);
|
|
if (ret != pdTRUE || 0 != urb->status) {//timeout
|
|
dwc2_urb_dequeue(&host->hcd, urb, 0);
|
|
if (actual_length)
|
|
*actual_length = 0;
|
|
if (0 != urb->status)
|
|
PrintVariableValueHex("usb bulk urb error", urb->status);
|
|
ret = urb->status;
|
|
} else {
|
|
if (actual_length)
|
|
*actual_length = urb->actual_length;
|
|
}
|
|
|
|
exit:
|
|
usb_urb_release(urb);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void usb_reset_endpoint()
|
|
{
|
|
int i;
|
|
struct dwc2_host_data *host = &dwc2_host;
|
|
|
|
if ((NULL == host->dw2_hc_driver) || (NULL == host->dw2_hc_driver->endpoint_reset))
|
|
return;
|
|
for (i = 0; i < 16; i++) {
|
|
host->dw2_hc_driver->endpoint_reset(&(host->hcd), &host->hep_in[i]);
|
|
host->dw2_hc_driver->endpoint_reset(&(host->hcd), &host->hep_out[i]);
|
|
}
|
|
}
|
|
|
|
void usb_disable_endpoint()
|
|
{
|
|
int i;
|
|
struct dwc2_host_data *host = &dwc2_host;
|
|
|
|
if ((NULL == host->dw2_hc_driver) || (NULL == host->dw2_hc_driver->endpoint_disable))
|
|
return;
|
|
for (i = 0; i < 16; i++) {
|
|
host->dw2_hc_driver->endpoint_disable(&(host->hcd), &host->hep_in[i]);
|
|
host->dw2_hc_driver->endpoint_disable(&(host->hcd), &host->hep_out[i]);
|
|
}
|
|
}
|
|
|
|
void reset_usb_phy()
|
|
{
|
|
vSysctlConfigure(SYS_SOFT_RST, 30, 1, 0);//phy reset
|
|
mdelay(10);
|
|
vSysctlConfigure(SYS_SOFT_RST, 30, 1, 1);//phy reset
|
|
}
|
|
|
|
void usb_sysctrl_init()
|
|
{
|
|
vSysctlConfigure(SYS_ANA_CFG, 8, 0xff, 4);
|
|
|
|
vSysctlConfigure(SYS_SOFT_RST, 30, 1, 0);//phy reset
|
|
vSysctlConfigure(SYS_SOFT_RST, 3, 1, 0);
|
|
mdelay(10);
|
|
vSysctlConfigure(SYS_SOFT_RST, 30, 1, 1);//phy reset
|
|
vSysctlConfigure(SYS_SOFT_RST, 3, 1, 1);
|
|
vSysctlConfigure(SYS_ANA_CFG, 24, 3, 1);
|
|
mdelay(10);
|
|
}
|
|
|
|
|
|
|
|
int hub_status_data(char buf[8])
|
|
{
|
|
int ret = 1;
|
|
struct dwc2_host_data *host = &dwc2_host;
|
|
//printf("prvUsbPortScanTimerCallback\r\n");
|
|
ret = host->dw2_hc_driver->hub_status_data(&(host->hcd), buf);
|
|
if (ret != 0) {
|
|
//printf("state:%d usb state changed now!\r\n", buf[0]);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void usb_dwc2_lowlevel_restart()
|
|
{
|
|
struct dwc2_host_data *host = &dwc2_host;
|
|
|
|
if (host->dw2_hc_driver && host->dw2_hc_driver->stop) {
|
|
host->dw2_hc_driver->stop(&(host->hcd));
|
|
}
|
|
msleep(50);
|
|
if (host->dw2_hc_driver && host->dw2_hc_driver->start) {
|
|
host->dw2_hc_driver->start(&(host->hcd));
|
|
}
|
|
}
|
|
|
|
|
|
//#define mainTIMER_SCAN_FREQUENCY_MS pdMS_TO_TICKS( 1000UL )
|
|
|
|
int usb_dwc2_lowlevel_init()
|
|
{
|
|
struct dwc2_host_data *host = &dwc2_host;
|
|
int ret;
|
|
|
|
INIT_LIST_HEAD(&host->free_urb_list);
|
|
spin_lock_init(&host->lock);
|
|
|
|
ret = dwc2_driver_init(&host->host, &(host->hcd));
|
|
if (!host->host) {
|
|
SendUartString("MUSB host is not registered\n");
|
|
return -ENODEV;
|
|
}
|
|
host->dw2_hc_driver = dwc2_get_driver();
|
|
|
|
|
|
return ret;
|
|
}
|
|
|
|
int usb_dwc2_lowlevel_uninit()
|
|
{
|
|
if (!dwc2_host.host) {
|
|
SendUartString("MUSB host is not registered\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
dwc2_driver_uninit(dwc2_host.host);
|
|
return 0;
|
|
}
|
|
|
|
int submit_control_msg(struct usb_device *dev, unsigned long pipe,
|
|
void *buffer, int length, struct devrequest *setup, int timeout)
|
|
{
|
|
if (dev->parent == NULL) {
|
|
return dwc_otg_submit_rh_msg(dev, pipe, buffer, length, setup);
|
|
} else {
|
|
return _dwc2_submit_control_msg(&dwc2_host, dev, pipe, buffer, length, setup, timeout);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* DWC2 to USB API interface
|
|
*/
|
|
/* Direction: In ; Request: Status */
|
|
static int dwc_otg_submit_rh_msg_in_status(struct usb_device *dev, void *buffer,
|
|
int txlen, struct devrequest *cmd)
|
|
{
|
|
int len = 0;
|
|
int stat = 0;
|
|
|
|
switch (cmd->requesttype & ~USB_DIR_IN) {
|
|
case 0:
|
|
*(uint16_t *)buffer = cpu_to_le16(1);
|
|
len = 2;
|
|
break;
|
|
case USB_RECIP_INTERFACE:
|
|
case USB_RECIP_ENDPOINT:
|
|
*(uint16_t *)buffer = cpu_to_le16(0);
|
|
len = 2;
|
|
break;
|
|
case USB_TYPE_CLASS:
|
|
*(uint32_t *)buffer = cpu_to_le32(0);
|
|
len = 4;
|
|
break;
|
|
case USB_RECIP_OTHER | USB_TYPE_CLASS:
|
|
len = 4;
|
|
stat = dwc2_host.dw2_hc_driver->hub_control(&dwc2_host.hcd, (cmd->requesttype << 8) | (cmd->request),
|
|
cmd->value, cmd->index, (char*)buffer, len);
|
|
|
|
break;
|
|
default:
|
|
//puts("unsupported root hub command\n");
|
|
stat = USB_ST_STALLED;
|
|
}
|
|
|
|
dev->act_len = min(len, txlen);
|
|
dev->status = stat;
|
|
|
|
return stat;
|
|
}
|
|
|
|
/* Direction: In ; Request: Descriptor */
|
|
|
|
/* roothub.a masks */
|
|
#define RH_A_NDP (0xff << 0) /* number of downstream ports */
|
|
#define RH_A_PSM (1 << 8) /* power switching mode */
|
|
#define RH_A_NPS (1 << 9) /* no power switching */
|
|
#define RH_A_DT (1 << 10) /* device type (mbz) */
|
|
#define RH_A_OCPM (1 << 11) /* over current protection mode */
|
|
#define RH_A_NOCP (1 << 12) /* no over current protection */
|
|
#define RH_A_POTPGT (0xffUL << 24) /* power on to power good time */
|
|
|
|
/* roothub.b masks */
|
|
#define RH_B_DR 0x0000ffff /* device removable flags */
|
|
#define RH_B_PPCM 0xffff0000 /* port power control mask */
|
|
|
|
static int dwc_otg_submit_rh_msg_in_descriptor(struct usb_device *dev,
|
|
void *buffer, int txlen,
|
|
struct devrequest *cmd)
|
|
{
|
|
|
|
unsigned char data[32];
|
|
uint32_t dsc;
|
|
int len = 0;
|
|
int stat = 0;
|
|
uint16_t wValue = cpu_to_le16(cmd->value);
|
|
uint16_t wLength = cpu_to_le16(cmd->length);
|
|
|
|
switch (cmd->requesttype & ~USB_DIR_IN) {
|
|
case 0:
|
|
{
|
|
switch (wValue & 0xff00) {
|
|
case 0x0100: /* device descriptor */
|
|
len = min3(txlen, (int)sizeof(root_hub_dev_des), (int)wLength);
|
|
memcpy(buffer, root_hub_dev_des, len);
|
|
break;
|
|
case 0x0200: /* configuration descriptor */
|
|
len = min3(txlen, (int)sizeof(root_hub_config_des), (int)wLength);
|
|
memcpy(buffer, root_hub_config_des, len);
|
|
break;
|
|
case 0x0300: /* string descriptors */
|
|
switch (wValue & 0xff) {
|
|
case 0x00:
|
|
len = min3(txlen, (int)sizeof(root_hub_str_index0),
|
|
(int)wLength);
|
|
memcpy(buffer, root_hub_str_index0, len);
|
|
break;
|
|
case 0x01:
|
|
len = min3(txlen, (int)sizeof(root_hub_str_index1),
|
|
(int)wLength);
|
|
memcpy(buffer, root_hub_str_index1, len);
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
stat = USB_ST_STALLED;
|
|
}
|
|
break;
|
|
}
|
|
case USB_TYPE_CLASS:
|
|
/* Root port config, set 1 port and nothing else. */
|
|
dsc = 0x00000001;
|
|
|
|
data[0] = 9; /* min length; */
|
|
data[1] = 0x29;
|
|
data[2] = dsc & RH_A_NDP;
|
|
data[3] = 0;
|
|
if (dsc & RH_A_PSM)
|
|
data[3] |= 0x1;
|
|
if (dsc & RH_A_NOCP)
|
|
data[3] |= 0x10;
|
|
else if (dsc & RH_A_OCPM)
|
|
data[3] |= 0x8;
|
|
|
|
/* corresponds to data[4-7] */
|
|
data[5] = (dsc & RH_A_POTPGT) >> 24;
|
|
data[7] = dsc & RH_B_DR;
|
|
if (data[2] < 7) {
|
|
data[8] = 0xff;
|
|
} else {
|
|
data[0] += 2;
|
|
data[8] = (dsc & RH_B_DR) >> 8;
|
|
data[9] = 0xff;
|
|
data[10] = data[9];
|
|
}
|
|
|
|
len = min3(txlen, (int)data[0], (int)wLength);
|
|
memcpy(buffer, data, len);
|
|
break;
|
|
default:
|
|
//puts("unsupported root hub command\n");
|
|
stat = USB_ST_STALLED;
|
|
}
|
|
|
|
dev->act_len = min(len, txlen);
|
|
dev->status = stat;
|
|
|
|
return stat;
|
|
}
|
|
|
|
/* Direction: In ; Request: Configuration */
|
|
static int dwc_otg_submit_rh_msg_in_configuration(struct usb_device *dev,
|
|
void *buffer, int txlen,
|
|
struct devrequest *cmd)
|
|
{
|
|
int len = 0;
|
|
int stat = 0;
|
|
|
|
switch (cmd->requesttype & ~USB_DIR_IN) {
|
|
case 0:
|
|
*(uint8_t *)buffer = 0x01;
|
|
len = 1;
|
|
break;
|
|
default:
|
|
//puts("unsupported root hub command\n");
|
|
stat = USB_ST_STALLED;
|
|
}
|
|
|
|
dev->act_len = min(len, txlen);
|
|
dev->status = stat;
|
|
|
|
return stat;
|
|
}
|
|
|
|
/* Direction: In */
|
|
static int dwc_otg_submit_rh_msg_in(
|
|
struct usb_device *dev, void *buffer,
|
|
int txlen, struct devrequest *cmd)
|
|
{
|
|
switch (cmd->request) {
|
|
case USB_REQ_GET_STATUS:
|
|
return dwc_otg_submit_rh_msg_in_status(dev, buffer,
|
|
txlen, cmd);
|
|
case USB_REQ_GET_DESCRIPTOR:
|
|
return dwc_otg_submit_rh_msg_in_descriptor(dev, buffer,
|
|
txlen, cmd);
|
|
case USB_REQ_GET_CONFIGURATION:
|
|
return dwc_otg_submit_rh_msg_in_configuration(dev, buffer,
|
|
txlen, cmd);
|
|
default:
|
|
//puts("unsupported root hub command\n");
|
|
return USB_ST_STALLED;
|
|
}
|
|
}
|
|
|
|
/* Direction: Out */
|
|
static int dwc_otg_submit_rh_msg_out(
|
|
struct usb_device *dev,
|
|
void *buffer, int txlen,
|
|
struct devrequest *cmd)
|
|
{
|
|
int len = 0;
|
|
int stat = 0;
|
|
uint16_t bmrtype_breq = cmd->requesttype | (cmd->request << 8);
|
|
uint16_t wValue = cpu_to_le16(cmd->value);
|
|
switch (bmrtype_breq & ~USB_DIR_IN) {
|
|
case (USB_REQ_CLEAR_FEATURE << 8) | USB_RECIP_ENDPOINT:
|
|
case (USB_REQ_CLEAR_FEATURE << 8) | USB_TYPE_CLASS:
|
|
break;
|
|
|
|
case (USB_REQ_CLEAR_FEATURE << 8) | USB_RECIP_OTHER | USB_TYPE_CLASS:
|
|
case (USB_REQ_SET_FEATURE << 8) | USB_RECIP_OTHER | USB_TYPE_CLASS:
|
|
dwc2_host.dw2_hc_driver->hub_control(&dwc2_host.hcd, (cmd->requesttype << 8) | (cmd->request),
|
|
cmd->value, cmd->index, (char*)buffer, txlen);
|
|
break;
|
|
case (USB_REQ_SET_ADDRESS << 8):
|
|
dwc2_host.root_hub_devnum = wValue;
|
|
dwc2_host.dw2_hc_driver->hub_control(&dwc2_host.hcd, (cmd->requesttype << 8) | (cmd->request),
|
|
cmd->value, cmd->index, (char*)buffer, txlen);
|
|
break;
|
|
case (USB_REQ_SET_CONFIGURATION << 8):
|
|
break;
|
|
default:
|
|
//puts("unsupported root hub command\n");
|
|
stat = USB_ST_STALLED;
|
|
}
|
|
|
|
len = min(len, txlen);
|
|
|
|
dev->act_len = len;
|
|
dev->status = stat;
|
|
|
|
return stat;
|
|
}
|
|
|
|
static int dwc_otg_submit_rh_msg(struct usb_device *dev,
|
|
unsigned long pipe, void *buffer, int txlen,
|
|
struct devrequest *cmd)
|
|
{
|
|
int stat = 0;
|
|
if (usb_pipeint(pipe)) {
|
|
//puts("Root-Hub submit IRQ: NOT implemented\n");
|
|
return 0;
|
|
}
|
|
|
|
if (cmd->requesttype & USB_DIR_IN)
|
|
stat = dwc_otg_submit_rh_msg_in(dev, buffer, txlen, cmd);
|
|
else
|
|
stat = dwc_otg_submit_rh_msg_out(dev, buffer, txlen, cmd);
|
|
|
|
stat = dev->act_len;
|
|
return stat;
|
|
}
|
|
|