Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: FatFileSystem TB6612FNG2 mbed
Diff: usb/UsbEndpoint.cpp
- Revision:
- 0:de03cbbcd0ff
diff -r 000000000000 -r de03cbbcd0ff usb/UsbEndpoint.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usb/UsbEndpoint.cpp Mon Nov 30 09:32:15 2015 +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