@ -145,9 +145,7 @@ uint8_t USB::ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bReque
uint16_t nak_limit = 0 ;
rcode = SetAddress ( addr , ep , & pep , & nak_limit ) ;
if ( rcode )
return rcode ;
if ( rcode ) return rcode ;
direction = ( ( bmReqType & 0x80 ) > 0 ) ;
@ -162,16 +160,11 @@ uint8_t USB::ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bReque
bytesWr ( rSUDFIFO , 8 , ( uint8_t * ) & setup_pkt ) ; //transfer to setup packet FIFO
rcode = dispatchPkt ( tokSETUP , ep , nak_limit ) ; //dispatch packet
if ( rcode ) return rcode ; // Return HRSLT if not zero
if ( rcode ) //return HRSLT if not zero
return ( rcode ) ;
if ( dataptr ! = NULL ) //data stage, if present
{
if ( direction ) //IN transfer
{
if ( dataptr ! = NULL ) { //data stage, if present
if ( direction ) { //IN transfer
uint16_t left = total ;
pep - > bmRcvToggle = 1 ; //bmRCVTOG1;
while ( left ) {
@ -186,25 +179,21 @@ uint8_t USB::ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bReque
continue ;
}
if ( rcode )
return rcode ;
if ( rcode ) return rcode ;
// Invoke callback function if inTransfer completed successfully and callback function pointer is specified
if ( ! rcode & & p )
( ( USBReadParser * ) p ) - > Parse ( read , dataptr , total - left ) ;
if ( ! rcode & & p ) ( ( USBReadParser * ) p ) - > Parse ( read , dataptr , total - left ) ;
left - = read ;
if ( read < nbytes )
break ;
if ( read < nbytes ) break ;
}
}
} else //OUT transfer
{
else { //OUT transfer
pep - > bmSndToggle = 1 ; //bmSNDTOG1;
rcode = OutTransfer ( pep , nak_limit , nbytes , dataptr ) ;
}
if ( rcode ) //return error
return ( rcode ) ;
if ( rcode ) return rcode ; // return error
}
// Status stage
return dispatchPkt ( ( direction ) ? tokOUTHS : tokINHS , ep , nak_limit ) ; //GET if direction
@ -220,7 +209,6 @@ uint8_t USB::inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t*
uint16_t nak_limit = 0 ;
uint8_t rcode = SetAddress ( addr , ep , & pep , & nak_limit ) ;
if ( rcode ) {
USBTRACE3 ( " (USB::InTransfer) SetAddress Failed " , rcode , 0x81 ) ;
USBTRACE3 ( " (USB::InTransfer) addr requested " , addr , 0x81 ) ;
@ -242,7 +230,7 @@ uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, ui
regWr ( rHCTL , ( pep - > bmRcvToggle ) ? bmRCVTOG1 : bmRCVTOG0 ) ; //set toggle value
// use a 'break' to exit this loop
while ( 1 ) {
for ( ; ; ) {
rcode = dispatchPkt ( tokIN , pep - > epAddr , nak_limit ) ; //IN packet to EP-'endpoint'. Function takes care of NAKS.
if ( rcode = = hrTOGERR ) {
// yes, we flip it wrong here so that next time it is actually correct!
@ -258,7 +246,7 @@ uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, ui
/* the only case when absence of RCVDAVIRQ makes sense is when toggle error occurred. Need to add handling for that */
if ( ( regRd ( rHIRQ ) & bmRCVDAVIRQ ) = = 0 ) {
//printf(">>>>>>>> Problem! NO RCVDAVIRQ!\r\n");
rcode = 0xf 0; //receive error
rcode = 0xF 0; //receive error
break ;
}
pktsize = regRd ( rRCVBC ) ; //number of received bytes
@ -273,9 +261,7 @@ uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, ui
}
int16_t mem_left = ( int16_t ) nbytes - * ( ( int16_t * ) nbytesptr ) ;
if ( mem_left < 0 )
mem_left = 0 ;
if ( mem_left < 0 ) mem_left = 0 ;
data = bytesRd ( rRCVFIFO , ( ( pktsize > mem_left ) ? mem_left : pktsize ) , data ) ;
@ -285,17 +271,17 @@ uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, ui
/* The transfer is complete under two conditions: */
/* 1. The device sent a short packet (L.T. maxPacketSize) */
/* 2. 'nbytes' have been transferred. */
if ( ( pktsize < maxpktsize ) | | ( * nbytesptr > = nbytes ) ) // have we transferred 'nbytes' bytes?
{
if ( pktsize < maxpktsize | | * nbytesptr > = nbytes ) { // Transferred 'nbytes' bytes?
// Save toggle value
pep - > bmRcvToggle = ( ( regRd ( rHRSL ) & bmRCVTOGRD ) ) ? 1 : 0 ;
//printf("\r\n");
rcode = 0 ;
break ;
} else if ( bInterval > 0 )
}
else if ( bInterval > 0 )
delay ( bInterval ) ; // Delay according to polling interval
} //while( 1 )
return ( rcode ) ;
}
return rcode ;
}
/* OUT transfer to arbitrary endpoint. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */
@ -307,9 +293,7 @@ uint8_t USB::outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dat
uint16_t nak_limit = 0 ;
uint8_t rcode = SetAddress ( addr , ep , & pep , & nak_limit ) ;
if ( rcode )
return rcode ;
if ( rcode ) return rcode ;
return OutTransfer ( pep , nak_limit , nbytes , data ) ;
}
@ -338,7 +322,7 @@ uint8_t USB::OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8
regWr ( rHXFR , ( tokOUT | pep - > epAddr ) ) ; //dispatch packet
while ( ! ( regRd ( rHIRQ ) & bmHXFRDNIRQ ) ) ; //wait for the completion IRQ
regWr ( rHIRQ , bmHXFRDNIRQ ) ; //clear IRQ
rcode = ( regRd ( rHRSL ) & 0x0 f ) ;
rcode = ( regRd ( rHRSL ) & 0x0 F ) ;
while ( rcode & & ( ( int32_t ) ( ( uint32_t ) millis ( ) - timeout ) < 0L ) ) {
switch ( rcode ) {
@ -361,7 +345,7 @@ uint8_t USB::OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8
break ;
default :
goto breakout ;
} //switch( rcode
}
/* process NAK according to Host out NAK bug */
regWr ( rSNDBC , 0 ) ;
@ -370,22 +354,23 @@ uint8_t USB::OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8
regWr ( rHXFR , ( tokOUT | pep - > epAddr ) ) ; //dispatch packet
while ( ! ( regRd ( rHIRQ ) & bmHXFRDNIRQ ) ) ; //wait for the completion IRQ
regWr ( rHIRQ , bmHXFRDNIRQ ) ; //clear IRQ
rcode = ( regRd ( rHRSL ) & 0x0 f ) ;
} // while( rcode && ....
rcode = ( regRd ( rHRSL ) & 0x0 F ) ;
} // while rcode && ....
bytes_left - = bytes_tosend ;
data_p + = bytes_tosend ;
} // while( bytes_left...
} // while bytes_left...
breakout :
pep - > bmSndToggle = ( regRd ( rHRSL ) & bmSNDTOGRD ) ? 1 : 0 ; //bmSNDTOG1 : bmSNDTOG0; //update toggle
return ( rcode ) ; //should be 0 in all cases
}
/* dispatch USB packet. Assumes peripheral address is set and relevant buffer is loaded/empty */
/* If NAK, tries to re-send up to nak_limit times */
/* If nak_limit == 0, do not count NAKs, exit after timeout */
/* If bus timeout, re-sends up to USB_RETRY_LIMIT times */
/* return codes 0x00-0x0 f are HRSLT( 0x00 being success ), 0xff means timeout */
/* return codes 0x00-0x0 F are HRSLT( 0x00 being success ), 0xFF means timeout */
uint8_t USB : : dispatchPkt ( uint8_t token , uint8_t ep , uint16_t nak_limit ) {
uint32_t timeout = ( uint32_t ) millis ( ) + USB_XFER_TIMEOUT ;
uint8_t tmpdata ;
@ -400,10 +385,9 @@ uint8_t USB::dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit) {
regWr ( rHXFR , ( token | ep ) ) ; //launch the transfer
rcode = USB_ERROR_TRANSFER_TIMEOUT ;
while ( ( int32_t ) ( ( uint32_t ) millis ( ) - timeout ) < 0L ) //wait for transfer completion
{
while ( ( int32_t ) ( ( uint32_t ) millis ( ) - timeout ) < 0L ) { //wait for transfer completion
# if defined(ESP8266) || defined(ESP32)
yield ( ) ; // needed in order to reset the watchdog timer on the ESP8266
yield ( ) ; // needed to reset the watchdog timer on the ESP8266
# endif
tmpdata = regRd ( rHIRQ ) ;
@ -411,14 +395,14 @@ uint8_t USB::dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit) {
regWr ( rHIRQ , bmHXFRDNIRQ ) ; //clear the interrupt
rcode = 0x00 ;
break ;
} //if( tmpdata & bmHXFRDNIRQ
}
} // while ( millis() < timeout
} // while millis() < timeout
//if (rcode != 0x00) //exit if timeout
// return ( rcode);
rcode = ( regRd ( rHRSL ) & 0x0 f ) ; //analyze transfer result
rcode = ( regRd ( rHRSL ) & 0x0 F ) ; //analyze transfer result
switch ( rcode ) {
case hrNAK :
@ -433,15 +417,14 @@ uint8_t USB::dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit) {
break ;
default :
return ( rcode ) ;
} //switch( rcode
}
} // while( timeout > millis()
return ( rcode ) ;
} // while timeout > millis()
return rcode ;
}
/* USB main task. Performs enumeration/cleanup */
void USB : : Task ( void ) //USB state machine
{
void USB : : Task ( void ) { //USB state machine
uint8_t rcode ;
uint8_t tmpdata ;
static uint32_t delay = 0 ;
@ -464,7 +447,6 @@ void USB::Task(void) //USB state machine
lowspeed = false ;
break ;
case LSHOST :
lowspeed = true ;
//intentional fallthrough
case FSHOST : //attached
@ -473,11 +455,10 @@ void USB::Task(void) //USB state machine
usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE ;
}
break ;
} // switch( tmpdata
}
for ( uint8_t i = 0 ; i < USB_NUMDEVICES ; i + + )
if ( devConfig [ i ] )
rcode = devConfig [ i ] - > Poll ( ) ;
if ( devConfig [ i ] ) rcode = devConfig [ i ] - > Poll ( ) ;
switch ( usb_task_state ) {
case USB_DETACHED_SUBSTATE_INITIALIZE :
@ -530,20 +511,19 @@ void USB::Task(void) //USB state machine
rcode = Configuring ( 0 , 0 , lowspeed ) ;
if ( rcode ) {
if ( rcode ! = USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE ) {
if ( ! rcode )
usb_task_state = USB_STATE_RUNNING ;
else if ( rcode ! = USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE ) {
usb_error = rcode ;
usb_task_state = USB_STATE_ERROR ;
}
} else
usb_task_state = USB_STATE_RUNNING ;
break ;
case USB_STATE_RUNNING :
break ;
case USB_STATE_ERROR :
//MAX3421E::Init();
break ;
} // switch( usb_task_state )
}
}
uint8_t USB : : DefaultAddressing ( uint8_t parent , uint8_t port , bool lowspeed ) {
@ -553,38 +533,28 @@ uint8_t USB::DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed) {
// Get pointer to pseudo device with address 0 assigned
p0 = addrPool . GetUsbDevicePtr ( 0 ) ;
if ( ! p0 ) return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL ;
if ( ! p0 - > epinfo ) return USB_ERROR_EPINFO_IS_NULL ;
if ( ! p0 )
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL ;
if ( ! p0 - > epinfo )
return USB_ERROR_EPINFO_IS_NULL ;
p0 - > lowspeed = ( lowspeed ) ? true : false ;
p0 - > lowspeed = lowspeed ;
// Allocate new address according to device class
uint8_t bAddress = addrPool . AllocAddress ( parent , false , port ) ;
if ( ! bAddress )
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL ;
if ( ! bAddress ) return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL ;
p = addrPool . GetUsbDevicePtr ( bAddress ) ;
if ( ! p )
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL ;
if ( ! p ) return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL ;
p - > lowspeed = lowspeed ;
// Assign new address to the device
rcode = setAddr ( 0 , 0 , bAddress ) ;
if ( rcode ) {
addrPool . FreeAddress ( bAddress ) ;
bAddress = 0 ;
}
return rcode ;
}
return 0 ;
} ;
uint8_t USB : : AttemptConfig ( uint8_t driver , uint8_t parent , uint8_t port , bool lowspeed ) {
//printf("AttemptConfig: parent = %i, port = %i\r\n", parent, port);
@ -597,15 +567,18 @@ again:
// Send a bus reset on the root interface.
regWr ( rHCTL , bmBUSRST ) ; //issue bus reset
delay ( 102 ) ; // delay 102ms, compensate for clock inaccuracy.
} else {
}
else {
// reset parent port
devConfig [ parent ] - > ResetHubPort ( port ) ;
}
} else if ( rcode = = hrJERR & & retries < 3 ) { // Some devices returns this when plugged in - trying to initialize the device again usually works
}
else if ( rcode = = hrJERR & & retries < 3 ) { // Some devices returns this when plugged in - trying to initialize the device again usually works
delay ( 100 ) ;
retries + + ;
goto again ;
} else if ( rcode )
}
else if ( rcode )
return rcode ;
rcode = devConfig [ driver ] - > Init ( parent , port , lowspeed ) ;
@ -614,13 +587,15 @@ again:
retries + + ;
goto again ;
}
if ( rcode ) {
// Issue a bus reset, because the device may be in a limbo state
if ( parent = = 0 ) {
// Send a bus reset on the root interface.
regWr ( rHCTL , bmBUSRST ) ; //issue bus reset
delay ( 102 ) ; // delay 102ms, compensate for clock inaccuracy.
} else {
}
else {
// reset parent port
devConfig [ parent ] - > ResetHubPort ( port ) ;
}
@ -628,11 +603,10 @@ again:
return rcode ;
}
/*
* This is broken . We need to enumerate differently .
/* *
* This is broken . It needs to enumerate differently .
* It causes major problems with several devices if detected in an unexpected order .
*
*
* Oleg - I wouldn ' t do anything before the newly connected device is considered sane .
* i . e . ( delays are not indicated for brevity ) :
* 1. reset
@ -718,10 +692,9 @@ uint8_t USB::Configuring(uint8_t parent, uint8_t port, bool lowspeed) {
// Allocate new address according to device class
//bAddress = addrPool.AllocAddress(parent, false, port);
uint16_t vid = udd - > idVendor ;
uint16_t pid = udd - > idProduct ;
uint8_t klass = udd - > bDeviceClass ;
uint8_t subklass = udd - > bDeviceSubClass ;
uint16_t vid = udd - > idVendor , pid = udd - > idProduct ;
uint8_t klass = udd - > bDeviceClass , subklass = udd - > bDeviceSubClass ;
// Attempt to configure if VID/PID or device class matches with a driver
// Qualify with subclass too.
//
@ -738,10 +711,7 @@ uint8_t USB::Configuring(uint8_t parent, uint8_t port, bool lowspeed) {
}
}
if ( devConfigIndex < USB_NUMDEVICES ) {
return rcode ;
}
if ( devConfigIndex < USB_NUMDEVICES ) return rcode ;
// blindly attempt to configure
for ( devConfigIndex = 0 ; devConfigIndex < USB_NUMDEVICES ; devConfigIndex + + ) {
@ -760,21 +730,18 @@ uint8_t USB::Configuring(uint8_t parent, uint8_t port, bool lowspeed) {
return rcode ;
}
}
// if we get here that means that the device class is not supported by any of registered classes
rcode = DefaultAddressing ( parent , port , lowspeed ) ;
return rcode ;
// Arriving here means the device class is unsupported by registered classes
return DefaultAddressing ( parent , port , lowspeed ) ;
}
uint8_t USB : : ReleaseDevice ( uint8_t addr ) {
if ( ! addr )
return 0 ;
if ( addr ) {
for ( uint8_t i = 0 ; i < USB_NUMDEVICES ; i + + ) {
if ( ! devConfig [ i ] ) continue ;
if ( devConfig [ i ] - > GetAddress ( ) = = addr )
return devConfig [ i ] - > Release ( ) ;
}
}
return 0 ;
}
@ -782,12 +749,12 @@ uint8_t USB::ReleaseDevice(uint8_t addr) {
//get device descriptor
uint8_t USB : : getDevDescr ( uint8_t addr , uint8_t ep , uint16_t nbytes , uint8_t * dataptr ) {
return ( ctrlReq( addr , ep , bmREQ_GET_DESCR , USB_REQUEST_GET_DESCRIPTOR , 0x00 , USB_DESCRIPTOR_DEVICE , 0x0000 , nbytes , nbytes , dataptr , NULL ) ) ;
return ctrlReq( addr , ep , bmREQ_GET_DESCR , USB_REQUEST_GET_DESCRIPTOR , 0x00 , USB_DESCRIPTOR_DEVICE , 0x0000 , nbytes , nbytes , dataptr , NULL ) ;
}
//get configuration descriptor
uint8_t USB : : getConfDescr ( uint8_t addr , uint8_t ep , uint16_t nbytes , uint8_t conf , uint8_t * dataptr ) {
return ( ctrlReq( addr , ep , bmREQ_GET_DESCR , USB_REQUEST_GET_DESCRIPTOR , conf , USB_DESCRIPTOR_CONFIGURATION , 0x0000 , nbytes , nbytes , dataptr , NULL ) ) ;
return ctrlReq( addr , ep , bmREQ_GET_DESCR , USB_REQUEST_GET_DESCRIPTOR , conf , USB_DESCRIPTOR_CONFIGURATION , 0x0000 , nbytes , nbytes , dataptr , NULL ) ;
}
/* Requests Configuration Descriptor. Sends two Get Conf Descr requests. The first one gets the total length of all descriptors, then the second one requests this
@ -798,21 +765,19 @@ uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser
USB_CONFIGURATION_DESCRIPTOR * ucd = reinterpret_cast < USB_CONFIGURATION_DESCRIPTOR * > ( buf ) ;
uint8_t ret = getConfDescr ( addr , ep , 9 , conf , buf ) ;
if ( ret )
return ret ;
if ( ret ) return ret ;
uint16_t total = ucd - > wTotalLength ;
//USBTRACE2("\r\ntotal conf.size:", total);
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
uint8_t USB : : getStrDescr ( uint8_t addr , uint8_t ep , uint16_t ns , 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 , NULL ) ) ;
return ctrlReq( addr , ep , bmREQ_GET_DESCR , USB_REQUEST_GET_DESCRIPTOR , index , USB_DESCRIPTOR_STRING , langid , ns , ns , dataptr , NULL ) ;
}
//set address
@ -821,12 +786,12 @@ uint8_t USB::setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr) {
//delay(2); //per USB 2.0 sect.9.2.6.3
delay ( 300 ) ; // Older spec says you should wait at least 200ms
return rcode ;
//return ( ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL) );
//return ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL);
}
//set configuration
uint8_t USB : : setConf ( uint8_t addr , uint8_t ep , uint8_t conf_value ) {
return ( ctrlReq( addr , ep , bmREQ_SET , USB_REQUEST_SET_CONFIGURATION , conf_value , 0x00 , 0x0000 , 0x0000 , 0x0000 , NULL , NULL ) ) ;
return ctrlReq( addr , ep , bmREQ_SET , USB_REQUEST_SET_CONFIGURATION , conf_value , 0x00 , 0x0000 , 0x0000 , 0x0000 , NULL , NULL ) ;
}
# endif // defined(USB_METHODS_INLINE)