Dependents:   TimeZoneDemo EthernetJackTestCode MMEx_Challenge ntp_mem ... more

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 
00026 #include "UsbDevice.h"
00027 
00028 #include "usb_mem.h"
00029 
00030 #include "netCfg.h"
00031 #if NET_USB
00032 
00033 //#define __DEBUG
00034 #include "dbg/dbg.h"
00035 
00036 UsbEndpoint::UsbEndpoint( UsbDevice* pDevice, uint8_t ep, bool dir, UsbEndpointType type, uint16_t size, int addr /*= -1*/ ) : m_pDevice(pDevice), m_result(true), m_status((int)USBERR_OK), m_len(0), m_pBufStartPtr(NULL),
00037 m_pCbItem(NULL), m_pCbMeth(NULL), m_pNextEp(NULL)
00038 {
00039   //Insert into Eps list
00040   //FIXME: Assert that no USB interrupt is triggered meanwhile
00041   if(m_pHeadEp)
00042   {
00043     m_pNextEp = m_pHeadEp;
00044     m_pHeadEp = this;
00045   }
00046   else
00047   {
00048     m_pNextEp = NULL;
00049     m_pHeadEp = this;
00050   }  
00051 
00052   m_pEd = (volatile HCED*)usb_get_ed();
00053   
00054   m_pTdHead = (volatile HCTD*)usb_get_td();
00055   m_pTdTail = (volatile HCTD*)usb_get_td();
00056   
00057   //printf("\r\n--m_pEd = %p--\r\n", m_pEd);
00058   DBG("m_pEd = %p\n", m_pEd);
00059   DBG("m_pTdHead = %p\n", m_pTdHead);
00060   DBG("m_pTdTail = %p\n", m_pTdTail);
00061   
00062   //Init Ed & Td
00063   //printf("\r\n--Ep Init--\r\n");
00064   memset((void*)m_pEd, 0, sizeof(HCED));
00065   //printf("\r\n--Td Init--\r\n");
00066 
00067   memset((void*)m_pTdHead, 0, sizeof(HCTD));
00068   memset((void*)m_pTdTail, 0, sizeof(HCTD));
00069   
00070   if(addr == -1)
00071     addr = pDevice->m_addr;
00072   
00073   //Setup Ed
00074   //printf("\r\n--Ep Setup--\r\n");
00075   m_pEd->Control =  addr        |      /* USB address           */
00076   ((ep & 0x7F) << 7)            |      /* Endpoint address      */
00077   (type!=USB_CONTROL?((dir?2:1) << 11):0)             |      /* direction : Out = 1, 2 = In */
00078   (size << 16);     /* MaxPkt Size           */
00079   
00080   m_dir = dir;
00081   m_setup = false;
00082   m_type = type;
00083   
00084   m_pEd->TailTd = m_pEd->HeadTd = (uint32_t) m_pTdTail; //Empty TD list
00085   
00086   DBG("Before link\n");
00087   
00088   //printf("\r\n--Ep Reg--\r\n");
00089   //Append Ed to Ed list
00090   volatile HCED* prevEd;
00091   switch( m_type )
00092   {
00093   case USB_CONTROL:
00094     prevEd = (volatile HCED*) LPC_USB->HcControlHeadED;
00095     break;
00096   case USB_BULK:
00097   default:
00098     prevEd = (volatile HCED*) LPC_USB->HcBulkHeadED;
00099     break;
00100   }
00101   
00102   DBG("prevEd is %p\n", prevEd);
00103   
00104   if(prevEd)
00105   {
00106     DBG("prevEd set\n")
00107   
00108     while(prevEd->Next)
00109     {
00110       DBG("prevEd->Next = %08x\n", prevEd->Next);
00111       prevEd = (volatile HCED*) prevEd->Next;
00112     }
00113     prevEd->Next = (uint32_t) m_pEd;
00114   
00115   }
00116   else
00117   {
00118     switch( m_type )
00119     {
00120     case USB_CONTROL:
00121       LPC_USB->HcControlHeadED = (uint32_t) m_pEd;
00122       break;
00123     case USB_BULK:
00124     default:
00125       LPC_USB->HcBulkHeadED = (uint32_t) m_pEd;
00126       break;
00127     }
00128   }
00129   
00130   DBG("Ep init\n");
00131 }
00132 
00133 UsbEndpoint::~UsbEndpoint()
00134 {
00135   //Remove from Eps list
00136   //FIXME: Assert that no USB interrupt is triggered meanwhile
00137   if(m_pHeadEp != this)
00138   {
00139     UsbEndpoint* prevEp = m_pHeadEp;
00140     while(prevEp->m_pNextEp != this)
00141       prevEp = prevEp->m_pNextEp;
00142     prevEp->m_pNextEp = m_pNextEp;
00143   }
00144   else
00145   {
00146     m_pHeadEp = m_pNextEp;
00147   }  
00148   
00149   m_pEd->Control |= ED_SKIP; //Skip this Ep in queue
00150 
00151   //Remove from queue
00152   volatile HCED* prevEd;
00153   switch( m_type )
00154   {
00155   case USB_CONTROL:
00156     prevEd = (volatile HCED*) LPC_USB->HcControlHeadED;
00157     break;
00158   case USB_BULK:
00159   default:
00160     prevEd = (volatile HCED*) LPC_USB->HcBulkHeadED;
00161     break;
00162   }
00163   if( m_pEd == prevEd )
00164   {
00165     switch( m_type )
00166     {
00167     case USB_CONTROL:
00168       LPC_USB->HcControlHeadED = m_pEd->Next;
00169       break;
00170     case USB_BULK:
00171     default:
00172       LPC_USB->HcBulkHeadED = m_pEd->Next;
00173       break;
00174     }
00175     LPC_USB->HcBulkHeadED = m_pEd->Next;
00176   }
00177   else
00178   {
00179     while( prevEd->Next != (uint32_t) m_pEd )
00180     {
00181       prevEd = (volatile HCED*) prevEd->Next;
00182     }
00183     prevEd->Next = m_pEd->Next;
00184   }
00185   
00186   //
00187   usb_free_ed((volatile byte*)m_pEd);
00188   
00189   usb_free_td((volatile byte*)m_pTdHead);
00190   usb_free_td((volatile byte*)m_pTdTail);
00191 }
00192 
00193 void UsbEndpoint::setNextToken(uint32_t token) //Only for control Eps
00194 {
00195   switch(token)
00196   {
00197     case TD_SETUP:
00198       m_dir = false;
00199       m_setup = true;
00200       break;
00201     case TD_IN:
00202       m_dir = true;
00203       m_setup = false;
00204       break;
00205     case TD_OUT:
00206       m_dir = false;
00207       m_setup = false;
00208       break;
00209   }
00210 }
00211 
00212 UsbErr UsbEndpoint::transfer(volatile uint8_t* buf, uint32_t len)
00213 {
00214   if(!m_result)
00215     return USBERR_BUSY; //The previous trasnfer is not completed 
00216     //FIXME: We should be able to queue the next transfer, still needs to be implemented
00217   
00218   if( !m_pDevice->connected() )
00219     return USBERR_DISCONNECTED;
00220   
00221   m_result = false;
00222   
00223   volatile uint32_t token = (m_setup?TD_SETUP:(m_dir?TD_IN:TD_OUT));
00224 
00225   volatile uint32_t td_toggle;
00226   if (m_type == USB_CONTROL)
00227   {
00228     if (m_setup)
00229     {
00230       td_toggle = TD_TOGGLE_0;
00231     }
00232     else
00233     {
00234       td_toggle = TD_TOGGLE_1;
00235     }
00236   }
00237   else
00238   {
00239     td_toggle = 0;
00240   }
00241 
00242   //Swap Tds
00243   volatile HCTD* pTdSwap;
00244   pTdSwap = m_pTdTail;
00245   m_pTdTail = m_pTdHead;
00246   m_pTdHead = pTdSwap;
00247 
00248   m_pTdHead->Control = (TD_ROUNDING    |
00249                        token           |
00250                        TD_DELAY_INT(0) |//7
00251                        td_toggle       |
00252                        TD_CC);
00253 
00254   m_pTdTail->Control = 0;
00255   m_pTdHead->CurrBufPtr   = (uint32_t) buf;
00256   m_pBufStartPtr = buf;
00257   m_pTdTail->CurrBufPtr   = 0;
00258   m_pTdHead->Next         = (uint32_t) m_pTdTail;
00259   m_pTdTail->Next         = 0;
00260   m_pTdHead->BufEnd       = (uint32_t)(buf + (len - 1));
00261   m_pTdTail->BufEnd       = 0;
00262   
00263   m_pEd->HeadTd  = (uint32_t)m_pTdHead | ((m_pEd->HeadTd) & 0x00000002); //Carry bit
00264   m_pEd->TailTd  = (uint32_t)m_pTdTail;
00265   
00266   //DBG("m_pEd->HeadTd = %08x\n", m_pEd->HeadTd);
00267 
00268   if(m_type == USB_CONTROL)
00269   {
00270     LPC_USB->HcCommandStatus = LPC_USB->HcCommandStatus | OR_CMD_STATUS_CLF;
00271     LPC_USB->HcControl       = LPC_USB->HcControl       | OR_CONTROL_CLE; //Enable control list
00272   }
00273   else //USB_BULK
00274   {
00275     LPC_USB->HcCommandStatus = LPC_USB->HcCommandStatus | OR_CMD_STATUS_BLF;
00276     LPC_USB->HcControl       = LPC_USB->HcControl       | OR_CONTROL_BLE; //Enable bulk list
00277   }
00278   
00279   //m_done = false;
00280   m_len = len;
00281 
00282   return USBERR_PROCESSING;
00283  
00284 }
00285   
00286 int UsbEndpoint::status()
00287 {
00288   if( !m_pDevice->connected() )
00289   {
00290     if(!m_result)
00291       onCompletion();
00292     m_result = true;
00293     return (int)USBERR_DISCONNECTED;
00294   }
00295   else if( !m_result )
00296   { 
00297     return (int)USBERR_PROCESSING;
00298   }
00299   /*else if( m_done )
00300   {
00301     return (int)USBERR_OK;
00302   }*/
00303   else
00304   {
00305     return m_status;
00306   }
00307 }
00308 
00309 void UsbEndpoint::updateAddr(int addr)
00310 {
00311   DBG("m_pEd->Control = %08x\n", m_pEd->Control);
00312   m_pEd->Control &= ~0x7F;
00313   m_pEd->Control |= addr;
00314   DBG("m_pEd->Control = %08x\n", m_pEd->Control);
00315 }
00316 
00317 void UsbEndpoint::updateSize(uint16_t size)
00318 {
00319   DBG("m_pEd->Control = %08x\n", m_pEd->Control);
00320   m_pEd->Control &= ~0x3FF0000;
00321   m_pEd->Control |= (size << 16);
00322   DBG("m_pEd->Control = %08x\n", m_pEd->Control);
00323 }
00324 
00325 #if 0 //For doc only
00326 template <class T>
00327 void UsbEndpoint::setOnCompletion( T* pCbItem, void (T::*pCbMeth)() )
00328 {
00329   m_pCbItem = (CDummy*) pCbItem;
00330   m_pCbMeth = (void (CDummy::*)()) pCbMeth;
00331 }
00332 #endif
00333 
00334 void UsbEndpoint::onCompletion()
00335 {
00336   //DBG("Transfer completed\n");
00337   if( m_pTdHead->Control >> 28  )
00338   {
00339     DBG("TD Failed with condition code %01x\n", m_pTdHead->Control >> 28 );
00340     m_status = (int)USBERR_TDFAIL;
00341   }
00342   else if( m_pEd->HeadTd & 0x1 )
00343   {
00344     m_pEd->HeadTd = m_pEd->HeadTd & ~0x1;
00345     DBG("\r\nHALTED!!\r\n");
00346     m_status = (int)USBERR_HALTED;
00347   }
00348   else if( (m_pEd->HeadTd & ~0xF) == (uint32_t) m_pTdTail )
00349   {
00350     //Done
00351     int len;
00352     //DBG("m_pTdHead->CurrBufPtr = %08x, m_pBufStartPtr=%08x\n", m_pTdHead->CurrBufPtr, (uint32_t) m_pBufStartPtr);
00353     if(m_pTdHead->CurrBufPtr)
00354       len = m_pTdHead->CurrBufPtr - (uint32_t) m_pBufStartPtr;
00355     else
00356       len = m_len;
00357     /*if(len == 0) //Packet transfered completely
00358       len = m_len;*/
00359     //m_done = true;
00360     DBG("Transfered %d bytes\n", len);
00361     m_status = len; 
00362   }
00363   else
00364   {
00365     DBG("Unknown error...\n");
00366     m_status = (int)USBERR_ERROR;
00367   }
00368   m_result = true;
00369   if(m_pCbItem && m_pCbMeth)
00370     (m_pCbItem->*m_pCbMeth)();
00371 }
00372 
00373 void UsbEndpoint::sOnCompletion(uint32_t pTd)
00374 {
00375   if(!m_pHeadEp)
00376       return;
00377   do
00378   {
00379     //DBG("sOnCompletion (pTd = %08x)\n", pTd);
00380     UsbEndpoint* pEp = m_pHeadEp;  
00381     do
00382     {
00383       if((uint32_t)pEp->m_pTdHead == pTd)
00384       {
00385         pEp->onCompletion();
00386         break;
00387       }
00388     } while(pEp = pEp->m_pNextEp);
00389   } while( pTd = (uint32_t)( ((HCTD*)pTd)->Next ) ); //Go around the Done queue
00390 }
00391 
00392 UsbEndpoint* UsbEndpoint::m_pHeadEp = NULL;
00393 
00394 #endif