mirror of
https://github.com/arduino/Arduino.git
synced 2025-03-14 11:29:26 +01:00
[sam] USBHost ADK+HID supported okay. Code is more documented.
This commit is contained in:
parent
96e8db0299
commit
3ba2e37651
@ -1,61 +1,54 @@
|
|||||||
#include "variant.h"
|
#include "variant.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <hidboot.h>
|
#include <adk.h>
|
||||||
|
|
||||||
class MouseRptParser : public MouseReportParser
|
// Accessory descriptor. It's how Arduino identifies itself to Android.
|
||||||
{
|
char applicationName[] = "Arduino_Terminal"; // the app on your phone
|
||||||
protected:
|
char accessoryName[] = "Arduino Due X"; // your Arduino board
|
||||||
virtual void OnMouseMove (MOUSEINFO *mi);
|
char companyName[] = "Arduino SA";
|
||||||
virtual void OnLeftButtonUp (MOUSEINFO *mi);
|
|
||||||
virtual void OnLeftButtonDown (MOUSEINFO *mi);
|
// Make up anything you want for these
|
||||||
virtual void OnRightButtonUp (MOUSEINFO *mi);
|
char versionNumber[] = "1.0";
|
||||||
virtual void OnRightButtonDown (MOUSEINFO *mi);
|
char serialNumber[] = "1";
|
||||||
virtual void OnMiddleButtonUp (MOUSEINFO *mi);
|
char url[] = "http://labs.arduino.cc/uploads/ADK/ArduinoTerminal/ThibaultTerminal_ICS_0001.apk";
|
||||||
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");
|
|
||||||
};
|
|
||||||
|
|
||||||
USBHost Usb;
|
USBHost Usb;
|
||||||
HIDBoot<HID_PROTOCOL_MOUSE> HostMouse(&Usb);
|
ADK adk(&Usb, companyName, applicationName, accessoryName,versionNumber,url,serialNumber);
|
||||||
MouseRptParser Prs;
|
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
cpu_irq_enable();
|
cpu_irq_enable();
|
||||||
printf("\r\nProgram started:\r\n");
|
printf("\r\nADK demo start\r\n");
|
||||||
delay(200);
|
delay(200);
|
||||||
|
|
||||||
HostMouse.SetReportParser(0,(HIDReportParser*)&Prs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define RCVSIZE 128
|
||||||
|
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
|
uint8_t buf[RCVSIZE];
|
||||||
|
uint32_t nbread = 0;
|
||||||
|
char helloworld[] = "Hello World!\r\n";
|
||||||
|
|
||||||
Usb.Task();
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ Circuits At Home, LTD
|
|||||||
Web : http://www.circuitsathome.com
|
Web : http://www.circuitsathome.com
|
||||||
e-mail : support@circuitsathome.com
|
e-mail : support@circuitsathome.com
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* USB functions */
|
/* USB functions */
|
||||||
|
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
@ -24,9 +25,9 @@ static uint32_t usb_error = 0;
|
|||||||
static uint32_t usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
|
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
|
// Set up state machine
|
||||||
usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
|
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()
|
void USBHost::init()
|
||||||
{
|
{
|
||||||
@ -44,8 +45,11 @@ void USBHost::init()
|
|||||||
bmHubPre = 0;
|
bmHubPre = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get USB state.
|
* \brief Get USBHost state.
|
||||||
|
*
|
||||||
|
* \return USB enumeration status (see USBHost::task).
|
||||||
*/
|
*/
|
||||||
uint32_t USBHost::getUsbTaskState(void)
|
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)
|
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)
|
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++)
|
for (uint32_t i = 0; i < p->epcount; i++)
|
||||||
{
|
{
|
||||||
if (pep->epAddr == ep)
|
if (pep->deviceEpNum == ep)
|
||||||
return pep;
|
return pep;
|
||||||
|
|
||||||
pep++;
|
pep++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set device end point entry.
|
* \brief Set device endpoint entry.
|
||||||
* Each device is different and has different number of endpoints.
|
*
|
||||||
* This function plugs endpoint record structure, defined in application to devtable.
|
* \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)
|
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;
|
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);
|
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)
|
if (!*ppep)
|
||||||
return USB_ERROR_EP_NOT_FOUND_IN_TBL;
|
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--;
|
nak_limit--;
|
||||||
|
|
||||||
// Set peripheral address
|
// Set peripheral address
|
||||||
//regWr( rPERADDR, addr );
|
TRACE_USBHOST(printf(" => SetAddress deviceEP=%lu configued as hostPIPE=%lu sending to address=%lu\r\n", ep, (*ppep)->hostPipeNum, addr);)
|
||||||
uhd_configure_address(ep, addr);
|
uhd_configure_address((*ppep)->hostPipeNum, 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));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a control request.
|
* \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.
|
* Sets address, endpoint, fills control packet with necessary data, dispatches
|
||||||
* Actual requests are defined as inlines.
|
* control packet, and initiates bulk IN transfer depending on request.
|
||||||
*
|
*
|
||||||
* return codes:
|
* \param addr USB device address.
|
||||||
* 00 = success
|
* \param ep USB device endpoint number.
|
||||||
* 01-0f = non-zero HRSLT
|
* \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)
|
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");)
|
TRACE_USBHOST(printf(" => ctrlReq\r\n");)
|
||||||
|
|
||||||
// Set peripheral address
|
// Set peripheral address
|
||||||
rcode = SetAddress(addr, ep, &pep, nak_limit);
|
rcode = setPipeAddress(addr, ep, &pep, nak_limit);
|
||||||
if (rcode)
|
if (rcode)
|
||||||
return rcode;
|
return rcode;
|
||||||
|
|
||||||
// Allocate EP0 with default 8 bytes size if not already initialized
|
// Allocate Pipe0 with default 64 bytes size if not already initialized
|
||||||
rcode = UHD_EP0_Alloc(0, 8);
|
// 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)
|
if (rcode)
|
||||||
{
|
{
|
||||||
TRACE_USBHOST(printf("/!\\ USBHost::ctrlReq : EP0 allocation error: %lu\r\n", 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
|
// Determine request direction
|
||||||
direction = (( bmReqType & 0x80 ) > 0);
|
direction = ((bmReqType & 0x80 ) > 0);
|
||||||
|
|
||||||
// Fill in setup packet
|
// Fill in setup packet
|
||||||
setup_pkt.ReqType_u.bmRequestType = bmReqType;
|
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;
|
setup_pkt.wLength = total;
|
||||||
|
|
||||||
// Configure and write the setup packet into the FIFO
|
// Configure and write the setup packet into the FIFO
|
||||||
//bytesWr(rSUDFIFO, 8, (uint8_t *)&setup_pkt);
|
|
||||||
uhd_configure_pipe_token(0, tokSETUP);
|
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
|
// Dispatch packet
|
||||||
rcode = dispatchPkt(tokSETUP, ep, nak_limit);
|
rcode = dispatchPkt(tokSETUP, pep->hostPipeNum, nak_limit);
|
||||||
if (rcode)
|
if (rcode)
|
||||||
{
|
{
|
||||||
// Return HRSLT if not zero
|
// 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
|
else
|
||||||
{
|
{
|
||||||
// OUT transfer
|
// OUT transfer
|
||||||
//devtable[addr].epinfo[ep].sndToggle = bmSNDTOG1;
|
|
||||||
TRACE_USBHOST(printf(" => ctrlData OUT\r\n");)
|
TRACE_USBHOST(printf(" => ctrlData OUT\r\n");)
|
||||||
rcode = OutTransfer(pep, nak_limit, nbytes, dataptr);
|
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
|
// Status stage
|
||||||
return dispatchPkt((direction) ? tokOUTHS : tokINHS, ep, nak_limit );
|
return dispatchPkt((direction) ? tokOUTHS : tokINHS, pep->hostPipeNum, nak_limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IN transfer to arbitrary endpoint.
|
* \brief Perform IN request to the specified USB device.
|
||||||
* Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes.
|
*
|
||||||
* Keep sending INs and writes data to memory area pointed by 'data'.
|
* \note This function handles multiple packets (if necessary) and can
|
||||||
* rcode 0 if no errors
|
* receive a maximum of 'nbytesptr' bytes. It keep sending INs and writes data
|
||||||
* 01-0f is relayed from dispatchPkt()
|
* to memory area pointed by 'data'. The actual amount of received bytes is
|
||||||
* f0 means RCVDAVIRQ error
|
* stored in 'nbytesptr'.
|
||||||
* fe USB xfer timeout
|
*
|
||||||
|
* \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)
|
uint32_t USBHost::inTransfer(uint32_t addr, uint32_t ep, uint32_t *nbytesptr, uint8_t* data)
|
||||||
{
|
{
|
||||||
EpInfo *pep = NULL;
|
EpInfo *pep = NULL;
|
||||||
uint32_t nak_limit = 0;
|
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)
|
if (rcode)
|
||||||
|
{
|
||||||
return rcode;
|
return rcode;
|
||||||
|
}
|
||||||
|
|
||||||
return InTransfer(pep, nak_limit, nbytesptr, data);
|
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 rcode = 0;
|
||||||
uint32_t pktsize = 0;
|
uint32_t pktsize = 0;
|
||||||
uint16_t nbytes = *nbytesptr;
|
uint32_t nbytes = *nbytesptr;
|
||||||
uint8_t maxpktsize = pep->maxPktSize;
|
uint32_t maxpktsize = pep->maxPktSize;
|
||||||
|
|
||||||
*nbytesptr = 0;
|
*nbytesptr = 0;
|
||||||
|
|
||||||
// Set toggle value
|
|
||||||
//regWr(rHCTL, devtable[addr].epinfo[ep].rcvToggle);
|
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
// Use a 'return' to exit this loop
|
// Use a 'return' to exit this loop
|
||||||
// IN packet to EP-'endpoint'. Function takes care of NAKS.
|
// 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)
|
if (rcode)
|
||||||
{
|
{
|
||||||
// Should be 0, indicating ACK. Else return error code.
|
if (rcode == 1)
|
||||||
return (rcode);
|
{
|
||||||
|
// 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
|
// Number of received bytes
|
||||||
//pktsize = regRd(rRCVBC);
|
pktsize = uhd_byte_count(pep->hostPipeNum);
|
||||||
//data = bytesRd(rRCVFIFO, pktsize, data);
|
|
||||||
pktsize = uhd_byte_count(pep->epAddr);
|
|
||||||
if (nbytes < pktsize)
|
if (nbytes < pktsize)
|
||||||
printf("ce test n'a pas ete fait...\r\n");
|
{
|
||||||
data += UHD_EP_Read(pep->epAddr, pktsize, data);
|
TRACE_USBHOST(printf("/!\\ USBHost::InTransfer : receive buffer is too small, size=%lu, expected=%lu\r\n", nbytes, pktsize);)
|
||||||
|
}
|
||||||
// Clear the IRQ & free the buffer
|
data += UHD_Pipe_Read(pep->hostPipeNum, pktsize, data);
|
||||||
//regWr(rHIRQ, bmRCVDAVIRQ);
|
|
||||||
|
|
||||||
// Add this packet's byte count to total transfer length
|
// Add this packet's byte count to total transfer length
|
||||||
*nbytesptr += pktsize;
|
*nbytesptr += pktsize;
|
||||||
@ -312,155 +353,116 @@ uint32_t USBHost::InTransfer(EpInfo *pep, uint32_t nak_limit, uint32_t *nbytespt
|
|||||||
// 2. 'nbytes' have been transferred.
|
// 2. 'nbytes' have been transferred.
|
||||||
if ((pktsize < maxpktsize) || (*nbytesptr >= nbytes))
|
if ((pktsize < maxpktsize) || (*nbytesptr >= nbytes))
|
||||||
{
|
{
|
||||||
/*// Have we transferred 'nbytes' bytes?
|
return 0;
|
||||||
if (regRd(rHRSL) & bmRCVTOGRD)
|
|
||||||
{
|
|
||||||
// Save toggle value
|
|
||||||
devtable[addr].epinfo[ep].rcvToggle = bmRCVTOG1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
devtable[addr].epinfo[ep].rcvToggle = bmRCVTOG0;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OUT transfer to arbitrary endpoint.
|
* \brief Perform OUT request to the specified USB device.
|
||||||
* 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
|
|
||||||
*
|
*
|
||||||
* 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)
|
uint32_t USBHost::outTransfer(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t* data)
|
||||||
{
|
{
|
||||||
/*
|
EpInfo *pep = NULL;
|
||||||
EpInfo *pep = NULL;
|
uint32_t nak_limit = 0;
|
||||||
uint16_t nak_limit;
|
|
||||||
|
|
||||||
uint8_t rcode = SetAddress(addr, ep, &pep, nak_limit);
|
uint32_t rcode = setPipeAddress(addr, ep, &pep, nak_limit);
|
||||||
|
|
||||||
if (rcode)
|
if (rcode)
|
||||||
|
{
|
||||||
return rcode;
|
return rcode;
|
||||||
|
}
|
||||||
|
|
||||||
return OutTransfer(pep, nak_limit, nbytes, data);
|
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)
|
uint32_t USBHost::OutTransfer(EpInfo *pep, uint32_t nak_limit, uint32_t nbytes, uint8_t *data)
|
||||||
{
|
{
|
||||||
/*
|
uint32_t rcode = 0;
|
||||||
uint8_t rcode, retry_count;
|
uint32_t bytes_tosend = 0;
|
||||||
uint8_t *data_p = data; //local copy of the data pointer
|
uint32_t bytes_left = nbytes;
|
||||||
uint16_t bytes_tosend, nak_count;
|
uint32_t maxpktsize = pep->maxPktSize;
|
||||||
uint16_t bytes_left = nbytes;
|
|
||||||
|
|
||||||
uint8_t maxpktsize = pep->maxPktSize;
|
if (maxpktsize < 1)
|
||||||
|
|
||||||
if (maxpktsize < 1 || maxpktsize > 64)
|
|
||||||
return USB_ERROR_INVALID_MAX_PKT_SIZE;
|
return USB_ERROR_INVALID_MAX_PKT_SIZE;
|
||||||
|
|
||||||
unsigned long timeout = millis() + USB_XFER_TIMEOUT;
|
while (bytes_left)
|
||||||
|
|
||||||
regWr( rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0 ); //set toggle value
|
|
||||||
|
|
||||||
while( bytes_left )
|
|
||||||
{
|
{
|
||||||
retry_count = 0;
|
bytes_tosend = (bytes_left >= maxpktsize) ? maxpktsize : bytes_left;
|
||||||
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 );
|
|
||||||
|
|
||||||
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 )
|
// Should be 0, indicating ACK. Else return error code.
|
||||||
{
|
return 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
|
|
||||||
|
|
||||||
// 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;
|
bytes_left -= bytes_tosend;
|
||||||
data_p += bytes_tosend;
|
data += bytes_tosend;
|
||||||
}//while( bytes_left...
|
}
|
||||||
pep->bmSndToggle = ( regRd( rHRSL ) & bmSNDTOGRD ) ? 1 : 0; //bmSNDTOG1 : bmSNDTOG0; //update toggle
|
|
||||||
return( rcode ); //should be 0 in all cases
|
// Should be 0 in all cases
|
||||||
*/
|
return rcode;
|
||||||
printf("j'ai beau etre matinal.. j'ai mal!!!! arggghh\r\n");
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispatch USB packet.
|
* \brief Dispatch USB packet.
|
||||||
* Assumes peripheral address is set and relevant buffer is loaded/empty.
|
*
|
||||||
|
* \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, tries to re-send up to nak_limit times.
|
||||||
* If nak_limit == 0, do not count NAKs, exit after timeout.
|
* 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,
|
* \param token Token type (Setup, In or Out).
|
||||||
* else packet may be corrupted.
|
* \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 timeout = millis() + USB_XFER_TIMEOUT;
|
||||||
uint32_t nak_count = 0;
|
uint32_t nak_count = 0;
|
||||||
uint32_t rcode = USB_ERROR_TRANSFER_TIMEOUT;
|
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
|
// Launch the transfer
|
||||||
//regWr(rHXFR, (token | ep));
|
UHD_Pipe_Send(hostPipeNum, token);
|
||||||
UHD_EP_Send(ep, 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
|
// Wait for transfer completion
|
||||||
if (UHD_EP_Is_Transfer_Complete(ep, token))
|
if (UHD_Pipe_Is_Transfer_Complete(hostPipeNum, token))
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
// Is NAK received?
|
||||||
if (Is_uhd_nak_received(ep))
|
if (Is_uhd_nak_received(hostPipeNum))
|
||||||
{
|
{
|
||||||
uhd_ack_nak_received(ep);
|
uhd_ack_nak_received(hostPipeNum);
|
||||||
nak_count++;
|
nak_count++;
|
||||||
|
|
||||||
if (nak_limit && (nak_count == nak_limit))
|
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.
|
* 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)
|
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;
|
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 case of an error devConfigIndex should be reset to 0
|
||||||
// in order to start from the very beginning the
|
// in order to start from the very beginning the next time
|
||||||
// next time the program gets here
|
// the program gets here
|
||||||
if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE)
|
if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE)
|
||||||
devConfigIndex = 0;
|
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;
|
devConfigIndex = 0;
|
||||||
|
|
||||||
rcode = DefaultAddressing(parent, port, lowspeed);
|
rcode = DefaultAddressing(parent, port, lowspeed);
|
||||||
@ -510,6 +527,15 @@ uint32_t USBHost::Configuring(uint32_t parent, uint32_t port, uint32_t lowspeed)
|
|||||||
return rcode;
|
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 USBHost::DefaultAddressing(uint32_t parent, uint32_t port, uint32_t lowspeed)
|
||||||
{
|
{
|
||||||
uint32_t rcode = 0;
|
uint32_t rcode = 0;
|
||||||
@ -553,30 +579,70 @@ uint32_t USBHost::DefaultAddressing(uint32_t parent, uint32_t port, uint32_t low
|
|||||||
return 0;
|
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)
|
uint32_t USBHost::ReleaseDevice(uint32_t addr)
|
||||||
{
|
{
|
||||||
if (!addr)
|
if (!addr)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < USB_NUMDEVICES; ++i)
|
for (uint32_t i = 0; i < USB_NUMDEVICES; ++i)
|
||||||
|
{
|
||||||
if (devConfig[i]->GetAddress() == addr)
|
if (devConfig[i]->GetAddress() == addr)
|
||||||
|
{
|
||||||
return devConfig[i]->Release();
|
return devConfig[i]->Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
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)
|
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));
|
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)
|
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));
|
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)
|
uint32_t USBHost::getConfDescr(uint32_t addr, uint32_t ep, uint32_t conf, USBReadParser *p)
|
||||||
{
|
{
|
||||||
const uint32_t bufSize = 64;
|
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));
|
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)
|
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);
|
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)
|
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));
|
return (ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, 0x0000, 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* USB main task.
|
* \brief USB main task, responsible for enumeration and clean up stage.
|
||||||
* Performs enumeration/cleanup.
|
*
|
||||||
|
* \note Must be periodically called from loop().
|
||||||
*/
|
*/
|
||||||
void USBHost::Task(void)
|
void USBHost::Task(void)
|
||||||
{
|
{
|
||||||
@ -648,16 +742,17 @@ void USBHost::Task(void)
|
|||||||
{
|
{
|
||||||
delay = millis() + USB_SETTLE_DELAY;
|
delay = millis() + USB_SETTLE_DELAY;
|
||||||
usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Poll connected devices (if required)
|
||||||
for (uint32_t i = 0; i < USB_NUMDEVICES; ++i)
|
for (uint32_t i = 0; i < USB_NUMDEVICES; ++i)
|
||||||
if (devConfig[i])
|
if (devConfig[i])
|
||||||
rcode = devConfig[i]->Poll();
|
rcode = devConfig[i]->Poll();
|
||||||
|
|
||||||
// USB state machine
|
// Perform USB enumeration stage and clean up
|
||||||
switch (usb_task_state)
|
switch (usb_task_state)
|
||||||
{
|
{
|
||||||
case USB_DETACHED_SUBSTATE_INITIALIZE:
|
case USB_DETACHED_SUBSTATE_INITIALIZE:
|
||||||
@ -667,6 +762,7 @@ void USBHost::Task(void)
|
|||||||
UHD_Init();
|
UHD_Init();
|
||||||
init();
|
init();
|
||||||
|
|
||||||
|
// Free all USB resources
|
||||||
for (uint32_t i = 0; i < USB_NUMDEVICES; ++i)
|
for (uint32_t i = 0; i < USB_NUMDEVICES; ++i)
|
||||||
if (devConfig[i])
|
if (devConfig[i])
|
||||||
rcode = devConfig[i]->Release();
|
rcode = devConfig[i]->Release();
|
||||||
|
@ -19,8 +19,8 @@ e-mail : support@circuitsathome.com
|
|||||||
#ifndef USB_H_INCLUDED
|
#ifndef USB_H_INCLUDED
|
||||||
#define USB_H_INCLUDED
|
#define USB_H_INCLUDED
|
||||||
|
|
||||||
#define TRACE_USBHOST(x) x
|
//#define TRACE_USBHOST(x) x
|
||||||
//#define TRACE_USBHOST(x)
|
#define TRACE_USBHOST(x)
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "usb_ch9.h"
|
#include "usb_ch9.h"
|
||||||
@ -120,7 +120,11 @@ typedef struct
|
|||||||
uint16_t wLength; // 6 Depends on bRequest
|
uint16_t wLength; // 6 Depends on bRequest
|
||||||
} SETUP_PKT, *PSETUP_PKT;
|
} SETUP_PKT, *PSETUP_PKT;
|
||||||
|
|
||||||
// Base class for incoming data parser
|
/**
|
||||||
|
* \class USBReadParser
|
||||||
|
*
|
||||||
|
* \brief Base class used for USB descriptor parsing.
|
||||||
|
*/
|
||||||
class USBReadParser
|
class USBReadParser
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -128,21 +132,30 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* USBDeviceConfig class.
|
* \class USBDeviceConfig
|
||||||
|
*
|
||||||
|
* \brief Device configuration class used for managing device life cycle.
|
||||||
*/
|
*/
|
||||||
class USBDeviceConfig
|
class USBDeviceConfig
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
//! @brief Perform final enumeration stage.
|
||||||
virtual uint32_t Init(uint32_t parent, uint32_t port, uint32_t lowspeed) = 0;
|
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;
|
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;
|
virtual uint32_t Poll() = 0;
|
||||||
|
|
||||||
|
//! @brief Retrieve USB device address.
|
||||||
virtual uint32_t GetAddress() = 0;
|
virtual uint32_t GetAddress() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* USBHost Class.
|
* \class USBHost
|
||||||
* 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.
|
* \brief Main USB host class.
|
||||||
*/
|
*/
|
||||||
class USBHost
|
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 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 nbytes, uint32_t conf, uint8_t* dataptr);
|
||||||
uint32_t getConfDescr(uint32_t addr, uint32_t ep, uint32_t conf, USBReadParser *p);
|
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 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 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,
|
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:
|
private:
|
||||||
void init();
|
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 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);
|
uint32_t InTransfer(EpInfo *pep, uint32_t nak_limit, uint32_t *nbytesptr, uint8_t* data);
|
||||||
};
|
};
|
||||||
|
@ -27,9 +27,22 @@ e-mail : support@circuitsathome.com
|
|||||||
#define USB_NAK_NOWAIT 1 //Single NAK stops transfer
|
#define USB_NAK_NOWAIT 1 //Single NAK stops transfer
|
||||||
#define USB_NAK_NONAK 0 //Do not count NAKs, stop retrying after USB Timeout
|
#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
|
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
|
uint32_t maxPktSize; // Maximum packet size
|
||||||
|
|
||||||
union
|
union
|
||||||
@ -45,15 +58,20 @@ struct EpInfo
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// 7 6 5 4 3 2 1 0
|
/**
|
||||||
// ---------------------------------
|
* \brief USB device address definition.
|
||||||
// | | H | P | P | P | A | A | A |
|
*
|
||||||
// ---------------------------------
|
* \note The 8 bits USB address is defined like this:
|
||||||
//
|
*
|
||||||
// H - if 1 the address is a hub address
|
* 7 6 5 4 3 2 1 0
|
||||||
// P - parent hub address
|
* ---------------------------------
|
||||||
// A - device address / port number in case of hub
|
* | | 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
|
struct UsbDeviceAddress
|
||||||
{
|
{
|
||||||
union
|
union
|
||||||
@ -73,6 +91,14 @@ struct UsbDeviceAddress
|
|||||||
#define bmUSB_DEV_ADDR_PARENT 0x38
|
#define bmUSB_DEV_ADDR_PARENT 0x38
|
||||||
#define bmUSB_DEV_ADDR_HUB 0x40
|
#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
|
struct UsbDevice
|
||||||
{
|
{
|
||||||
EpInfo *epinfo; // endpoint info pointer
|
EpInfo *epinfo; // endpoint info pointer
|
||||||
@ -81,6 +107,9 @@ struct UsbDevice
|
|||||||
uint32_t lowspeed; // indicates if a device is the low speed one
|
uint32_t lowspeed; // indicates if a device is the low speed one
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class Abstract AddressPool definition.
|
||||||
|
*/
|
||||||
class AddressPool
|
class AddressPool
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -94,28 +123,46 @@ typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev);
|
|||||||
#define ADDR_ERROR_INVALID_INDEX 0xFF
|
#define ADDR_ERROR_INVALID_INDEX 0xFF
|
||||||
#define ADDR_ERROR_INVALID_ADDRESS 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 <const uint32_t MAX_DEVICES_ALLOWED>
|
template <const uint32_t MAX_DEVICES_ALLOWED>
|
||||||
class AddressPoolImpl : public AddressPool
|
class AddressPoolImpl : public AddressPool
|
||||||
{
|
{
|
||||||
private:
|
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
|
uint32_t hubCounter; // hub counter is kept
|
||||||
// in order to avoid hub address duplication
|
// in order to avoid hub address duplication
|
||||||
|
|
||||||
UsbDevice thePool[MAX_DEVICES_ALLOWED];
|
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)
|
void InitEntry(uint32_t index)
|
||||||
{
|
{
|
||||||
thePool[index].address = 0;
|
thePool[index].address = 0;
|
||||||
thePool[index].epcount = 1;
|
thePool[index].epcount = 1;
|
||||||
thePool[index].lowspeed = 0;
|
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)
|
uint32_t FindAddressIndex(uint32_t address = 0)
|
||||||
{
|
{
|
||||||
for (uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
|
for (uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
|
||||||
@ -126,21 +173,45 @@ private:
|
|||||||
return 0;
|
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)
|
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)
|
if (((UsbDeviceAddress*)&thePool[i].address)->bmParent == addr.bmAddress)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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)
|
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)
|
if (index == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -154,10 +225,13 @@ private:
|
|||||||
if (hubCounter == ((UsbDeviceAddress*)&thePool[index].address)->bmAddress)
|
if (hubCounter == ((UsbDeviceAddress*)&thePool[index].address)->bmAddress)
|
||||||
hubCounter --;
|
hubCounter --;
|
||||||
}
|
}
|
||||||
|
|
||||||
InitEntry(index);
|
InitEntry(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initializes the whole address pool at once
|
/**
|
||||||
|
* \brief Initialize all address poll entries at once.
|
||||||
|
*/
|
||||||
void InitAllAddresses()
|
void InitAllAddresses()
|
||||||
{
|
{
|
||||||
for (uint32_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
|
for (uint32_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
|
||||||
@ -167,6 +241,9 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* \brief AddressPoolImpl class constructor.
|
||||||
|
*/
|
||||||
AddressPoolImpl() : hubCounter(0)
|
AddressPoolImpl() : hubCounter(0)
|
||||||
{
|
{
|
||||||
// Init address zero (reserved)
|
// Init address zero (reserved)
|
||||||
@ -176,11 +253,18 @@ public:
|
|||||||
InitAllAddresses();
|
InitAllAddresses();
|
||||||
|
|
||||||
// Configure ep0 used for enumeration
|
// Configure ep0 used for enumeration
|
||||||
dev0ep.epAddr = 0;
|
dev0ep.deviceEpNum = 0;
|
||||||
dev0ep.maxPktSize = 8;
|
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)
|
virtual UsbDevice* GetUsbDevicePtr(uint32_t addr)
|
||||||
{
|
{
|
||||||
if (!addr)
|
if (!addr)
|
||||||
@ -191,7 +275,12 @@ public:
|
|||||||
return (!index) ? 0 : (thePool + index);
|
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)
|
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc)
|
||||||
{
|
{
|
||||||
if (!pfunc)
|
if (!pfunc)
|
||||||
@ -202,7 +291,18 @@ public:
|
|||||||
pfunc(thePool + i);
|
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)
|
virtual uint32_t AllocAddress(uint32_t parent, uint32_t is_hub = 0, uint32_t port = 0)
|
||||||
{
|
{
|
||||||
if (parent > 127 || port > 7)
|
if (parent > 127 || port > 7)
|
||||||
@ -223,7 +323,7 @@ public:
|
|||||||
if (is_hub)
|
if (is_hub)
|
||||||
{
|
{
|
||||||
thePool[index].address = 0x41;
|
thePool[index].address = 0x41;
|
||||||
hubCounter ++;
|
hubCounter++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
thePool[index].address = 1;
|
thePool[index].address = 1;
|
||||||
@ -238,52 +338,51 @@ public:
|
|||||||
if (is_hub)
|
if (is_hub)
|
||||||
{
|
{
|
||||||
addr.bmHub = 1;
|
addr.bmHub = 1;
|
||||||
addr.bmAddress = ++hubCounter;
|
addr.bmAddress = hubCounter++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
addr.bmHub = 0;
|
addr.bmHub = 0;
|
||||||
addr.bmAddress = port;
|
addr.bmAddress = port;
|
||||||
}
|
}
|
||||||
|
|
||||||
thePool[index].address = *((uint8_t*)&addr);
|
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;
|
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)
|
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)
|
if (addr == 0x41)
|
||||||
{
|
{
|
||||||
InitAllAddresses();
|
InitAllAddresses();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t index = FindAddressIndex(addr);
|
uint32_t index = FindAddressIndex(addr);
|
||||||
FreeAddressByIndex(index);
|
FreeAddressByIndex(index);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns number of hubs attached
|
// 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.
|
// 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;
|
return hubCounter;
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t GetNumDevices()
|
uint32_t GetNumDevices()
|
||||||
{
|
{
|
||||||
uint8_t counter = 0;
|
uint32_t counter = 0;
|
||||||
|
|
||||||
for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
|
for (uint32_t i = 1; i < MAX_DEVICES_ALLOWED; ++i)
|
||||||
if (thePool[i].address != 0);
|
if (thePool[i].address != 0);
|
||||||
counter ++;
|
counter++;
|
||||||
|
|
||||||
return counter;
|
return counter;
|
||||||
};*/
|
};*/
|
||||||
|
405
hardware/arduino/sam/system/USBHost/adk.cpp
Normal file
405
hardware/arduino/sam/system/USBHost/adk.cpp
Normal file
@ -0,0 +1,405 @@
|
|||||||
|
/* 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 */
|
||||||
|
|
||||||
|
#include "adk.h"
|
||||||
|
|
||||||
|
const uint32_t ADK::epDataInIndex = 1;
|
||||||
|
const uint32_t ADK::epDataOutIndex = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief ADK class constructor.
|
||||||
|
*/
|
||||||
|
ADK::ADK(USBHost *p, const char* pmanufacturer,
|
||||||
|
const char* pmodel,
|
||||||
|
const char* pdescription,
|
||||||
|
const char* pversion,
|
||||||
|
const char* puri,
|
||||||
|
const char* pserial) :
|
||||||
|
manufacturer(pmanufacturer),
|
||||||
|
model(pmodel),
|
||||||
|
description(pdescription),
|
||||||
|
version(pversion),
|
||||||
|
uri(puri),
|
||||||
|
serial(pserial),
|
||||||
|
pUsb(p),
|
||||||
|
bAddress(0),
|
||||||
|
bNumEP(1),
|
||||||
|
ready(false)
|
||||||
|
{
|
||||||
|
// Initialize endpoint data structures
|
||||||
|
for (uint32_t i = 0; i < ADK_MAX_ENDPOINTS; ++i)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register in USB subsystem
|
||||||
|
if (pUsb)
|
||||||
|
{
|
||||||
|
pUsb->RegisterDeviceClass(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);
|
||||||
|
}
|
150
hardware/arduino/sam/system/USBHost/adk.h
Normal file
150
hardware/arduino/sam/system/USBHost/adk.h
Normal file
@ -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 <stdint.h>
|
||||||
|
#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 */
|
@ -21,6 +21,11 @@ e-mail : support@circuitsathome.com
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "parsetools.h"
|
#include "parsetools.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class Abstract UsbConfigXtracter definition.
|
||||||
|
*
|
||||||
|
* \note This class is used for extracting USB endpoint descriptors.
|
||||||
|
*/
|
||||||
class UsbConfigXtracter
|
class UsbConfigXtracter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -32,7 +37,11 @@ public:
|
|||||||
#define CP_MASK_COMPARE_PROTOCOL 4
|
#define CP_MASK_COMPARE_PROTOCOL 4
|
||||||
#define CP_MASK_COMPARE_ALL 7
|
#define CP_MASK_COMPARE_ALL 7
|
||||||
|
|
||||||
// Configuration Descriptor Parser Class Template
|
/**
|
||||||
|
* \class ConfigDescParser definition.
|
||||||
|
*
|
||||||
|
* \note This class is used for parsing configuration descriptors.
|
||||||
|
*/
|
||||||
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
||||||
class ConfigDescParser : public USBReadParser
|
class ConfigDescParser : public USBReadParser
|
||||||
{
|
{
|
||||||
@ -62,6 +71,18 @@ public:
|
|||||||
virtual void Parse(const uint32_t len, const uint8_t *pbuf, const uint32_t &offset);
|
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 <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
||||||
ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ConfigDescParser(UsbConfigXtracter *xtractor) :
|
ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ConfigDescParser(UsbConfigXtracter *xtractor) :
|
||||||
theXtractor(xtractor),
|
theXtractor(xtractor),
|
||||||
@ -74,18 +95,37 @@ ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ConfigDescParser(Usb
|
|||||||
theSkipper.Initialize(&theBuffer);
|
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 <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
||||||
void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::Parse(const uint32_t len, const uint8_t *pbuf, const uint32_t &offset)
|
void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::Parse(const uint32_t len, const uint8_t *pbuf, const uint32_t &offset)
|
||||||
{
|
{
|
||||||
uint32_t cntdn = len;
|
uint32_t cntdn = len;
|
||||||
uint8_t *p = (uint8_t*)pbuf;
|
uint8_t *p = (uint8_t*)pbuf;
|
||||||
|
|
||||||
while(cntdn)
|
while (cntdn)
|
||||||
if (!ParseDescriptor(&p, &cntdn))
|
if (!ParseDescriptor(&p, &cntdn))
|
||||||
return;
|
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 <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
||||||
bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor(uint8_t **pp, uint32_t *pcntdn)
|
bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor(uint8_t **pp, uint32_t *pcntdn)
|
||||||
{
|
{
|
||||||
@ -112,102 +152,90 @@ bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor
|
|||||||
case 3:
|
case 3:
|
||||||
switch (dscrType)
|
switch (dscrType)
|
||||||
{
|
{
|
||||||
case USB_DESCRIPTOR_INTERFACE:
|
case USB_DESCRIPTOR_INTERFACE:
|
||||||
isGoodInterface = false;
|
isGoodInterface = false;
|
||||||
case USB_DESCRIPTOR_CONFIGURATION:
|
case USB_DESCRIPTOR_CONFIGURATION:
|
||||||
theBuffer.valueSize = sizeof(USB_CONFIGURATION_DESCRIPTOR) - 2;
|
theBuffer.valueSize = sizeof(USB_CONFIGURATION_DESCRIPTOR) - 2;
|
||||||
break;
|
break;
|
||||||
case USB_DESCRIPTOR_ENDPOINT:
|
case USB_DESCRIPTOR_ENDPOINT:
|
||||||
theBuffer.valueSize = sizeof(USB_ENDPOINT_DESCRIPTOR) - 2;
|
theBuffer.valueSize = sizeof(USB_ENDPOINT_DESCRIPTOR) - 2;
|
||||||
break;
|
break;
|
||||||
case HID_DESCRIPTOR_HID:
|
case HID_DESCRIPTOR_HID:
|
||||||
theBuffer.valueSize = dscrLen - 2;
|
theBuffer.valueSize = dscrLen - 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
valParser.Initialize(&theBuffer);
|
valParser.Initialize(&theBuffer);
|
||||||
stateParseDescr = 4;
|
stateParseDescr = 4;
|
||||||
case 4:
|
case 4:
|
||||||
switch (dscrType)
|
switch (dscrType)
|
||||||
{
|
{
|
||||||
case USB_DESCRIPTOR_CONFIGURATION:
|
case USB_DESCRIPTOR_CONFIGURATION:
|
||||||
if (!valParser.Parse(pp, pcntdn))
|
if (!valParser.Parse(pp, pcntdn))
|
||||||
return false;
|
return false;
|
||||||
confValue = ((USB_CONFIGURATION_DESCRIPTOR*)varBuffer)->bConfigurationValue;
|
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;
|
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;
|
isGoodInterface = true;
|
||||||
ifaceNumber = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceNumber;
|
ifaceNumber = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceNumber;
|
||||||
ifaceAltSet = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bAlternateSetting;
|
ifaceAltSet = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bAlternateSetting;
|
||||||
protoValue = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceProtocol;
|
protoValue = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceProtocol;
|
||||||
break;
|
break;
|
||||||
case USB_DESCRIPTOR_ENDPOINT:
|
case USB_DESCRIPTOR_ENDPOINT:
|
||||||
if (!valParser.Parse(pp, pcntdn))
|
if (!valParser.Parse(pp, pcntdn))
|
||||||
return false;
|
return false;
|
||||||
if (isGoodInterface)
|
if (isGoodInterface)
|
||||||
if (theXtractor)
|
if (theXtractor)
|
||||||
theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_ENDPOINT_DESCRIPTOR*)varBuffer);
|
theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_ENDPOINT_DESCRIPTOR*)varBuffer);
|
||||||
break;
|
break;
|
||||||
//case HID_DESCRIPTOR_HID:
|
//case HID_DESCRIPTOR_HID:
|
||||||
// if (!valParser.Parse(pp, pcntdn))
|
// if (!valParser.Parse(pp, pcntdn))
|
||||||
// return false;
|
// return false;
|
||||||
// PrintHidDescriptor((const USB_HID_DESCRIPTOR*)varBuffer);
|
// PrintHidDescriptor((const USB_HID_DESCRIPTOR*)varBuffer);
|
||||||
// break;
|
// break;
|
||||||
default:
|
default:
|
||||||
if (!theSkipper.Skip(pp, pcntdn, dscrLen-2))
|
if (!theSkipper.Skip(pp, pcntdn, dscrLen - 2))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
theBuffer.pValue = varBuffer;
|
theBuffer.pValue = varBuffer;
|
||||||
stateParseDescr = 0;
|
stateParseDescr = 0;
|
||||||
}
|
}
|
||||||
return true;
|
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 <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
||||||
void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc)
|
void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc)
|
||||||
{
|
{
|
||||||
/*Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"));
|
TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : bDescLength: %d\r\n", pDesc->bLength);)
|
||||||
Notify(PSTR("bDescLength:\t\t"));
|
TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : bDescriptorType: %d\r\n", pDesc->bDescriptorType);)
|
||||||
PrintHex<uint8_t>(pDesc->bLength);
|
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"));
|
for (uint32_t i = 0; i < pDesc->bNumDescriptors; ++i)
|
||||||
PrintHex<uint8_t>(pDesc->bDescriptorType);
|
|
||||||
|
|
||||||
Notify(PSTR("\r\nbcdHID:\t\t\t"));
|
|
||||||
PrintHex<uint16_t>(pDesc->bcdHID);
|
|
||||||
|
|
||||||
Notify(PSTR("\r\nbCountryCode:\t\t"));
|
|
||||||
PrintHex<uint8_t>(pDesc->bCountryCode);
|
|
||||||
|
|
||||||
Notify(PSTR("\r\nbNumDescriptors:\t"));
|
|
||||||
PrintHex<uint8_t>(pDesc->bNumDescriptors);
|
|
||||||
|
|
||||||
//Notify(PSTR("\r\nbDescrType:\t\t"));
|
|
||||||
//PrintHex<uint8_t>(pDesc->bDescrType);
|
|
||||||
//
|
|
||||||
//Notify(PSTR("\r\nwDescriptorLength:\t"));
|
|
||||||
//PrintHex<uint16_t>(pDesc->wDescriptorLength);
|
|
||||||
|
|
||||||
for (uint8_t i=0; i<pDesc->bNumDescriptors; i++)
|
|
||||||
{
|
{
|
||||||
HID_CLASS_DESCRIPTOR_LEN_AND_TYPE *pLT = (HID_CLASS_DESCRIPTOR_LEN_AND_TYPE*)&(pDesc->bDescrType);
|
HID_CLASS_DESCRIPTOR_LEN_AND_TYPE *pLT = (HID_CLASS_DESCRIPTOR_LEN_AND_TYPE*)&(pDesc->bDescrType);
|
||||||
|
|
||||||
Notify(PSTR("\r\nbDescrType:\t\t"));
|
TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : bDescrType: %d\r\n", pLT[i].bDescrType);)
|
||||||
PrintHex<uint8_t>(pLT[i].bDescrType);
|
TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : wDescriptorLength: %d\r\n", pLT[i].wDescriptorLength);)
|
||||||
|
|
||||||
Notify(PSTR("\r\nwDescriptorLength:\t"));
|
|
||||||
PrintHex<uint16_t>(pLT[i].wDescriptorLength);
|
|
||||||
}
|
}
|
||||||
Notify(PSTR("\r\n"));*/
|
|
||||||
printf("somebody save me!!!! orgazmo?!!!\r\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFDESCPARSER_H_INCLUDED */
|
#endif /* CONFDESCPARSER_H_INCLUDED */
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
#include "variant.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <adk.h>
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -95,7 +95,10 @@ e-mail : support@circuitsathome.com
|
|||||||
#define HID_PROTOCOL_KEYBOARD 0x01
|
#define HID_PROTOCOL_KEYBOARD 0x01
|
||||||
#define HID_PROTOCOL_MOUSE 0x02
|
#define HID_PROTOCOL_MOUSE 0x02
|
||||||
|
|
||||||
struct HidItemPrefix
|
/**
|
||||||
|
* \brief HidItemPrefix definition.
|
||||||
|
*/
|
||||||
|
struct HidItemPrefix // Not used
|
||||||
{
|
{
|
||||||
uint8_t bSize : 2;
|
uint8_t bSize : 2;
|
||||||
uint8_t bType : 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_SWITCH 5
|
||||||
#define HID_MAIN_ITEM_COLLECTION_USAGE_MODIFIER 6
|
#define HID_MAIN_ITEM_COLLECTION_USAGE_MODIFIER 6
|
||||||
|
|
||||||
struct MainItemIOFeature
|
/**
|
||||||
|
* \brief MainItemIOFeature definition.
|
||||||
|
*/
|
||||||
|
struct MainItemIOFeature // Not used
|
||||||
{
|
{
|
||||||
uint8_t bmIsConstantOrData : 1;
|
uint8_t bmIsConstantOrData : 1;
|
||||||
uint8_t bmIsArrayOrVariable : 1;
|
uint8_t bmIsArrayOrVariable : 1;
|
||||||
@ -139,6 +145,11 @@ struct MainItemIOFeature
|
|||||||
|
|
||||||
class HID;
|
class HID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class Abstract HIDReportParser definition.
|
||||||
|
*
|
||||||
|
* \note This class is used to implement HID report parsing.
|
||||||
|
*/
|
||||||
class HIDReportParser
|
class HIDReportParser
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -148,6 +159,9 @@ public:
|
|||||||
#define MAX_REPORT_PARSERS 2
|
#define MAX_REPORT_PARSERS 2
|
||||||
#define HID_MAX_HID_CLASS_DESCRIPTORS 5
|
#define HID_MAX_HID_CLASS_DESCRIPTORS 5
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class HID definition.
|
||||||
|
*/
|
||||||
class HID : public USBDeviceConfig, public UsbConfigXtracter
|
class HID : public USBDeviceConfig, public UsbConfigXtracter
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
@ -17,7 +17,14 @@ e-mail : support@circuitsathome.com
|
|||||||
|
|
||||||
#include "hid.h"
|
#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)
|
uint32_t HID::GetReportDescr(uint32_t ep, USBReadParser *parser)
|
||||||
{
|
{
|
||||||
const uint32_t constBufLen = 64;
|
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));
|
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)
|
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));
|
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)
|
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));
|
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)
|
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));
|
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)
|
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));
|
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)
|
/**
|
||||||
{
|
* \brief Print HID descriptor.
|
||||||
/*Notify(PSTR("Endpoint descriptor:"));
|
*
|
||||||
Notify(PSTR("\r\nLength:\t\t"));
|
* \note TRACE_USBHOST macro must be enabled. See Usb.h for reference.
|
||||||
PrintHex<uint8_t>(ep_ptr->bLength);
|
*
|
||||||
Notify(PSTR("\r\nType:\t\t"));
|
* \param pDesc Pointer to HID descriptor.
|
||||||
PrintHex<uint8_t>(ep_ptr->bDescriptorType);
|
*/
|
||||||
Notify(PSTR("\r\nAddress:\t"));
|
|
||||||
PrintHex<uint8_t>(ep_ptr->bEndpointAddress);
|
|
||||||
Notify(PSTR("\r\nAttributes:\t"));
|
|
||||||
PrintHex<uint8_t>(ep_ptr->bmAttributes);
|
|
||||||
Notify(PSTR("\r\nMaxPktSize:\t"));
|
|
||||||
PrintHex<uint16_t>(ep_ptr->wMaxPacketSize);
|
|
||||||
Notify(PSTR("\r\nPoll Intrv:\t"));
|
|
||||||
PrintHex<uint8_t>(ep_ptr->bInterval);*/
|
|
||||||
}
|
|
||||||
|
|
||||||
void HID::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc)
|
void HID::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc)
|
||||||
{
|
{
|
||||||
/* Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"));
|
TRACE_USBHOST(printf("HID::PrintHidDescriptor : bDescLength: %d\r\n", pDesc->bLength);)
|
||||||
Notify(PSTR("bDescLength:\t\t"));
|
TRACE_USBHOST(printf("HID::PrintHidDescriptor : bDescriptorType: %d\r\n", pDesc->bDescriptorType);)
|
||||||
PrintHex<uint8_t>(pDesc->bLength);
|
TRACE_USBHOST(printf("HID::PrintHidDescriptor : bcdHID: %d\r\n", pDesc->bcdHID);)
|
||||||
|
TRACE_USBHOST(printf("HID::PrintHidDescriptor : bCountryCode: %d\r\n", pDesc->bCountryCode);)
|
||||||
Notify(PSTR("\r\nbDescriptorType:\t"));
|
TRACE_USBHOST(printf("HID::PrintHidDescriptor : bNumDescriptors: %d\r\n", pDesc->bNumDescriptors);)
|
||||||
PrintHex<uint8_t>(pDesc->bDescriptorType);
|
TRACE_USBHOST(printf("HID::PrintHidDescriptor : bDescrType: %d\r\n", pDesc->bDescrType);)
|
||||||
|
TRACE_USBHOST(printf("HID::PrintHidDescriptor : wDescriptorLength: %d\r\n", pDesc->wDescriptorLength);)
|
||||||
Notify(PSTR("\r\nbcdHID:\t\t\t"));
|
|
||||||
PrintHex<uint16_t>(pDesc->bcdHID);
|
|
||||||
|
|
||||||
Notify(PSTR("\r\nbCountryCode:\t\t"));
|
|
||||||
PrintHex<uint8_t>(pDesc->bCountryCode);
|
|
||||||
|
|
||||||
Notify(PSTR("\r\nbNumDescriptors:\t"));
|
|
||||||
PrintHex<uint8_t>(pDesc->bNumDescriptors);
|
|
||||||
|
|
||||||
Notify(PSTR("\r\nbDescrType:\t\t"));
|
|
||||||
PrintHex<uint8_t>(pDesc->bDescrType);
|
|
||||||
|
|
||||||
Notify(PSTR("\r\nwDescriptorLength:\t"));
|
|
||||||
PrintHex<uint16_t>(pDesc->wDescriptorLength);*/
|
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,14 @@ e-mail : support@circuitsathome.com
|
|||||||
|
|
||||||
#include "hidboot.h"
|
#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)
|
void MouseReportParser::Parse(HID *hid, bool is_rpt_id, uint32_t len, uint8_t *buf)
|
||||||
{
|
{
|
||||||
MOUSEINFO *pmi = (MOUSEINFO*)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];
|
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)
|
void KeyboardReportParser::Parse(HID *hid, bool is_rpt_id, uint32_t len, uint8_t *buf)
|
||||||
{
|
{
|
||||||
// On error - return
|
// 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];
|
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 KeyboardReportParser::HandleLockingKeys(HID *hid, uint8_t key)
|
||||||
{
|
{
|
||||||
uint8_t old_keys = kbdLockingKeys.bLeds;
|
uint8_t old_keys = kbdLockingKeys.bLeds;
|
||||||
@ -109,6 +134,14 @@ const uint8_t KeyboardReportParser::symKeysUp[] = { '_', '+', '{', '}', '|', '~'
|
|||||||
const uint8_t KeyboardReportParser::symKeysLo[] = { '-', '=', '[', ']', '\\', ' ', ';', '\'', '`', ',', '.', '/' };
|
const uint8_t KeyboardReportParser::symKeysLo[] = { '-', '=', '[', ']', '\\', ' ', ';', '\'', '`', ',', '.', '/' };
|
||||||
const uint8_t KeyboardReportParser::padKeys[] = { '/', '*', '-', '+', 0x13 };
|
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 KeyboardReportParser::OemToAscii(uint8_t mod, uint8_t key)
|
||||||
{
|
{
|
||||||
uint8_t shift = (mod & 0x22);
|
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);
|
case KEY_PERIOD: return ((kbdLockingKeys.kbdLeds.bmNumLock == 1) ? '.' : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,9 @@ e-mail : support@circuitsathome.com
|
|||||||
#define KEY_ENTER 0x28
|
#define KEY_ENTER 0x28
|
||||||
#define KEY_PERIOD 0x63
|
#define KEY_PERIOD 0x63
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief MOUSEINFO definition.
|
||||||
|
*/
|
||||||
struct MOUSEINFO
|
struct MOUSEINFO
|
||||||
{
|
{
|
||||||
struct
|
struct
|
||||||
@ -44,6 +47,9 @@ struct MOUSEINFO
|
|||||||
int8_t dY;
|
int8_t dY;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class MouseReportParser definition.
|
||||||
|
*/
|
||||||
class MouseReportParser : public HIDReportParser
|
class MouseReportParser : public HIDReportParser
|
||||||
{
|
{
|
||||||
union
|
union
|
||||||
@ -65,6 +71,9 @@ protected:
|
|||||||
virtual void OnMiddleButtonDown (MOUSEINFO *mi) {};
|
virtual void OnMiddleButtonDown (MOUSEINFO *mi) {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief MODIFIERKEYS definition.
|
||||||
|
*/
|
||||||
struct MODIFIERKEYS
|
struct MODIFIERKEYS
|
||||||
{
|
{
|
||||||
uint8_t bmLeftCtrl : 1;
|
uint8_t bmLeftCtrl : 1;
|
||||||
@ -77,6 +86,9 @@ struct MODIFIERKEYS
|
|||||||
uint8_t bmRightGUI : 1;
|
uint8_t bmRightGUI : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief KBDINFO definition.
|
||||||
|
*/
|
||||||
struct KBDINFO
|
struct KBDINFO
|
||||||
{
|
{
|
||||||
struct
|
struct
|
||||||
@ -94,6 +106,9 @@ struct KBDINFO
|
|||||||
uint8_t Keys[6];
|
uint8_t Keys[6];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief KBDLEDS definition.
|
||||||
|
*/
|
||||||
struct KBDLEDS
|
struct KBDLEDS
|
||||||
{
|
{
|
||||||
uint8_t bmNumLock : 1;
|
uint8_t bmNumLock : 1;
|
||||||
@ -105,9 +120,18 @@ struct KBDLEDS
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define KEY_NUM_LOCK 0x53
|
#define KEY_NUM_LOCK 0x53
|
||||||
|
|
||||||
|
// Clear compiler warning
|
||||||
|
#ifdef KEY_CAPS_LOCK
|
||||||
|
#undef KEY_CAPS_LOCK
|
||||||
|
#endif
|
||||||
|
|
||||||
#define KEY_CAPS_LOCK 0x39
|
#define KEY_CAPS_LOCK 0x39
|
||||||
#define KEY_SCROLL_LOCK 0x47
|
#define KEY_SCROLL_LOCK 0x47
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class KeyboardReportParser definition.
|
||||||
|
*/
|
||||||
class KeyboardReportParser : public HIDReportParser
|
class KeyboardReportParser : public HIDReportParser
|
||||||
{
|
{
|
||||||
static const uint8_t numKeys[];
|
static const uint8_t numKeys[];
|
||||||
@ -146,6 +170,9 @@ protected:
|
|||||||
|
|
||||||
#define HID_MAX_HID_CLASS_DESCRIPTORS 5
|
#define HID_MAX_HID_CLASS_DESCRIPTORS 5
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class HIDBoot definition.
|
||||||
|
*/
|
||||||
template <const uint8_t BOOT_PROTOCOL>
|
template <const uint8_t BOOT_PROTOCOL>
|
||||||
class HIDBoot : public HID
|
class HIDBoot : public HID
|
||||||
{
|
{
|
||||||
@ -167,7 +194,7 @@ class HIDBoot : public HID
|
|||||||
public:
|
public:
|
||||||
HIDBoot(USBHost *p);
|
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
|
// USBDeviceConfig implementation
|
||||||
virtual uint32_t Init(uint32_t parent, uint32_t port, uint32_t lowspeed);
|
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);
|
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 <const uint8_t BOOT_PROTOCOL>
|
template <const uint8_t BOOT_PROTOCOL>
|
||||||
HIDBoot<BOOT_PROTOCOL>::HIDBoot(USBHost *p) :
|
HIDBoot<BOOT_PROTOCOL>::HIDBoot(USBHost *p) :
|
||||||
HID(p),
|
HID(p),
|
||||||
@ -192,21 +222,35 @@ HIDBoot<BOOT_PROTOCOL>::HIDBoot(USBHost *p) :
|
|||||||
pUsb->RegisterDeviceClass(this);
|
pUsb->RegisterDeviceClass(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Initialize HIDBoot class.
|
||||||
|
*/
|
||||||
template <const uint8_t BOOT_PROTOCOL>
|
template <const uint8_t BOOT_PROTOCOL>
|
||||||
void HIDBoot<BOOT_PROTOCOL>::Initialize()
|
void HIDBoot<BOOT_PROTOCOL>::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].maxPktSize = (i) ? 0 : 8;
|
||||||
epInfo[i].epAttribs = 0;
|
epInfo[i].epAttribs = 0;
|
||||||
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
|
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
|
||||||
}
|
}
|
||||||
|
|
||||||
bNumEP = 1;
|
bNumEP = 1;
|
||||||
bNumIface = 0;
|
bNumIface = 0;
|
||||||
bConfNum = 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 <const uint8_t BOOT_PROTOCOL>
|
template <const uint8_t BOOT_PROTOCOL>
|
||||||
uint32_t HIDBoot<BOOT_PROTOCOL>::Init(uint32_t parent, uint32_t port, uint32_t lowspeed)
|
uint32_t HIDBoot<BOOT_PROTOCOL>::Init(uint32_t parent, uint32_t port, uint32_t lowspeed)
|
||||||
{
|
{
|
||||||
@ -214,14 +258,16 @@ uint32_t HIDBoot<BOOT_PROTOCOL>::Init(uint32_t parent, uint32_t port, uint32_t l
|
|||||||
|
|
||||||
uint8_t buf[constBufSize];
|
uint8_t buf[constBufSize];
|
||||||
uint32_t rcode = 0;
|
uint32_t rcode = 0;
|
||||||
UsbDevice *p = NULL;
|
UsbDevice *p = 0;
|
||||||
EpInfo *oldep_ptr = NULL;
|
EpInfo *oldep_ptr = 0;
|
||||||
uint32_t len = 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();
|
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||||
|
|
||||||
|
TRACE_USBHOST(printf("HIDBoot::Init\r\n");)
|
||||||
|
|
||||||
if (bAddress)
|
if (bAddress)
|
||||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||||
|
|
||||||
@ -246,9 +292,9 @@ uint32_t HIDBoot<BOOT_PROTOCOL>::Init(uint32_t parent, uint32_t port, uint32_t l
|
|||||||
p->lowspeed = lowspeed;
|
p->lowspeed = lowspeed;
|
||||||
|
|
||||||
// Get device descriptor
|
// 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];
|
len = (buf[0] > constBufSize) ? constBufSize : buf[0];
|
||||||
|
|
||||||
if (rcode)
|
if (rcode)
|
||||||
@ -312,14 +358,12 @@ uint32_t HIDBoot<BOOT_PROTOCOL>::Init(uint32_t parent, uint32_t port, uint32_t l
|
|||||||
|
|
||||||
for (uint32_t i = 0; i < num_of_conf; ++i)
|
for (uint32_t i = 0; i < num_of_conf; ++i)
|
||||||
{
|
{
|
||||||
//HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
|
|
||||||
ConfigDescParser<
|
ConfigDescParser<
|
||||||
USB_CLASS_HID,
|
USB_CLASS_HID,
|
||||||
HID_BOOT_INTF_SUBCLASS,
|
HID_BOOT_INTF_SUBCLASS,
|
||||||
BOOT_PROTOCOL,
|
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);
|
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
|
||||||
|
|
||||||
if (bNumEP > 1)
|
if (bNumEP > 1)
|
||||||
@ -364,31 +408,41 @@ uint32_t HIDBoot<BOOT_PROTOCOL>::Init(uint32_t parent, uint32_t port, uint32_t l
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
FailGetDevDescr:
|
FailGetDevDescr:
|
||||||
//USBTRACE("getDevDescr:");
|
TRACE_USBHOST(printf("HIDBoot::Init getDevDescr : ");)
|
||||||
goto Fail;
|
goto Fail;
|
||||||
|
|
||||||
FailSetDevTblEntry:
|
FailSetDevTblEntry:
|
||||||
//USBTRACE("setDevTblEn:");
|
TRACE_USBHOST(printf("HIDBoot::Init setDevTblEn : ");)
|
||||||
goto Fail;
|
goto Fail;
|
||||||
|
|
||||||
FailSetProtocol:
|
FailSetProtocol:
|
||||||
//USBTRACE("SetProto:");
|
TRACE_USBHOST(printf("HIDBoot::Init SetProto : ");)
|
||||||
goto Fail;
|
goto Fail;
|
||||||
|
|
||||||
FailSetIdle:
|
FailSetIdle:
|
||||||
//USBTRACE("SetIdle:");
|
TRACE_USBHOST(printf("HIDBoot::Init SetIdle : ");)
|
||||||
goto Fail;
|
goto Fail;
|
||||||
|
|
||||||
FailSetConfDescr:
|
FailSetConfDescr:
|
||||||
//USBTRACE("setConf:");
|
TRACE_USBHOST(printf("HIDBoot::Init setConf : ");)
|
||||||
goto Fail;
|
goto Fail;
|
||||||
|
|
||||||
Fail:
|
Fail:
|
||||||
//Serial.println(rcode, HEX);
|
TRACE_USBHOST(printf("error code: %lu\r\n", rcode);)
|
||||||
Release();
|
Release();
|
||||||
return rcode;
|
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 <const uint8_t BOOT_PROTOCOL>
|
template <const uint8_t BOOT_PROTOCOL>
|
||||||
void HIDBoot<BOOT_PROTOCOL>::EndpointXtract(uint32_t conf, uint32_t iface, uint32_t alt, uint32_t proto, const USB_ENDPOINT_DESCRIPTOR *pep)
|
void HIDBoot<BOOT_PROTOCOL>::EndpointXtract(uint32_t conf, uint32_t iface, uint32_t alt, uint32_t proto, const USB_ENDPOINT_DESCRIPTOR *pep)
|
||||||
{
|
{
|
||||||
@ -396,41 +450,56 @@ void HIDBoot<BOOT_PROTOCOL>::EndpointXtract(uint32_t conf, uint32_t iface, uint3
|
|||||||
if (bNumEP > 1 && conf != bConfNum)
|
if (bNumEP > 1 && conf != bConfNum)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//ErrorMessage<uint8_t>(PSTR("\r\nConf.Val"), conf);
|
bConfNum = conf;
|
||||||
//ErrorMessage<uint8_t>(PSTR("Iface Num"), iface);
|
bIfaceNum = iface;
|
||||||
//ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
|
|
||||||
|
|
||||||
bConfNum = conf;
|
uint32_t index = 0;
|
||||||
bIfaceNum = iface;
|
uint32_t pipe = 0;
|
||||||
|
|
||||||
uint32_t index;
|
|
||||||
|
|
||||||
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
|
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
|
||||||
{
|
{
|
||||||
index = epInterruptInIndex;
|
index = epInterruptInIndex;
|
||||||
|
|
||||||
// Fill in the endpoint info structure
|
// 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].maxPktSize = (uint8_t)pep->wMaxPacketSize;
|
||||||
epInfo[index].epAttribs = 0;
|
epInfo[index].epAttribs = 0;
|
||||||
|
|
||||||
bNumEP++;
|
|
||||||
|
|
||||||
TRACE_USBHOST(printf("HIDBoot::EndpointXtract : Found new endpoint\r\n");)
|
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 : maxPktSize: %lu\r\n", epInfo[index].maxPktSize);)
|
||||||
TRACE_USBHOST(printf("HIDBoot::EndpointXtract : index: %lu\r\n", index);)
|
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 <const uint8_t BOOT_PROTOCOL>
|
template <const uint8_t BOOT_PROTOCOL>
|
||||||
uint32_t HIDBoot<BOOT_PROTOCOL>::Release()
|
uint32_t HIDBoot<BOOT_PROTOCOL>::Release()
|
||||||
{
|
{
|
||||||
|
// Free allocated host pipes
|
||||||
|
UHD_Pipe_Free(epInfo[epInterruptInIndex].hostPipeNum);
|
||||||
|
|
||||||
|
// Free allocated USB address
|
||||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||||
|
|
||||||
bConfNum = 0;
|
bConfNum = 0;
|
||||||
@ -439,9 +508,17 @@ uint32_t HIDBoot<BOOT_PROTOCOL>::Release()
|
|||||||
bAddress = 0;
|
bAddress = 0;
|
||||||
qNextPollTime = 0;
|
qNextPollTime = 0;
|
||||||
bPollEnable = false;
|
bPollEnable = false;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Poll USB device activity.
|
||||||
|
*
|
||||||
|
* \note Poll call is periodically made from USBHost.task().
|
||||||
|
*
|
||||||
|
* \return 0 on success, error code otherwise.
|
||||||
|
*/
|
||||||
template <const uint8_t BOOT_PROTOCOL>
|
template <const uint8_t BOOT_PROTOCOL>
|
||||||
uint32_t HIDBoot<BOOT_PROTOCOL>::Poll()
|
uint32_t HIDBoot<BOOT_PROTOCOL>::Poll()
|
||||||
{
|
{
|
||||||
@ -459,12 +536,10 @@ uint32_t HIDBoot<BOOT_PROTOCOL>::Poll()
|
|||||||
|
|
||||||
uint32_t read = epInfo[epInterruptInIndex].maxPktSize;
|
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)
|
||||||
{
|
{
|
||||||
//if (rcode != hrNAK)
|
|
||||||
//USBTRACE2("Poll:", rcode);
|
|
||||||
return rcode;
|
return rcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,6 +90,7 @@ e-mail : support@circuitsathome.com
|
|||||||
#define USB_FEATURE_ENDPOINT_STALL 0 // Endpoint recipient
|
#define USB_FEATURE_ENDPOINT_STALL 0 // Endpoint recipient
|
||||||
#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // Device recipient
|
#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // Device recipient
|
||||||
#define USB_FEATURE_TEST_MODE 2 // Device recipient
|
#define USB_FEATURE_TEST_MODE 2 // Device recipient
|
||||||
|
|
||||||
_Pragma("pack(1)")
|
_Pragma("pack(1)")
|
||||||
|
|
||||||
/* descriptor data structures */
|
/* descriptor data structures */
|
||||||
@ -147,7 +148,7 @@ typedef struct
|
|||||||
uint8_t bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT).
|
uint8_t bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT).
|
||||||
uint8_t bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN).
|
uint8_t bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN).
|
||||||
uint8_t bmAttributes; // Endpoint transfer type.
|
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.
|
uint8_t bInterval; // Polling interval in frames.
|
||||||
} USB_ENDPOINT_DESCRIPTOR;
|
} USB_ENDPOINT_DESCRIPTOR;
|
||||||
|
|
||||||
|
@ -55,17 +55,16 @@ typedef enum {
|
|||||||
|
|
||||||
//extern uhd_speed_t uhd_get_speed(void);
|
//extern uhd_speed_t uhd_get_speed(void);
|
||||||
|
|
||||||
|
|
||||||
extern void UHD_SetStack(void (*pf_isr)(void));
|
extern void UHD_SetStack(void (*pf_isr)(void));
|
||||||
extern void UHD_Init(void);
|
extern void UHD_Init(void);
|
||||||
extern void UHD_BusReset(void);
|
extern void UHD_BusReset(void);
|
||||||
extern uhd_vbus_state_t UHD_GetVBUSState(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_Pipe0_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 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_EP_Free(uint32_t add, uint32_t endp);
|
extern void UHD_Pipe_Free(uint32_t ul_pipe);
|
||||||
extern uint32_t UHD_EP_Read(uint32_t ul_ep, uint32_t ul_size, uint8_t* data);
|
extern uint32_t UHD_Pipe_Read(uint32_t ul_pipe, 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_Pipe_Write(uint32_t ul_pipe, uint32_t ul_size, uint8_t* data);
|
||||||
extern void UHD_EP_Send(uint32_t ul_ep, uint32_t ul_token_type);
|
extern void UHD_Pipe_Send(uint32_t ul_pipe, 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_Pipe_Is_Transfer_Complete(uint32_t ul_pipe, uint32_t ul_token_type);
|
||||||
|
|
||||||
#endif /* USB_HOST_H_INCLUDED */
|
#endif /* USB_HOST_H_INCLUDED */
|
||||||
|
@ -32,13 +32,17 @@
|
|||||||
|
|
||||||
#if SAM3XA_SERIES
|
#if SAM3XA_SERIES
|
||||||
|
|
||||||
#define TRACE_UOTGHS_HOST(x) x
|
//#define TRACE_UOTGHS_HOST(x) x
|
||||||
//#define TRACE_UOTGHS_HOST(x)
|
#define TRACE_UOTGHS_HOST(x)
|
||||||
|
|
||||||
extern void (*gpf_isr)(void);
|
extern void (*gpf_isr)(void);
|
||||||
|
|
||||||
|
// Handle UOTGHS Host driver state
|
||||||
static uhd_vbus_state_t uhd_state = UHD_STATE_NO_VBUS;
|
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)
|
static void UHD_ISR(void)
|
||||||
{
|
{
|
||||||
// Manage dis/connection event
|
// Manage dis/connection event
|
||||||
@ -74,7 +78,7 @@ static void UHD_ISR(void)
|
|||||||
{
|
{
|
||||||
TRACE_UOTGHS_HOST(printf(">>> UHD_ISR : VBUS error INT\r\n");)
|
TRACE_UOTGHS_HOST(printf(">>> UHD_ISR : VBUS error INT\r\n");)
|
||||||
uhd_ack_vbus_error_interrupt();
|
uhd_ack_vbus_error_interrupt();
|
||||||
uhd_state = UHD_STATE_ERROR;
|
uhd_state = UHD_STATE_DISCONNECTED; //UHD_STATE_ERROR;
|
||||||
return;
|
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))
|
void UHD_SetStack(void (*pf_isr)(void))
|
||||||
{
|
{
|
||||||
gpf_isr = pf_isr;
|
gpf_isr = pf_isr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Initialize the UOTGHS host driver.
|
||||||
|
*/
|
||||||
void UHD_Init(void)
|
void UHD_Init(void)
|
||||||
{
|
{
|
||||||
irqflags_t flags;
|
irqflags_t flags;
|
||||||
@ -178,7 +190,7 @@ void UHD_Init(void)
|
|||||||
|
|
||||||
// Enable main control interrupt
|
// Enable main control interrupt
|
||||||
// Connection, SOF and reset
|
// 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();
|
otg_freeze_clock();
|
||||||
|
|
||||||
@ -187,11 +199,19 @@ void UHD_Init(void)
|
|||||||
cpu_irq_restore(flags);
|
cpu_irq_restore(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Trigger a USB bus reset.
|
||||||
|
*/
|
||||||
void UHD_BusReset(void)
|
void UHD_BusReset(void)
|
||||||
{
|
{
|
||||||
uhd_start_reset();
|
uhd_start_reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get VBUS state.
|
||||||
|
*
|
||||||
|
* \return VBUS status.
|
||||||
|
*/
|
||||||
uhd_vbus_state_t UHD_GetVBUSState(void)
|
uhd_vbus_state_t UHD_GetVBUSState(void)
|
||||||
{
|
{
|
||||||
return uhd_state;
|
return uhd_state;
|
||||||
@ -224,7 +244,7 @@ uhd_vbus_state_t UHD_GetVBUSState(void)
|
|||||||
* \retval 0 success.
|
* \retval 0 success.
|
||||||
* \retval 1 error.
|
* \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)
|
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.
|
* \note UOTGHS maximum pipe number is limited to 10, meaning that only a limited
|
||||||
* \param ul_ep_size Actual size of the FIFO in bytes.
|
* 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.
|
* \param ul_dev_addr Address of remote device.
|
||||||
* \retval 1 error.
|
* \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;
|
||||||
|
|
||||||
/*
|
for (ul_pipe = 1; ul_pipe < UOTGHS_EPT_NUM; ++ul_pipe)
|
||||||
* 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))
|
|
||||||
{
|
{
|
||||||
// Pipe is already allocated
|
if (Is_uhd_pipe_enabled(ul_pipe))
|
||||||
return 0;
|
{
|
||||||
|
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;
|
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
|
// Unalloc pipe
|
||||||
for (uint8_t pipe = 0; pipe < UOTGHS_EPT_NUM; pipe++)
|
uhd_disable_pipe(ul_pipe);
|
||||||
{
|
uhd_unallocate_memory(ul_pipe);
|
||||||
if (!Is_uhd_pipe_enabled(pipe))
|
uhd_reset_pipe(ul_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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 *ptr_ep_data = 0;
|
||||||
uint8_t nb_byte_received = 0;
|
uint8_t nb_byte_received = 0;
|
||||||
uint32_t ul_nb_trans = 0;
|
uint32_t ul_nb_trans = 0;
|
||||||
|
|
||||||
// Get information to read data
|
// 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
|
// Copy data from pipe to payload buffer
|
||||||
while (ul_size && nb_byte_received) {
|
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;
|
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;
|
volatile uint8_t *ptr_ep_data = 0;
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
|
|
||||||
// Check pipe
|
// Check pipe
|
||||||
if (!Is_uhd_pipe_enabled(ul_ep))
|
if (!Is_uhd_pipe_enabled(ul_pipe))
|
||||||
{
|
{
|
||||||
// Endpoint not valid
|
// Endpoint not valid
|
||||||
TRACE_UOTGHS_HOST(printf("/!\\ UHD_EP_Send : pipe is not enabled!\r\n");)
|
TRACE_UOTGHS_HOST(printf("/!\\ UHD_EP_Send : pipe is not enabled!\r\n");)
|
||||||
return;
|
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)
|
for (i = 0; i < ul_size; ++i)
|
||||||
*ptr_ep_data++ = *data++;
|
*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
|
// Check pipe
|
||||||
if (!Is_uhd_pipe_enabled(ul_ep))
|
if (!Is_uhd_pipe_enabled(ul_pipe))
|
||||||
{
|
{
|
||||||
// Endpoint not valid
|
// 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set token type for zero length packet
|
// Set token type for zero length packet
|
||||||
// When actually using the FIFO, pipe token MUST be configured first
|
// 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
|
// Clear interrupt flags
|
||||||
uhd_ack_setup_ready(ul_ep);
|
uhd_ack_setup_ready(ul_pipe);
|
||||||
uhd_ack_in_received(ul_ep);
|
uhd_ack_in_received(ul_pipe);
|
||||||
uhd_ack_out_ready(ul_ep);
|
uhd_ack_out_ready(ul_pipe);
|
||||||
uhd_ack_short_packet(ul_ep);
|
uhd_ack_short_packet(ul_pipe);
|
||||||
|
uhd_ack_nak_received(ul_pipe);
|
||||||
|
|
||||||
// Send actual packet
|
// Send actual packet
|
||||||
uhd_ack_fifocon(ul_ep);
|
uhd_ack_fifocon(ul_pipe);
|
||||||
uhd_unfreeze_pipe(ul_ep);
|
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_pipe Pipe number.
|
||||||
* \param ul_ep_size Actual size of the FIFO in bytes.
|
* \param ul_token_type Token type.
|
||||||
*
|
*
|
||||||
* \retval 0 transfer is not complete.
|
* \retval 0 transfer is not complete.
|
||||||
* \retval 1 transfer is 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
|
// Check for transfer completion depending on token type
|
||||||
switch (ul_token_type)
|
switch (ul_token_type)
|
||||||
{
|
{
|
||||||
case UOTGHS_HSTPIPCFG_PTOKEN_SETUP:
|
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_freeze_pipe(ul_pipe);
|
||||||
uhd_ack_setup_ready(ul_ep);
|
uhd_ack_setup_ready(ul_pipe);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
case UOTGHS_HSTPIPCFG_PTOKEN_IN:
|
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,
|
// In case of low USB speed and with a high CPU frequency,
|
||||||
// a ACK from host can be always running on USB line
|
// a ACK from host can be always running on USB line
|
||||||
// then wait end of ACK on IN pipe.
|
// 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
|
// IN packet received
|
||||||
uhd_ack_in_received(ul_ep);
|
uhd_ack_in_received(ul_pipe);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
case UOTGHS_HSTPIPCFG_PTOKEN_OUT:
|
case UOTGHS_HSTPIPCFG_PTOKEN_OUT:
|
||||||
if (Is_uhd_out_ready(ul_ep))
|
if (Is_uhd_out_ready(ul_pipe))
|
||||||
{
|
{
|
||||||
// OUT packet sent
|
// OUT packet sent
|
||||||
uhd_freeze_pipe(ul_ep);
|
uhd_freeze_pipe(ul_pipe);
|
||||||
uhd_ack_out_ready(ul_ep);
|
uhd_ack_out_ready(ul_pipe);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nothing to report
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Binary file not shown.
@ -99,14 +99,14 @@ pwmc.o:
|
|||||||
00000000 T PWMC_SetSyncChannelUpdateUnlock
|
00000000 T PWMC_SetSyncChannelUpdateUnlock
|
||||||
00000000 T PWMC_WriteBuffer
|
00000000 T PWMC_WriteBuffer
|
||||||
U __assert_func
|
U __assert_func
|
||||||
00000000 r __func__.3296
|
00000000 r __func__.3295
|
||||||
00000000 r __func__.3307
|
00000000 r __func__.3306
|
||||||
00000000 r __func__.3322
|
00000000 r __func__.3321
|
||||||
00000000 r __func__.3333
|
00000000 r __func__.3332
|
||||||
00000000 r __func__.3344
|
00000000 r __func__.3343
|
||||||
00000000 r __func__.3351
|
00000000 r __func__.3350
|
||||||
00000000 r __func__.3435
|
00000000 r __func__.3434
|
||||||
00000000 r __func__.3441
|
00000000 r __func__.3440
|
||||||
|
|
||||||
rtc.o:
|
rtc.o:
|
||||||
00000000 T RTC_ClearSCCR
|
00000000 T RTC_ClearSCCR
|
||||||
@ -122,9 +122,9 @@ rtc.o:
|
|||||||
00000000 T RTC_SetTime
|
00000000 T RTC_SetTime
|
||||||
00000000 T RTC_SetTimeAlarm
|
00000000 T RTC_SetTimeAlarm
|
||||||
U __assert_func
|
U __assert_func
|
||||||
00000000 r __func__.3293
|
00000000 r __func__.3292
|
||||||
00000000 r __func__.3302
|
00000000 r __func__.3301
|
||||||
00000000 r __func__.3307
|
00000000 r __func__.3306
|
||||||
|
|
||||||
rtt.o:
|
rtt.o:
|
||||||
00000000 T RTT_EnableIT
|
00000000 T RTT_EnableIT
|
||||||
@ -133,8 +133,8 @@ rtt.o:
|
|||||||
00000000 T RTT_SetAlarm
|
00000000 T RTT_SetAlarm
|
||||||
00000000 T RTT_SetPrescaler
|
00000000 T RTT_SetPrescaler
|
||||||
U __assert_func
|
U __assert_func
|
||||||
00000000 r __func__.3300
|
00000000 r __func__.3299
|
||||||
00000000 r __func__.3308
|
00000000 r __func__.3307
|
||||||
|
|
||||||
spi.o:
|
spi.o:
|
||||||
00000000 T SPI_Configure
|
00000000 T SPI_Configure
|
||||||
@ -155,9 +155,9 @@ tc.o:
|
|||||||
00000000 T TC_Start
|
00000000 T TC_Start
|
||||||
00000000 T TC_Stop
|
00000000 T TC_Stop
|
||||||
U __assert_func
|
U __assert_func
|
||||||
00000000 r __func__.3295
|
00000000 r __func__.3294
|
||||||
00000000 r __func__.3301
|
00000000 r __func__.3300
|
||||||
00000000 r __func__.3307
|
00000000 r __func__.3306
|
||||||
|
|
||||||
timetick.o:
|
timetick.o:
|
||||||
00000000 T GetTickCount
|
00000000 T GetTickCount
|
||||||
@ -184,18 +184,18 @@ twi.o:
|
|||||||
00000000 T TWI_TransferComplete
|
00000000 T TWI_TransferComplete
|
||||||
00000000 T TWI_WriteByte
|
00000000 T TWI_WriteByte
|
||||||
U __assert_func
|
U __assert_func
|
||||||
00000000 r __func__.3660
|
00000000 r __func__.3659
|
||||||
00000000 r __func__.3675
|
00000000 r __func__.3674
|
||||||
00000000 r __func__.3679
|
00000000 r __func__.3678
|
||||||
00000000 r __func__.3686
|
00000000 r __func__.3685
|
||||||
00000000 r __func__.3690
|
00000000 r __func__.3689
|
||||||
00000000 r __func__.3695
|
00000000 r __func__.3694
|
||||||
00000000 r __func__.3703
|
00000000 r __func__.3702
|
||||||
00000000 r __func__.3717
|
00000000 r __func__.3716
|
||||||
00000000 r __func__.3722
|
00000000 r __func__.3721
|
||||||
00000000 r __func__.3726
|
00000000 r __func__.3725
|
||||||
00000000 r __func__.3731
|
00000000 r __func__.3730
|
||||||
00000000 r __func__.3735
|
00000000 r __func__.3734
|
||||||
|
|
||||||
usart.o:
|
usart.o:
|
||||||
00000000 T USART_Configure
|
00000000 T USART_Configure
|
||||||
@ -214,7 +214,7 @@ usart.o:
|
|||||||
00000000 T USART_Write
|
00000000 T USART_Write
|
||||||
00000000 T USART_WriteBuffer
|
00000000 T USART_WriteBuffer
|
||||||
U __assert_func
|
U __assert_func
|
||||||
00000000 r __func__.3581
|
00000000 r __func__.3580
|
||||||
|
|
||||||
wdt.o:
|
wdt.o:
|
||||||
00000000 T WDT_Disable
|
00000000 T WDT_Disable
|
||||||
@ -385,20 +385,19 @@ uotghs_device.o:
|
|||||||
|
|
||||||
uotghs_host.o:
|
uotghs_host.o:
|
||||||
00000000 T UHD_BusReset
|
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_GetVBUSState
|
||||||
00000000 t UHD_ISR
|
00000000 t UHD_ISR
|
||||||
00000000 T UHD_Init
|
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
|
00000000 T UHD_SetStack
|
||||||
U g_interrupt_enabled
|
U g_interrupt_enabled
|
||||||
U gpf_isr
|
U gpf_isr
|
||||||
U iprintf
|
|
||||||
U pmc_enable_periph_clk
|
U pmc_enable_periph_clk
|
||||||
U pmc_enable_udpck
|
U pmc_enable_udpck
|
||||||
U pmc_enable_upll_clock
|
U pmc_enable_upll_clock
|
||||||
|
Loading…
x
Reference in New Issue
Block a user