Webcam Server.
Dependencies: uvchost FatFileSystem mbed HTTPServer NetServicesMin
Diff: usb/UsbEndpoint.cpp
- Revision:
- 0:2b4ea8a138e5
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usb/UsbEndpoint.cpp Wed Jun 06 11:47:06 2012 +0000 @@ -0,0 +1,373 @@ + +/* +Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "UsbEndpoint.h" +#include "UsbDevice.h" +#include "usb_mem.h" +#include "Usb_td.h" +#include "netCfg.h" +#if NET_USB + +//#define __DEBUG +//#define __DEBUG3 +//#include "dbg/dbg.h" +#include "mydbg.h" + +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), + m_pCbItem(NULL), m_pCbMeth(NULL) +{ + if (type == USB_ISO) { + UsbEndpoint_iso(pDevice, ep, dir, type, size, addr); + return; + } + + m_pEd = (volatile HCED*)usb_get_ed(); + DBG_ASSERT(m_pEd); + memset((void*)m_pEd, 0, sizeof(HCED)); + + m_pTdHead = (volatile HCTD*)usb_get_td((uint32_t)this); + DBG_ASSERT(m_pTdHead); + m_pTdTail = (volatile HCTD*)usb_get_td((uint32_t)this); + DBG_ASSERT(m_pTdTail); + DBG("m_pEd =%p\n", m_pEd); + DBG("m_pTdHead=%p\n", m_pTdHead); + DBG("m_pTdTail=%p\n", m_pTdTail); + + if(addr == -1) + addr = pDevice->m_addr; + + //Setup Ed + //printf("\r\n--Ep Setup--\r\n"); + m_pEd->Control = addr | /* USB address */ + ((ep & 0x7F) << 7) | /* Endpoint address */ + (type!=USB_CONTROL?((dir?2:1) << 11):0) | /* direction : Out = 1, 2 = In */ + (size << 16); /* MaxPkt Size */ + DBG3("m_pEd->Control=%08X\n", m_pEd->Control); + m_dir = dir; + m_setup = false; + m_type = type; + + m_pEd->TailTd = m_pEd->HeadTd = (uint32_t) m_pTdTail; //Empty TD list + + DBG("Before link\n"); + + //printf("\r\n--Ep Reg--\r\n"); + //Append Ed to Ed list + HCCA* hcca; + //volatile HCED* nextEd; + DBG("m_type=%d\n", m_type); + switch( m_type ) + { + case USB_CONTROL: + m_pEd->Next = LPC_USB->HcControlHeadED; + LPC_USB->HcControlHeadED = (uint32_t)m_pEd; + return; + + case USB_BULK: + m_pEd->Next = LPC_USB->HcBulkHeadED; + LPC_USB->HcBulkHeadED = (uint32_t)m_pEd; + return; + + case USB_INT: + hcca = (HCCA*)usb_get_hcca(); + m_pEd->Next = hcca->IntTable[0]; + hcca->IntTable[0] = (uint32_t)m_pEd; + return; + + default: + DBG_ASSERT(0); + } +} + + +UsbEndpoint::~UsbEndpoint() +{ + DBG_ASSERT(0); + + m_pEd->Control |= ED_SKIP; //Skip this Ep in queue + + //Remove from queue + volatile HCED* prevEd; + HCCA* hcca; + switch( m_type ) + { + case USB_CONTROL: + prevEd = (volatile HCED*) LPC_USB->HcControlHeadED; + break; + case USB_BULK: + prevEd = (volatile HCED*) LPC_USB->HcBulkHeadED; + break; + case USB_INT: + hcca = (HCCA*)usb_get_hcca(); + prevEd = (volatile HCED*)hcca->IntTable[0]; + break; + default: + DBG_ASSERT(0); + } + if( m_pEd == prevEd ) + { + switch( m_type ) + { + case USB_CONTROL: + LPC_USB->HcControlHeadED = m_pEd->Next; + break; + case USB_BULK: + LPC_USB->HcBulkHeadED = m_pEd->Next; + break; + case USB_INT: + hcca = (HCCA*)usb_get_hcca(); + hcca->IntTable[0] = m_pEd->Next; + break; + default: + DBG_ASSERT(0); + } + LPC_USB->HcBulkHeadED = m_pEd->Next; + } + else + { + while( prevEd->Next != (uint32_t) m_pEd ) + { + prevEd = (volatile HCED*) prevEd->Next; + } + prevEd->Next = m_pEd->Next; + } + + // + usb_free_ed((volatile byte*)m_pEd); + + usb_free_td((volatile byte*)m_pTdHead); + usb_free_td((volatile byte*)m_pTdTail); +} + +void UsbEndpoint::setNextToken(uint32_t token) //Only for control Eps +{ + switch(token) + { + case TD_SETUP: + m_dir = false; + m_setup = true; + break; + case TD_IN: + m_dir = true; + m_setup = false; + break; + case TD_OUT: + m_dir = false; + m_setup = false; + break; + } +} + +UsbErr UsbEndpoint::transfer(volatile uint8_t* buf, uint32_t len) +{ + DBG("buf=%p\n", buf); + if(!m_result) + return USBERR_BUSY; //The previous trasnfer is not completed + //FIXME: We should be able to queue the next transfer, still needs to be implemented + + if( !m_pDevice->connected() ) + return USBERR_DISCONNECTED; + + m_result = false; + + volatile uint32_t token = (m_setup?TD_SETUP:(m_dir?TD_IN:TD_OUT)); + + volatile uint32_t td_toggle; + if (m_type == USB_CONTROL) + { + if (m_setup) + { + td_toggle = TD_TOGGLE_0; + } + else + { + td_toggle = TD_TOGGLE_1; + } + } + else + { + td_toggle = 0; + } + + //Swap Tds + volatile HCTD* pTdSwap; + pTdSwap = m_pTdTail; + m_pTdTail = m_pTdHead; + m_pTdHead = pTdSwap; + + m_pTdHead->Control = (TD_ROUNDING | + token | + TD_DELAY_INT(0) |//7 + td_toggle | + TD_CC); + + m_pTdTail->Control = 0; + m_pTdHead->CurrBufPtr = (uint32_t) buf; + m_pBufStartPtr = buf; + m_pTdTail->CurrBufPtr = 0; + m_pTdHead->Next = (uint32_t) m_pTdTail; + m_pTdTail->Next = 0; + m_pTdHead->BufEnd = (uint32_t)(buf + (len - 1)); + m_pTdTail->BufEnd = 0; + + m_pEd->HeadTd = (uint32_t)m_pTdHead | ((m_pEd->HeadTd) & 0x00000002); //Carry bit + m_pEd->TailTd = (uint32_t)m_pTdTail; + + //DBG("m_pEd->HeadTd = %08x\n", m_pEd->HeadTd); + + if(m_type == USB_CONTROL) { + LPC_USB->HcCommandStatus = LPC_USB->HcCommandStatus | OR_CMD_STATUS_CLF; + LPC_USB->HcControl = LPC_USB->HcControl | OR_CONTROL_CLE; //Enable control list + } else if (m_type == USB_BULK) { //USB_BULK + LPC_USB->HcCommandStatus = LPC_USB->HcCommandStatus | OR_CMD_STATUS_BLF; + LPC_USB->HcControl = LPC_USB->HcControl | OR_CONTROL_BLE; //Enable bulk list + } else if (m_type == USB_INT) { // USB_INT + LPC_USB->HcControl = LPC_USB->HcControl | OR_CONTROL_PLE; //Enable Periodic + } else { // USB_ISO + DBG_ASSERT(0); + } + + //m_done = false; + m_len = len; + + return USBERR_PROCESSING; + +} + +int UsbEndpoint::status() +{ + if( !m_pDevice->connected() ) + { + if(!m_result) + onCompletion(); + m_result = true; + return (int)USBERR_DISCONNECTED; + } + else if( !m_result ) + { + return (int)USBERR_PROCESSING; + } + /*else if( m_done ) + { + return (int)USBERR_OK; + }*/ + else + { + return m_status; + } +} + +void UsbEndpoint::updateAddr(int addr) +{ + DBG("m_pEd->Control = %08x\n", m_pEd->Control); + m_pEd->Control &= ~0x7F; + m_pEd->Control |= addr; + DBG("m_pEd->Control = %08x\n", m_pEd->Control); +} + +void UsbEndpoint::updateSize(uint16_t size) +{ + DBG("m_pEd->Control = %08x\n", m_pEd->Control); + m_pEd->Control &= ~0x3FF0000; + m_pEd->Control |= (size << 16); + DBG("m_pEd->Control = %08x\n", m_pEd->Control); +} + +#if 0 //For doc only +template <class T> +void UsbEndpoint::setOnCompletion( T* pCbItem, void (T::*pCbMeth)() ) +{ + m_pCbItem = (CDummy*) pCbItem; + m_pCbMeth = (void (CDummy::*)()) pCbMeth; +} +#endif + +void UsbEndpoint::onCompletion() +{ + DBG_ASSERT(m_type != USB_ISO); + DBG_ASSERT(m_pTdHead); + //DBG("Transfer completed\n"); + if( m_pTdHead->Control >> 28 ) + { + DBG("TD Failed with condition code %01x\n", m_pTdHead->Control >> 28 ); + m_status = (int)USBERR_TDFAIL; + } + else if( m_pEd->HeadTd & 0x1 ) + { + m_pEd->HeadTd = m_pEd->HeadTd & ~0x1; + DBG("\r\nHALTED!!\r\n"); + m_status = (int)USBERR_HALTED; + } + else if( (m_pEd->HeadTd & ~0xF) == (uint32_t) m_pTdTail ) + { + //Done + int len; + DBG("m_pEp=%p\n", m_pEd); + DBG("m_pTdHead->CurrBufPtr=%08x\n", (uint32_t)m_pTdHead->CurrBufPtr); + DBG("m_pBufStartPtr=%08x\n", (uint32_t) m_pBufStartPtr); + if(m_pTdHead->CurrBufPtr) + len = m_pTdHead->CurrBufPtr - (uint32_t) m_pBufStartPtr; + else + len = m_len; + /*if(len == 0) //Packet transfered completely + len = m_len;*/ + //m_done = true; + DBG("Transfered %d bytes\n", len); + m_status = len; + } + else + { + DBG("Unknown error...\n"); + m_status = (int)USBERR_ERROR; + } + m_result = true; + if(m_pCbItem && m_pCbMeth) + (m_pCbItem->*m_pCbMeth)(); +} + + + +void UsbEndpoint::sOnCompletion(uint32_t pTd) +{ + HCTD* td = td_reverse((HCTD*)pTd); + while(td) { + HCTD* next = (HCTD*)td->Next; + HCUTD* utd = (HCUTD*)td; + UsbEndpoint* pEp = (UsbEndpoint*)utd->UsbEndpoint; + DBG_ASSERT(pEp); + if (usb_is_itd((byte*)td)) { + HCITD* itd = (HCITD*)td; + DBG_ASSERT(pEp->m_type == USB_ISO); + pEp->queue_done_itd.push(itd); + } else { + DBG_ASSERT(pEp->m_pTdHead == td); + if(pEp->m_pTdHead == td) { // found? + pEp->onCompletion(); + } + } + td = next; + } +} + +#endif