📄 usbhost.c
字号:
volatile Uint32 inx;
volatile Uint32 outx;
volatile Uint32 tick;
volatile Boolean sleeping;
volatile Boolean DeviceReady;
} HOST_STATE_STRUCT;
typedef struct {
Boolean needClass;
int Config;
int iface;
int ifaceAlt;
int MaxLUN;
int ep_in;
int ep_in_pksize;
int ep_out;
int ep_out_pksize;
int ep_intr;
int ep_intr_pksize;
int ep_intr_pollms;
} USB_CLASS;
/* For now, leave this public for doing a post-mortum */
HOST_STATE_STRUCT usb_host;
Boolean USBCancelHost = FALSE;
static DEVICE_DESC DeviceDesc;
static CONFIG_DESC ConfigDesc;
static INTERFACE_DESC InterfaceDesc;
static ENDPOINT_DESC EndpointDesc;
/* Prototypes */
static void USBH_isr(int arg);
static void process_token_done_ISR(Uint32 rstatus);
static void ProcessIN_ISR(Uint32 rstatus);
static void ProcessOUT_ISR(Uint32 rstatus);
static void Start_USB_Host_Task(Uint8 code, Uint32 rstatus);
static void USBH_hisr(void);
static Sint32 USB_Host_Task(void *arg);
static Boolean USB_enumerate(void);
static void USB_UnsupportedDevice(void);
static Boolean USB_GetConfiguration(void);
static void reset_the_device(void);
static Uint8 USB_Request(Uint32 *rstatus);
static int USB_GetDescriptor(Uint8 type, Uint8 index, void *desc, Uint16 length);
static Boolean USB_device_request(Uint8 *setup);
static Boolean USB_DoConfiguration(USB_CLASS *class);
static PTPIO_RETN doPTP_USB_ReadInterrupt(Uint8 *Input, Uint32 Size,
Uint32 *retCount);
static Boolean PollInterruptEndpoint(void);
#define MAX_INT_PACKETS 5
static Uint8 intbuff[64];
static Sint32 intcount = -1;
#if USBH_VERBOSE
static int USB_GetString(Uint8 index, Uint16 lang_id);
static void USB_PrintString(Uint8 index, Uint16 lang_id);
#endif
/* NUCLEUS O/S and ts task related declarations */
#define HISR_STACKSIZE 400
#ifndef USBHTASK_STACKSIZE
#define USBHTASK_STACKSIZE 5000
#endif
#ifndef USBHTASK_PRIORITY
#define USBHTASK_PRIORITY 45
#endif
/* hISR (High Interrupt Service Routine) declaration */
static NU_HISR usbh_hisr;
static Uint32 pHISRStack[HISR_STACKSIZE/4];
/* ts: task and semaphore */
static void *TaskUSBH_data;
static tsTaskID TaskUSBH_ID;
static int TaskUSBH_arg;
static Uint32 TaskUSBH_stack[USBHTASK_STACKSIZE/4];
static tsSemaphore USBHSemaphore;
#ifdef MSCLASS_HOST_PASSTHROUGH
/*
* This semaphore is only required for passthrough mode to protect the
* the USB host routines from being reentered by the USB_task in usbch9.c
* which calls the MSCLASS_HOST_PASSTHROUGH camera I/O routines via
* USBMassStorage() and USB_Host_Task() in this module.
*/
static tsSemaphore BLOCKsemaphore;
#define PASSTHROUGH_BLOCK TaskSemWait(BLOCKsemaphore);
#define PASSTHROUGH_UNBLOCK TaskSemSignal(BLOCKsemaphore);
#else
#define PASSTHROUGH_BLOCK
#define PASSTHROUGH_UNBLOCK
#endif
static USB_CLASS MassStorage;
static USB_CLASS StillImage;
/***********************************************************************/
/* Function Name : USBH_isr */
/* Returned Value : None */
/* */
/* Service all the interrupts in the VUSB1.1 host hardware */
/***********************************************************************/
static void USBH_isr(int arg)
{
/* Mask off USB interrupts because we're moving to HISR */
*(unsigned long *)EXMSK1A &= ~(1 << USB1_INTERRUPT_BIT);
NU_Activate_HISR(&usbh_hisr);
/* Clear bit in exception register. */
*(Uint32 *)EXCLRA = (1 << USB1_INTERRUPT_BIT);
}
static void USBH_hisr(void)
{
Uint8 istatus, status, error;
Uint32 rstatus;
/* While any of the enabled interrupts are asserted... */
istatus = *regINT_STAT & *regINT_ENB;
while (istatus) {
error = *regERR_STAT;
status = *regSTATUS;
#ifdef DEBUG
if (status & 0xf0)
status |= 1;
else if (usb_host.cur_pipe)
status |= usb_host.cur_pipe->EP << 4;
#endif
rstatus = ((Uint32)istatus << 16) | ((Uint32)error << 8) | status;
/* Clear error bits */
*regERR_STAT = error & *regERR_ENB;
/* Previous token transmission should already be done */
if (*regCTL & CTRL_TOKEN_BUSY) {
usb_host.state = NO_REQUEST;
usb_host.reset_required = TRUE;
usb_host.DeviceReady = FALSE;
Start_USB_Host_Task(USBH_ERROR, rstatus);
/* Clear all enabled interrupts */
*regINT_STAT = istatus;
/* Check for another interrupt pending */
istatus = *regINT_STAT & *regINT_ENB;
/* Clear bit in exception register. */
*(unsigned long *)EXMSK1A |= (1 << USB1_INTERRUPT_BIT);
*(Uint32 *)EXCLRA = (1 << USB1_INTERRUPT_BIT);
return;
}
/* Check if STALL interrupt */
if (istatus & INTR_STALL) {
/* A bad-CRC16 error is OK with STALL, clear error */
if (error & VUSB_ERR_STAT_CRC16) {
error ^= VUSB_ERR_STAT_CRC16;
if (!error) {
istatus ^= VUSB_INT_STAT_ERROR;
*regINT_STAT = VUSB_INT_STAT_ERROR;
}
}
rstatus = ((Uint32)istatus << 16) | ((Uint32)error << 8) | status;
Start_USB_Host_Task(USBH_STALL, rstatus);
}
/*
* Check if interrupt due to error (but not RESET or ATTACH or
* EOF error) Note: EOF error is caused by SOF_THRESHOLD being
* too small and shouldn't happen in a shipping product.
*/
if ((error & ~2) && !(istatus & (INTR_USB_RST | INTR_ATTACH))) {
if (!(error & 0x60) && usb_host.cur_pipe) {
volatile PIPE_STRUCT *pipe;
BDT_STRUCT *bdt;
/* Get the current pipe and BDT and resend the last token */
pipe = usb_host.cur_pipe;
bdt = (BDT_STRUCT *)((Uint32)pipe->bdt ^ BDT_ODD_EVEN_BIT);
pipe->bdt = bdt;
if ((Uint32)bdt & BDT_OUT_BIT)
usb_host.even_odd_OUT ^= BDT_ODD_EVEN_BIT;
else
usb_host.even_odd_IN ^= BDT_ODD_EVEN_BIT;
bdt->PID = usb_host.nxt_bdt.PID;
bdt->BC = usb_host.nxt_bdt.BC;
bdt->ADDRL = usb_host.nxt_bdt.ADDRL;
bdt->ADDRH = usb_host.nxt_bdt.ADDRH;
*regEP0CTL = pipe->type;
*regADDR = usb_host.USB_addr;
*regTOKEN = pipe->pid_ep;
}
else {
/*
* Force hardware reset if error is DMA or OWN error
* or no pipe
*/
Start_USB_Host_Task(USBH_ERROR, rstatus);
/* Clear all enabled interrupts */
*regINT_STAT = istatus;
/* Check for another interrupt pending */
istatus = *regINT_STAT & *regINT_ENB;
/* Clear bit in exception register. */
*(Uint32 *)EXCLRA = (1 << USB1_INTERRUPT_BIT);
return;
}
}
/* Check if RESET interrupt */
else if (istatus & INTR_USB_RST) {
*regCTL = 0;
/* Let polling routine know that device went bye-bye */
usb_host.DeviceReady = FALSE;
Start_USB_Host_Task(USBH_RESET, rstatus);
}
/* Check if ATTACH interrupt */
else if (istatus & INTR_ATTACH)
Start_USB_Host_Task(USBH_ATTACH, rstatus);
else {
/* Check if token-done interrupt */
if (usb_host.cur_pipe && (istatus & INTR_TOK_DNE))
process_token_done_ISR(rstatus);
#if 0
/* Check if Start of Frame interrupt */
else if (istatus & INTR_SOF_TOK) {
/*
* Update the current interval on the interrupt pipes if
* we supported interrupt pipes
*/
}
#endif
else {
DEBUG_LOG(USBH_INTR, rstatus);
}
}
/* Clear all enabled interrupts */
*regINT_STAT = istatus;
/* Check for another interrupt pending */
istatus = *regINT_STAT & *regINT_ENB;
}
/* Clear bit in exception register. */
*(unsigned long *)EXMSK1A |= (1 << USB1_INTERRUPT_BIT);
*(Uint32 *)EXCLRA = (1 << USB1_INTERRUPT_BIT);
}
/***********************************************************************/
static void process_token_done_ISR(Uint32 rstatus)
{
Uint8 status;
volatile PIPE_STRUCT *pipe;
BDT_STRUCT *bdt;
/* Get the current pipe and BDT */
pipe = usb_host.cur_pipe;
/* Get the status from BDT */
status = pipe->bdt->PID & BDT_PID_MASKS;
if (!status || (status == BDT_NAK_PID)) {
if (pipe->pipe_type == PIPE_INT) {
/* Interrupt pipe NAKed - nothing there so let task know */
Start_USB_Host_Task(USBH_INTNAK, rstatus);
}
else {
/* Warning: NAKs can overflow debug log buffer */
/* DEBUG_LOG(USBH_NAK, rstatus); */
/*
* If a protocol error occurred, host may get NAK'ed forever.
* This timer will force an NAK condition and allow connection
* with camera to be reset and re-enumerated. However, the camera
* may legitimately NAK a bunch of times, so we break out every
* once in a while to intersperse interrupt-endpoint polling,
* as required by certain PictBridge cameras, e.g., Fugi.
*/
if (BIOSTimerMS() - pipe->NAKstart > pipe->NAKtime) {
Start_USB_Host_Task(USBH_INTNAK, rstatus);
pipe->NAKstart = BIOSTimerMS();
return;
}
/* Got an error or a NAK... resend the last token */
bdt = (BDT_STRUCT *)((Uint32)pipe->bdt ^ BDT_ODD_EVEN_BIT);
pipe->bdt = bdt;
if ((Uint32)bdt & BDT_OUT_BIT)
usb_host.even_odd_OUT ^= BDT_ODD_EVEN_BIT;
else
usb_host.even_odd_IN ^= BDT_ODD_EVEN_BIT;
bdt->PID = usb_host.nxt_bdt.PID;
bdt->BC = usb_host.nxt_bdt.BC;
bdt->ADDRL = usb_host.nxt_bdt.ADDRL;
bdt->ADDRH = usb_host.nxt_bdt.ADDRH;
*regEP0CTL = pipe->type;
*regADDR = usb_host.USB_addr;
*regTOKEN = pipe->pid_ep;
}
return;
}
pipe->NAKstart = BIOSTimerMS();
if (usb_host.state == CNTRL_SETUP) {
if (pipe[0].setup_bf[0] & USB_SETUP_DEV2HOST) {
//DEBUG_LOG(USBH_IN, rstatus);
usb_host.state = PROCESS_IN;
pipe[0].pid_ep = VUSB_TOKEN_IN;
bdt = (BDT_STRUCT *)(USB_BDT_PAGE | usb_host.even_odd_IN);
pipe->bdt = bdt;
usb_host.even_odd_IN ^= BDT_ODD_EVEN_BIT;
usb_host.nxt_bdt.PID = BDT_PID_OWN | pipe[0].DATAx;
usb_host.nxt_bdt.BC = pipe->pksize;
usb_host.nxt_bdt.ADDRL = (Uint32)pipe[0].pipe_bf;
usb_host.nxt_bdt.ADDRH = (Uint32)pipe[0].pipe_bf >> 8;
bdt->BC = usb_host.nxt_bdt.BC;
bdt->ADDRL = usb_host.nxt_bdt.ADDRL;
bdt->ADDRH = usb_host.nxt_bdt.ADDRH;
bdt->PID = usb_host.nxt_bdt.PID;
*regEP0CTL = pipe[0].type;
*regADDR = usb_host.USB_addr;
*regTOKEN = pipe[0].pid_ep;
return;
}
else {
usb_host.state = PROCESS_OUT;
pipe[0].pid_ep = VUSB_TOKEN_OUT;
ProcessOUT_ISR(rstatus);
}
}
else if (usb_host.state == PROCESS_IN)
ProcessIN_ISR(rstatus);
else if (usb_host.state == PROCESS_OUT)
ProcessOUT_ISR(rstatus);
else if (usb_host.state == PROCESS_NUL) {
/* Toggle on success after sending null OUT packet */
pipe->DATAx ^= BDT_PID_DATA01;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -