📄 usbh_hcds_urb.c
字号:
/*
* description : USBH HCD URB Management(static)
* Maker : Hiromichi Kondo
* Copyright : (C)2005,SEIKO EPSON Corp. All Rights Reserved.
*/
#include <OSCall.h>
#include <string.h> /* memset */
#include <SPRDEF.h>
#include <SPRSTS.h>
#include <usbh_hcd.h>
#include <usbh_hcds_common.h>
#include <usbh_hcds_channel.h>
#include <usbh_hcds_vhub.h>
#include <usbh_hcds_user_config.h>
/*****************************************
* Define definition
*****************************************/
#define NUM_USB_CH USBH_HCDS_CH_NUM_USB_CH
#define NUM_PENDING_CH NUM_USB_CH
#define CH_NUM_PENDING (0xFE)
#define CH_NUM_UNKNOWN (0xFF)
#define BO_CBW_SIZE (31)
#define BO_CSW_SIZE (13)
#define HUB_BIT (0x01)
#define HUB_PORT_BIT (0x02)
#define OFFSET_BO_CBW_DATA_LENGTH (0x08)
#define BO_CBW_DATA_LENGTH (0x04)
/*****************************************
* Structure definition
*****************************************/
typedef struct tagCH_INFO{
unsigned char chNum;
unsigned char chType;
}CH_INFO;
typedef struct tagURB_MANAGER{
USBH_HCD_LIST_HEAD sActiveURBList;
USBH_HCD_LIST_HEAD sCtrlURBList;
USBH_HCD_LIST_HEAD sBulkURBList;
USBH_HCD_LIST_HEAD sIntURBList;
USBH_HCD_LIST_HEAD sIsoURBList;
USBH_HCD_LIST_HEAD sStrgURBList;
USBH_HCD_URB *psRootIntUrb;
unsigned short pendingAsyncSetupCount;
CH_INFO sCHInfo[NUM_USB_CH + 1];
}URB_MANAGER;
/*****************************************
* Function prototype declaration
*****************************************/
#ifdef DEBUG_C
long NotifyStatusChanged( unsigned long param0, unsigned long param1, void *pParam );
#else /* #ifdef DEBUG_C */
static long NotifyStatusChanged( unsigned long param0, unsigned long param1, void *pParam );
#endif /* #ifdef DEBUG_C */
Inline void URBListEndpointSearchCancel( USBH_HCD_LIST_HEAD *psSearchList, USBH_HCD_USBDEV *psRootDev,
unsigned char devNum, unsigned char epAddress );
static long URBTranCmpCallback( unsigned long chNum, unsigned long urbStatus, void *pParam );
Inline void CheckQueuedURB( CH_INFO *psCHInfo );
Inline long CheckStorageModeURB( USBH_HCD_URB *psUrb );
Inline void ExecURBCallback( USBH_HCD_URB *psUrb, unsigned long urbStatus );
Inline unsigned long GetFIFOSize( USBH_HCD_URB *psUrb, unsigned char chType );
/*****************************************
* Variable definition
*****************************************/
#ifdef DEBUG_C
URB_MANAGER URBStatus;
#else /* #ifdef DEBUG_C */
static URB_MANAGER URBStatus;
#endif /* #ifdef DEBUG_C */
/*=============================================================================================
// Function_Name: USBH_HCDS_URBInit
//
// description : URB management block initialization
//
// Initialize URB Management block
//
// argument : None
//
// return : None
===============================================================================================*/
void USBH_HCDS_URBInit( void )
{
unsigned int i;
memset(&URBStatus, 0, sizeof(URBStatus));
USBH_HCDS_InitListHead(&URBStatus.sActiveURBList);
USBH_HCDS_InitListHead(&URBStatus.sCtrlURBList);
USBH_HCDS_InitListHead(&URBStatus.sBulkURBList);
USBH_HCDS_InitListHead(&URBStatus.sIntURBList);
USBH_HCDS_InitListHead(&URBStatus.sIsoURBList);
USBH_HCDS_InitListHead(&URBStatus.sStrgURBList);
URBStatus.psRootIntUrb = NULL;
for( i = 0; i < NUM_USB_CH; i++ ){
URBStatus.sCHInfo[i].chNum = CH_NUM_UNKNOWN;
}
URBStatus.sCHInfo[NUM_PENDING_CH].chNum = CH_NUM_PENDING;
}
/*=============================================================================================
// Function_Name: USBH_HCDS_URBSubmit
//
// description : URB register and execute
//
// Passed URB is checked, registered and executed
//
// argument : *psUrb (in)Pointer of URB structure
// pfnCallback (in)Pointer of callback function that is called when completed
//
// return : STATUS_SUCCESS Processing completed successfully
// STATUS_INVALID_PARAMETER Parameter error
===============================================================================================*/
long USBH_HCDS_URBSubmit( USBH_HCD_URB *psUrb, USBH_HCD_USBDEV *psRootDev )
{
unsigned char pipeType, chNum, chType;
unsigned long fifoSize;
long retValue;
/*==========================/
Common URB parameter check /
/==========================*/
if( psUrb->pHCPriv != NULL ){
/* Private area for Host Control is used */
return STATUS_INVALID_PARAMETER;
}
if( psUrb->psDev == NULL ){
/* The pointer of the USB device information structure is NULL */
return STATUS_INVALID_PARAMETER;
}
if( psUrb->transBufLength != 0 ){
/* There are datas to transfer */
if( (psUrb->transFlag & USBH_HCD_URB_DIRECT_COPY) == 0 ){
/* URB_DIRECT_COPY is not set in the transfer flag */
if( psUrb->pTransBuf == NULL ){
/* The pointer in the transfer buffer is NULL */
return STATUS_INVALID_PARAMETER;
}
}
}
pipeType = USBH_HCDS_GetPipeType(psUrb->pipe);
/*=============================/
Checks route hub addressing/
/=============================*/
if( psUrb->psDev == psRootDev ){
/* Route hub addressing */
if( pipeType == USBH_HCD_PIPE_CONTROL ){
/* URB of USB request */
if( psUrb->pSetupPacket == NULL ){
/* The pointer of the SETUP packet data is NULL */
return STATUS_INVALID_PARAMETER;
}
retValue = USBH_HCDS_VHUBRequest(psUrb);
if( retValue != STATUS_SUCCESS ){
return retValue;
}
/*==============================/
Call the callback of URB completion/
/==============================*/
ExecURBCallback(psUrb, USBH_HCD_URBSTS_SUCCESS);
} else if( pipeType == USBH_HCD_PIPE_INTERRUPT ){
/* URB of interrupt IN */
/*================================================================/
Save URB of Interrupt IN, and register the notification destination of port status changing /
/================================================================*/
URBStatus.psRootIntUrb = psUrb;
USBH_HCDS_VHUBRegisterCBR(NotifyStatusChanged);
/*=======================/
Buried Channel information /
/=======================*/
psUrb->pHCPriv = psUrb;
} else {
/* Invalid URB */
return STATUS_INVALID_PARAMETER;
}
} else {
/* USB device addressing*/
/*=================/
Channel allocation/
/=================*/
switch( pipeType ){
case USBH_HCD_PIPE_ISOCHRONOUS:
chType = USBH_HCDS_CH_TYPE_ISO;
break;
case USBH_HCD_PIPE_INTERRUPT:
chType = USBH_HCDS_CH_TYPE_INT;
break;
case USBH_HCD_PIPE_CONTROL:
chType = USBH_HCDS_CH_TYPE_CTRL;
break;
case USBH_HCD_PIPE_BULK:
if( psUrb->transFlag & USBH_HCD_URB_STRG_MODE ){
/* URB_STRG_MODE is set in the transfer flag */
retValue = CheckStorageModeURB(psUrb);
if( retValue != STATUS_SUCCESS ){
return retValue;
}
chType = USBH_HCDS_CH_TYPE_STRG;
} else {
chType = USBH_HCDS_CH_TYPE_BULK;
}
break;
default:
return STATUS_INVALID_PARAMETER;
}
fifoSize = GetFIFOSize(psUrb, chType);
chNum = CH_NUM_UNKNOWN;
if( (chType == USBH_HCDS_CH_TYPE_BULK) && (URBStatus.pendingAsyncSetupCount != 0)){
/* The Bulk transfer is required while reserving synchronous transfer(Interrupt/Isochronous) setting */
retValue = STATUS_UNSUCCESSFUL; /* The channel is not allocated and it be putted into the queue. */
} else {
USBH_HCDS_InterruptDisable();
retValue = USBH_HCDS_CHAlloc(&chNum, chType, fifoSize);
USBH_HCDS_InterruptEnable();
}
if( retValue != STATUS_SUCCESS ){
/* Channel allocation failure */
if( retValue == STATUS_CANNOT_SETUP ){
/* It is used by Bulk transfer and when it is not possible to set it */
URBStatus.pendingAsyncSetupCount++; /* Update the synchronous transfer(Interrupt/Isochronous) setting reservation counter */
} else if( retValue == STATUS_UNSUCCESSFUL ){
/* Channel allocate failed */
if( (chType == USBH_HCDS_CH_TYPE_INT) || (chType == USBH_HCDS_CH_TYPE_ISO) ){
/* It makes an error because queuing cannot be done for synchronous transfer type(Interrupt/Isochronous) */
psUrb->pHCPriv = NULL;
return retValue;
}
} else {
/* parameter error or the memory allocate error */
psUrb->pHCPriv = NULL;
return retValue;
}
/*=======================/
Buried channel information /
/=======================*/
psUrb->pHCPriv = &URBStatus.sCHInfo[NUM_PENDING_CH];
/*=================================/
/Be putted into the queue by the channel empty waiting /
/=================================*/
USBH_HCDS_InterruptDisable();
switch( chType ){
case USBH_HCDS_CH_TYPE_ISO:
USBH_HCDS_ListAddTail(&(psUrb->sList), &(URBStatus.sIsoURBList));
break;
case USBH_HCDS_CH_TYPE_INT:
USBH_HCDS_ListAddTail(&(psUrb->sList), &(URBStatus.sIntURBList));
break;
case USBH_HCDS_CH_TYPE_CTRL:
USBH_HCDS_ListAddTail(&(psUrb->sList), &(URBStatus.sCtrlURBList));
break;
case USBH_HCDS_CH_TYPE_BULK:
USBH_HCDS_ListAddTail(&(psUrb->sList), &(URBStatus.sBulkURBList));
break;
case USBH_HCDS_CH_TYPE_STRG:
USBH_HCDS_ListAddTail(&(psUrb->sList), &(URBStatus.sStrgURBList));
break;
}
USBH_HCDS_InterruptEnable();
} else {
/* Channel allocation success */
/*=======================/
Buried channel information /
/=======================*/
psUrb->pHCPriv = &URBStatus.sCHInfo[chNum];
URBStatus.sCHInfo[chNum].chNum = chNum;
URBStatus.sCHInfo[chNum].chType = chType;
/*==========================================/
Put into URB active queue, and execute the channel/
/==========================================*/
USBH_HCDS_InterruptDisable();
USBH_HCDS_ListAddTail(&(psUrb->sList), &(URBStatus.sActiveURBList));
USBH_HCDS_InterruptEnable();
retValue = USBH_HCDS_CHTranGo(psUrb, chNum, URBTranCmpCallback);
if( retValue != STATUS_SUCCESS ){
psUrb->pHCPriv = NULL;
return retValue;
}
}
}
return STATUS_SUCCESS;
}
/*=============================================================================================
// Function_Name: USBH_HCDS_URBUnlink
//
// description : URB cancel and delete process
//
// Passed URB is checked, canceled and deleted
//
// argument : *psUrb (in)Pointer of URB structure
// pfnCallback (in)Pointer of callback function that is called when completed
//
// return : STATUS_SUCCESS Processing completed successfully
// STATUS_INVALID_PARAMETER Parameter error
===============================================================================================*/
long USBH_HCDS_URBUnlink( USBH_HCD_URB *psUrb, USBH_HCD_USBDEV *psRootDev )
{
CH_INFO *psCHInfo;
long retValue;
/*==========================/
Common URB parameter check /
/==========================*/
if( psUrb->psDev == NULL ){
/* The pointer of the USB device information structure is NULL */
return STATUS_INVALID_PARAMETER;
}
if( psUrb->pHCPriv == NULL ){
/* Nothing is done because URB is not registered and not executed */
;
} else {
/* Private area for Host Control is used */
if( psUrb->transFlag & USBH_HCD_URB_STRG_MODE ){
/* URB_STRG_MODE is set in the transfer flag */
retValue = CheckStorageModeURB(psUrb);
if( retValue != STATUS_SUCCESS ){
return retValue;
}
}
/*=============================/
Check if it is the route hub addressing /
/=============================*/
if( psUrb->psDev == psRootDev ){
/* Route hub addressing */
if( psUrb == URBStatus.psRootIntUrb ){
/* URB of Interrupt IN */
/*================================================================/
URB of Interrupt IN is deleted, and the notification destination of port status changing is deleted /
/================================================================*/
URBStatus.psRootIntUrb = NULL;
USBH_HCDS_VHUBRegisterCBR(NULL);
psUrb->pHCPriv = NULL;
}
} else {
/* USB device addressing */
/* URB is executed or is in execution waiting */
USBH_HCDS_InterruptDisable();
psCHInfo = (CH_INFO *)psUrb->pHCPriv;
if( psCHInfo->chNum != CH_NUM_UNKNOWN && psCHInfo->chNum != CH_NUM_PENDING ){
/* In executing */
#ifdef HCD_PARAMCHK_C
retValue = USBH_HCDS_CHTranCancel(psUrb, psCHInfo->chNum);
if( retValue != STATUS_SUCCESS ){
USBH_HCDS_InterruptEnable();
return retValue;
}
#else /* #ifdef HCD_PARAMCHK_C */
USBH_HCDS_CHTranCancel(psUrb, psCHInfo->chNum);
#endif /* #ifdef HCD_PARAMCHK_C */
}
USBH_HCDS_ListDel(&(psUrb->sList));
psUrb->pHCPriv = NULL;
USBH_HCDS_InterruptEnable();
/* Queuing URB is checked */
CheckQueuedURB(psCHInfo);
}
if( (psUrb->transFlag & USBH_HCD_URB_ASYNC_UNLINK) != 0 ){
/* The callback of URB is called before it reports on the cancel completion */
/*==============================/
Call the completion callback of URB/
/==============================*/
ExecURBCallback(psUrb, USBH_HCD_URBSTS_CONNRESET);
}
}
return STATUS_SUCCESS;
}
/*=============================================================================================
// Function_Name: USBH_HCDS_URBEndpointAllCancel
//
// description : Cancel all URB of corresponding Endpoint
//
// Corresponding URB is canceled from passed USB device information structure and Endpoint address
//
// argument : *psDev (in)Pointer of USB device information structure
// epAddress (in)Endpoint address(Direction+EP number)
//
// return : STATUS_SUCCESS Processing completed successfully
// STATUS_INVALID_PARAMETER Parameter error
===============================================================================================*/
long USBH_HCDS_URBEndpointAllCancel( USBH_HCD_USBDEV *psDev, USBH_HCD_USBDEV *psRootDev, unsigned char epAddress )
{
unsigned char targetDevNum;
if( psDev == psRootDev ){
/* Route hub addressing */
/*===============/
Cancel process/
/===============*/
if( URBStatus.psRootIntUrb != NULL ){
/* URB for interrupt has been registered */
USBH_HCDS_URBUnlink(URBStatus.psRootIntUrb, psRootDev);
}
} else {
/* USB device addressing */
targetDevNum = psDev->devNum;
USBH_HCDS_InterruptDisable();
URBListEndpointSearchCancel(&URBStatus.sCtrlURBList, psRootDev, targetDevNum, epAddress);
URBListEndpointSearchCancel(&URBStatus.sBulkURBList, psRootDev, targetDevNum, epAddress);
URBListEndpointSearchCancel(&URBStatus.sIntURBList, psRootDev, targetDevNum, epAddress);
URBListEndpointSearchCancel(&URBStatus.sIsoURBList, psRootDev, targetDevNum, epAddress);
URBListEndpointSearchCancel(&URBStatus.sStrgURBList, psRootDev, targetDevNum, epAddress);
URBListEndpointSearchCancel(&URBStatus.sActiveURBList, psRootDev, targetDevNum, epAddress);
USBH_HCDS_InterruptEnable();
}
return STATUS_SUCCESS;
}
/*=============================================================================================
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -