From 3ba2e37651db31c47213c4a021618ee39a5a0443 Mon Sep 17 00:00:00 2001 From: Thibault RICHARD Date: Tue, 26 Jun 2012 16:20:26 +0200 Subject: [PATCH] [sam] USBHost ADK+HID supported okay. Code is more documented. --- .../validation_usb_host/test_usb_host.cpp | 83 ++-- hardware/arduino/sam/system/USBHost/Usb.cpp | 456 +++++++++++------- hardware/arduino/sam/system/USBHost/Usb.h | 31 +- hardware/arduino/sam/system/USBHost/address.h | 185 +++++-- hardware/arduino/sam/system/USBHost/adk.cpp | 405 ++++++++++++++++ hardware/arduino/sam/system/USBHost/adk.h | 150 ++++++ .../sam/system/USBHost/confdescparser.h | 188 +++++--- .../USBHost/examples/adk/test_usb_host.cpp | 54 +++ hardware/arduino/sam/system/USBHost/hid.h | 18 +- hardware/arduino/sam/system/USBHost/hid2.cpp | 128 +++-- .../arduino/sam/system/USBHost/hidboot.cpp | 34 ++ hardware/arduino/sam/system/USBHost/hidboot.h | 143 ++++-- hardware/arduino/sam/system/USBHost/usb_ch9.h | 3 +- .../sam/system/libsam/include/USB_host.h | 15 +- .../sam/system/libsam/source/uotghs_host.c | 219 +++++---- .../arduino_due_x/libsam_sam3x8e_gcc_rel.a | Bin 86236 -> 85302 bytes .../libsam_sam3x8e_gcc_rel.a.txt | 73 ++- 17 files changed, 1609 insertions(+), 576 deletions(-) create mode 100644 hardware/arduino/sam/system/USBHost/adk.cpp create mode 100644 hardware/arduino/sam/system/USBHost/adk.h create mode 100644 hardware/arduino/sam/system/USBHost/examples/adk/test_usb_host.cpp diff --git a/hardware/arduino/sam/cores/arduino/validation_usb_host/test_usb_host.cpp b/hardware/arduino/sam/cores/arduino/validation_usb_host/test_usb_host.cpp index a836acfd5..7c2f540c2 100644 --- a/hardware/arduino/sam/cores/arduino/validation_usb_host/test_usb_host.cpp +++ b/hardware/arduino/sam/cores/arduino/validation_usb_host/test_usb_host.cpp @@ -1,61 +1,54 @@ #include "variant.h" #include -#include +#include -class MouseRptParser : public MouseReportParser -{ -protected: - virtual void OnMouseMove (MOUSEINFO *mi); - virtual void OnLeftButtonUp (MOUSEINFO *mi); - virtual void OnLeftButtonDown (MOUSEINFO *mi); - virtual void OnRightButtonUp (MOUSEINFO *mi); - virtual void OnRightButtonDown (MOUSEINFO *mi); - virtual void OnMiddleButtonUp (MOUSEINFO *mi); - virtual void OnMiddleButtonDown (MOUSEINFO *mi); -}; -void MouseRptParser::OnMouseMove(MOUSEINFO *mi) -{ - printf("Pos={%d,%d}\r\n", mi->dX, mi->dY); -}; -void MouseRptParser::OnLeftButtonUp (MOUSEINFO *mi) -{ - printf("L Butt Up\r\n"); -}; -void MouseRptParser::OnLeftButtonDown (MOUSEINFO *mi) -{ - printf("L Butt Dn\r\n"); -}; -void MouseRptParser::OnRightButtonUp (MOUSEINFO *mi) -{ - printf("R Butt Up\r\n"); -}; -void MouseRptParser::OnRightButtonDown (MOUSEINFO *mi) -{ - printf("R Butt Dn\r\n"); -}; -void MouseRptParser::OnMiddleButtonUp (MOUSEINFO *mi) -{ - printf("M Butt Up\r\n"); -}; -void MouseRptParser::OnMiddleButtonDown (MOUSEINFO *mi) -{ - printf("M Butt Dn\r\n"); -}; +// Accessory descriptor. It's how Arduino identifies itself to Android. +char applicationName[] = "Arduino_Terminal"; // the app on your phone +char accessoryName[] = "Arduino Due X"; // your Arduino board +char companyName[] = "Arduino SA"; + +// Make up anything you want for these +char versionNumber[] = "1.0"; +char serialNumber[] = "1"; +char url[] = "http://labs.arduino.cc/uploads/ADK/ArduinoTerminal/ThibaultTerminal_ICS_0001.apk"; USBHost Usb; -HIDBoot HostMouse(&Usb); -MouseRptParser Prs; +ADK adk(&Usb, companyName, applicationName, accessoryName,versionNumber,url,serialNumber); void setup() { cpu_irq_enable(); - printf("\r\nProgram started:\r\n"); + printf("\r\nADK demo start\r\n"); delay(200); - - HostMouse.SetReportParser(0,(HIDReportParser*)&Prs); } +#define RCVSIZE 128 + void loop() { + uint8_t buf[RCVSIZE]; + uint32_t nbread = 0; + char helloworld[] = "Hello World!\r\n"; + Usb.Task(); + + if (adk.isReady()) + { + /* Write hello string to ADK */ + adk.write(strlen(helloworld), (uint8_t *)helloworld); + + delay(1000); + + /* Read data from ADK and print to UART */ + adk.read(&nbread, RCVSIZE, buf); + if (nbread > 0) + { + printf("RCV: "); + for (uint32_t i = 0; i < nbread; ++i) + { + printf("%c", (char)buf[i]); + } + printf("\r\n"); + } + } } diff --git a/hardware/arduino/sam/system/USBHost/Usb.cpp b/hardware/arduino/sam/system/USBHost/Usb.cpp index 175f21ca8..ce74b4890 100644 --- a/hardware/arduino/sam/system/USBHost/Usb.cpp +++ b/hardware/arduino/sam/system/USBHost/Usb.cpp @@ -14,6 +14,7 @@ Circuits At Home, LTD Web : http://www.circuitsathome.com e-mail : support@circuitsathome.com */ + /* USB functions */ #include "Arduino.h" @@ -24,9 +25,9 @@ static uint32_t usb_error = 0; static uint32_t usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; /** - * Class Constructor. + * \brief USBHost class constructor. */ -USBHost::USBHost () : bmHubPre(0) +USBHost::USBHost() : bmHubPre(0) { // Set up state machine usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; @@ -36,7 +37,7 @@ USBHost::USBHost () : bmHubPre(0) } /** - * Initialize data structures. + * \brief Initialize USBHost class. */ void USBHost::init() { @@ -44,8 +45,11 @@ void USBHost::init() bmHubPre = 0; } + /** - * Get USB state. + * \brief Get USBHost state. + * + * \return USB enumeration status (see USBHost::task). */ uint32_t USBHost::getUsbTaskState(void) { @@ -53,7 +57,9 @@ uint32_t USBHost::getUsbTaskState(void) } /** - * Set USB state. + * \brief Set USB state. + * + * \param state New USBHost status to be set. */ void USBHost::setUsbTaskState(uint32_t state) { @@ -61,7 +67,15 @@ void USBHost::setUsbTaskState(uint32_t state) } /** - * Get end point info from address. + * \brief Get endpoint info from USB device address and device endpoint. + * + * \note This function should be used to know which host pipe is being used for + * the corresponding device endpoint. + * + * \param addr USB device address. + * \param ep USB device endpoint number. + * + * \return Pointer to an EpInfo structure. */ EpInfo* USBHost::getEpInfoEntry(uint32_t addr, uint32_t ep) { @@ -74,18 +88,27 @@ EpInfo* USBHost::getEpInfoEntry(uint32_t addr, uint32_t ep) for (uint32_t i = 0; i < p->epcount; i++) { - if (pep->epAddr == ep) + if (pep->deviceEpNum == ep) return pep; pep++; } + return NULL; } /** - * Set device end point entry. - * Each device is different and has different number of endpoints. - * This function plugs endpoint record structure, defined in application to devtable. + * \brief Set device endpoint entry. + * + * \note Each device is different and has a different number of endpoints. + * This function sets endpoint record structure to the device using address + * addr in the address pool. + * + * \param ul_pipe Pipe address. + * \param ul_token_type Token type. + * + * \retval 0 on success. + * \retval USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL device not found. */ uint32_t USBHost::setEpInfoEntry(uint32_t addr, uint32_t epcount, EpInfo* eprecord_ptr) { @@ -104,7 +127,21 @@ uint32_t USBHost::setEpInfoEntry(uint32_t addr, uint32_t epcount, EpInfo* epreco return 0; } -uint32_t USBHost::SetAddress(uint32_t addr, uint32_t ep, EpInfo **ppep, uint32_t &nak_limit) +/** + * \brief Set host pipe target address and set ppep pointer to the endpoint + * structure matching the specified USB device address and endpoint. + * + * \param addr USB device address. + * \param ep USB device endpoint number. + * \param ppep Endpoint info structure pointer set by setPipeAddress. + * \param nak_limit Maximum number of NAK permitted. + * + * \retval 0 on success. + * \retval USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL device not found. + * \retval USB_ERROR_EPINFO_IS_NULL no endpoint structure found for this device. + * \retval USB_ERROR_EP_NOT_FOUND_IN_TBL the specified device endpoint cannot be found. + */ +uint32_t USBHost::setPipeAddress(uint32_t addr, uint32_t ep, EpInfo **ppep, uint32_t &nak_limit) { UsbDevice *p = addrPool.GetUsbDevicePtr(addr); @@ -119,29 +156,34 @@ uint32_t USBHost::SetAddress(uint32_t addr, uint32_t ep, EpInfo **ppep, uint32_t if (!*ppep) return USB_ERROR_EP_NOT_FOUND_IN_TBL; - nak_limit = (0x0001UL << ( ( (*ppep)->bmNakPower > USB_NAK_MAX_POWER ) ? USB_NAK_MAX_POWER : (*ppep)->bmNakPower) ); + nak_limit = (0x0001UL << (((*ppep)->bmNakPower > USB_NAK_MAX_POWER ) ? USB_NAK_MAX_POWER : (*ppep)->bmNakPower)); nak_limit--; // Set peripheral address - //regWr( rPERADDR, addr ); - uhd_configure_address(ep, addr); - - ///////////////////////////////////////////////////////////////////////////////////////////// Y A TIL QQCHOSE A FAIRE??? - //uint8_t mode = regRd( rMODE ); - // Set bmLOWSPEED and bmHUBPRE in case of low-speed device, reset them otherwise - //regWr( rMODE, (p->lowspeed) ? mode | bmLOWSPEED | bmHubPre : mode & ~(bmHUBPRE | bmLOWSPEED)); + TRACE_USBHOST(printf(" => SetAddress deviceEP=%lu configued as hostPIPE=%lu sending to address=%lu\r\n", ep, (*ppep)->hostPipeNum, addr);) + uhd_configure_address((*ppep)->hostPipeNum, addr); return 0; } /** - * Send a control request. - * Sets address, endpoint, fills control packet with necessary data, dispatches control packet, and initiates bulk IN transfer depending on request. - * Actual requests are defined as inlines. + * \brief Send a control request. + * Sets address, endpoint, fills control packet with necessary data, dispatches + * control packet, and initiates bulk IN transfer depending on request. * - * return codes: - * 00 = success - * 01-0f = non-zero HRSLT + * \param addr USB device address. + * \param ep USB device endpoint number. + * \param bmReqType Request direction. + * \param bRequest Request type. + * \param wValLo Value low. + * \param wValHi Value high. + * \param wInd Index field. + * \param total Request length. + * \param nbytes Number of bytes to read. + * \param dataptr Data pointer. + * \param p USB class reader. + * + * \return 0 on success, error code otherwise. */ uint32_t USBHost::ctrlReq(uint32_t addr, uint32_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, uint16_t wInd, uint16_t total, uint32_t nbytes, uint8_t* dataptr, USBReadParser *p) { @@ -156,12 +198,13 @@ uint32_t USBHost::ctrlReq(uint32_t addr, uint32_t ep, uint8_t bmReqType, uint8_t TRACE_USBHOST(printf(" => ctrlReq\r\n");) // Set peripheral address - rcode = SetAddress(addr, ep, &pep, nak_limit); + rcode = setPipeAddress(addr, ep, &pep, nak_limit); if (rcode) return rcode; - // Allocate EP0 with default 8 bytes size if not already initialized - rcode = UHD_EP0_Alloc(0, 8); + // Allocate Pipe0 with default 64 bytes size if not already initialized + // TODO : perform a get device descriptor first to get device endpoint size (else data can be missed if device ep0 > host pipe0) + rcode = UHD_Pipe0_Alloc(0, 64); if (rcode) { TRACE_USBHOST(printf("/!\\ USBHost::ctrlReq : EP0 allocation error: %lu\r\n", rcode);) @@ -169,7 +212,7 @@ uint32_t USBHost::ctrlReq(uint32_t addr, uint32_t ep, uint8_t bmReqType, uint8_t } // Determine request direction - direction = (( bmReqType & 0x80 ) > 0); + direction = ((bmReqType & 0x80 ) > 0); // Fill in setup packet setup_pkt.ReqType_u.bmRequestType = bmReqType; @@ -180,12 +223,11 @@ uint32_t USBHost::ctrlReq(uint32_t addr, uint32_t ep, uint8_t bmReqType, uint8_t setup_pkt.wLength = total; // Configure and write the setup packet into the FIFO - //bytesWr(rSUDFIFO, 8, (uint8_t *)&setup_pkt); uhd_configure_pipe_token(0, tokSETUP); - UHD_EP_Write(ep, 8, (uint8_t *)&setup_pkt); + UHD_Pipe_Write(pep->hostPipeNum, 8, (uint8_t *)&setup_pkt); // Dispatch packet - rcode = dispatchPkt(tokSETUP, ep, nak_limit); + rcode = dispatchPkt(tokSETUP, pep->hostPipeNum, nak_limit); if (rcode) { // Return HRSLT if not zero @@ -224,7 +266,6 @@ uint32_t USBHost::ctrlReq(uint32_t addr, uint32_t ep, uint8_t bmReqType, uint8_t else { // OUT transfer - //devtable[addr].epinfo[ep].sndToggle = bmSNDTOG1; TRACE_USBHOST(printf(" => ctrlData OUT\r\n");) rcode = OutTransfer(pep, nak_limit, nbytes, dataptr); } @@ -237,27 +278,36 @@ uint32_t USBHost::ctrlReq(uint32_t addr, uint32_t ep, uint8_t bmReqType, uint8_t } // Status stage - return dispatchPkt((direction) ? tokOUTHS : tokINHS, ep, nak_limit ); + return dispatchPkt((direction) ? tokOUTHS : tokINHS, pep->hostPipeNum, nak_limit); } /** - * IN transfer to arbitrary endpoint. - * Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. - * Keep sending INs and writes data to memory area pointed by 'data'. - * rcode 0 if no errors - * 01-0f is relayed from dispatchPkt() - * f0 means RCVDAVIRQ error - * fe USB xfer timeout + * \brief Perform IN request to the specified USB device. + * + * \note This function handles multiple packets (if necessary) and can + * receive a maximum of 'nbytesptr' bytes. It keep sending INs and writes data + * to memory area pointed by 'data'. The actual amount of received bytes is + * stored in 'nbytesptr'. + * + * \param addr USB device address. + * \param ep USB device endpoint number. + * \param nbytesptr Receive buffer size. It is set to the amount of received + * bytes when the function returns. + * \param data Buffer to store received data. + * + * \return 0 on success, error code otherwise. */ uint32_t USBHost::inTransfer(uint32_t addr, uint32_t ep, uint32_t *nbytesptr, uint8_t* data) { EpInfo *pep = NULL; uint32_t nak_limit = 0; - uint32_t rcode = SetAddress(addr, ep, &pep, nak_limit); + uint32_t rcode = setPipeAddress(addr, ep, &pep, nak_limit); if (rcode) + { return rcode; + } return InTransfer(pep, nak_limit, nbytesptr, data); } @@ -266,43 +316,34 @@ uint32_t USBHost::InTransfer(EpInfo *pep, uint32_t nak_limit, uint32_t *nbytespt { uint32_t rcode = 0; uint32_t pktsize = 0; - uint16_t nbytes = *nbytesptr; - uint8_t maxpktsize = pep->maxPktSize; + uint32_t nbytes = *nbytesptr; + uint32_t maxpktsize = pep->maxPktSize; *nbytesptr = 0; - // Set toggle value - //regWr(rHCTL, devtable[addr].epinfo[ep].rcvToggle); - while (1) { // Use a 'return' to exit this loop // IN packet to EP-'endpoint'. Function takes care of NAKS. - rcode = dispatchPkt(tokIN, pep->epAddr, nak_limit); + rcode = dispatchPkt(tokIN, pep->hostPipeNum, nak_limit); if (rcode) { - // Should be 0, indicating ACK. Else return error code. - return (rcode); + if (rcode == 1) + { + // Pipe freeze is mandatory to avoid sending IN endlessly (else reception becomes messy then) + uhd_freeze_pipe(pep->hostPipeNum); + } + // Should be 1, indicating NAK. Else return error code. + return rcode; } - // check for RCVDAVIRQ and generate error if not present - // the only case when absense of RCVDAVIRQ makes sense is when toggle error occured. Need to add handling for that - /*if ((regRd(rHIRQ) & bmRCVDAVIRQ) == 0) - { - // Receive error - return (0xf0); - }*/ - // Number of received bytes - //pktsize = regRd(rRCVBC); - //data = bytesRd(rRCVFIFO, pktsize, data); - pktsize = uhd_byte_count(pep->epAddr); + pktsize = uhd_byte_count(pep->hostPipeNum); if (nbytes < pktsize) - printf("ce test n'a pas ete fait...\r\n"); - data += UHD_EP_Read(pep->epAddr, pktsize, data); - - // Clear the IRQ & free the buffer - //regWr(rHIRQ, bmRCVDAVIRQ); + { + TRACE_USBHOST(printf("/!\\ USBHost::InTransfer : receive buffer is too small, size=%lu, expected=%lu\r\n", nbytes, pktsize);) + } + data += UHD_Pipe_Read(pep->hostPipeNum, pktsize, data); // Add this packet's byte count to total transfer length *nbytesptr += pktsize; @@ -312,155 +353,116 @@ uint32_t USBHost::InTransfer(EpInfo *pep, uint32_t nak_limit, uint32_t *nbytespt // 2. 'nbytes' have been transferred. if ((pktsize < maxpktsize) || (*nbytesptr >= nbytes)) { - /*// Have we transferred 'nbytes' bytes? - if (regRd(rHRSL) & bmRCVTOGRD) - { - // Save toggle value - devtable[addr].epinfo[ep].rcvToggle = bmRCVTOG1; - } - else - { - devtable[addr].epinfo[ep].rcvToggle = bmRCVTOG0; - }*/ - - return (0); + return 0; } } } /** - * OUT transfer to arbitrary endpoint. - * Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. - * Handles NAK bug per Maxim Application Note 4000 for single buffer transfer - * rcode 0 if no errors - * 01-0f is relayed from HRSL + * \brief Perform OUT request to the specified USB device. * - * Major part of this function borrowed from code shared by Richard Ibbotson + * \note This function handles multiple packets (if necessary) and sends + * 'nbytes' bytes. + * + * \param addr USB device address. + * \param ep USB device endpoint number. + * \param nbytes Buffer size to be sent. + * \param data Buffer to send. + * + * \return 0 on success, error code otherwise. */ uint32_t USBHost::outTransfer(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t* data) { -/* - EpInfo *pep = NULL; - uint16_t nak_limit; + EpInfo *pep = NULL; + uint32_t nak_limit = 0; - uint8_t rcode = SetAddress(addr, ep, &pep, nak_limit); + uint32_t rcode = setPipeAddress(addr, ep, &pep, nak_limit); if (rcode) + { return rcode; + } return OutTransfer(pep, nak_limit, nbytes, data); -*/ -printf("j'ai beau etre matinal.. j'ai mal!!!!\r\n"); -return 1; } uint32_t USBHost::OutTransfer(EpInfo *pep, uint32_t nak_limit, uint32_t nbytes, uint8_t *data) { -/* - uint8_t rcode, retry_count; - uint8_t *data_p = data; //local copy of the data pointer - uint16_t bytes_tosend, nak_count; - uint16_t bytes_left = nbytes; + uint32_t rcode = 0; + uint32_t bytes_tosend = 0; + uint32_t bytes_left = nbytes; + uint32_t maxpktsize = pep->maxPktSize; - uint8_t maxpktsize = pep->maxPktSize; - - if (maxpktsize < 1 || maxpktsize > 64) + if (maxpktsize < 1) return USB_ERROR_INVALID_MAX_PKT_SIZE; - unsigned long timeout = millis() + USB_XFER_TIMEOUT; - - regWr( rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0 ); //set toggle value - - while( bytes_left ) + while (bytes_left) { - retry_count = 0; - nak_count = 0; - bytes_tosend = ( bytes_left >= maxpktsize ) ? maxpktsize : bytes_left; - bytesWr( rSNDFIFO, bytes_tosend, data_p ); //filling output FIFO - regWr( rSNDBC, bytes_tosend ); //set number of bytes - regWr( rHXFR, ( tokOUT | pep->epAddr )); //dispatch packet - while(!(regRd( rHIRQ ) & bmHXFRDNIRQ )); //wait for the completion IRQ - regWr( rHIRQ, bmHXFRDNIRQ ); //clear IRQ - rcode = ( regRd( rHRSL ) & 0x0f ); + bytes_tosend = (bytes_left >= maxpktsize) ? maxpktsize : bytes_left; - while( rcode && ( timeout > millis())) + // Write FIFO + UHD_Pipe_Write(pep->hostPipeNum, bytes_tosend, data); + + // Use a 'return' to exit this loop + // OUT packet to EP-'endpoint'. Function takes care of NAKS. + rcode = dispatchPkt(tokOUT, pep->hostPipeNum, nak_limit); + if (rcode) { - switch( rcode ) - { - case hrNAK: - nak_count ++; - if( nak_limit && ( nak_count == nak_limit )) - return( rcode ); - break; - case hrTIMEOUT: - retry_count ++; - if( retry_count == USB_RETRY_LIMIT ) - return( rcode ); - break; - default: - return( rcode ); - }//switch( rcode + // Should be 0, indicating ACK. Else return error code. + return rcode; + } - // process NAK according to Host out NAK bug - regWr( rSNDBC, 0 ); - regWr( rSNDFIFO, *data_p ); - regWr( rSNDBC, bytes_tosend ); - regWr( rHXFR, ( tokOUT | pep->epAddr )); //dispatch packet - while(!(regRd( rHIRQ ) & bmHXFRDNIRQ )); //wait for the completion IRQ - regWr( rHIRQ, bmHXFRDNIRQ ); //clear IRQ - rcode = ( regRd( rHRSL ) & 0x0f ); - }//while( rcode && .... bytes_left -= bytes_tosend; - data_p += bytes_tosend; - }//while( bytes_left... - pep->bmSndToggle = ( regRd( rHRSL ) & bmSNDTOGRD ) ? 1 : 0; //bmSNDTOG1 : bmSNDTOG0; //update toggle - return( rcode ); //should be 0 in all cases - */ - printf("j'ai beau etre matinal.. j'ai mal!!!! arggghh\r\n"); -return 1; + data += bytes_tosend; + } + + // Should be 0 in all cases + return rcode; } /** - * Dispatch USB packet. - * Assumes peripheral address is set and relevant buffer is loaded/empty. + * \brief Dispatch USB packet. + * + * \note Ensure peripheral address is set and relevant buffer is loaded/empty. * If NAK, tries to re-send up to nak_limit times. * If nak_limit == 0, do not count NAKs, exit after timeout. - * If bus timeout, re-sends up to USB_RETRY_LIMIT times. - * rcode 0 for success - * 1 for naked - * 2 for timeout * - * Note: pipe token MUST be configured first when the corresponding FIFO is used, - * else packet may be corrupted. + * \param token Token type (Setup, In or Out). + * \param hostPipeNum Host pipe number to use for sending USB packet. + * \param nak_limit Maximum number of NAK permitted. + * + * \return 0 on success, error code otherwise. */ -uint32_t USBHost::dispatchPkt(uint32_t token, uint32_t ep, uint32_t nak_limit) +uint32_t USBHost::dispatchPkt(uint32_t token, uint32_t hostPipeNum, uint32_t nak_limit) { uint32_t timeout = millis() + USB_XFER_TIMEOUT; uint32_t nak_count = 0; uint32_t rcode = USB_ERROR_TRANSFER_TIMEOUT; - TRACE_USBHOST(printf(" => dispatchPkt token=%lu\r\n", token);) + TRACE_USBHOST(printf(" => dispatchPkt token=%lu pipe=%lu nak_limit=%lu\r\n", token, hostPipeNum, nak_limit);) // Launch the transfer - //regWr(rHXFR, (token | ep)); - UHD_EP_Send(ep, token); + UHD_Pipe_Send(hostPipeNum, token); - while (timeout > millis()) + // Check timeout but don't hold timeout if VBUS is lost + while ((timeout > millis()) && (UHD_GetVBUSState() == UHD_STATE_CONNECTED)) { // Wait for transfer completion - if (UHD_EP_Is_Transfer_Complete(ep, token)) + if (UHD_Pipe_Is_Transfer_Complete(hostPipeNum, token)) { return 0; } - // - if (Is_uhd_nak_received(ep)) + // Is NAK received? + if (Is_uhd_nak_received(hostPipeNum)) { - uhd_ack_nak_received(ep); + uhd_ack_nak_received(hostPipeNum); nak_count++; + if (nak_limit && (nak_count == nak_limit)) { - return 1; //////////////////////////// cree un code pour ca + // Return NAK + return 1; } } } @@ -469,8 +471,14 @@ uint32_t USBHost::dispatchPkt(uint32_t token, uint32_t ep, uint32_t nak_limit) } /** - * Configure a device using known device classes. + * \brief Configure device using known device classes. * The device get a new address even if its class remain unknown. + * + * \param parent USB device address of the device's parent (0 if root). + * \param port USB device base address (see AddressPoolImpl). + * \param lowspeed Device speed. + * + * \return 0 on success, error code otherwise. */ uint32_t USBHost::Configuring(uint32_t parent, uint32_t port, uint32_t lowspeed) { @@ -490,11 +498,20 @@ uint32_t USBHost::Configuring(uint32_t parent, uint32_t port, uint32_t lowspeed) return 0; } - if (!(rcode == USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED || rcode == USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE)) + + if (rcode == USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED) + { + TRACE_USBHOST(printf("USBHost::Configuring : ERROR : device not supported!\r\n");) + } + else if (rcode == USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE) + { + TRACE_USBHOST(printf("USBHost::Configuring : ERROR : class instance already in use!\r\n");) + } + else { // in case of an error devConfigIndex should be reset to 0 - // in order to start from the very beginning the - // next time the program gets here + // in order to start from the very beginning the next time + // the program gets here if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE) devConfigIndex = 0; @@ -502,7 +519,7 @@ uint32_t USBHost::Configuring(uint32_t parent, uint32_t port, uint32_t lowspeed) } } - // if we get here that means that the device class is not supported by any of registered classes + // Device class is not supported by any of the registered classes devConfigIndex = 0; rcode = DefaultAddressing(parent, port, lowspeed); @@ -510,6 +527,15 @@ uint32_t USBHost::Configuring(uint32_t parent, uint32_t port, uint32_t lowspeed) return rcode; } +/** + * \brief Configure device with unknown USB class. + * + * \param parent USB device address of the device's parent (0 if root). + * \param port USB device base address (see AddressPoolImpl). + * \param lowspeed Device speed. + * + * \return 0 on success, error code otherwise. + */ uint32_t USBHost::DefaultAddressing(uint32_t parent, uint32_t port, uint32_t lowspeed) { uint32_t rcode = 0; @@ -553,30 +579,70 @@ uint32_t USBHost::DefaultAddressing(uint32_t parent, uint32_t port, uint32_t low return 0; } +/** + * \brief Release device and free associated resources. + * + * \param addr USB device address. + * + * \return 0 on success, error code otherwise. + */ uint32_t USBHost::ReleaseDevice(uint32_t addr) { if (!addr) return 0; for (uint32_t i = 0; i < USB_NUMDEVICES; ++i) + { if (devConfig[i]->GetAddress() == addr) + { return devConfig[i]->Release(); + } + } return 0; } -// Get device descriptor +/** + * \brief Get device descriptor. + * + * \param addr USB device address. + * \param ep USB device endpoint number. + * \param nbytes Buffer size. + * \param dataptr Buffer to store received descriptor. + * + * \return 0 on success, error code otherwise. + */ uint32_t USBHost::getDevDescr(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t* dataptr) { return (ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, nbytes, dataptr, 0)); } -// Get configuration descriptor +/** + * \brief Get configuration descriptor. + * + * \param addr USB device address. + * \param ep USB device endpoint number. + * \param nbytes Buffer size. + * \param conf Configuration number. + * \param dataptr Buffer to store received descriptor. + * + * \return 0 on success, error code otherwise. + */ uint32_t USBHost::getConfDescr(uint32_t addr, uint32_t ep, uint32_t nbytes, uint32_t conf, uint8_t* dataptr) { return (ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, nbytes, dataptr, 0)); } +/** + * \brief Get configuration descriptor and extract endpoints using USBReadParser object. + * + * \param addr USB device address. + * \param ep USB device endpoint number. + * \param conf Configuration number. + * \param p USBReadParser object pointer used to extract endpoints. + * + * \return 0 on success, error code otherwise. + */ uint32_t USBHost::getConfDescr(uint32_t addr, uint32_t ep, uint32_t conf, USBReadParser *p) { const uint32_t bufSize = 64; @@ -593,28 +659,56 @@ uint32_t USBHost::getConfDescr(uint32_t addr, uint32_t ep, uint32_t conf, USBRea return (ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, total, bufSize, buf, p)); } -// Get string descriptor -uint32_t USBHost::getStrDescr(uint32_t addr, uint32_t ep, uint16_t ns, uint8_t index, uint16_t langid, uint8_t* dataptr) +/** + * \brief Get string descriptor. + * + * \param addr USB device address. + * \param ep USB device endpoint number. + * \param nbytes Buffer size. + * \param index String index. + * \param langid Language ID. + * \param dataptr Buffer to store received descriptor. + * + * \return 0 on success, error code otherwise. + */ +uint32_t USBHost::getStrDescr(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t index, uint16_t langid, uint8_t* dataptr) { - return (ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, ns, ns, dataptr, 0)); + return (ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, nbytes, nbytes, dataptr, 0)); } -// Set address +/** + * \brief Set USB device address. + * + * \param oldaddr Current USB device address. + * \param ep USB device endpoint number. + * \param addr New USB device address to be set. + * + * \return 0 on success, error code otherwise. + */ uint32_t USBHost::setAddr(uint32_t oldaddr, uint32_t ep, uint32_t newaddr) { - TRACE_USBHOST(printf(" => setAddr\r\n");) + TRACE_USBHOST(printf(" => USBHost::setAddr\r\n");) return ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, 0, 0); } -// Set configuration +/** + * \brief Set configuration. + * + * \param addr USB device address. + * \param ep USB device endpoint number. + * \param conf_value New configuration value to be set. + * + * \return 0 on success, error code otherwise. + */ uint32_t USBHost::setConf(uint32_t addr, uint32_t ep, uint32_t conf_value) { return (ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, 0x0000, 0, 0)); } /** - * USB main task. - * Performs enumeration/cleanup. + * \brief USB main task, responsible for enumeration and clean up stage. + * + * \note Must be periodically called from loop(). */ void USBHost::Task(void) { @@ -648,16 +742,17 @@ void USBHost::Task(void) { delay = millis() + USB_SETTLE_DELAY; usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE; - ///////////////////////////////////////////////////////////lowspeed = 0 ou 1; faire un get speed + //FIXME TODO: lowspeed = 0 ou 1; already done by hardware? } break; } + // Poll connected devices (if required) for (uint32_t i = 0; i < USB_NUMDEVICES; ++i) if (devConfig[i]) rcode = devConfig[i]->Poll(); - // USB state machine + // Perform USB enumeration stage and clean up switch (usb_task_state) { case USB_DETACHED_SUBSTATE_INITIALIZE: @@ -667,6 +762,7 @@ void USBHost::Task(void) UHD_Init(); init(); + // Free all USB resources for (uint32_t i = 0; i < USB_NUMDEVICES; ++i) if (devConfig[i]) rcode = devConfig[i]->Release(); diff --git a/hardware/arduino/sam/system/USBHost/Usb.h b/hardware/arduino/sam/system/USBHost/Usb.h index 2dfd0ff09..9b1203d70 100644 --- a/hardware/arduino/sam/system/USBHost/Usb.h +++ b/hardware/arduino/sam/system/USBHost/Usb.h @@ -19,8 +19,8 @@ e-mail : support@circuitsathome.com #ifndef USB_H_INCLUDED #define USB_H_INCLUDED -#define TRACE_USBHOST(x) x -//#define TRACE_USBHOST(x) +//#define TRACE_USBHOST(x) x +#define TRACE_USBHOST(x) #include #include "usb_ch9.h" @@ -120,7 +120,11 @@ typedef struct uint16_t wLength; // 6 Depends on bRequest } SETUP_PKT, *PSETUP_PKT; -// Base class for incoming data parser +/** + * \class USBReadParser + * + * \brief Base class used for USB descriptor parsing. + */ class USBReadParser { public: @@ -128,21 +132,30 @@ public: }; /** - * USBDeviceConfig class. + * \class USBDeviceConfig + * + * \brief Device configuration class used for managing device life cycle. */ class USBDeviceConfig { public: + //! @brief Perform final enumeration stage. virtual uint32_t Init(uint32_t parent, uint32_t port, uint32_t lowspeed) = 0; + + //! @brief Free USB allocated resources (pipes and address). virtual uint32_t Release() = 0; + + //! @brief Poll USB device. Call is made for each connected USB device on USBHost.task() call. virtual uint32_t Poll() = 0; + + //! @brief Retrieve USB device address. virtual uint32_t GetAddress() = 0; }; /** - * USBHost Class. - * The device table is filled during enumeration. - * Index corresponds to device address and each entry contains pointer to endpoint structure and device class to use. + * \class USBHost + * + * \brief Main USB host class. */ class USBHost { @@ -190,7 +203,7 @@ class USBHost uint32_t getDevDescr(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t* dataptr); uint32_t getConfDescr(uint32_t addr, uint32_t ep, uint32_t nbytes, uint32_t conf, uint8_t* dataptr); uint32_t getConfDescr(uint32_t addr, uint32_t ep, uint32_t conf, USBReadParser *p); - uint32_t getStrDescr(uint32_t addr, uint32_t ep, uint16_t ns, uint8_t index, uint16_t langid, uint8_t* dataptr); + uint32_t getStrDescr(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t index, uint16_t langid, uint8_t* dataptr); uint32_t setAddr(uint32_t oldaddr, uint32_t ep, uint32_t newaddr); uint32_t setConf(uint32_t addr, uint32_t ep, uint32_t conf_value); uint32_t ctrlReq(uint32_t addr, uint32_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, @@ -209,7 +222,7 @@ class USBHost private: void init(); - uint32_t SetAddress(uint32_t addr, uint32_t ep, EpInfo **ppep, uint32_t &nak_limit); + uint32_t setPipeAddress(uint32_t addr, uint32_t ep, EpInfo **ppep, uint32_t &nak_limit); uint32_t OutTransfer(EpInfo *pep, uint32_t nak_limit, uint32_t nbytes, uint8_t *data); uint32_t InTransfer(EpInfo *pep, uint32_t nak_limit, uint32_t *nbytesptr, uint8_t* data); }; diff --git a/hardware/arduino/sam/system/USBHost/address.h b/hardware/arduino/sam/system/USBHost/address.h index 4a1d5e4bc..2ea99e90c 100644 --- a/hardware/arduino/sam/system/USBHost/address.h +++ b/hardware/arduino/sam/system/USBHost/address.h @@ -27,9 +27,22 @@ e-mail : support@circuitsathome.com #define USB_NAK_NOWAIT 1 //Single NAK stops transfer #define USB_NAK_NONAK 0 //Do not count NAKs, stop retrying after USB Timeout +/** + * \brief Device endpoint definition. + * + * \note hostPipeNum is the allocated pipe used for the communication with + * deviceEpNum remote device endpoint. + * There is exactly one hostPipeNum corresponding to a deviceEpNum. + * + * \note The number of host pipe is limited by the hardware (10 on SAM3X). + * Moreover hostPipeNum allocation is static, meaning that only a limited + * amount of device endpoints can be opened at the same time, thus limitating + * the maximum number of connected devices at the same time. + */ struct EpInfo { - uint32_t epAddr; // Endpoint address + uint32_t deviceEpNum; // Device endpoint number + uint32_t hostPipeNum; // Host corresponding pipe number uint32_t maxPktSize; // Maximum packet size union @@ -45,15 +58,20 @@ struct EpInfo }; }; -// 7 6 5 4 3 2 1 0 -// --------------------------------- -// | | H | P | P | P | A | A | A | -// --------------------------------- -// -// H - if 1 the address is a hub address -// P - parent hub address -// A - device address / port number in case of hub -// +/** + * \brief USB device address definition. + * + * \note The 8 bits USB address is defined like this: + * + * 7 6 5 4 3 2 1 0 + * --------------------------------- + * | | H | P | P | P | A | A | A | + * --------------------------------- + * + * H - if 1 the address is a hub address + * P - parent hub address + * A - device address / port number in case of hub + */ struct UsbDeviceAddress { union @@ -73,6 +91,14 @@ struct UsbDeviceAddress #define bmUSB_DEV_ADDR_PARENT 0x38 #define bmUSB_DEV_ADDR_HUB 0x40 +/** + * \brief USB device definition. + * + * \note epinfo is used to store the list of device endpoints currently used + * by the USBHost stack. This field is set during enumeration process when + * a supported USB class is found. See any USB classes implementing + * USBDeviceConfig and init() method for reference. + */ struct UsbDevice { EpInfo *epinfo; // endpoint info pointer @@ -81,6 +107,9 @@ struct UsbDevice uint32_t lowspeed; // indicates if a device is the low speed one }; +/** + * \class Abstract AddressPool definition. + */ class AddressPool { public: @@ -94,28 +123,46 @@ typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev); #define ADDR_ERROR_INVALID_INDEX 0xFF #define ADDR_ERROR_INVALID_ADDRESS 0xFF +/** + * \class AddressPoolImpl definition. + * Used to store the list of connected devices and to keep track of free USB + * addresses. + */ template class AddressPoolImpl : public AddressPool { private: - EpInfo dev0ep; //Endpoint data structure used during enumeration for uninitialized device + EpInfo dev0ep; // Endpoint data structure used during enumeration for uninitialized device uint32_t hubCounter; // hub counter is kept // in order to avoid hub address duplication UsbDevice thePool[MAX_DEVICES_ALLOWED]; - // Initializes address pool entry + /** + * \brief Initialize the specified address pool entry. + * + * \param index Index pointing to a UsbDevice instance in the address pool. + */ void InitEntry(uint32_t index) { - thePool[index].address = 0; - thePool[index].epcount = 1; + thePool[index].address = 0; + thePool[index].epcount = 1; thePool[index].lowspeed = 0; - thePool[index].epinfo = &dev0ep; + thePool[index].epinfo = &dev0ep; }; - // Returns thePool index for a given address + /** + * \brief Return an address pool index for a given address. This index can + * further be used to retrieve the corresponding USB device instance + * UsbDevice. + * + * \param index Index pointing to a UsbDevice instance in the address pool. + * + * \return Index number if found, 0 otherwise. + * \note Index 0 is reserved for address 0 and shall never be used. + */ uint32_t FindAddressIndex(uint32_t address = 0) { for (uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++) @@ -126,21 +173,45 @@ private: return 0; }; - // Returns thePool child index for a given parent + /** + * \brief Return address pool child index for a given parent. This index can + * further be used to retrieve the corresponding USB device instance + * UsbDevice. + * + * \param addr Parent USB address. + * \param start Search in the pool from this index. Calling multiple time + * this function with the returned index + 1 can be used to walk through + * all children. + * + * \return Child index number if found, 0 otherwise. + * \note Index 0 is reserved for address 0 and shall never be used. + */ uint32_t FindChildIndex(UsbDeviceAddress addr, uint32_t start = 1) { - for (uint32_t i = (start < 1 || start >= MAX_DEVICES_ALLOWED) ? 1 : start; i < MAX_DEVICES_ALLOWED; i++) + for (uint32_t i = (start < 1 || start >= MAX_DEVICES_ALLOWED) ? 1 : start; i < MAX_DEVICES_ALLOWED; ++i) { if (((UsbDeviceAddress*)&thePool[i].address)->bmParent == addr.bmAddress) return i; } + return 0; }; - // Frees address entry specified by index parameter + /** + * \brief Free address entry specified by index parameter. + * + * \note Calling FreeAddressByIndex only frees the USB address for possible + * further assignement. However, it does not free the actual USB resources + * used by the device. This can be made by calling the release() method + * from any UsbDevice class implementing USBDeviceConfig. + * + * \param index Index pointing to a UsbDevice instance in the address pool. + * + * \note Calling FreeAddressByIndex with a 0 index param has no effect. + */ void FreeAddressByIndex(uint32_t index) { - // Zerro field is reserved and should not be affected + // Zero field is reserved and should not be affected if (index == 0) return; @@ -154,10 +225,13 @@ private: if (hubCounter == ((UsbDeviceAddress*)&thePool[index].address)->bmAddress) hubCounter --; } + InitEntry(index); } - // Initializes the whole address pool at once + /** + * \brief Initialize all address poll entries at once. + */ void InitAllAddresses() { for (uint32_t i = 1; i < MAX_DEVICES_ALLOWED; i++) @@ -167,6 +241,9 @@ private: }; public: + /** + * \brief AddressPoolImpl class constructor. + */ AddressPoolImpl() : hubCounter(0) { // Init address zero (reserved) @@ -176,11 +253,18 @@ public: InitAllAddresses(); // Configure ep0 used for enumeration - dev0ep.epAddr = 0; - dev0ep.maxPktSize = 8; + dev0ep.deviceEpNum = 0; + dev0ep.hostPipeNum = 0; + dev0ep.maxPktSize = 8; }; - // Returns a pointer to a specified address entry + /** + * \brief Get a UsbDevice pointer from a USB device address. + * + * \param addr USB device address. + * + * \return UsbDevice pointer on success, 0 otherwise. + */ virtual UsbDevice* GetUsbDevicePtr(uint32_t addr) { if (!addr) @@ -191,7 +275,12 @@ public: return (!index) ? 0 : (thePool + index); }; - // Performs an operation specified by pfunc for each addressed device + /** + * \brief Perform an operation specified by pfunc for each addressed + * USB device. + * + * \param pfunc Any function pointer with type UsbDeviceHandleFunc. + */ void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) { if (!pfunc) @@ -202,7 +291,18 @@ public: pfunc(thePool + i); }; - // Allocates new address + /** + * \brief Allocate a new USB device address. + * + * \note See UsbDeviceAddress definition for better understanding. + * + * \param parent USB device address of the Parent device. + * \param is_hub Set to true if the corresponding device is a Hub, false + * otherwise. + * \param port USB device base address. + * + * \return UsbDevice pointer on success, 0 otherwise. + */ virtual uint32_t AllocAddress(uint32_t parent, uint32_t is_hub = 0, uint32_t port = 0) { if (parent > 127 || port > 7) @@ -223,7 +323,7 @@ public: if (is_hub) { thePool[index].address = 0x41; - hubCounter ++; + hubCounter++; } else thePool[index].address = 1; @@ -238,52 +338,51 @@ public: if (is_hub) { addr.bmHub = 1; - addr.bmAddress = ++hubCounter; + addr.bmAddress = hubCounter++; } else { addr.bmHub = 0; addr.bmAddress = port; } + thePool[index].address = *((uint8_t*)&addr); -/* - Serial.print("Addr:"); - Serial.print(addr.bmHub, HEX); - Serial.print("."); - Serial.print(addr.bmParent, HEX); - Serial.print("."); - Serial.println(addr.bmAddress, HEX); -*/ + return thePool[index].address; }; - // Empties pool entry + /** + * \brief Free the specified USB device address. + * + * \param addr USB device address to free. + */ virtual void FreeAddress(uint32_t addr) { - // if the root hub is disconnected all the addresses should be initialized + // If the root hub is disconnected all the addresses should be initialized if (addr == 0x41) { InitAllAddresses(); return; } + uint32_t index = FindAddressIndex(addr); FreeAddressByIndex(index); }; // Returns number of hubs attached // It can be rather helpfull to find out if there are hubs attached than getting the exact number of hubs. - /*uint8_t GetNumHubs() + /*uint32_t GetNumHubs() { return hubCounter; }; - uint8_t GetNumDevices() + uint32_t GetNumDevices() { - uint8_t counter = 0; + uint32_t counter = 0; - for (uint8_t i=1; iRegisterDeviceClass(this); + } +} + +/** + * \brief Initialize connection to an Android Phone. + * + * \param parent USB device address of the Parent device. + * \param port USB device base address. + * \param lowspeed USB device speed. + * + * \return 0 on success, error code otherwise. + */ +uint32_t ADK::Init(uint32_t parent, uint32_t port, uint32_t lowspeed) +{ + + uint8_t buf[sizeof(USB_DEVICE_DESCRIPTOR)]; + uint32_t rcode = 0; + UsbDevice *p = NULL; + EpInfo *oldep_ptr = NULL; + uint32_t adkproto = -1; + uint32_t num_of_conf = 0; + + // Get memory address of USB device address pool + AddressPool &addrPool = pUsb->GetAddressPool(); + + TRACE_USBHOST(printf("ADK::Init\r\n");) + + // Check if address has already been assigned to an instance + if (bAddress) + { + return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; + } + + // Get pointer to pseudo device with address 0 assigned + p = addrPool.GetUsbDevicePtr(0); + + if (!p) + { + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + } + + if (!p->epinfo) + { + return USB_ERROR_EPINFO_IS_NULL; + } + + // Save old pointer to EP_RECORD of address 0 + oldep_ptr = p->epinfo; + + // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence + p->epinfo = epInfo; + + p->lowspeed = lowspeed; + + // Get device descriptor + rcode = pUsb->getDevDescr(0, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)buf); + + // Restore p->epinfo + p->epinfo = oldep_ptr; + + if (rcode) + { + goto FailGetDevDescr; + } + + // Allocate new address according to device class + bAddress = addrPool.AllocAddress(parent, false, port); + + // Extract Max Packet Size from device descriptor + epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0; + + // Assign new address to the device + rcode = pUsb->setAddr(0, 0, bAddress); + if (rcode) + { + p->lowspeed = false; + addrPool.FreeAddress(bAddress); + bAddress = 0; + TRACE_USBHOST(printf("ADK::Init : setAddr failed with rcode %lu\r\n", rcode);) + return rcode; + } + + TRACE_USBHOST(printf("ADK::Init : device address is now %lu\r\n", bAddress);) + + p->lowspeed = false; + + //get pointer to assigned address record + p = addrPool.GetUsbDevicePtr(bAddress); + if (!p) + { + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + } + + p->lowspeed = lowspeed; + + // Assign epInfo to epinfo pointer - only EP0 is known + rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); + if (rcode) + { + goto FailSetDevTblEntry; + } + + // Check if ADK device is already in accessory mode; if yes, configure and exit + if (((USB_DEVICE_DESCRIPTOR*)buf)->idVendor == ADK_VID && + (((USB_DEVICE_DESCRIPTOR*)buf)->idProduct == ADK_PID || ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct == ADB_PID)) + { + TRACE_USBHOST(printf("ADK::Init : Accessory mode device detected\r\n");) + + /* Go through configurations, find first bulk-IN, bulk-OUT EP, fill epInfo and quit */ + num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations; + + TRACE_USBHOST(printf("ADK::Init : number of configuration is %lu\r\n", num_of_conf);) + + for (uint32_t i = 0; i < num_of_conf; ++i) + { + ConfigDescParser<0, 0, 0, 0> confDescrParser(this); + + delay(1); + rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); + +#if defined(XOOM) + //Added by Jaylen Scott Vanorden + if (rcode) + { + TRACE_USBHOST(printf("ADK::Init : Got 1st bad code for config: %lu\r\n", rcode);) + + // Try once more + rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); + } +#endif + + if (rcode) + { + goto FailGetConfDescr; + } + + if (bNumEP > 2) + { + break; + } + } + + if (bNumEP == 3) + { + // Assign epInfo to epinfo pointer - this time all 3 endpoins + rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo); + if (rcode) + { + goto FailSetDevTblEntry; + } + } + + // Set Configuration Value + rcode = pUsb->setConf(bAddress, 0, bConfNum); + if (rcode) + { + goto FailSetConf; + } + + TRACE_USBHOST(printf("ADK::Init : ADK device configured successfully\r\n");) + ready = true; + + return 0; + } + + // Probe device - get accessory protocol revision + delay(1); + rcode = getProto((uint8_t*)&adkproto); + +#if defined(XOOM) + // Added by Jaylen Scott Vanorden + if (rcode) + { + TRACE_USBHOST(printf("ADK::Init : Got 1st bad code for config: %lu\r\n", rcode);) + + // Try once more + rcode = getProto((uint8_t*)&adkproto ); + } +#endif + + if (rcode) + { + goto FailGetProto; + } + TRACE_USBHOST(printf("ADK::Init : DK protocol rev. %lu", adkproto);) + + // Send ID strings + sendStr(ACCESSORY_STRING_MANUFACTURER, manufacturer); + sendStr(ACCESSORY_STRING_MODEL, model); + sendStr(ACCESSORY_STRING_DESCRIPTION, description); + sendStr(ACCESSORY_STRING_VERSION, version); + sendStr(ACCESSORY_STRING_URI, uri); + sendStr(ACCESSORY_STRING_SERIAL, serial); + + // Switch to accessory mode + // The Android phone will reset + rcode = switchAcc(); + if (rcode) + { + goto FailSwAcc; + } + rcode = -1; + goto SwAttempt; // Switch to accessory mode + + // Diagnostic messages +FailGetDevDescr: + TRACE_USBHOST(printf("ADK::Init getDevDescr : ");) + goto Fail; + +FailSetDevTblEntry: + TRACE_USBHOST(printf("ADK::Init setDevTblEn : ");) + goto Fail; + +FailGetProto: + TRACE_USBHOST(printf("ADK::Init getProto : ");) + goto Fail; + +FailSwAcc: + TRACE_USBHOST(printf("ADK::Init swAcc : ");) + goto Fail; + +SwAttempt: + TRACE_USBHOST(printf("ADK::Init Accessory mode switch attempt : ");) + goto Fail; + +FailGetConfDescr: + TRACE_USBHOST(printf("ADK::Init getConf : ");) + goto Fail; + +FailSetConf: + TRACE_USBHOST(printf("ADK::Init setConf : ");) + goto Fail; + +Fail: + TRACE_USBHOST(printf("error code: %lu\r\n", rcode);) + Release(); + return rcode; +} + +/** + * \brief Extract bulk-IN and bulk-OUT endpoint information from configuration + * descriptor. + * + * \param conf Configuration number. + * \param iface Interface number. + * \param alt Alternate setting. + * \param proto Protocol version used. + * \param pep Pointer to endpoint descriptor. + */ +void ADK::EndpointXtract(uint32_t conf, uint32_t iface, uint32_t alt, uint32_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) +{ + if (bNumEP == 3) + { + return; + } + + bConfNum = conf; + + uint32_t index = 0; + uint32_t pipe = 0; + + if ((pep->bmAttributes & 0x02) == 2) + { + index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; + } + + // Fill in the endpoint info structure + epInfo[index].deviceEpNum = pep->bEndpointAddress & 0x0F; + epInfo[index].maxPktSize = pep->wMaxPacketSize; + + TRACE_USBHOST(printf("ADK::EndpointXtract : Found new endpoint\r\n");) + TRACE_USBHOST(printf("ADK::EndpointXtract : deviceEpNum: %lu\r\n", epInfo[index].deviceEpNum);) + TRACE_USBHOST(printf("ADK::EndpointXtract : maxPktSize: %lu\r\n", epInfo[index].maxPktSize);) + TRACE_USBHOST(printf("ADK::EndpointXtract : index: %lu\r\n", index);) + + if (index == epDataInIndex) + pipe = UHD_Pipe_Alloc(bAddress, epInfo[index].deviceEpNum, UOTGHS_HSTPIPCFG_PTYPE_BLK, UOTGHS_HSTPIPCFG_PTOKEN_IN, epInfo[index].maxPktSize, 0, UOTGHS_HSTPIPCFG_PBK_1_BANK); + else if (index == epDataOutIndex) + pipe = UHD_Pipe_Alloc(bAddress, epInfo[index].deviceEpNum, UOTGHS_HSTPIPCFG_PTYPE_BLK, UOTGHS_HSTPIPCFG_PTOKEN_OUT, epInfo[index].maxPktSize, 0, UOTGHS_HSTPIPCFG_PBK_1_BANK); + + // Ensure pipe allocation is okay + if (pipe == 0) + { + TRACE_USBHOST(printf("ADK::EndpointXtract : Pipe allocation failure\r\n");) + // Enumeration failed, so user should not perform write/read since isConnected will return false + return; + } + + epInfo[index].hostPipeNum = pipe; + + bNumEP++; +} + +/** + * \brief Release USB allocated resources (pipes and address). + * + * \note Release call is made from USBHost.task() on disconnection events. + * \note Release call is made from Init() on enumeration failure. + * + * \return Always 0. + */ +uint32_t ADK::Release() +{ + // Free allocated host pipes + UHD_Pipe_Free(epInfo[epDataInIndex].hostPipeNum); + UHD_Pipe_Free(epInfo[epDataOutIndex].hostPipeNum); + + // Free allocated USB address + pUsb->GetAddressPool().FreeAddress(bAddress); + + // Must have to be reset to 1 + bNumEP = 1; + + bAddress = 0; + ready = false; + + return 0; +} + +/** + * \brief Read from ADK. + * + * \param nreadbytes Return value containing the number of read bytes. + * \param datalen Buffer length. + * \param dataptr Buffer to store the incoming data. + * + * \return 0 on success, error code otherwise. + */ +uint32_t ADK::read(uint32_t *nreadbytes, uint32_t datalen, uint8_t *dataptr) +{ + *nreadbytes = datalen; + return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].deviceEpNum, nreadbytes, dataptr); +} + +/** + * \brief Write to ADK. + * + * \param datalen Amount of data to send. This parameter shall not exceed + * dataptr length. + * \param dataptr Buffer containing the data to be sent. + * + * \return 0 on success, error code otherwise. + */ +uint32_t ADK::write(uint32_t datalen, uint8_t *dataptr) +{ + return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].deviceEpNum, datalen, dataptr); +} diff --git a/hardware/arduino/sam/system/USBHost/adk.h b/hardware/arduino/sam/system/USBHost/adk.h new file mode 100644 index 000000000..edf05c535 --- /dev/null +++ b/hardware/arduino/sam/system/USBHost/adk.h @@ -0,0 +1,150 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This software may be distributed and modified under the terms of the GNU +General Public License version 2 (GPL2) as published by the Free Software +Foundation and appearing in the file GPL2.TXT included in the packaging of +this file. Please note that GPL2 Section 2[b] requires that all works based +on this software must also be made publicly available under the terms of +the GPL2 ("Copyleft"). + +Contact information +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com +*/ + +/* Google ADK interface support header */ + +#ifndef ADK_H_INCLUDED +#define ADK_H_INCLUDED + +#include +#include "usb_ch9.h" +#include "Usb.h" +#include "hid.h" +#include "Arduino.h" +#include "confdescparser.h" + +#define ADK_VID 0x18D1 +#define ADK_PID 0x2D00 +#define ADB_PID 0x2D01 + +#define XOOM //enables repeating getProto() and getConf() attempts + //necessary for slow devices such as Motorola XOOM + //defined by default, can be commented out to save memory + +/* Requests */ + +#define ADK_GETPROTO 51 //check USB accessory protocol version +#define ADK_SENDSTR 52 //send identifying string +#define ADK_ACCSTART 53 //start device in accessory mode + +#define bmREQ_ADK_GET USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_VENDOR|USB_SETUP_RECIPIENT_DEVICE +#define bmREQ_ADK_SEND USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_VENDOR|USB_SETUP_RECIPIENT_DEVICE + +#define ACCESSORY_STRING_MANUFACTURER 0 +#define ACCESSORY_STRING_MODEL 1 +#define ACCESSORY_STRING_DESCRIPTION 2 +#define ACCESSORY_STRING_VERSION 3 +#define ACCESSORY_STRING_URI 4 +#define ACCESSORY_STRING_SERIAL 5 + +#define ADK_MAX_ENDPOINTS 3 //endpoint 0, bulk_IN, bulk_OUT + +/** + * \class ADK definition. + */ +class ADK : public USBDeviceConfig, public UsbConfigXtracter +{ +private: + /* ID strings */ + const char* manufacturer; + const char* model; + const char* description; + const char* version; + const char* uri; + const char* serial; + + /* ADK proprietary requests */ + uint32_t getProto(uint8_t* adkproto); + uint32_t sendStr(uint32_t index, const char* str); + uint32_t switchAcc(void); + +protected: + static const uint32_t epDataInIndex; // DataIn endpoint index + static const uint32_t epDataOutIndex; // DataOUT endpoint index + + /* Mandatory members */ + USBHost *pUsb; + uint32_t bAddress; // Device USB address + uint32_t bConfNum; // configuration number + + uint32_t bNumEP; // total number of EP in the configuration + bool ready; + + /* Endpoint data structure describing the device EP */ + EpInfo epInfo[ADK_MAX_ENDPOINTS]; + +public: + ADK(USBHost *pUsb, const char* pmanufacturer, + const char* pmodel, + const char* pdescription, + const char* pversion, + const char* puri, + const char* pserial); + + // Methods for receiving and sending data + uint32_t read(uint32_t *nreadbytes, uint32_t datalen, uint8_t *dataptr); + uint32_t write(uint32_t datalen, uint8_t *dataptr); + + + // USBDeviceConfig implementation + virtual uint32_t Init(uint32_t parent, uint32_t port, uint32_t lowspeed); + virtual uint32_t Release(); + virtual uint32_t Poll() { return 0; }; // not implemented + virtual uint32_t GetAddress() { return bAddress; }; + virtual bool isReady() { return ready; }; + + // UsbConfigXtracter implementation + virtual void EndpointXtract(uint32_t conf, uint32_t iface, uint32_t alt, uint32_t proto, const USB_ENDPOINT_DESCRIPTOR *ep); +}; + +/** + * \brief Get ADK protocol version. + * + * \param adkproto Empty buffer to be filled by getProto (2 bytes) with the ADK + * protocol version value. + * + * \return 0 on success, error code otherwise. + */ +inline uint32_t ADK::getProto(uint8_t* adkproto) +{ + return (pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_GET, ADK_GETPROTO, 0, 0, 0, 2, 2, adkproto, NULL)); +} + +/** + * \brief Send ADK string. + * + * \param index String index. + * \param str String to send. + * + * \return 0 on success, error code otherwise. + */ +inline uint32_t ADK::sendStr(uint32_t index, const char* str) +{ + return (pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_SEND, ADK_SENDSTR, 0, 0, index, strlen(str) + 1, strlen(str) + 1, (uint8_t*)str, NULL)); +} + +/** + * \brief Send a switch to accessory mode request. + * + * \return 0 on success, error code otherwise. + */ +inline uint32_t ADK::switchAcc(void) +{ + return (pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_SEND, ADK_ACCSTART, 0, 0, 0, 0, 0, NULL, NULL)); +} + +#endif /* ADK_H_INCLUDED */ diff --git a/hardware/arduino/sam/system/USBHost/confdescparser.h b/hardware/arduino/sam/system/USBHost/confdescparser.h index 58a85b11d..eabe12546 100644 --- a/hardware/arduino/sam/system/USBHost/confdescparser.h +++ b/hardware/arduino/sam/system/USBHost/confdescparser.h @@ -21,6 +21,11 @@ e-mail : support@circuitsathome.com #include #include "parsetools.h" +/** + * \class Abstract UsbConfigXtracter definition. + * + * \note This class is used for extracting USB endpoint descriptors. + */ class UsbConfigXtracter { public: @@ -32,7 +37,11 @@ public: #define CP_MASK_COMPARE_PROTOCOL 4 #define CP_MASK_COMPARE_ALL 7 -// Configuration Descriptor Parser Class Template +/** + * \class ConfigDescParser definition. + * + * \note This class is used for parsing configuration descriptors. + */ template class ConfigDescParser : public USBReadParser { @@ -62,6 +71,18 @@ public: virtual void Parse(const uint32_t len, const uint8_t *pbuf, const uint32_t &offset); }; +/** + * \brief ConfigDescParser class constructor. + * + * \param xtractor Is saved as ConfigDescParser attribute and later used as a + * callback for parsing the endpoint descriptors. + * + * \note During enumeration stage, all supported USB classes invoke + * ConfigDescParser with "this" as parameter, meaning that one class is also + * responsible for parsing its endpoint descriptors. This makes sense since + * each USB class handles different number of endpoints and configurations. + * For instance see ADK::Init from ADK class. + */ template ConfigDescParser::ConfigDescParser(UsbConfigXtracter *xtractor) : theXtractor(xtractor), @@ -74,18 +95,37 @@ ConfigDescParser::ConfigDescParser(Usb theSkipper.Initialize(&theBuffer); }; +/** + * \brief Parse a complete USB configuration descriptor. + * + * \param len Buffer length. + * \param pbuf Buffer containing the configuration descriptor. + * \param offset Current offset position. + */ template void ConfigDescParser::Parse(const uint32_t len, const uint8_t *pbuf, const uint32_t &offset) { uint32_t cntdn = len; uint8_t *p = (uint8_t*)pbuf; - while(cntdn) + while (cntdn) if (!ParseDescriptor(&p, &cntdn)) return; } -/* Parser for the configuration descriptor. Takes values for class, subclass, protocol fields in interface descriptor and - compare masks for them. When the match is found, calls EndpointXtract passing buffer containing endpoint descriptor */ + +/** + * \brief Parse a USB configuration descriptor. + * Takes values for class, subclass, protocol fields in interface descriptor + * and compare masks for them. When the match is found, calls EndpointXtract + * passing buffer containing endpoint descriptor. + * + * \note This method should not be called directly, use Parse() instead. + * + * \param pcntdn Buffer length. + * \param pp Buffer containing the configuration descriptor. + * + * \return true if data remains in the buffer for parsing, false otherwise. + */ template bool ConfigDescParser::ParseDescriptor(uint8_t **pp, uint32_t *pcntdn) { @@ -112,102 +152,90 @@ bool ConfigDescParser::ParseDescriptor case 3: switch (dscrType) { - case USB_DESCRIPTOR_INTERFACE: - isGoodInterface = false; - case USB_DESCRIPTOR_CONFIGURATION: - theBuffer.valueSize = sizeof(USB_CONFIGURATION_DESCRIPTOR) - 2; - break; - case USB_DESCRIPTOR_ENDPOINT: - theBuffer.valueSize = sizeof(USB_ENDPOINT_DESCRIPTOR) - 2; - break; - case HID_DESCRIPTOR_HID: - theBuffer.valueSize = dscrLen - 2; - break; + case USB_DESCRIPTOR_INTERFACE: + isGoodInterface = false; + case USB_DESCRIPTOR_CONFIGURATION: + theBuffer.valueSize = sizeof(USB_CONFIGURATION_DESCRIPTOR) - 2; + break; + case USB_DESCRIPTOR_ENDPOINT: + theBuffer.valueSize = sizeof(USB_ENDPOINT_DESCRIPTOR) - 2; + break; + case HID_DESCRIPTOR_HID: + theBuffer.valueSize = dscrLen - 2; + break; } valParser.Initialize(&theBuffer); stateParseDescr = 4; case 4: switch (dscrType) { - case USB_DESCRIPTOR_CONFIGURATION: - if (!valParser.Parse(pp, pcntdn)) - return false; - confValue = ((USB_CONFIGURATION_DESCRIPTOR*)varBuffer)->bConfigurationValue; - break; - case USB_DESCRIPTOR_INTERFACE: - if (!valParser.Parse(pp, pcntdn)) - return false; - if ((MASK & CP_MASK_COMPARE_CLASS) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceClass != CLASS_ID) - break; - if ((MASK & CP_MASK_COMPARE_SUBCLASS) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceSubClass != SUBCLASS_ID) - break; - if ((MASK & CP_MASK_COMPARE_PROTOCOL) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceProtocol != PROTOCOL_ID) + case USB_DESCRIPTOR_CONFIGURATION: + if (!valParser.Parse(pp, pcntdn)) + return false; + confValue = ((USB_CONFIGURATION_DESCRIPTOR*)varBuffer)->bConfigurationValue; break; + case USB_DESCRIPTOR_INTERFACE: + if (!valParser.Parse(pp, pcntdn)) + return false; + if ((MASK & CP_MASK_COMPARE_CLASS) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceClass != CLASS_ID) + break; + if ((MASK & CP_MASK_COMPARE_SUBCLASS) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceSubClass != SUBCLASS_ID) + break; + if ((MASK & CP_MASK_COMPARE_PROTOCOL) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceProtocol != PROTOCOL_ID) + break; - isGoodInterface = true; - ifaceNumber = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceNumber; - ifaceAltSet = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bAlternateSetting; - protoValue = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceProtocol; - break; - case USB_DESCRIPTOR_ENDPOINT: - if (!valParser.Parse(pp, pcntdn)) - return false; - if (isGoodInterface) - if (theXtractor) - theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_ENDPOINT_DESCRIPTOR*)varBuffer); - break; - //case HID_DESCRIPTOR_HID: - // if (!valParser.Parse(pp, pcntdn)) - // return false; - // PrintHidDescriptor((const USB_HID_DESCRIPTOR*)varBuffer); - // break; - default: - if (!theSkipper.Skip(pp, pcntdn, dscrLen-2)) - return false; - } - theBuffer.pValue = varBuffer; - stateParseDescr = 0; + isGoodInterface = true; + ifaceNumber = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceNumber; + ifaceAltSet = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bAlternateSetting; + protoValue = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceProtocol; + break; + case USB_DESCRIPTOR_ENDPOINT: + if (!valParser.Parse(pp, pcntdn)) + return false; + if (isGoodInterface) + if (theXtractor) + theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_ENDPOINT_DESCRIPTOR*)varBuffer); + break; + //case HID_DESCRIPTOR_HID: + // if (!valParser.Parse(pp, pcntdn)) + // return false; + // PrintHidDescriptor((const USB_HID_DESCRIPTOR*)varBuffer); + // break; + default: + if (!theSkipper.Skip(pp, pcntdn, dscrLen - 2)) + return false; + } + theBuffer.pValue = varBuffer; + stateParseDescr = 0; } return true; } +/** + * \brief Print HID descriptor. + * + * \note TRACE_USBHOST macro must be enabled. See Usb.h for reference. + * + * \param pDesc Pointer to HID descriptor. + */ template void ConfigDescParser::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc) { - /*Notify(PSTR("\r\n\r\nHID Descriptor:\r\n")); - Notify(PSTR("bDescLength:\t\t")); - PrintHex(pDesc->bLength); + TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : bDescLength: %d\r\n", pDesc->bLength);) + TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : bDescriptorType: %d\r\n", pDesc->bDescriptorType);) + TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : bcdHID: %d\r\n", pDesc->bcdHID);) + TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : bCountryCode: %d\r\n", pDesc->bCountryCode);) + TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : bNumDescriptors: %d\r\n", pDesc->bNumDescriptors);) + TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : bDescrType: %d\r\n", pDesc->bDescrType);) + TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : wDescriptorLength: %d\r\n", pDesc->wDescriptorLength);) - Notify(PSTR("\r\nbDescriptorType:\t")); - PrintHex(pDesc->bDescriptorType); - - Notify(PSTR("\r\nbcdHID:\t\t\t")); - PrintHex(pDesc->bcdHID); - - Notify(PSTR("\r\nbCountryCode:\t\t")); - PrintHex(pDesc->bCountryCode); - - Notify(PSTR("\r\nbNumDescriptors:\t")); - PrintHex(pDesc->bNumDescriptors); - - //Notify(PSTR("\r\nbDescrType:\t\t")); - //PrintHex(pDesc->bDescrType); - // - //Notify(PSTR("\r\nwDescriptorLength:\t")); - //PrintHex(pDesc->wDescriptorLength); - - for (uint8_t i=0; ibNumDescriptors; i++) + for (uint32_t i = 0; i < pDesc->bNumDescriptors; ++i) { HID_CLASS_DESCRIPTOR_LEN_AND_TYPE *pLT = (HID_CLASS_DESCRIPTOR_LEN_AND_TYPE*)&(pDesc->bDescrType); - Notify(PSTR("\r\nbDescrType:\t\t")); - PrintHex(pLT[i].bDescrType); - - Notify(PSTR("\r\nwDescriptorLength:\t")); - PrintHex(pLT[i].wDescriptorLength); + TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : bDescrType: %d\r\n", pLT[i].bDescrType);) + TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : wDescriptorLength: %d\r\n", pLT[i].wDescriptorLength);) } - Notify(PSTR("\r\n"));*/ - printf("somebody save me!!!! orgazmo?!!!\r\n"); } #endif /* CONFDESCPARSER_H_INCLUDED */ diff --git a/hardware/arduino/sam/system/USBHost/examples/adk/test_usb_host.cpp b/hardware/arduino/sam/system/USBHost/examples/adk/test_usb_host.cpp new file mode 100644 index 000000000..7c2f540c2 --- /dev/null +++ b/hardware/arduino/sam/system/USBHost/examples/adk/test_usb_host.cpp @@ -0,0 +1,54 @@ +#include "variant.h" +#include +#include + +// Accessory descriptor. It's how Arduino identifies itself to Android. +char applicationName[] = "Arduino_Terminal"; // the app on your phone +char accessoryName[] = "Arduino Due X"; // your Arduino board +char companyName[] = "Arduino SA"; + +// Make up anything you want for these +char versionNumber[] = "1.0"; +char serialNumber[] = "1"; +char url[] = "http://labs.arduino.cc/uploads/ADK/ArduinoTerminal/ThibaultTerminal_ICS_0001.apk"; + +USBHost Usb; +ADK adk(&Usb, companyName, applicationName, accessoryName,versionNumber,url,serialNumber); + +void setup() +{ + cpu_irq_enable(); + printf("\r\nADK demo start\r\n"); + delay(200); +} + +#define RCVSIZE 128 + +void loop() +{ + uint8_t buf[RCVSIZE]; + uint32_t nbread = 0; + char helloworld[] = "Hello World!\r\n"; + + Usb.Task(); + + if (adk.isReady()) + { + /* Write hello string to ADK */ + adk.write(strlen(helloworld), (uint8_t *)helloworld); + + delay(1000); + + /* Read data from ADK and print to UART */ + adk.read(&nbread, RCVSIZE, buf); + if (nbread > 0) + { + printf("RCV: "); + for (uint32_t i = 0; i < nbread; ++i) + { + printf("%c", (char)buf[i]); + } + printf("\r\n"); + } + } +} diff --git a/hardware/arduino/sam/system/USBHost/hid.h b/hardware/arduino/sam/system/USBHost/hid.h index e95b120d8..2191ddfc7 100644 --- a/hardware/arduino/sam/system/USBHost/hid.h +++ b/hardware/arduino/sam/system/USBHost/hid.h @@ -95,7 +95,10 @@ e-mail : support@circuitsathome.com #define HID_PROTOCOL_KEYBOARD 0x01 #define HID_PROTOCOL_MOUSE 0x02 -struct HidItemPrefix +/** + * \brief HidItemPrefix definition. + */ +struct HidItemPrefix // Not used { uint8_t bSize : 2; uint8_t bType : 2; @@ -125,7 +128,10 @@ struct HidItemPrefix #define HID_MAIN_ITEM_COLLECTION_USAGE_SWITCH 5 #define HID_MAIN_ITEM_COLLECTION_USAGE_MODIFIER 6 -struct MainItemIOFeature +/** + * \brief MainItemIOFeature definition. + */ +struct MainItemIOFeature // Not used { uint8_t bmIsConstantOrData : 1; uint8_t bmIsArrayOrVariable : 1; @@ -139,6 +145,11 @@ struct MainItemIOFeature class HID; +/** + * \class Abstract HIDReportParser definition. + * + * \note This class is used to implement HID report parsing. + */ class HIDReportParser { public: @@ -148,6 +159,9 @@ public: #define MAX_REPORT_PARSERS 2 #define HID_MAX_HID_CLASS_DESCRIPTORS 5 +/** + * \class HID definition. + */ class HID : public USBDeviceConfig, public UsbConfigXtracter { protected: diff --git a/hardware/arduino/sam/system/USBHost/hid2.cpp b/hardware/arduino/sam/system/USBHost/hid2.cpp index cc3b46ebe..71238210c 100644 --- a/hardware/arduino/sam/system/USBHost/hid2.cpp +++ b/hardware/arduino/sam/system/USBHost/hid2.cpp @@ -17,7 +17,14 @@ e-mail : support@circuitsathome.com #include "hid.h" -// Get HID report descriptor +/** + * \brief Get HID report descriptor and parse it. + * + * \param ep USB device endpoint. + * \param parser Parser used to decode report. + * + * \return 0 on success, error code otherwise. + */ uint32_t HID::GetReportDescr(uint32_t ep, USBReadParser *parser) { const uint32_t constBufLen = 64; @@ -27,75 +34,108 @@ uint32_t HID::GetReportDescr(uint32_t ep, USBReadParser *parser) HID_DESCRIPTOR_REPORT, 0x0000, 128, constBufLen, buf, (USBReadParser*)parser)); } - +/** + * \brief Set HID report descriptor. + * + * \param ep USB device endpoint. + * \param iface Interface number. + * \param report_type HID report type. + * \param report_id HID report ID. + * \param nbytes Buffer length. + * \param dataptr Buffer containing the HID report to send. + * + * \return 0 on success, error code otherwise. + */ uint32_t HID::SetReport(uint32_t ep, uint32_t iface, uint32_t report_type, uint32_t report_id, uint32_t nbytes, uint8_t* dataptr) { return (pUsb->ctrlReq(bAddress, ep, bmREQ_HIDOUT, HID_REQUEST_SET_REPORT, report_id, report_type, iface, nbytes, nbytes, dataptr, NULL)); } +/** + * \brief Get HID report descriptor. + * + * \param ep USB device endpoint. + * \param iface Interface number. + * \param report_type HID report type. + * \param report_id HID report ID. + * \param nbytes Buffer length. + * \param dataptr Buffer containing the HID report to send. + * + * \return 0 on success, error code otherwise. + */ uint32_t HID::GetReport(uint32_t ep, uint32_t iface, uint32_t report_type, uint32_t report_id, uint32_t nbytes, uint8_t* dataptr) { return (pUsb->ctrlReq(bAddress, ep, bmREQ_HIDIN, HID_REQUEST_GET_REPORT, report_id, report_type, iface, nbytes, nbytes, dataptr, NULL)); } -uint32_t HID::GetIdle(uint32_t iface, uint32_t reportID, uint8_t* dataptr) +/** + * \brief Get HID idle status. + * + * \param iface Interface number. + * \param report_id HID report ID. + * \param dataptr Buffer to receive data. Size must be >= 1. + * + * \return 0 on success, error code otherwise. + */ +uint32_t HID::GetIdle(uint32_t iface, uint32_t report_id, uint8_t* dataptr) { - return (pUsb->ctrlReq(bAddress, 0, bmREQ_HIDIN, HID_REQUEST_GET_IDLE, reportID, 0, iface, 0x0001, 0x0001, dataptr, NULL)); + return (pUsb->ctrlReq(bAddress, 0, bmREQ_HIDIN, HID_REQUEST_GET_IDLE, report_id, 0, iface, 0x0001, 0x0001, dataptr, NULL)); } -uint32_t HID::SetIdle(uint32_t iface, uint32_t reportID, uint32_t duration) +/** + * \brief Set HID idle status. + * + * \param iface Interface number. + * \param report_id HID report ID. + * \param duration Status duration. + * + * \return 0 on success, error code otherwise. + */ +uint32_t HID::SetIdle(uint32_t iface, uint32_t report_id, uint32_t duration) { - return (pUsb->ctrlReq(bAddress, 0, bmREQ_HIDOUT, HID_REQUEST_SET_IDLE, reportID, duration, iface, 0x0000, 0x0000, NULL, NULL)); + return (pUsb->ctrlReq(bAddress, 0, bmREQ_HIDOUT, HID_REQUEST_SET_IDLE, report_id, duration, iface, 0x0000, 0x0000, NULL, NULL)); } +/** + * \brief Set HID protocol. + * + * \param iface Interface number. + * \param protocol Protocol value. + * + * \return 0 on success, error code otherwise. + */ uint32_t HID::SetProtocol(uint32_t iface, uint32_t protocol) { return (pUsb->ctrlReq(bAddress, 0, bmREQ_HIDOUT, HID_REQUEST_SET_PROTOCOL, protocol, 0x00, iface, 0x0000, 0x0000, NULL, NULL)); } +/** + * \brief Get HID protocol. + * + * \param iface Interface number. + * \param dataptr Buffer used to store protocol value. Size must be >= 1. + * + * \return 0 on success, error code otherwise. + */ uint32_t HID::GetProtocol(uint32_t iface, uint8_t* dataptr) { return (pUsb->ctrlReq(bAddress, 0, bmREQ_HIDIN, HID_REQUEST_GET_PROTOCOL, 0x00, 0x00, iface, 0x0001, 0x0001, dataptr, NULL)); } -void HID::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) -{ - /*Notify(PSTR("Endpoint descriptor:")); - Notify(PSTR("\r\nLength:\t\t")); - PrintHex(ep_ptr->bLength); - Notify(PSTR("\r\nType:\t\t")); - PrintHex(ep_ptr->bDescriptorType); - Notify(PSTR("\r\nAddress:\t")); - PrintHex(ep_ptr->bEndpointAddress); - Notify(PSTR("\r\nAttributes:\t")); - PrintHex(ep_ptr->bmAttributes); - Notify(PSTR("\r\nMaxPktSize:\t")); - PrintHex(ep_ptr->wMaxPacketSize); - Notify(PSTR("\r\nPoll Intrv:\t")); - PrintHex(ep_ptr->bInterval);*/ -} - +/** + * \brief Print HID descriptor. + * + * \note TRACE_USBHOST macro must be enabled. See Usb.h for reference. + * + * \param pDesc Pointer to HID descriptor. + */ void HID::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc) { - /* Notify(PSTR("\r\n\r\nHID Descriptor:\r\n")); - Notify(PSTR("bDescLength:\t\t")); - PrintHex(pDesc->bLength); - - Notify(PSTR("\r\nbDescriptorType:\t")); - PrintHex(pDesc->bDescriptorType); - - Notify(PSTR("\r\nbcdHID:\t\t\t")); - PrintHex(pDesc->bcdHID); - - Notify(PSTR("\r\nbCountryCode:\t\t")); - PrintHex(pDesc->bCountryCode); - - Notify(PSTR("\r\nbNumDescriptors:\t")); - PrintHex(pDesc->bNumDescriptors); - - Notify(PSTR("\r\nbDescrType:\t\t")); - PrintHex(pDesc->bDescrType); - - Notify(PSTR("\r\nwDescriptorLength:\t")); - PrintHex(pDesc->wDescriptorLength);*/ + TRACE_USBHOST(printf("HID::PrintHidDescriptor : bDescLength: %d\r\n", pDesc->bLength);) + TRACE_USBHOST(printf("HID::PrintHidDescriptor : bDescriptorType: %d\r\n", pDesc->bDescriptorType);) + TRACE_USBHOST(printf("HID::PrintHidDescriptor : bcdHID: %d\r\n", pDesc->bcdHID);) + TRACE_USBHOST(printf("HID::PrintHidDescriptor : bCountryCode: %d\r\n", pDesc->bCountryCode);) + TRACE_USBHOST(printf("HID::PrintHidDescriptor : bNumDescriptors: %d\r\n", pDesc->bNumDescriptors);) + TRACE_USBHOST(printf("HID::PrintHidDescriptor : bDescrType: %d\r\n", pDesc->bDescrType);) + TRACE_USBHOST(printf("HID::PrintHidDescriptor : wDescriptorLength: %d\r\n", pDesc->wDescriptorLength);) } diff --git a/hardware/arduino/sam/system/USBHost/hidboot.cpp b/hardware/arduino/sam/system/USBHost/hidboot.cpp index fa96e5d0d..fb85bd707 100644 --- a/hardware/arduino/sam/system/USBHost/hidboot.cpp +++ b/hardware/arduino/sam/system/USBHost/hidboot.cpp @@ -17,6 +17,14 @@ e-mail : support@circuitsathome.com #include "hidboot.h" +/** + * \brief Parse HID mouse report. + * + * \param hid HID device pointer. + * \param is_rpt_id True if this is a report ID. + * \param len Buffer length. + * \param buf Buffer containing report data. + */ void MouseReportParser::Parse(HID *hid, bool is_rpt_id, uint32_t len, uint8_t *buf) { MOUSEINFO *pmi = (MOUSEINFO*)buf; @@ -46,6 +54,14 @@ void MouseReportParser::Parse(HID *hid, bool is_rpt_id, uint32_t len, uint8_t *b prevState.bInfo[i] = buf[i]; }; +/** + * \brief Parse HID keyboard report. + * + * \param hid HID device pointer. + * \param is_rpt_id True if this is a report ID. + * \param len Buffer length. + * \param buf Buffer containing report data. + */ void KeyboardReportParser::Parse(HID *hid, bool is_rpt_id, uint32_t len, uint8_t *buf) { // On error - return @@ -81,6 +97,15 @@ void KeyboardReportParser::Parse(HID *hid, bool is_rpt_id, uint32_t len, uint8_t prevState.bInfo[i] = buf[i]; }; +/** + * \brief Handle keyboard locking keys and manage keyboard leds using USB + * report. + * + * \param hid HID device pointer. + * \param key Locking key. + * + * \return 0 on success, error code otherwise. + */ uint8_t KeyboardReportParser::HandleLockingKeys(HID *hid, uint8_t key) { uint8_t old_keys = kbdLockingKeys.bLeds; @@ -109,6 +134,14 @@ const uint8_t KeyboardReportParser::symKeysUp[] = { '_', '+', '{', '}', '|', '~' const uint8_t KeyboardReportParser::symKeysLo[] = { '-', '=', '[', ']', '\\', ' ', ';', '\'', '`', ',', '.', '/' }; const uint8_t KeyboardReportParser::padKeys[] = { '/', '*', '-', '+', 0x13 }; +/** + * \brief Manage keyboard OEM to ASCII conversion. + * + * \param mod Keyboard modifier. + * \param key Key value to convert. + * + * \return Keyboard corresponding ASCII value on success, 0 otherwise. + */ uint8_t KeyboardReportParser::OemToAscii(uint8_t mod, uint8_t key) { uint8_t shift = (mod & 0x22); @@ -154,5 +187,6 @@ uint8_t KeyboardReportParser::OemToAscii(uint8_t mod, uint8_t key) case KEY_PERIOD: return ((kbdLockingKeys.kbdLeds.bmNumLock == 1) ? '.' : 0); } } + return 0; } diff --git a/hardware/arduino/sam/system/USBHost/hidboot.h b/hardware/arduino/sam/system/USBHost/hidboot.h index a669771e4..66f630ffb 100644 --- a/hardware/arduino/sam/system/USBHost/hidboot.h +++ b/hardware/arduino/sam/system/USBHost/hidboot.h @@ -31,6 +31,9 @@ e-mail : support@circuitsathome.com #define KEY_ENTER 0x28 #define KEY_PERIOD 0x63 +/** + * \brief MOUSEINFO definition. + */ struct MOUSEINFO { struct @@ -44,6 +47,9 @@ struct MOUSEINFO int8_t dY; }; +/** + * \class MouseReportParser definition. + */ class MouseReportParser : public HIDReportParser { union @@ -65,6 +71,9 @@ protected: virtual void OnMiddleButtonDown (MOUSEINFO *mi) {}; }; +/** + * \brief MODIFIERKEYS definition. + */ struct MODIFIERKEYS { uint8_t bmLeftCtrl : 1; @@ -77,6 +86,9 @@ struct MODIFIERKEYS uint8_t bmRightGUI : 1; }; +/** + * \brief KBDINFO definition. + */ struct KBDINFO { struct @@ -94,6 +106,9 @@ struct KBDINFO uint8_t Keys[6]; }; +/** + * \brief KBDLEDS definition. + */ struct KBDLEDS { uint8_t bmNumLock : 1; @@ -105,9 +120,18 @@ struct KBDLEDS }; #define KEY_NUM_LOCK 0x53 + +// Clear compiler warning +#ifdef KEY_CAPS_LOCK +#undef KEY_CAPS_LOCK +#endif + #define KEY_CAPS_LOCK 0x39 #define KEY_SCROLL_LOCK 0x47 +/** + * \class KeyboardReportParser definition. + */ class KeyboardReportParser : public HIDReportParser { static const uint8_t numKeys[]; @@ -146,6 +170,9 @@ protected: #define HID_MAX_HID_CLASS_DESCRIPTORS 5 +/** + * \class HIDBoot definition. + */ template class HIDBoot : public HID { @@ -167,7 +194,7 @@ class HIDBoot : public HID public: HIDBoot(USBHost *p); - virtual bool SetReportParser(uint32_t id, HIDReportParser *prs) { pRptParser = prs; return true;}; /////////////////////// le return ne sert a rien ?!!! + virtual bool SetReportParser(uint32_t id, HIDReportParser *prs) { pRptParser = prs; return true; }; // USBDeviceConfig implementation virtual uint32_t Init(uint32_t parent, uint32_t port, uint32_t lowspeed); @@ -179,6 +206,9 @@ public: virtual void EndpointXtract(uint32_t conf, uint32_t iface, uint32_t alt, uint32_t proto, const USB_ENDPOINT_DESCRIPTOR *ep); }; +/** + * \brief HIDBoot class constructor. + */ template HIDBoot::HIDBoot(USBHost *p) : HID(p), @@ -192,21 +222,35 @@ HIDBoot::HIDBoot(USBHost *p) : pUsb->RegisterDeviceClass(this); } +/** + * \brief Initialize HIDBoot class. + */ template void HIDBoot::Initialize() { - for(uint32_t i = 0; i < totalEndpoints; ++i) + for (uint32_t i = 0; i < totalEndpoints; ++i) { - epInfo[i].epAddr = 0; + epInfo[i].deviceEpNum = 0; + epInfo[i].hostPipeNum = 0; epInfo[i].maxPktSize = (i) ? 0 : 8; epInfo[i].epAttribs = 0; epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER; } + bNumEP = 1; bNumIface = 0; bConfNum = 0; } +/** + * \brief Initialize connection to an HID device. + * + * \param parent USB device address of the Parent device. + * \param port USB device base address. + * \param lowspeed USB device speed. + * + * \return 0 on success, error code otherwise. + */ template uint32_t HIDBoot::Init(uint32_t parent, uint32_t port, uint32_t lowspeed) { @@ -214,14 +258,16 @@ uint32_t HIDBoot::Init(uint32_t parent, uint32_t port, uint32_t l uint8_t buf[constBufSize]; uint32_t rcode = 0; - UsbDevice *p = NULL; - EpInfo *oldep_ptr = NULL; + UsbDevice *p = 0; + EpInfo *oldep_ptr = 0; uint32_t len = 0; - uint32_t num_of_conf; // number of configurations + uint32_t num_of_conf = 0; // number of configurations AddressPool &addrPool = pUsb->GetAddressPool(); + TRACE_USBHOST(printf("HIDBoot::Init\r\n");) + if (bAddress) return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; @@ -246,9 +292,9 @@ uint32_t HIDBoot::Init(uint32_t parent, uint32_t port, uint32_t l p->lowspeed = lowspeed; // Get device descriptor - rcode = pUsb->getDevDescr( 0, 0, 8, (uint8_t*)buf ); + rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*)buf); - if (!rcode) + if (!rcode) len = (buf[0] > constBufSize) ? constBufSize : buf[0]; if (rcode) @@ -312,14 +358,12 @@ uint32_t HIDBoot::Init(uint32_t parent, uint32_t port, uint32_t l for (uint32_t i = 0; i < num_of_conf; ++i) { - //HexDumper HexDump; ConfigDescParser< USB_CLASS_HID, HID_BOOT_INTF_SUBCLASS, BOOT_PROTOCOL, - CP_MASK_COMPARE_ALL> confDescrParser(this); + CP_MASK_COMPARE_ALL> confDescrParser(this); - //rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump); rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); if (bNumEP > 1) @@ -364,31 +408,41 @@ uint32_t HIDBoot::Init(uint32_t parent, uint32_t port, uint32_t l return 0; FailGetDevDescr: - //USBTRACE("getDevDescr:"); + TRACE_USBHOST(printf("HIDBoot::Init getDevDescr : ");) goto Fail; FailSetDevTblEntry: - //USBTRACE("setDevTblEn:"); + TRACE_USBHOST(printf("HIDBoot::Init setDevTblEn : ");) goto Fail; FailSetProtocol: - //USBTRACE("SetProto:"); + TRACE_USBHOST(printf("HIDBoot::Init SetProto : ");) goto Fail; FailSetIdle: - //USBTRACE("SetIdle:"); + TRACE_USBHOST(printf("HIDBoot::Init SetIdle : ");) goto Fail; FailSetConfDescr: - //USBTRACE("setConf:"); + TRACE_USBHOST(printf("HIDBoot::Init setConf : ");) goto Fail; Fail: - //Serial.println(rcode, HEX); + TRACE_USBHOST(printf("error code: %lu\r\n", rcode);) Release(); return rcode; } +/** + * \brief Extract interrupt-IN endpoint information from configuration + * descriptor. + * + * \param conf Configuration number. + * \param iface Interface number. + * \param alt Alternate setting. + * \param proto Protocol version used. + * \param pep Pointer to endpoint descriptor. + */ template void HIDBoot::EndpointXtract(uint32_t conf, uint32_t iface, uint32_t alt, uint32_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) { @@ -396,41 +450,56 @@ void HIDBoot::EndpointXtract(uint32_t conf, uint32_t iface, uint3 if (bNumEP > 1 && conf != bConfNum) return; - //ErrorMessage(PSTR("\r\nConf.Val"), conf); - //ErrorMessage(PSTR("Iface Num"), iface); - //ErrorMessage(PSTR("Alt.Set"), alt); + bConfNum = conf; + bIfaceNum = iface; - bConfNum = conf; - bIfaceNum = iface; - - uint32_t index; + uint32_t index = 0; + uint32_t pipe = 0; if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) { index = epInterruptInIndex; // Fill in the endpoint info structure - epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); + epInfo[index].deviceEpNum = (pep->bEndpointAddress & 0x0F); epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize; epInfo[index].epAttribs = 0; - bNumEP++; - TRACE_USBHOST(printf("HIDBoot::EndpointXtract : Found new endpoint\r\n");) - TRACE_USBHOST(printf("HIDBoot::EndpointXtract : epAddr: %lu\r\n", epInfo[index].epAddr);) + TRACE_USBHOST(printf("HIDBoot::EndpointXtract : deviceEpNum: %lu\r\n", epInfo[index].deviceEpNum);) TRACE_USBHOST(printf("HIDBoot::EndpointXtract : maxPktSize: %lu\r\n", epInfo[index].maxPktSize);) TRACE_USBHOST(printf("HIDBoot::EndpointXtract : index: %lu\r\n", index);) - UHD_EP_Alloc(epInfo[index].epAddr, bAddress, 10, UOTGHS_HSTPIPCFG_PTYPE_INTRPT, UOTGHS_HSTPIPCFG_PTOKEN_IN, epInfo[index].maxPktSize, UOTGHS_HSTPIPCFG_PBK_1_BANK); + // Ensure pipe allocation is okay + pipe = UHD_Pipe_Alloc(bAddress, epInfo[index].deviceEpNum, UOTGHS_HSTPIPCFG_PTYPE_INTRPT, UOTGHS_HSTPIPCFG_PTOKEN_IN, epInfo[index].maxPktSize, 10, UOTGHS_HSTPIPCFG_PBK_1_BANK); + if (pipe == 0) + { + TRACE_USBHOST(printf("HIDBoot::EndpointXtract : Pipe allocation failure\r\n");) + // Enumeration failed + return; + } - //PrintEndpointDescriptor(pep); + epInfo[index].hostPipeNum = pipe; + + bNumEP++; } } - +/** + * \brief Release USB allocated resources (pipes and address). + * + * \note Release call is made from USBHost.task() on disconnection events. + * \note Release call is made from Init() on enumeration failure. + * + * \return Always 0. + */ template uint32_t HIDBoot::Release() { + // Free allocated host pipes + UHD_Pipe_Free(epInfo[epInterruptInIndex].hostPipeNum); + + // Free allocated USB address pUsb->GetAddressPool().FreeAddress(bAddress); bConfNum = 0; @@ -439,9 +508,17 @@ uint32_t HIDBoot::Release() bAddress = 0; qNextPollTime = 0; bPollEnable = false; + return 0; } +/** + * \brief Poll USB device activity. + * + * \note Poll call is periodically made from USBHost.task(). + * + * \return 0 on success, error code otherwise. + */ template uint32_t HIDBoot::Poll() { @@ -459,12 +536,10 @@ uint32_t HIDBoot::Poll() uint32_t read = epInfo[epInterruptInIndex].maxPktSize; - rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, &read, buf); + rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].deviceEpNum, &read, buf); if (rcode) { - //if (rcode != hrNAK) - //USBTRACE2("Poll:", rcode); return rcode; } diff --git a/hardware/arduino/sam/system/USBHost/usb_ch9.h b/hardware/arduino/sam/system/USBHost/usb_ch9.h index 86eb1f954..4e3fb02ee 100644 --- a/hardware/arduino/sam/system/USBHost/usb_ch9.h +++ b/hardware/arduino/sam/system/USBHost/usb_ch9.h @@ -90,6 +90,7 @@ e-mail : support@circuitsathome.com #define USB_FEATURE_ENDPOINT_STALL 0 // Endpoint recipient #define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // Device recipient #define USB_FEATURE_TEST_MODE 2 // Device recipient + _Pragma("pack(1)") /* descriptor data structures */ @@ -147,7 +148,7 @@ typedef struct uint8_t bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT). uint8_t bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN). uint8_t bmAttributes; // Endpoint transfer type. - uint16_t wMaxPacketSize; // Maximum packet size. + uint16_t wMaxPacketSize; // Maximum packet size. uint8_t bInterval; // Polling interval in frames. } USB_ENDPOINT_DESCRIPTOR; diff --git a/hardware/arduino/sam/system/libsam/include/USB_host.h b/hardware/arduino/sam/system/libsam/include/USB_host.h index 4257a6d30..43d559ee8 100644 --- a/hardware/arduino/sam/system/libsam/include/USB_host.h +++ b/hardware/arduino/sam/system/libsam/include/USB_host.h @@ -55,17 +55,16 @@ typedef enum { //extern uhd_speed_t uhd_get_speed(void); - extern void UHD_SetStack(void (*pf_isr)(void)); extern void UHD_Init(void); extern void UHD_BusReset(void); extern uhd_vbus_state_t UHD_GetVBUSState(void); -extern uint32_t UHD_EP0_Alloc(uint32_t ul_add, uint32_t ul_ep_size); -extern uint32_t UHD_EP_Alloc(uint32_t ul_pipe, uint32_t ul_addr, uint32_t ul_interval, uint32_t ul_type, uint32_t ul_dir, uint32_t ul_maxsize, uint32_t ul_bank); -extern void UHD_EP_Free(uint32_t add, uint32_t endp); -extern uint32_t UHD_EP_Read(uint32_t ul_ep, uint32_t ul_size, uint8_t* data); -extern void UHD_EP_Write(uint32_t ul_ep, uint32_t ul_size, uint8_t* data); -extern void UHD_EP_Send(uint32_t ul_ep, uint32_t ul_token_type); -extern uint32_t UHD_EP_Is_Transfer_Complete(uint32_t ul_ep, uint32_t ul_token_type); +extern uint32_t UHD_Pipe0_Alloc(uint32_t ul_add, uint32_t ul_ep_size); +extern uint32_t UHD_Pipe_Alloc(uint32_t ul_dev_addr, uint32_t ul_dev_ep, uint32_t ul_type, uint32_t ul_dir, uint32_t ul_maxsize, uint32_t ul_interval, uint32_t ul_nb_bank); +extern void UHD_Pipe_Free(uint32_t ul_pipe); +extern uint32_t UHD_Pipe_Read(uint32_t ul_pipe, uint32_t ul_size, uint8_t* data); +extern void UHD_Pipe_Write(uint32_t ul_pipe, uint32_t ul_size, uint8_t* data); +extern void UHD_Pipe_Send(uint32_t ul_pipe, uint32_t ul_token_type); +extern uint32_t UHD_Pipe_Is_Transfer_Complete(uint32_t ul_pipe, uint32_t ul_token_type); #endif /* USB_HOST_H_INCLUDED */ diff --git a/hardware/arduino/sam/system/libsam/source/uotghs_host.c b/hardware/arduino/sam/system/libsam/source/uotghs_host.c index 64b75a8ca..47a9ca12c 100644 --- a/hardware/arduino/sam/system/libsam/source/uotghs_host.c +++ b/hardware/arduino/sam/system/libsam/source/uotghs_host.c @@ -32,13 +32,17 @@ #if SAM3XA_SERIES -#define TRACE_UOTGHS_HOST(x) x -//#define TRACE_UOTGHS_HOST(x) +//#define TRACE_UOTGHS_HOST(x) x +#define TRACE_UOTGHS_HOST(x) extern void (*gpf_isr)(void); +// Handle UOTGHS Host driver state static uhd_vbus_state_t uhd_state = UHD_STATE_NO_VBUS; +/** + * \brief Interrupt sub routine for USB Host state machine management. + */ static void UHD_ISR(void) { // Manage dis/connection event @@ -74,7 +78,7 @@ static void UHD_ISR(void) { TRACE_UOTGHS_HOST(printf(">>> UHD_ISR : VBUS error INT\r\n");) uhd_ack_vbus_error_interrupt(); - uhd_state = UHD_STATE_ERROR; + uhd_state = UHD_STATE_DISCONNECTED; //UHD_STATE_ERROR; return; } @@ -111,11 +115,19 @@ static void UHD_ISR(void) } } +/** + * \brief Set the interrupt sub routines callback for USB interrupts. + * + * \param pf_isr the ISR address. + */ void UHD_SetStack(void (*pf_isr)(void)) { gpf_isr = pf_isr; } +/** + * \brief Initialize the UOTGHS host driver. + */ void UHD_Init(void) { irqflags_t flags; @@ -178,7 +190,7 @@ void UHD_Init(void) // Enable main control interrupt // Connection, SOF and reset - UOTGHS->UOTGHS_HSTIER = UOTGHS_HSTICR_DCONNIC;// | UOTGHS_HSTICR_RSTIC;// | UOTGHS_HSTICR_HSOFIC; + UOTGHS->UOTGHS_HSTIER = UOTGHS_HSTICR_DCONNIC; otg_freeze_clock(); @@ -187,11 +199,19 @@ void UHD_Init(void) cpu_irq_restore(flags); } +/** + * \brief Trigger a USB bus reset. + */ void UHD_BusReset(void) { uhd_start_reset(); } +/** + * \brief Get VBUS state. + * + * \return VBUS status. + */ uhd_vbus_state_t UHD_GetVBUSState(void) { return uhd_state; @@ -224,7 +244,7 @@ uhd_vbus_state_t UHD_GetVBUSState(void) * \retval 0 success. * \retval 1 error. */ -uint32_t UHD_EP0_Alloc(uint32_t ul_add, uint32_t ul_ep_size) +uint32_t UHD_Pipe0_Alloc(uint32_t ul_add, uint32_t ul_ep_size) { if (ul_ep_size < 8) { @@ -262,88 +282,88 @@ uint32_t UHD_EP0_Alloc(uint32_t ul_add, uint32_t ul_ep_size) } /** - * \brief Allocate FIFO for the specified pipe. + * \brief Allocate a new pipe. * - * \param ul_add Address of remote device for pipe 0. - * \param ul_ep_size Actual size of the FIFO in bytes. + * \note UOTGHS maximum pipe number is limited to 10, meaning that only a limited + * amount of devices can be connected. Unfortunately, using only one pipe shared accross + * various endpoints and devices is not possible because the UOTGHS IP does not allow to + * change the data toggle value through register interface. * - * \retval 0 success. - * \retval 1 error. + * \param ul_dev_addr Address of remote device. + * \param ul_dev_ep Targeted endpoint of remote device. + * \param ul_type Pipe type. + * \param ul_dir Pipe direction. + * \param ul_maxsize Pipe size. + * \param ul_interval Polling interval (if applicable to pipe type). + * \param ul_nb_bank Number of banks associated with this pipe. + * + * \return the newly allocated pipe number on success, 0 otherwise. */ -uint32_t UHD_EP_Alloc(uint32_t ul_pipe, uint32_t ul_addr, uint32_t ul_interval, uint32_t ul_type, uint32_t ul_dir, uint32_t ul_maxsize, uint32_t ul_bank) +uint32_t UHD_Pipe_Alloc(uint32_t ul_dev_addr, uint32_t ul_dev_ep, uint32_t ul_type, uint32_t ul_dir, uint32_t ul_maxsize, uint32_t ul_interval, uint32_t ul_nb_bank) { + uint32_t ul_pipe = 1; -/* - * Warning: this is a first implementation, pipe allocation is very limited. - * We should probably check maxsize and if maxsize > current size, then realloc with maxsize. - * If pipe type is changed, a pipe reset and re-configuration is required. - */ - - if (Is_uhd_pipe_enabled(ul_pipe)) + for (ul_pipe = 1; ul_pipe < UOTGHS_EPT_NUM; ++ul_pipe) { - // Pipe is already allocated - return 0; + if (Is_uhd_pipe_enabled(ul_pipe)) + { + continue; + } + + uhd_enable_pipe(ul_pipe); + + uhd_configure_pipe(ul_pipe, ul_interval, ul_dev_ep, ul_type, ul_dir, + ul_maxsize, ul_nb_bank, UOTGHS_HSTPIPCFG_AUTOSW); + + uhd_allocate_memory(ul_pipe); + + if (!Is_uhd_pipe_configured(ul_pipe)) + { + uhd_disable_pipe(ul_pipe); + return 0; + } + + uhd_configure_address(ul_pipe, ul_dev_addr); + + // Pipe is configured and allocated successfully + return ul_pipe; } - uhd_enable_pipe(ul_pipe); - - uhd_configure_pipe(ul_pipe, ul_interval, ul_addr, ul_type, ul_dir, - ul_maxsize, ul_bank, UOTGHS_HSTPIPCFG_AUTOSW); - - uhd_allocate_memory(ul_pipe); - - if (!Is_uhd_pipe_configured(ul_pipe)) - { - uhd_disable_pipe(ul_pipe); - return 1; - } - - uhd_configure_address(ul_pipe, ul_addr); - return 0; } -void UHD_EP_Free(uint32_t add, uint32_t endp) +/** + * \brief Free a pipe. + * + * \param ul_pipe Pipe number to free. + */ +void UHD_Pipe_Free(uint32_t ul_pipe) { - // Search endpoint(s) in all pipes - for (uint8_t pipe = 0; pipe < UOTGHS_EPT_NUM; pipe++) - { - if (!Is_uhd_pipe_enabled(pipe)) - { - continue; - } - - if (add != uhd_get_configured_address(pipe)) - { - continue; - } - - /* if (endp != 0xFF) - { - // Disable specific endpoint number - if (endp != uhd_get_pipe_endpoint_address(pipe)) - { - continue; // Mismatch - } - } -*/ - // Unalloc pipe - uhd_disable_pipe(pipe); - uhd_unallocate_memory(pipe); - uhd_reset_pipe(pipe); - } + // Unalloc pipe + uhd_disable_pipe(ul_pipe); + uhd_unallocate_memory(ul_pipe); + uhd_reset_pipe(ul_pipe); } -uint32_t UHD_EP_Read(uint32_t ul_ep, uint32_t ul_size, uint8_t* data) +/** + * \brief Read from a pipe. + * + * \param ul_pipe Pipe number. + * \param ul_size Maximum number of data to read. + * \param data Buffer to store the data. + * + * \return number of data read. + */ +uint32_t UHD_Pipe_Read(uint32_t ul_pipe, uint32_t ul_size, uint8_t* data) { uint8_t *ptr_ep_data = 0; uint8_t nb_byte_received = 0; uint32_t ul_nb_trans = 0; // Get information to read data - nb_byte_received = uhd_byte_count(ul_ep); + nb_byte_received = uhd_byte_count(ul_pipe); - ptr_ep_data = (uint8_t *) & uhd_get_pipe_fifo_access(ul_ep, 8); + ptr_ep_data = (uint8_t *) & uhd_get_pipe_fifo_access(ul_pipe, 8); // Copy data from pipe to payload buffer while (ul_size && nb_byte_received) { @@ -356,98 +376,111 @@ uint32_t UHD_EP_Read(uint32_t ul_ep, uint32_t ul_size, uint8_t* data) return ul_nb_trans; } -void UHD_EP_Write(uint32_t ul_ep, uint32_t ul_size, uint8_t* data) +/** + * \brief Write into a pipe. + * + * \param ul_pipe Pipe number. + * \param ul_size Maximum number of data to read. + * \param data Buffer containing data to write. + */ +void UHD_Pipe_Write(uint32_t ul_pipe, uint32_t ul_size, uint8_t* data) { volatile uint8_t *ptr_ep_data = 0; uint32_t i = 0; // Check pipe - if (!Is_uhd_pipe_enabled(ul_ep)) + if (!Is_uhd_pipe_enabled(ul_pipe)) { // Endpoint not valid TRACE_UOTGHS_HOST(printf("/!\\ UHD_EP_Send : pipe is not enabled!\r\n");) return; } - ptr_ep_data = (volatile uint8_t *)&uhd_get_pipe_fifo_access(ul_ep, 8); + ptr_ep_data = (volatile uint8_t *)&uhd_get_pipe_fifo_access(ul_pipe, 8); for (i = 0; i < ul_size; ++i) *ptr_ep_data++ = *data++; } -void UHD_EP_Send(uint32_t ul_ep, uint32_t ul_token_type) +/** + * \brief Send a pipe content. + * + * \param ul_pipe Pipe number. + * \param ul_token_type Token type. + */ +void UHD_Pipe_Send(uint32_t ul_pipe, uint32_t ul_token_type) { // Check pipe - if (!Is_uhd_pipe_enabled(ul_ep)) + if (!Is_uhd_pipe_enabled(ul_pipe)) { // Endpoint not valid - TRACE_UOTGHS_HOST(printf("/!\\ UHD_EP_Send : pipe %lu is not enabled!\r\n", ul_ep);) + TRACE_UOTGHS_HOST(printf("/!\\ UHD_EP_Send : pipe %lu is not enabled!\r\n", ul_pipe);) return; } // Set token type for zero length packet // When actually using the FIFO, pipe token MUST be configured first - uhd_configure_pipe_token(ul_ep, ul_token_type); + uhd_configure_pipe_token(ul_pipe, ul_token_type); // Clear interrupt flags - uhd_ack_setup_ready(ul_ep); - uhd_ack_in_received(ul_ep); - uhd_ack_out_ready(ul_ep); - uhd_ack_short_packet(ul_ep); + uhd_ack_setup_ready(ul_pipe); + uhd_ack_in_received(ul_pipe); + uhd_ack_out_ready(ul_pipe); + uhd_ack_short_packet(ul_pipe); + uhd_ack_nak_received(ul_pipe); // Send actual packet - uhd_ack_fifocon(ul_ep); - uhd_unfreeze_pipe(ul_ep); + uhd_ack_fifocon(ul_pipe); + uhd_unfreeze_pipe(ul_pipe); } /** - * \brief Check is transfer is complete. + * \brief Check for pipe transfer completion. * - * \param ul_add Address of remote device for pipe 0. - * \param ul_ep_size Actual size of the FIFO in bytes. + * \param ul_pipe Pipe number. + * \param ul_token_type Token type. * * \retval 0 transfer is not complete. * \retval 1 transfer is complete. */ -uint32_t UHD_EP_Is_Transfer_Complete(uint32_t ul_ep, uint32_t ul_token_type) +uint32_t UHD_Pipe_Is_Transfer_Complete(uint32_t ul_pipe, uint32_t ul_token_type) { // Check for transfer completion depending on token type switch (ul_token_type) { case UOTGHS_HSTPIPCFG_PTOKEN_SETUP: - if (Is_uhd_setup_ready(ul_ep)) + if (Is_uhd_setup_ready(ul_pipe)) { - uhd_freeze_pipe(ul_ep); - uhd_ack_setup_ready(ul_ep); + uhd_freeze_pipe(ul_pipe); + uhd_ack_setup_ready(ul_pipe); return 1; } case UOTGHS_HSTPIPCFG_PTOKEN_IN: - if (Is_uhd_in_received(ul_ep)) + if (Is_uhd_in_received(ul_pipe)) { // In case of low USB speed and with a high CPU frequency, // a ACK from host can be always running on USB line // then wait end of ACK on IN pipe. - while(!Is_uhd_pipe_frozen(ul_ep)) + while(!Is_uhd_pipe_frozen(ul_pipe)) ; // IN packet received - uhd_ack_in_received(ul_ep); + uhd_ack_in_received(ul_pipe); return 1; } case UOTGHS_HSTPIPCFG_PTOKEN_OUT: - if (Is_uhd_out_ready(ul_ep)) + if (Is_uhd_out_ready(ul_pipe)) { // OUT packet sent - uhd_freeze_pipe(ul_ep); - uhd_ack_out_ready(ul_ep); + uhd_freeze_pipe(ul_pipe); + uhd_ack_out_ready(ul_pipe); return 1; } } - // Nothing to report return 0; } diff --git a/hardware/arduino/sam/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a b/hardware/arduino/sam/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a index 8e44d6a6375b056f501ffcca779d9102cdc114b8..df3d8bd041016b6d507c391415f5bfdcd6c70095 100644 GIT binary patch delta 5790 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 F@n5`LFXjLM diff --git a/hardware/arduino/sam/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a.txt b/hardware/arduino/sam/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a.txt index 86c0b679d..6a04614cb 100644 --- a/hardware/arduino/sam/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a.txt +++ b/hardware/arduino/sam/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a.txt @@ -99,14 +99,14 @@ pwmc.o: 00000000 T PWMC_SetSyncChannelUpdateUnlock 00000000 T PWMC_WriteBuffer U __assert_func -00000000 r __func__.3296 -00000000 r __func__.3307 -00000000 r __func__.3322 -00000000 r __func__.3333 -00000000 r __func__.3344 -00000000 r __func__.3351 -00000000 r __func__.3435 -00000000 r __func__.3441 +00000000 r __func__.3295 +00000000 r __func__.3306 +00000000 r __func__.3321 +00000000 r __func__.3332 +00000000 r __func__.3343 +00000000 r __func__.3350 +00000000 r __func__.3434 +00000000 r __func__.3440 rtc.o: 00000000 T RTC_ClearSCCR @@ -122,9 +122,9 @@ rtc.o: 00000000 T RTC_SetTime 00000000 T RTC_SetTimeAlarm U __assert_func -00000000 r __func__.3293 -00000000 r __func__.3302 -00000000 r __func__.3307 +00000000 r __func__.3292 +00000000 r __func__.3301 +00000000 r __func__.3306 rtt.o: 00000000 T RTT_EnableIT @@ -133,8 +133,8 @@ rtt.o: 00000000 T RTT_SetAlarm 00000000 T RTT_SetPrescaler U __assert_func -00000000 r __func__.3300 -00000000 r __func__.3308 +00000000 r __func__.3299 +00000000 r __func__.3307 spi.o: 00000000 T SPI_Configure @@ -155,9 +155,9 @@ tc.o: 00000000 T TC_Start 00000000 T TC_Stop U __assert_func -00000000 r __func__.3295 -00000000 r __func__.3301 -00000000 r __func__.3307 +00000000 r __func__.3294 +00000000 r __func__.3300 +00000000 r __func__.3306 timetick.o: 00000000 T GetTickCount @@ -184,18 +184,18 @@ twi.o: 00000000 T TWI_TransferComplete 00000000 T TWI_WriteByte U __assert_func -00000000 r __func__.3660 -00000000 r __func__.3675 -00000000 r __func__.3679 -00000000 r __func__.3686 -00000000 r __func__.3690 -00000000 r __func__.3695 -00000000 r __func__.3703 -00000000 r __func__.3717 -00000000 r __func__.3722 -00000000 r __func__.3726 -00000000 r __func__.3731 -00000000 r __func__.3735 +00000000 r __func__.3659 +00000000 r __func__.3674 +00000000 r __func__.3678 +00000000 r __func__.3685 +00000000 r __func__.3689 +00000000 r __func__.3694 +00000000 r __func__.3702 +00000000 r __func__.3716 +00000000 r __func__.3721 +00000000 r __func__.3725 +00000000 r __func__.3730 +00000000 r __func__.3734 usart.o: 00000000 T USART_Configure @@ -214,7 +214,7 @@ usart.o: 00000000 T USART_Write 00000000 T USART_WriteBuffer U __assert_func -00000000 r __func__.3581 +00000000 r __func__.3580 wdt.o: 00000000 T WDT_Disable @@ -385,20 +385,19 @@ uotghs_device.o: uotghs_host.o: 00000000 T UHD_BusReset -00000000 T UHD_EP0_Alloc -00000000 T UHD_EP_Alloc -00000000 T UHD_EP_Free -00000000 T UHD_EP_Is_Transfer_Complete -00000000 T UHD_EP_Read -00000000 T UHD_EP_Send -00000000 T UHD_EP_Write 00000000 T UHD_GetVBUSState 00000000 t UHD_ISR 00000000 T UHD_Init +00000000 T UHD_Pipe0_Alloc +00000000 T UHD_Pipe_Alloc +00000000 T UHD_Pipe_Free +00000000 T UHD_Pipe_Is_Transfer_Complete +00000000 T UHD_Pipe_Read +00000000 T UHD_Pipe_Send +00000000 T UHD_Pipe_Write 00000000 T UHD_SetStack U g_interrupt_enabled U gpf_isr - U iprintf U pmc_enable_periph_clk U pmc_enable_udpck U pmc_enable_upll_clock