S3C2440 USB 設(shè)備控制器
        s3c2440 
soc集成了一個usb1.1設(shè)備控制器,可以進(jìn)行全速/低速的控制,中斷與批量傳輸。除了端點(diǎn)0,具有四個端點(diǎn),每個端點(diǎn)都可以作為中斷與批量的端點(diǎn),
每個端點(diǎn)具有128 
byte的FIFO,所以端點(diǎn)最大packet可以設(shè)置成128byte。并且支持DMA傳輸。任何一種設(shè)備控制器對于軟件來說都是一組寄存器:數(shù)據(jù),狀
態(tài),控制。usb 
設(shè)備控制器也不例外。設(shè)置好相應(yīng)的控制寄存器,并且在數(shù)據(jù)來時讀取數(shù)據(jù)寄存器,需要發(fā)送數(shù)據(jù)的時候?qū)?shù)據(jù)寫入輸出寄存器。而這種數(shù)據(jù)的通信建立在對狀態(tài)寄
存器的讀取上,往往還會有中斷與DMA的操作。s3c2440
 usb設(shè)備控制器的寄存器分為以下幾組:
(1):電源管理寄存器
        PWR_REG 負(fù)責(zé)USB設(shè)備掛起等電源設(shè)置
(2):地址寄存器
        存儲USB設(shè)備的地址,當(dāng)主機(jī)枚舉設(shè)備設(shè)備的時候設(shè)置
(3):中斷控制寄存器
        EP_INT_REG    端點(diǎn)中斷狀態(tài)寄存器,每當(dāng)一個端點(diǎn)事件發(fā)生的時候,相應(yīng)的位就會置1
        USB_INT_REG   設(shè)備中斷狀態(tài)寄存器,主要有三個中斷:喚醒,復(fù)位,掛起
        EP_INT_EN_REG  端點(diǎn)中斷使能寄存器
        EP_INT_EN_REG  設(shè)備中斷使能寄存器
(4):編號寄存器
        因為USB 設(shè)備控制器有五個端點(diǎn),并且五個端點(diǎn)寄存器大同小異,所以硬件設(shè)計上使用了編號寄存器:名字相同但物理寄存器不同。有一個INDEX_REG寄存器,它里面的值指示了具體的哪組物理寄存器。這樣的寄存器有七個分別是:
        MAXP_REG: 端點(diǎn)最大信息包大小
        IN_CSR1_REG
        IN_CSR2_REG
        OUT_CSR1_REG
        OUT_CSR2_REG
        OUT_FIFO_CNT1_REG
        OUT_FIFO_CNT2_REG
(5):FIFO寄存器
        EPO_FIFO_REG
        EP1_FIFO_REG
        EP2_FIFO_REG
        EP3_FIFO_REG
        EP4_FIFO_REG
(6):DMA寄存器
        端點(diǎn)1~4,每個端點(diǎn)六個,用于設(shè)置端點(diǎn)的DMA傳輸。
        
USB設(shè)備控制器處理了大部分的USB傳輸細(xì)節(jié),并產(chǎn)生相應(yīng)的中斷。所以對USB設(shè)備控制器的編程,最關(guān)鍵的部分就是中斷處理的部分。比如端點(diǎn)每收到一個
token以及后面的數(shù)據(jù)包,就會產(chǎn)生相應(yīng)的中斷。軟件只需要在中斷處理程序中讀取數(shù)據(jù),并且清除中斷標(biāo)志。USB設(shè)備控制器就會自動發(fā)送應(yīng)答包?,F(xiàn)在網(wǎng)
上比較流行的操作s3c2440 usb 
設(shè)備控制器的程序就是移植到u-boot里面的usb下載程序。因為在u-boot的環(huán)境下所以調(diào)試起來沒有在裸機(jī)上來的方便,所以我將這個程序移植到了
裸機(jī)上,編譯環(huán)境arm-linux-gcc。下面大體介紹以下這個程序的流程:
        
這個程序主要是完成了USB設(shè)備的枚舉,與批量OUT傳輸,并且開啟了DMA,OUT傳輸用的端點(diǎn)是端點(diǎn)3。這個程序首先從
init_usb_slave() 開始:這個函數(shù)主要是設(shè)置usb slave的引腳以及控制寄存器,設(shè)置中斷處理程序的入口,以及開啟中斷。
- void usb_init_slave(void)  
- {  
-         struct s3c24x0_gpio * const gpioregs = s3c24x0_get_base_gpio();  
-         char *mode;  
-   
-         Delay(10);  
-   
-         Usb_Isr_Init();    
-         
-          writel((readl(&gpioregs->MISCCR) & ~((1<<3) | (1<<13))), &gpioregs->MISCCR);  
-   
-   
-   
-   
-   
-         isUsbdSetConfiguration=0;  
-   
-         UsbdMain();   
-         Delay(10);  
-   
-         writel((readl(&gpioregs->GPCDAT) | (1<<5)), &gpioregs->GPCDAT);  
-           
-   
-    
- #if USBDMA  
-         mode="DMA";     
- #else  
-         mode="Int";  
- #endif  
-         download_run=0;   
-         printk("USB slave is enable!\n");  
-           
- }  
        在配置完設(shè)備后,給GPC5一個高電平,主機(jī)就開始枚舉設(shè)備的過程了。能不能開始這個過程關(guān)鍵是看設(shè)備是否配置正確。這就是要看UsbMain()這個函數(shù)了。他在usbmain.c中,如下:
- void UsbdMain(void)  
- {  
-     InitDescriptorTable();  
-     ConfigUsbd();   
-     PrepareEp1Fifo();   
- }  
 
       
這個函數(shù)挺簡單,但是調(diào)用了三個函數(shù)可不簡單。第一個就是初始化一些USB描述符,比如設(shè)備描述符,配置描述符等,在usb控制傳輸?shù)臅r候返回給設(shè)備。這
個函數(shù)在usbsetup.c中。PrepareEp1Fifo()是配置端點(diǎn)1的,這里沒有用到。關(guān)鍵的是ConfigUsbd()函數(shù),這個函數(shù)是最
主要的配置函數(shù)。在usblib.c中:
- void ConfigUsbd(void)  
- {  
-         struct s3c24x0_interrupt * intregs = s3c24x0_get_base_interrupt();  
-         ReconfigUsbd();  
-         writel((readl(&intregs->INTMSK) & ~(BIT_USBD)), &intregs->INTMSK);  
- }  
        這個函數(shù)是個封裝函數(shù),第一次配置調(diào)用他,并且開啟中斷。在重置USB的過程中調(diào)用的是ReconfigUsbd(),這個函數(shù)也在usblib.c中:
- void ReconfigUsbd(void)  
- {  
-   
-   
-   
-   
-   
-   
-     struct s3c24x0_usb_device * const usbdevregs    = s3c24x0_get_base_usb_device();     
-    
-     writeb(PWR_REG_DEFAULT_VALUE, &usbdevregs->PWR_REG);   
-     writeb(0, &usbdevregs->INDEX_REG);   
-     writeb(FIFO_SIZE_8, &usbdevregs->MAXP_REG);   
-     writeb((EP0_SERVICED_OUT_PKT_RDY | EP0_SERVICED_SETUP_END), & usbdevregs->EP0_CSR_IN_CSR1_REG);   
-     writeb(1, &usbdevregs->INDEX_REG);   
-   
- #if (EP1_PKT_SIZE==32)  
-     writeb(FIFO_SIZE_32, &usbdevregs->MAXP_REG);   
- #else  
-     writeb(FIFO_SIZE_64, &usbdevregs->MAXP_REG);       
- #endif    
-     writeb((EPI_FIFO_FLUSH | EPI_CDT), &usbdevregs->EP0_CSR_IN_CSR1_REG);   
-     writeb((EPI_MODE_IN | EPI_IN_DMA_INT_MASK | EPI_BULK), &usbdevregs->IN_CSR2_REG);    
-     writeb(EPO_CDT, &usbdevregs->OUT_CSR1_REG);   
-     writeb((EPO_BULK | EPO_OUT_DMA_INT_MASK), &usbdevregs->OUT_CSR2_REG);   
-   
-     writeb(2, &usbdevregs->INDEX_REG);   
-     writeb(FIFO_SIZE_64, &usbdevregs->MAXP_REG);   
-     writeb((EPI_FIFO_FLUSH | EPI_CDT | EPI_BULK), &usbdevregs->EP0_CSR_IN_CSR1_REG);   
-     writeb((EPI_MODE_IN | EPI_IN_DMA_INT_MASK), &usbdevregs->IN_CSR2_REG);    
-     writeb(EPO_CDT, &usbdevregs->OUT_CSR1_REG);   
-     writeb((EPO_BULK | EPO_OUT_DMA_INT_MASK), &usbdevregs->OUT_CSR2_REG);   
-   
-     writeb(3, &usbdevregs->INDEX_REG);   
-     #if (EP3_PKT_SIZE==32)  
-     writeb(FIFO_SIZE_32, &usbdevregs->MAXP_REG);   
-     #else  
-     writeb(FIFO_SIZE_64, &usbdevregs->MAXP_REG);   
-     #endif  
-     writeb((EPI_FIFO_FLUSH | EPI_CDT | EPI_BULK), &usbdevregs->EP0_CSR_IN_CSR1_REG);       
-     writeb((EPI_MODE_OUT | EPI_IN_DMA_INT_MASK), &usbdevregs->IN_CSR2_REG);   
-     writeb(EPO_CDT, &usbdevregs->OUT_CSR1_REG);   
-           
-       
-     writeb((EPO_BULK | EPO_OUT_DMA_INT_MASK), &usbdevregs->OUT_CSR2_REG);   
-   
-     writeb(4, &usbdevregs->INDEX_REG);   
-     writeb(FIFO_SIZE_64, &usbdevregs->MAXP_REG);   
-     writeb((EPI_FIFO_FLUSH | EPI_CDT | EPI_BULK), &usbdevregs->EP0_CSR_IN_CSR1_REG);   
-     writeb((EPI_MODE_OUT | EPI_IN_DMA_INT_MASK), &usbdevregs->IN_CSR2_REG);   
-     writeb(EPO_CDT, &usbdevregs->OUT_CSR1_REG);   
-           
-       
-     writeb((EPO_BULK | EPO_OUT_DMA_INT_MASK), &usbdevregs->OUT_CSR2_REG);   
-       
-     writeb((EP0_INT | EP1_INT | EP2_INT | EP3_INT | EP4_INT), &usbdevregs->EP_INT_REG);   
-     writeb((RESET_INT | SUSPEND_INT | RESUME_INT), &usbdevregs->USB_INT_REG);   
-           
-           
-     writeb((EP0_INT | EP1_INT | EP3_INT), &usbdevregs->EP_INT_EN_REG);   
-     writeb(RESET_INT, &usbdevregs->USB_INT_EN_REG);   
-         ep0State = EP0_STATE_INIT;  
-       
- }  
        可以看出首先是操作電源管理寄存器關(guān)閉自動掛起功能,然后就是針對每個端點(diǎn)來配置,主要設(shè)置端點(diǎn)的最大信息包的大小,端點(diǎn)類型,傳輸方向。以及是否支持DMA。最主要的是端點(diǎn)0與端點(diǎn)3因為其他三個端點(diǎn)沒有用到。最后清除所有的中斷狀態(tài)寄存器的標(biāo)志。
        usb 設(shè)備控制器最主要的部分就是中斷處理程序,本程序中的USB中斷處理程序是void IsrUsbd(void),在usbmain.c中:
- void IsrUsbd(void)  
- {  
-     struct s3c24x0_usb_device * const usbdevregs    = s3c24x0_get_base_usb_device();  
-     U8 usbdIntpnd,epIntpnd;  
-     U8 saveIndexReg = readb(&usbdevregs->INDEX_REG);  
-   
-     usbdIntpnd = readb(&usbdevregs->USB_INT_REG);  
-     epIntpnd = readb(&usbdevregs->EP_INT_REG);  
-   
-     if(usbdIntpnd&SUSPEND_INT)  
-     {  
-     writeb(SUSPEND_INT, &usbdevregs->USB_INT_REG);  
-       
-     }  
-     if(usbdIntpnd&RESUME_INT)  
-     {  
-     writeb(RESUME_INT, &usbdevregs->USB_INT_REG);  
-       
-     }  
-     if(usbdIntpnd&RESET_INT)  
-     {  
-       
-           
-           
-         ReconfigUsbd();  
-     writeb(RESET_INT, &usbdevregs->USB_INT_REG);   
-         PrepareEp1Fifo();   
-     }  
-       
-     if(epIntpnd&EP0_INT)  
-     {  
-     writeb(EP0_INT, &usbdevregs->EP_INT_REG);  
-         Ep0Handler();  
-     }  
-       
-     if(epIntpnd&EP1_INT)  
-     {  
-     writeb(EP1_INT, &usbdevregs->EP_INT_REG);  
-         Ep1Handler();  
-     }  
-       
-     if(epIntpnd&EP2_INT)  
-     {  
-     writeb(EP2_INT, &usbdevregs->EP_INT_REG);  
-       
-           
-     }  
-   
-     if(epIntpnd&EP3_INT)  
-     {  
-     writeb(EP3_INT, &usbdevregs->EP_INT_REG);  
-     printk("Ep3hander\n");  
-         Ep3Handler();  
-     }  
-   
-     if(epIntpnd&EP4_INT)  
-     {  
-     writeb(EP4_INT, &usbdevregs->EP_INT_REG);  
-     
-           
-     }  
-   
-     ClearPending_my((int)BIT_USBD);    
-     writeb(saveIndexReg, &usbdevregs->INDEX_REG);      
- }  
 
       USB 
最重要要的是時序,打印函數(shù)是很費(fèi)時間的,所以如果在USB中斷處理程序中加入打印函數(shù),有可能造成總線超時,從而使得USB傳輸不能成功。下面針對
USB設(shè)備枚舉來說明以下控制傳輸,相應(yīng)的中斷處理程序Ep0Handler(),在usbsetup.c中:
        這個函數(shù)比較長,我就不貼代碼了。這個函數(shù)主要就是針對中斷的類型類進(jìn)行相應(yīng)的處理:
        writeb(0, &usbdevregs->INDEX_REG);
        ep0_csr = readb(&usbdevregs->EP0_CSR_IN_CSR1_REG);
        
EP0_CSR_IN_CSR1_REG寄存器里面有相應(yīng)端點(diǎn)的相應(yīng)中斷類型。其中有兩種中斷是不正常狀態(tài),EP0_SETUP_END這個標(biāo)志表示,控
制傳輸,SETUP階段在數(shù)據(jù)包到來前,傳輸就結(jié)束了。造成這個原因有可能是總線超時,如果主機(jī)在送出SETUP包以及數(shù)據(jù)包之后,USB設(shè)備遲遲不發(fā)送
應(yīng)答包。EP0_SENT_STALL 當(dāng)設(shè)備不正常的時候這個標(biāo)志會置位。
        EP0_OUT_PKT_READY 
這個標(biāo)志是正常的狀態(tài),在USB設(shè)備接收到了一個正確的Token以及數(shù)據(jù)包是,這個標(biāo)志就置位,從而程序可以從FIFO中讀取數(shù)據(jù)根據(jù)setup包中根
據(jù)請求類型來進(jìn)行相應(yīng)的處理。然后清除這個標(biāo)志。USB設(shè)備控制器就會自動發(fā)送ACK包給主機(jī),從而結(jié)束一個事務(wù)。類似,程序用到用于下載的OUT批量傳
輸端點(diǎn)3的中斷處理程序Ep3Handler也是這樣一個流程。但是不同的是這里還用到了DMA傳輸。
- void Ep3Handler(void)  
- {  
-     struct s3c24x0_interrupt * intregs = s3c24x0_get_base_interrupt();  
-     struct s3c24x0_usb_device * const usbdevregs = s3c24x0_get_base_usb_device();  
-         U8 out_csr3;  
-         int fifoCnt;  
-     writeb(3, &usbdevregs->INDEX_REG);  
-     out_csr3 = readb(&usbdevregs->OUT_CSR1_REG);  
-       
-     printk("<3:%x]",out_csr3);  
-   
-     if(out_csr3 & EPO_OUT_PKT_READY)  
-     {    
-     printk("EPO_OUT_PKT_READ\n");   
-     fifoCnt = readb(&usbdevregs->OUT_FIFO_CNT1_REG);  
- #if 0  
-     RdPktEp3(ep3Buf,fifoCnt);  
-     PrintEpoPkt(ep3Buf,fifoCnt);  
- #else  
-   
-     if(downloadFileSize==0)  
-     {  
-         RdPktEp3((U8 *)downPt,8);     
-           
-         if(download_run==0)  
-         {  
-             downloadAddress=tempDownloadAddress;  
-         }  
-         else  
-         {  
-             downloadAddress=  
-                 *((U8 *)(downPt+0))+  
-             (*((U8 *)(downPt+1))<<8)+  
-             (*((U8 *)(downPt+2))<<16)+  
-             (*((U8 *)(downPt+3))<<24);  
-               
-             dwUSBBufReadPtr = downloadAddress;  
-             dwUSBBufWritePtr = downloadAddress;  
-         }  
-         downloadFileSize=  
-             *((U8 *)(downPt+4))+  
-         (*((U8 *)(downPt+5))<<8)+  
-         (*((U8 *)(downPt+6))<<16)+  
-         (*((U8 *)(downPt+7))<<24);  
-         checkSum=0;  
-         downPt=(U8 *)downloadAddress;  
-   
-         RdPktEp3_CheckSum((U8 *)downPt,fifoCnt-8);   
-         downPt+=fifoCnt-8;    
-           
-     #if USBDMA  
-               
-               
-         writel((readl(&intregs->INTMSK) | BIT_USBD), &intregs->INTMSK);  
-             return;   
-     #endif    
-     }  
-     else  
-     {  
-     #if USBDMA        
-         printk("<ERROR>");  
-     #endif      
-         RdPktEp3_CheckSum((U8 *)downPt,fifoCnt);          
-         downPt+=fifoCnt;    
-     }  
- #endif  
-     CLR_EP3_OUT_PKT_READY();  
-     return;  
-     }  
-   
-       
-       
-     if(out_csr3 & EPO_SENT_STALL)  
-     {     
-     printk("[STALL]");  
-     CLR_EP3_SENT_STALL();  
-     return;  
-     }     
- }  
 
       
可以看出中斷狀態(tài)EPO_OUT_PKT_READY標(biāo)志置位就代表著一個數(shù)據(jù)包的到來,這里是處理第一個數(shù)據(jù)包,由于端點(diǎn)3配置的大小為32個字節(jié),所
以一個包的數(shù)據(jù)就是32個字節(jié)。因為主機(jī)軟件DNW在每個文件的頭部加了8個字節(jié)的信息來標(biāo)示下載地址與文件長度,所以這個就是處理下載地址與文件長度的
信息的。最后下載地址保存在downloadAddress里,文件長度保存在downloadFileSize里。處理完第一個包后,首先禁止USBD
中斷這個為了設(shè)置端點(diǎn)3的DMA功能。在中斷禁止的時候,主機(jī)發(fā)送的數(shù)據(jù)包都會被USB設(shè)備忽略,從而主機(jī)會從新發(fā)送。貌似這個中斷處理函數(shù)只處理一個包
的數(shù)據(jù)就關(guān)了中斷,USB批量傳輸就進(jìn)行不下去了。但是別急,程序中還有一個函數(shù)是進(jìn)行批量傳輸先運(yùn)行的,這就是usb_receive:
- u32 usb_receive(char *buf, size_t len, U32 wait)  
- {  
-     int first=1;  
-     U8 tempMem[16];  
-     U32 j;  
-     unsigned int dwRecvTimeSec = 0;  
-     char c;  
-     struct s3c24x0_interrupt * intregs = s3c24x0_get_base_interrupt();  
-   
-     dwUSBBufReadPtr = dwUSBBufBase;   
-     dwUSBBufWritePtr = dwUSBBufBase;   
-     bDMAPending = 0;  
-   
-       
-     tempDownloadAddress = dwUSBBufBase;   
-   
-     downloadAddress=(U32)tempMem;   
-     downPt=(unsigned char *)downloadAddress;  
-       
-     downloadFileSize=0;  
-       
-   
-       
-       
-       
-     if(isUsbdSetConfiguration==0)  
-     {  
-         printk("USB host is not connected yet.\n");  
-     }  
-   
-     while(downloadFileSize==0)   
-     {  
-         if(first==1 && isUsbdSetConfiguration!=0)  
-         {  
-             printk("USB host is connected. Waiting a download.\n");  
-             first=0;  
-         }  
-     }  
-   
-     printk("get downloadFileSize = %d !!\n",downloadFileSize);  
-   
-       
-     if (downloadFileSize - 10 > len)  
-     {  
-         printk("Length of file is too big : %d > %d\n", downloadFileSize - 10, len);  
-         return 0;  
-     }  
-       
-     Timer_InitEx();  
-     Timer_StartEx();  
-           
- #if USBDMA      
-   
-     writel((readl(&intregs->INTMSK) & ~(BIT_DMA2)), &intregs->INTMSK);   
-   
-     ClearEp3OutPktReady();   
-           
-           
-   
-     if(downloadFileSize>EP3_PKT_SIZE)   
-     {  
-         if(downloadFileSize - EP3_PKT_SIZE<=(0x80000))   
-         {  
-               
-             dwUSBBufWritePtr = downloadAddress + EP3_PKT_SIZE-8;  
-             dwWillDMACnt = downloadFileSize - EP3_PKT_SIZE;  
-     }  
-         else   
-         {  
-             dwUSBBufWritePtr = downloadAddress + EP3_PKT_SIZE - 8;  
-               
-               
-              
-  
-  
-  
-  
-  
-   
-             dwWillDMACnt = 0x80000 + 8 - EP3_PKT_SIZE;  
-         }  
-         totalDmaCount = 0;    
-     ConfigEp3DmaMode(dwUSBBufWritePtr, dwWillDMACnt);   
-     }  
-     else   
-     {  
-         dwUSBBufWritePtr = downloadAddress + downloadFileSize - 8;  
-         totalDmaCount = downloadFileSize;  
-     }  
- #endif  
-   
-     printk("\nNow, Downloading [ADDRESS:%xh,TOTAL:%d]\n",  
-             downloadAddress,downloadFileSize);  
-   
-     if (wait)  
-     {  
-         printk("RECEIVED FILE SIZE:%8d",0);  
-   
-         j = totalDmaCount + 0x10000;  
-         while (totalDmaCount != downloadFileSize)  
-         {  
-             if (totalDmaCount > j)  
-             {  
-                 printk("\b\b\b\b\b\b\b\b%8d", j);  
-                 j = totalDmaCount + 0x10000;  
-             }  
-         }  
-         printk("\b\b\b\b\b\b\b\b%8d ", totalDmaCount);  
-         dwRecvTimeSec = Timer_StopEx();  
-         if (dwRecvTimeSec == 0)  
-         {  
-             dwRecvTimeSec = 1;  
-         }  
-         printk("(%dKB/S, %dS)\n", (downloadFileSize/dwRecvTimeSec/1024), dwRecvTimeSec);  
-     }  
-   
-     return downloadFileSize - 10;  
- }  
 
       
usb_receive函數(shù)緊接著usb_init_slave運(yùn)行,如果主機(jī)枚舉成功設(shè)備,那么就會設(shè)置downloadFileSize = 
1,”USB host is connected. Waiting a 
download“就會輸出到終端,從而執(zhí)行以下的代碼,否則就會等待USB設(shè)備配置完畢。頭文件中是定義了USBDMA的,所以#if USBDMA 
下面的代碼就會執(zhí)行。在說這段代碼之前首先說一下Timer_InitEx(); Timer_StartEx();這兩個函數(shù)的作用還有
 if 
(wait)下面代碼的作用,起始這些都是為了顯示現(xiàn)在進(jìn)度,以及下載平均耗時的,這里主要用了看門狗定時器作為定時硬件,如果定義了wait,那么程序
會將下載信息顯示在終端,然后還統(tǒng)計每秒傳輸?shù)淖止?jié)數(shù)。下面重點(diǎn)說明#if USBDMA下面的代碼。
        
這段代碼的主要作用就是針對傳輸文件的大小來決定DMA的使用情況,如果使用DMA,則配置端點(diǎn)3為DMA模式,設(shè)置DMA傳輸?shù)慕K點(diǎn)地址以及每次DMA
傳輸?shù)拇笮?,開啟DMA中斷。當(dāng)設(shè)置好DMA時,并打開了DMA中斷,每傳完一個設(shè)置的大小,就會進(jìn)入DMA中斷。所以如果傳輸文件的大小小于
1023KB,那么只會進(jìn)入一次DMA中斷。下面就是DMA中斷處理程序:
- void IsrDma2(void)  
- {  
-     struct s3c24x0_interrupt * intregs = s3c24x0_get_base_interrupt();  
-     struct s3c24x0_usb_device * const usbdevregs    = s3c24x0_get_base_usb_device();  
-         U8 out_csr3;  
-         U32 dwEmptyCnt;  
-     U8 saveIndexReg = readb(&usbdevregs->INDEX_REG);  
-     writeb(3, &usbdevregs->INDEX_REG);  
-     out_csr3 = readb(&usbdevregs->OUT_CSR1_REG);  
-   
-     ClearPending_my((int)BIT_DMA2);       
-   
-      
-  
-   
-     if (!totalDmaCount)   
-         totalDmaCount = dwWillDMACnt + EP3_PKT_SIZE;   
-     else  
-         totalDmaCount+=dwWillDMACnt;  
-   
-   
-     dwUSBBufWritePtr = ((dwUSBBufWritePtr + dwWillDMACnt - dwUSBBufBase) % dwUSBBufSize) + dwUSBBufBase;  
-       
-     if(totalDmaCount>=downloadFileSize)  
-     {  
-         totalDmaCount=downloadFileSize;  
-       
-         ConfigEp3IntMode();   
-   
-         if(out_csr3& EPO_OUT_PKT_READY)  
-         {  
-             CLR_EP3_OUT_PKT_READY();  
-     }  
-     writel(((readl(&intregs->INTMSK) | BIT_DMA2) & ~(BIT_USBD)), &intregs->INTMSK);  
-           
-     }  
-     else  
-     {  
-         if((totalDmaCount+0x80000)<downloadFileSize)   
-         {  
-             dwWillDMACnt = 0x80000;  
-     }  
-         else     
-         {  
-             dwWillDMACnt = downloadFileSize - totalDmaCount;  
-         }  
-   
-         dwEmptyCnt = (dwUSBBufReadPtr - dwUSBBufWritePtr - 1 + dwUSBBufSize) % dwUSBBufSize;  
-         if (dwEmptyCnt >= dwWillDMACnt)  
-         {  
-             ConfigEp3DmaMode(dwUSBBufWritePtr, dwWillDMACnt);    
-         }  
-         else  
-         {  
-             bDMAPending = 1;  
-         }  
-     }  
-     writeb(saveIndexReg, &usbdevregs->INDEX_REG);  
- }  
        DMA中斷處理程序在每次DMA傳輸完成后進(jìn)入,根據(jù)還剩文件的字節(jié)數(shù)來決定是否繼續(xù)傳輸,以及怎樣傳輸。當(dāng)傳輸完成后,禁止DMA中斷,將端點(diǎn)3配置成中斷模式,好進(jìn)行下一次的批量傳輸。
程序源代碼在 http://download.csdn.net/detail/yaozhenguo2006/4182352