Takao Aratani / uvchost

Dependents:   WebCamera_SD

Fork of uvchost by Norimasa Okamoto

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers UsbEndpoint.cpp Source File

UsbEndpoint.cpp

00001 
00002 /*
00003 Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
00004  
00005 Permission is hereby granted, free of charge, to any person obtaining a copy
00006 of this software and associated documentation files (the "Software"), to deal
00007 in the Software without restriction, including without limitation the rights
00008 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00009 copies of the Software, and to permit persons to whom the Software is
00010 furnished to do so, subject to the following conditions:
00011  
00012 The above copyright notice and this permission notice shall be included in
00013 all copies or substantial portions of the Software.
00014  
00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00018 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00019 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00020 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00021 THE SOFTWARE.
00022 */
00023 
00024 #include "UsbEndpoint.h"
00025 #include "UsbDevice.h"
00026 #include "usb_mem.h"
00027 #include "Usb_td.h"
00028 
00029 //#define __DEBUG
00030 //#define __DEBUG3
00031 //#include "dbg/dbg.h"
00032 #include "mydbg.h"
00033 
00034 UsbEndpoint::UsbEndpoint( UsbDevice* pDevice, uint8_t ep, bool dir, UsbEndpointType type, uint16_t size, int addr /*= -1*/ ) 
00035 : m_pDevice(pDevice), m_result(true), m_status((int)USBERR_OK), m_len(0), m_pBufStartPtr(NULL),
00036   m_pCbItem(NULL), m_pCbMeth(NULL)
00037 {
00038   if (type == USB_ISO) {
00039       UsbEndpoint_iso(pDevice, ep, dir, type, size, addr);
00040       return;
00041   }
00042 
00043   m_pEd = (volatile HCED*)usb_get_ed();
00044   DBG_ASSERT(m_pEd);
00045   memset((void*)m_pEd, 0, sizeof(HCED));
00046   
00047   m_pTdHead = (volatile HCTD*)usb_get_td((uint32_t)this);
00048   DBG_ASSERT(m_pTdHead);
00049   m_pTdTail = (volatile HCTD*)usb_get_td((uint32_t)this);
00050   DBG_ASSERT(m_pTdTail);
00051   DBG("m_pEd    =%p\n", m_pEd);
00052   DBG("m_pTdHead=%p\n", m_pTdHead);
00053   DBG("m_pTdTail=%p\n", m_pTdTail);
00054   
00055   if(addr == -1)
00056     addr = pDevice->m_addr;
00057   
00058   //Setup Ed
00059   //printf("\r\n--Ep Setup--\r\n");
00060   m_pEd->Control =  addr        |      /* USB address           */
00061   ((ep & 0x7F) << 7)            |      /* Endpoint address      */
00062   (type!=USB_CONTROL?((dir?2:1) << 11):0)             |      /* direction : Out = 1, 2 = In */
00063   ((pDevice->m_lowspeed?1:0) << 13) |  /* speed full=0 low=1 */
00064   (size << 16);     /* MaxPkt Size           */
00065   DBG3("m_pEd->Control=%08X\n", m_pEd->Control);
00066   m_dir = dir;
00067   m_setup = false;
00068   m_type = type;
00069   
00070   m_pEd->TailTd = m_pEd->HeadTd = (uint32_t) m_pTdTail; //Empty TD list
00071   
00072   DBG("Before link\n");
00073   
00074   //printf("\r\n--Ep Reg--\r\n");
00075   //Append Ed to Ed list
00076   HCCA* hcca;
00077   //volatile HCED* nextEd;
00078   DBG("m_type=%d\n", m_type);
00079   switch( m_type )
00080   {
00081   case USB_CONTROL:
00082     m_pEd->Next = LPC_USB->HcControlHeadED;
00083     LPC_USB->HcControlHeadED = (uint32_t)m_pEd;
00084     return;
00085 
00086   case USB_BULK:
00087     m_pEd->Next = LPC_USB->HcBulkHeadED;
00088     LPC_USB->HcBulkHeadED = (uint32_t)m_pEd;
00089     return;
00090 
00091   case USB_INT:
00092     hcca = (HCCA*)usb_get_hcca();
00093     m_pEd->Next = hcca->IntTable[0];
00094     hcca->IntTable[0] = (uint32_t)m_pEd;
00095     return;
00096   
00097   default:
00098     DBG_ASSERT(0);
00099   }
00100 }
00101 
00102 
00103 UsbEndpoint::~UsbEndpoint()
00104 {
00105   DBG_ASSERT(m_type != USB_ISO);
00106 
00107   m_pEd->Control |= ED_SKIP; //Skip this Ep in queue
00108 
00109   //Remove from queue
00110   volatile HCED* prevEd;
00111   HCCA* hcca;
00112   switch( m_type )
00113   {
00114   case USB_CONTROL:
00115     prevEd = (volatile HCED*) LPC_USB->HcControlHeadED;
00116     break;
00117   case USB_BULK:
00118     prevEd = (volatile HCED*) LPC_USB->HcBulkHeadED;
00119     break;
00120   case USB_INT:
00121     hcca = (HCCA*)usb_get_hcca();
00122     prevEd = (volatile HCED*)hcca->IntTable[0];
00123     break;
00124   default:
00125     DBG_ASSERT(0);
00126   }
00127   if( m_pEd == prevEd )
00128   {
00129     switch( m_type )
00130     {
00131     case USB_CONTROL:
00132       LPC_USB->HcControlHeadED = m_pEd->Next;
00133       break;
00134     case USB_BULK:
00135       LPC_USB->HcBulkHeadED = m_pEd->Next;
00136       break;
00137     case USB_INT:
00138       hcca = (HCCA*)usb_get_hcca();
00139       hcca->IntTable[0] = m_pEd->Next;
00140       break;
00141     default:
00142       DBG_ASSERT(0);
00143     }
00144     LPC_USB->HcBulkHeadED = m_pEd->Next;
00145   }
00146   else
00147   {
00148     while( prevEd->Next != (uint32_t) m_pEd )
00149     {
00150       prevEd = (volatile HCED*) prevEd->Next;
00151     }
00152     prevEd->Next = m_pEd->Next;
00153   }
00154   
00155   //
00156   usb_free_ed((volatile byte*)m_pEd);
00157   
00158   usb_free_td((volatile byte*)m_pTdHead);
00159   usb_free_td((volatile byte*)m_pTdTail);
00160 }
00161 
00162 void UsbEndpoint::setNextToken(uint32_t token) //Only for control Eps
00163 {
00164   switch(token)
00165   {
00166     case TD_SETUP:
00167       m_dir = false;
00168       m_setup = true;
00169       break;
00170     case TD_IN:
00171       m_dir = true;
00172       m_setup = false;
00173       break;
00174     case TD_OUT:
00175       m_dir = false;
00176       m_setup = false;
00177       break;
00178   }
00179 }
00180 
00181 UsbErr UsbEndpoint::transfer(volatile uint8_t* buf, uint32_t len)
00182 {
00183   DBG("buf=%p\n", buf);
00184   if(!m_result)
00185     return USBERR_BUSY; //The previous trasnfer is not completed 
00186     //FIXME: We should be able to queue the next transfer, still needs to be implemented
00187   
00188   if( !m_pDevice->connected() )
00189     return USBERR_DISCONNECTED;
00190   
00191   m_result = false;
00192   
00193   volatile uint32_t token = (m_setup?TD_SETUP:(m_dir?TD_IN:TD_OUT));
00194 
00195   volatile uint32_t td_toggle;
00196   if (m_type == USB_CONTROL)
00197   {
00198     if (m_setup)
00199     {
00200       td_toggle = TD_TOGGLE_0;
00201     }
00202     else
00203     {
00204       td_toggle = TD_TOGGLE_1;
00205     }
00206   }
00207   else
00208   {
00209     td_toggle = 0;
00210   }
00211 
00212   //Swap Tds
00213   volatile HCTD* pTdSwap;
00214   pTdSwap = m_pTdTail;
00215   m_pTdTail = m_pTdHead;
00216   m_pTdHead = pTdSwap;
00217 
00218   m_pTdHead->Control = (TD_ROUNDING    |
00219                        token           |
00220                        TD_DELAY_INT(0) |//7
00221                        td_toggle       |
00222                        TD_CC);
00223 
00224   m_pTdTail->Control = 0;
00225   m_pTdHead->CurrBufPtr   = (uint32_t) buf;
00226   m_pBufStartPtr = buf;
00227   m_pTdTail->CurrBufPtr   = 0;
00228   m_pTdHead->Next         = (uint32_t) m_pTdTail;
00229   m_pTdTail->Next         = 0;
00230   m_pTdHead->BufEnd       = (uint32_t)(buf + (len - 1));
00231   m_pTdTail->BufEnd       = 0;
00232   
00233   m_pEd->HeadTd  = (uint32_t)m_pTdHead | ((m_pEd->HeadTd) & 0x00000002); //Carry bit
00234   m_pEd->TailTd  = (uint32_t)m_pTdTail;
00235   
00236   //DBG("m_pEd->HeadTd = %08x\n", m_pEd->HeadTd);
00237 
00238   if(m_type == USB_CONTROL) {
00239     LPC_USB->HcCommandStatus = LPC_USB->HcCommandStatus | OR_CMD_STATUS_CLF;
00240     LPC_USB->HcControl       = LPC_USB->HcControl       | OR_CONTROL_CLE; //Enable control list
00241   } else if (m_type == USB_BULK) { //USB_BULK
00242     LPC_USB->HcCommandStatus = LPC_USB->HcCommandStatus | OR_CMD_STATUS_BLF;
00243     LPC_USB->HcControl       = LPC_USB->HcControl       | OR_CONTROL_BLE; //Enable bulk list
00244   } else if (m_type == USB_INT) { // USB_INT
00245     LPC_USB->HcControl       = LPC_USB->HcControl       | OR_CONTROL_PLE; //Enable Periodic
00246   } else { // USB_ISO
00247     DBG_ASSERT(0);
00248   }
00249   
00250   //m_done = false;
00251   m_len = len;
00252 
00253   return USBERR_PROCESSING;
00254  
00255 }
00256 
00257 int UsbEndpoint::status()
00258 {
00259   if( !m_pDevice->connected() )
00260   {
00261     if(!m_result)
00262       onCompletion();
00263     m_result = true;
00264     return (int)USBERR_DISCONNECTED;
00265   }
00266   else if( !m_result )
00267   { 
00268     return (int)USBERR_PROCESSING;
00269   }
00270   /*else if( m_done )
00271   {
00272     return (int)USBERR_OK;
00273   }*/
00274   else
00275   {
00276     return m_status;
00277   }
00278 }
00279 
00280 void UsbEndpoint::updateAddr(int addr)
00281 {
00282   DBG("m_pEd->Control = %08x\n", m_pEd->Control);
00283   m_pEd->Control &= ~0x7F;
00284   m_pEd->Control |= addr;
00285   DBG("m_pEd->Control = %08x\n", m_pEd->Control);
00286 }
00287 
00288 void UsbEndpoint::updateSize(uint16_t size)
00289 {
00290   DBG("m_pEd->Control = %08x\n", m_pEd->Control);
00291   m_pEd->Control &= ~0x3FF0000;
00292   m_pEd->Control |= (size << 16);
00293   DBG("m_pEd->Control = %08x\n", m_pEd->Control);
00294 }
00295 
00296 #if 0 //For doc only
00297 template <class T>
00298 void UsbEndpoint::setOnCompletion( T* pCbItem, void (T::*pCbMeth)() )
00299 {
00300   m_pCbItem = (CDummy*) pCbItem;
00301   m_pCbMeth = (void (CDummy::*)()) pCbMeth;
00302 }
00303 #endif
00304 
00305 void UsbEndpoint::onCompletion()
00306 {
00307   DBG_ASSERT(m_type != USB_ISO);
00308   DBG_ASSERT(m_pTdHead);
00309   //DBG("Transfer completed\n");
00310   if( m_pTdHead->Control >> 28  )
00311   {
00312     DBG("TD Failed with condition code %01x\n", m_pTdHead->Control >> 28 );
00313     m_status = (int)USBERR_TDFAIL;
00314   }
00315   else if( m_pEd->HeadTd & 0x1 )
00316   {
00317     m_pEd->HeadTd = m_pEd->HeadTd & ~0x1;
00318     DBG("\r\nHALTED!!\r\n");
00319     m_status = (int)USBERR_HALTED;
00320   }
00321   else if( (m_pEd->HeadTd & ~0xF) == (uint32_t) m_pTdTail )
00322   {
00323     //Done
00324     int len;
00325     DBG("m_pEp=%p\n", m_pEd);
00326     DBG("m_pTdHead->CurrBufPtr=%08x\n", (uint32_t)m_pTdHead->CurrBufPtr);
00327     DBG("m_pBufStartPtr=%08x\n", (uint32_t) m_pBufStartPtr);
00328     if(m_pTdHead->CurrBufPtr)
00329       len = m_pTdHead->CurrBufPtr - (uint32_t) m_pBufStartPtr;
00330     else
00331       len = m_len;
00332     /*if(len == 0) //Packet transfered completely
00333       len = m_len;*/
00334     //m_done = true;
00335     DBG("Transfered %d bytes\n", len);
00336     m_status = len; 
00337   }
00338   else
00339   {
00340     DBG("Unknown error...\n");
00341     m_status = (int)USBERR_ERROR;
00342   }
00343   m_result = true;
00344   if(m_pCbItem && m_pCbMeth)
00345     (m_pCbItem->*m_pCbMeth)();
00346 }
00347 
00348 
00349  
00350 void UsbEndpoint::sOnCompletion(uint32_t pTd)
00351 {
00352     HCTD* td = td_reverse((HCTD*)pTd);
00353     while(td) {
00354         HCTD* next = (HCTD*)td->Next;
00355         HCUTD* utd = (HCUTD*)td;
00356         UsbEndpoint* pEp = (UsbEndpoint*)utd->UsbEndpoint;
00357         DBG_ASSERT(pEp);
00358         if (usb_is_itd((byte*)td)) {
00359             HCITD* itd = (HCITD*)td;
00360             DBG_ASSERT(pEp->m_type == USB_ISO);
00361             pEp->queue_done_itd.push(itd);
00362         } else {
00363             DBG_ASSERT(pEp->m_pTdHead == td);
00364             if(pEp->m_pTdHead == td) { // found?
00365                 pEp->onCompletion();
00366             }
00367         }
00368         td = next;
00369     }
00370 }