?? usbh_hw.c
字號:
/*2005/12/15 jessefanchiang
bug: Bulk In Second data will save to First Bulk IN Last one Buffer position
from:
1.HISR token Done Enable BulkIN Last one transaction.
2.SOF Interrupt will Find BulkIN transaction to Enable
*/
#include "standard.h"
#include "nucleus.h"
#include "usbhost.h"
//#define HOSTHW_PRINTF logprintf
#define HOSTHW_PRINTF if(0) printf
#define HISR_STACKSIZE 800
#define USB_BDT_PAGE ( (Uint32) USB10BDT0REG0 )
static Uint32 pHISRStack[HISR_STACKSIZE];
static NU_HISR usbh_hisr;
EP_DATA *Ctrl_ep;
DEV_INFO *device_info;
HOST_QUEUE_HEAD ISO_QH,INT_QH,CONTROL_QH,BULK_QH;
void QH_init(void)
{
HOST_QUEUE_HEAD *curr_QH;
// HOSTHW_PRINTF("BULK QH init\n");
BULK_QH.TD_num=4;
BULK_QH.TD_head=NULL;
BULK_QH.TD_tail=NULL;
// HOSTHW_PRINTF("CONTROL QH init\n");
CONTROL_QH.TD_num=3;
CONTROL_QH.TD_head=NULL;
CONTROL_QH.TD_tail=NULL;
// HOSTHW_PRINTF("INT QH init\n");
INT_QH.TD_num=2;
INT_QH.TD_head=NULL;
INT_QH.TD_tail=NULL;
// HOSTHW_PRINTF("ISO QH init\n");
ISO_QH.TD_num=1;
ISO_QH.TD_head=NULL;
ISO_QH.TD_tail=NULL;
// HOSTHW_PRINTF("QH Link\n");
ISO_QH.QH_next = &INT_QH;
INT_QH.QH_next = &CONTROL_QH;
CONTROL_QH.QH_next = &BULK_QH;
BULK_QH.QH_next = &ISO_QH;
//verify QH link
HOSTHW_PRINTF("USBH: ISO QH Addr=0x%x, next QH=0x%x\n",&ISO_QH,ISO_QH.QH_next);
HOSTHW_PRINTF("USBH: INT QH Addr=0x%x, next QH=0x%x\n",&INT_QH,INT_QH.QH_next);
HOSTHW_PRINTF("USBH: CONTROL QH Addr=0x%x, next QH=0x%x\n",&CONTROL_QH,CONTROL_QH.QH_next);
HOSTHW_PRINTF("USBH: BULK QH Addr=0x%x, next QH=0x%x\n",&BULK_QH,BULK_QH.QH_next);
}
/*Transfer Setting Fill to Register*/
void Fill2REG_FCT(TRANSACTION_STRUCT *currTD)
{
BDT_STRUCT *bdt;
//Select Data IN/OUT
if((currTD->state&0x0F)==PROCESS_IN)
{
//Data IN Setting
//1.Get Data IN BDT
//2.Link to Txf
//3.BDT Buffer Setting
//4.COntrol Register Setting
bdt = (BDT_STRUCT *)((Uint32)USB_BDT_PAGE | USBHOST_EVEN_ODD_IN_GET());//usb_host.even_odd_IN);
currTD->bdt = bdt;
USBHOST_EVEN_ODD_IN_SET();
//usb_host.even_odd_IN ^= BDT_ODD_EVEN_BIT;
}
else if(((currTD->state&0x0F)==PROCESS_OUT)||
((currTD->state&0x0f)==CNTRL_SETUP)||
((currTD->state&0x0f)==CNTRL_LAST))
{
//Data OUT Setting
//1.Get Data OUT BDT
//2.Link to Txf
//3.BDT Buffer Setting
//4.COntrol Register Setting
bdt = (BDT_STRUCT *)((Uint32)USB_BDT_PAGE | USBHOST_EVEN_ODD_OUT_GET());//usb_host.even_odd_OUT);
currTD->bdt = bdt;
USBHOST_EVEN_ODD_OUT_SET();
//usb_host.even_odd_OUT ^= BDT_ODD_EVEN_BIT;
}
*regBUFBASEL = currTD->BUFBASEL;
*regBUFBASEH = currTD->BUFBASEH;
/* Enable the token done, error, STALL and RESET interrupts */
// *regINT_ENB = INTR_TOK_DNE | INTR_ERROR | INTR_STALL | INTR_USB_RST | INTR_SOF_TOK;
/* Ship it */
bdt->PID = currTD->bdt_PID;
bdt->BC = currTD->bdt_BC;
bdt->ADDRL = currTD->bdt_ADDRL;
bdt->ADDRH = currTD->bdt_ADDRH;
*regEP0CTL = currTD->EP0CTL;
*regADDR = currTD->ADDR;
*regTOKEN = currTD->TOKEN;
}
TRANSACTION_STRUCT *SearchQHsTD(HOST_QUEUE_HEAD *QH)
{
Uint8 i;
TRANSACTION_STRUCT *TD;
HOST_QUEUE_HEAD *CurrQH, *NextQH;
CurrQH=QH;
NextQH=QH->QH_next;
for(i=1;i<=4;i++){
if(CurrQH->TD_head!=NULL){ //Check QH 's Has TD or Not
return CurrQH->TD_head;
}
else{
CurrQH=NextQH; //Get Next QH
NextQH=CurrQH->QH_next;
}
}
return NULL;
}
void QH_RemoveTD(HOST_QUEUE_HEAD *QH, TRANSACTION_STRUCT *CurrTD)
{
TRANSACTION_STRUCT *head, *prve, *next;
head=QH->TD_head;
next=CurrTD->TD_next;
/*Case 1. QH First TD*/
if(head==CurrTD){
/*Case1.1 TD Tail*/
if(next==NULL){
QH->TD_head=NULL;
QH->TD_tail=NULL;
}
/*Case1.2 Link to Next TD*/
else
QH->TD_head=next;
}
/*Case 2. Multi TD*/
else{
//prve=usb_host.prve_TD; /*Get Prve TD*/
prve=(TRANSACTION_STRUCT *)USBHOST_PRVE_TD_GET();
/*Case2.1 TD Tail*/
if(next==NULL){
prve->TD_next=NULL; /*Init Prve TD_next=NULL*/
QH->TD_tail=prve;
}
/*Case2.2 Link to Next TD*/
else
prve->TD_next=next; /*Prve Link to TD->TD_next*/
}
free(CurrTD);
}
void SOF_ISR(void)
{
TRANSACTION_STRUCT *currTD;
currTD=SearchQHsTD(&ISO_QH);
if(currTD==NULL){/*No Any More TD Link to QH*/
// usb_host.curr_QH=NULL;
// usb_host.prve_TD=NULL;
// usb_host.curr_TD=NULL;
USBHOST_CURR_QH_RESET();
USBHOST_CURR_TD_RESET();
USBHOST_PRVE_TD_RESET();
return;
}
// //2005/12/14 jessefanchiang
// //Check Curr TD BDT OWN Setting
// if((currTD->bdt->PID&&BDT_PID_OWN)==BDT_PID_OWN)
// return;
//2.QH Init
// usb_host.curr_QH=(HOST_QUEUE_HEAD*)currTD->QH;
USBHOST_CURR_QH_SET((HOST_QUEUE_HEAD*)currTD->QH);
//3.TD Init
// usb_host.prve_TD=currTD;
// usb_host.curr_TD=currTD;
USBHOST_CURR_TD_SET(currTD);
USBHOST_PRVE_TD_SET(currTD);
//4.Setting
Fill2REG_FCT(currTD);
}
//Get Curr TD Data
//Set Next TD
//Remove Finish TD
Uint8 debug_tokendone_log[500];
Uint16 Debug_tokendone_count=0;
Uint32 Debug_tokendone_step=0;
void Debug_TokenDone_record(Uint32 data)
{
if(Debug_tokendone_count>499)
Debug_tokendone_count=0;
debug_tokendone_log[Debug_tokendone_count]=(Uint8)data;
Debug_tokendone_count++;
}
void TokenDone_ISR(Uint32 rstatus)
{
Uint8 status, tmp;
Uint32 PROCESS_ID, new_Addr, remain_byte, bytecnt;
EP_DATA *ep;
BDT_STRUCT *bdt;
HOST_QUEUE_HEAD *this_qh;
TRANSACTION_STRUCT *this_td, *nextTD;
Uint32 dbg_log=0;
this_qh = (HOST_QUEUE_HEAD *)USBHOST_CURR_QH_GET();
this_td = (TRANSACTION_STRUCT *)USBHOST_CURR_TD_GET();
nextTD = this_td->TD_next;
PROCESS_ID = (Uint32)this_td->state;
ep = this_td->curr_EP;
status = this_td->bdt->PID & BDT_PID_MASKS; /* Get the status from BDT */
if (!status || (status == BDT_NAK_PID)) /*When TD NAK From USB Device*/
{
dbg_log=0x30000000;
/*Interrupt IN NAK*/
if((this_td->state&0xF0) == INT_TRANSACTION){
QH_RemoveTD(this_qh, this_td); /*Remove Curr TD*/
USBH_work_report(USBH_INTNAK, PROCESS_ID, rstatus);
dbg_log |=0x1000000;
}
/*Others NAK*/
else{
dbg_log |=0x2000000;
if (++this_td->NAKcount > 30000) {
QH_RemoveTD(this_qh, this_td); /*Remove Curr TD*/
USBH_work_report(USBH_NAK, PROCESS_ID, rstatus); //Notify to Call Bake FCT
this_td->NAKcount = 0;
dbg_log |=0x400000;
goto next_td_setting;
}
USBHOST_PRVE_TD_SET(this_td);
dbg_log |=0x300000;
}
goto next_td_setting;
}
if(((this_td->state&0x0f)==CNTRL_SETUP)||((this_td->state&0x0f)==CNTRL_LAST)){
QH_RemoveTD(this_qh, this_td);/*Remove Curr TD*/
USBH_work_report(USBH_DONE, PROCESS_ID, rstatus);
dbg_log=0x20000000;
// HOSTHW_PRINTF("log 0x%x\n",dbg_log);
return;
}
dbg_log=0x10000000;
/* Endpoint Data Toggle*/
ep->DATAx ^= BDT_PID_DATA01;
bdt = this_td->bdt; /*Host Buffer Descriptor Table*/
bytecnt = bdt->BC; /*Data Bytes Count*/
ep->curr_count += bytecnt;
/*--------------------------------Debug Log Message-----------------------------------------*/
// temp to disable 2005/12/19 jessefanchiang debug for USBD 1.1
// HOSTHW_PRINTF("ByteCount %d InOdd:%d InEven:%d OutOdd:%d OutEven:%d\n",
// bytecnt,*(Uint8 *)0xE0480031,*(Uint8 *)0xE0480035,*(Uint8 *)0xE0480039,*(Uint8 *)0xE048003D);
// HOSTHW_PRINTF("DATAx %x Curraddr %x%x%x%x\n",
// ep->DATAx,this_td->BUFBASEH,this_td->BUFBASEL,this_td->bdt_ADDRH,this_td->bdt_ADDRL);
// bdt->BC=0;
/*--------------------------------Debug Log Message-----------------------------------------*/
/*Get Remain Bytes*/
remain_byte = this_td->length - ep->curr_count;
this_td->bdt_BC = ep->pksize; /*Set BDT Byte Count*/
if (remain_byte < ep->pksize) /*Set BDT Byte Count if Short Packet*/
this_td->bdt_BC = (Uint8)remain_byte;
/*2.Done Condition*/
if((this_td->length==ep->curr_count)||(bytecnt != this_td->curr_EP->pksize)){
dbg_log |=0x3000000;
//Bulk OUT Zero Packet
//1.total length mod 64 ==0
//2.transaction ID is Bulk OUT
//3.curr byte count=64
//4.Finish Send Zero Packet byte count=0
if(((this_td->length%64)==0)&&((this_td->state&0x0F)==PROCESS_OUT)&&(bytecnt)){
this_td->bdt_BC=0;
HOSTHW_PRINTF("BULK OUT Send Zero Packet\n");
dbg_log |=0x500000;
}
else{
QH_RemoveTD(this_qh, this_td);/*Remove Curr TD*/
USBH_work_report(USBH_DONE, PROCESS_ID, rstatus);
dbg_log |=0x400000;
goto next_td_setting;
}
}
dbg_log |=0x60000;
/*Init Next Packet Data Toggle*/
this_td->bdt_PID = BDT_PID_OWN | ep->DATAx;
/*init Next Packet Buffer head*/
new_Addr=(Uint32)(this_td->io_bf+ep->curr_count); //Get Next Data Buffer Start
if(new_Addr >(Uint32)(this_td->io_bf+this_td->length)){
HOSTHW_PRINTF("USBH IO Buffer Error\n");
while(1);
}
IObf_2_BDT(this_td, (Uint8 *)new_Addr); //TD Buffer Address Converter
HOSTHW_PRINTF("NextAddr %x\n",new_Addr);
next_td_setting:
return;//Direct EXit,Don't Enable Next transaction Descriptor
//SOF Interrupt Check
tmp=(Uint8)(rstatus>>16);
if((tmp&INTR_SOF_TOK)==INTR_SOF_TOK){
dbg_log |=0x1000;
// HOSTHW_PRINTF("log 0x%x BC %d\n",dbg_log,bytecnt);
return;
}
dbg_log |=0x2000;
USBHOST_PRVE_TD_SET(this_td); //Change Next TD to Do,Remeber Curr TD
/*QH TD Tail Get Next QH's TD*/
if(nextTD==NULL){
dbg_log |=0x100;
nextTD=SearchQHsTD(this_qh->QH_next);
if(nextTD==NULL){/*No Any More TD Link to QH*/
USBHOST_CURR_QH_RESET();
USBHOST_CURR_TD_RESET();
USBHOST_PRVE_TD_RESET();
dbg_log |=0x10;
// HOSTHW_PRINTF("log 0x%x BC %d\n",dbg_log,bytecnt);
return;
}
dbg_log |=0x20;
USBHOST_CURR_QH_SET((HOST_QUEUE_HEAD*)nextTD->QH);
USBHOST_PRVE_TD_SET(nextTD);
}
dbg_log |=1;
USBHOST_CURR_TD_SET(nextTD);
Fill2REG_FCT(nextTD);
// HOSTHW_PRINTF("log 0x%x BC %d\n",dbg_log,bytecnt);
}
static void USBH_hisr(void)
{
Uint8 istatus, status, error;
Uint32 rstatus;
Uint32 PROCESS_ID=0;
/* While any of the enabled interrupts are asserted... */
istatus = *regINT_STAT & *regINT_ENB;
while (istatus)
{
error = *regERR_STAT;
status = *regSTATUS;
/*Action Status+INT Status+Error Status+Transaction Status*/
/*Action Status is Current Action Status */
/*INT Status is Interrupt Status Register Value */
/*ERROR Status is Error Occurred Status Value */
/*Transation Status is HOST Controller Transaction Status */
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 = NOT_READY;
// 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;
USBH_work_report(USBH_STALL, PROCESS_ID, rstatus);
}
/* Check if ATTACH interrupt */
else if (istatus & INTR_ATTACH)
{
*regINT_ENB=0;
USBH_work_report(USBH_ATTACH, PROCESS_ID, rstatus);
}
else if (istatus & INTR_TOK_DNE){
*regINT_STAT = istatus; /* Clear all enabled interrupts */
TokenDone_ISR(rstatus);
istatus = *regINT_STAT & *regINT_ENB; /* Check for another interrupt pending */
continue;
}
else if (istatus & INTR_SOF_TOK)
SOF_ISR(); /*SOF 1ms do one time start from ISO transfer*/
else if (istatus & INTR_ERROR)
USBH_work_report(USBH_ERROR, PROCESS_ID, rstatus);
/* Check if RESET interrupt */
else if (istatus & INTR_USB_RST)
{
*regCTL = 0;
/* Let polling routine know that device went bye-bye */
USBHOST_DEVICEREADY_SET(NOT_READY);
//usb_host.DeviceReady = NOT_READY;
USBH_work_report(USBH_RESET, PROCESS_ID, 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);
}
/***********************************************************************/
/* Function Name : USBH_isr */
/* Returned Value : None */
/* */
/* Service all the interrupts in the VUSB1.1 host hardware */
/***********************************************************************/
static void USBH_isr(int vector)
{
/* 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);
}
void usbh_hw_init(void)
{
DEV_INFO *DEV;
STATUS status;
void (*old_lisr)(int);
//Default Pipe Create
Ctrl_ep=(EP_DATA *)calloc(sizeof(EP_DATA),1);
//Device Info Struct
device_info=(DEV_INFO *)calloc(sizeof(DEV_INFO)*DEVID_MAX,1);
QH_init();
/* Register HISR */
status = NU_Create_HISR(&usbh_hisr, "HostHISR", USBH_hisr, 2, pHISRStack,
HISR_STACKSIZE);
ASSERT(status == NU_SUCCESS);
/* Install the LISR (Low Interrupt Service Routine). */
status = NU_Register_LISR(USB1_INTERRUPT_BIT, USBH_isr, &old_lisr);
ASSERT(status == NU_SUCCESS);
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -