avrpins with mega1280/2560 support

This commit is contained in:
Oleg Mazurov 2011-03-01 11:26:31 -07:00
parent e238472454
commit 600e5c3a07
10 changed files with 2013 additions and 368 deletions

681
Usb.cpp
View file

@ -5,11 +5,12 @@
#include "usbhost.h"
#include "Usb.h"
#include "WProgram.h"
//#include <ptpdebug.h>
static uint8_t usb_error = 0;
static uint8_t usb_task_state;
DEV_RECORD devtable[ USB_NUMDEVICES + 1 ];
EP_RECORD dev0ep; //Endpoint data structure used during enumeration for uninitialized device
//DEV_RECORD devtable[ USB_NUMDEVICES + 1 ];
//EP_RECORD dev0ep; //Endpoint data structure used during enumeration for uninitialized device
/* constructor */
@ -19,19 +20,23 @@ USB::USB ()
usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; //set up state machine
init();
}
/* Initialize data structures */
void USB::init()
{
uint8_t i;
for( i = 0; i < ( USB_NUMDEVICES + 1 ); i++ ) {
devtable[ i ].epinfo = NULL; //clear device table
devtable[ i ].devclass = 0;
}
devtable[ 0 ].epinfo = &dev0ep; //set single ep for uninitialized device
// not necessary dev0ep.MaxPktSize = 8; //minimum possible
dev0ep.sndToggle = bmSNDTOG0; //set DATA0/1 toggles to 0
dev0ep.rcvToggle = bmRCVTOG0;
devConfigIndex = 0;
//UsbDevice *p = addrPool.GetUsbDevicePtr(0);
//if (p)
//{
// p->epinfo = &dev0ep;
// dev0ep.sndToggle = bmSNDTOG0; //set DATA0/1 toggles to 0
// dev0ep.rcvToggle = bmRCVTOG0;
//}
}
uint8_t USB::getUsbTaskState( void )
{
return( usb_task_state );
@ -42,17 +47,30 @@ void USB::setUsbTaskState( uint8_t state )
}
EP_RECORD* USB::getDevTableEntry( uint8_t addr, uint8_t ep )
{
EP_RECORD* ptr;
ptr = devtable[ addr ].epinfo;
ptr += ep;
return( ptr );
UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
if (p)
return (p->epinfo + ep);
return NULL;
}
/* set device table entry */
/* each device is different and has different number of endpoints. This function plugs endpoint record structure, defined in application, to devtable */
void USB::setDevTableEntry( uint8_t addr, EP_RECORD* eprecord_ptr )
uint8_t USB::setDevTableEntry( uint8_t addr, EP_RECORD* eprecord_ptr )
{
devtable[ addr ].epinfo = eprecord_ptr;
//return();
if (!eprecord_ptr)
return USB_ERROR_INVALID_ARGUMENT;
UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
if (!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
p->address = addr;
p->devclass = 0;
p->epinfo = eprecord_ptr;
return 0;
}
/* Control transfer. Sets address, endpoint, fills control packet with necessary data, dispatches control packet, and initiates bulk IN transfer, */
/* depending on request. Actual requests are defined as inlines */
@ -61,14 +79,15 @@ void USB::setDevTableEntry( uint8_t addr, EP_RECORD* eprecord_ptr )
/* 01-0f = non-zero HRSLT */
uint8_t USB::ctrlReq( uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, unsigned int wInd, unsigned int nbytes, uint8_t* dataptr, unsigned int nak_limit )
{
boolean direction = false; //request direction, IN or OUT
uint8_t rcode;
SETUP_PKT setup_pkt;
boolean direction = false; //request direction, IN or OUT
uint8_t rcode;
SETUP_PKT setup_pkt;
regWr( rPERADDR, addr ); //set peripheral address
if( bmReqType & 0x80 )
direction = true; //determine request direction
regWr( rPERADDR, addr ); //set peripheral address
if( bmReqType & 0x80 ) {
direction = true; //determine request direction
}
/* fill in setup packet */
setup_pkt.ReqType_u.bmRequestType = bmReqType;
setup_pkt.bRequest = bRequest;
@ -100,7 +119,7 @@ uint8_t USB::ctrlReq( uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequ
/* Assumed peripheral address is already set */
uint8_t USB::ctrlStatus( uint8_t ep, boolean direction, unsigned int nak_limit )
{
uint8_t rcode;
uint8_t rcode;
if( direction ) { //GET
rcode = dispatchPkt( tokOUTHS, ep, nak_limit );
}
@ -112,17 +131,34 @@ uint8_t USB::ctrlStatus( uint8_t ep, boolean direction, unsigned int nak_limit )
/* Control transfer with data stage. Stages 2 and 3 of control transfer. Assumes preipheral address is set and setup packet has been sent */
uint8_t USB::ctrlData( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t* dataptr, boolean direction, unsigned int nak_limit )
{
uint8_t rcode;
if( direction ) { //IN transfer
devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG1;
rcode = inTransfer( addr, ep, nbytes, dataptr, nak_limit );
return( rcode );
}
else { //OUT transfer
devtable[ addr ].epinfo[ ep ].sndToggle = bmSNDTOG1;
rcode = outTransfer( addr, ep, nbytes, dataptr, nak_limit );
return( rcode );
}
uint8_t rcode;
UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
//Serial.print("cD");
//Serial.print("\tA:");
//Serial.print(addr, HEX);
//Serial.print("\tE:");
//Serial.println(ep, HEX);
if (!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if (!p->epinfo)
return USB_ERROR_EPINFO_IS_NULL;
EP_RECORD *pep = &p->epinfo[ep];
if( direction ) //IN transfer
{
pep->rcvToggle = bmRCVTOG1;
rcode = inTransfer( addr, ep, nbytes, dataptr, nak_limit );
}
else //OUT transfer
{
pep->sndToggle = bmSNDTOG1;
rcode = outTransfer( addr, ep, nbytes, dataptr, nak_limit );
}
return( rcode );
}
/* IN transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */
/* Keep sending INs and writes data to memory area pointed by 'data' */
@ -130,16 +166,33 @@ uint8_t USB::ctrlData( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t* d
fe USB xfer timeout */
uint8_t USB::inTransfer( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t* data, unsigned int nak_limit )
{
uint8_t rcode;
uint8_t pktsize;
uint8_t maxpktsize = devtable[ addr ].epinfo[ ep ].MaxPktSize;
unsigned int xfrlen = 0;
regWr( rHCTL, devtable[ addr ].epinfo[ ep ].rcvToggle ); //set toggle value
while( 1 ) { // use a 'return' to exit this loop
uint8_t rcode;
uint8_t pktsize;
//Serial.println("iT");
UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
if (!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if (!p->epinfo)
return USB_ERROR_EPINFO_IS_NULL;
EP_RECORD *pep = &p->epinfo[ep];
uint8_t maxpktsize = pep->MaxPktSize;
unsigned int xfrlen = 0;
regWr( rHCTL, pep->rcvToggle ); //set toggle value
while( 1 ) // use a 'return' to exit this loop
{
rcode = dispatchPkt( tokIN, ep, nak_limit ); //IN packet to EP-'endpoint'. Function takes care of NAKS.
if( rcode ) {
if( rcode )
return( rcode ); //should be 0, indicating ACK. Else return error code.
}
/* 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 ) {
@ -152,16 +205,16 @@ uint8_t USB::inTransfer( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t*
/* 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 ) || (xfrlen >= nbytes )) { // have we transferred 'nbytes' bytes?
if( regRd( rHRSL ) & bmRCVTOGRD ) { //save toggle value
devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG1;
}
else {
devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG0;
}
return( 0 );
}
}//while( 1 )
if (( pktsize < maxpktsize ) || (xfrlen >= nbytes )) // have we transferred 'nbytes' bytes?
{
if( regRd( rHRSL ) & bmRCVTOGRD ) //save toggle value
pep->rcvToggle = bmRCVTOG1;
else
pep->rcvToggle = bmRCVTOG0;
return( 0 );
} // if
} //while( 1 )
}
/* OUT transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */
/* Handles NAK bug per Maxim Application Note 4000 for single buffer transfer */
@ -169,59 +222,77 @@ uint8_t USB::inTransfer( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t*
/* major part of this function borrowed from code shared by Richard Ibbotson */
uint8_t USB::outTransfer( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t* data, unsigned int nak_limit )
{
uint8_t rcode, retry_count;
uint8_t* data_p = data; //local copy of the data pointer
unsigned int bytes_tosend, nak_count;
unsigned int bytes_left = nbytes;
uint8_t maxpktsize = devtable[ addr ].epinfo[ ep ].MaxPktSize;
unsigned long timeout = millis() + USB_XFER_TIMEOUT;
uint8_t rcode, retry_count;
uint8_t* data_p = data; //local copy of the data pointer
unsigned int bytes_tosend, nak_count;
unsigned int bytes_left = nbytes;
if (!maxpktsize) { //todo: move this check close to epinfo init. Make it 1< pktsize <64
return 0xFE;
}
UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
regWr( rHCTL, devtable[ addr ].epinfo[ ep ].sndToggle ); //set toggle value
while( bytes_left ) {
retry_count = 0;
nak_count = 0;
bytes_tosend = ( bytes_left >= maxpktsize ) ? maxpktsize : bytes_left;
bytesWr( rSNDFIFO, bytes_tosend, data_p ); //filling output FIFO
regWr( rSNDBC, bytes_tosend ); //set number of bytes
regWr( rHXFR, ( tokOUT | ep )); //dispatch packet
while(!(regRd( rHIRQ ) & bmHXFRDNIRQ )); //wait for the completion IRQ
regWr( rHIRQ, bmHXFRDNIRQ ); //clear IRQ
rcode = ( regRd( rHRSL ) & 0x0f );
while( rcode && ( timeout > millis())) {
switch( rcode ) {
case hrNAK:
nak_count++;
if( nak_limit && ( nak_count == USB_NAK_LIMIT )) {
return( rcode); //return NAK
}
break;
case hrTIMEOUT:
retry_count++;
if( retry_count == USB_RETRY_LIMIT ) {
return( rcode ); //return TIMEOUT
}
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 | ep )); //dispatch packet
while(!(regRd( rHIRQ ) & bmHXFRDNIRQ )); //wait for the completion IRQ
regWr( rHIRQ, bmHXFRDNIRQ ); //clear IRQ
rcode = ( regRd( rHRSL ) & 0x0f );
}//while( rcode && ....
bytes_left -= bytes_tosend;
data_p += bytes_tosend;
}//while( bytes_left...
devtable[ addr ].epinfo[ ep ].sndToggle = ( regRd( rHRSL ) & bmSNDTOGRD ) ? bmSNDTOG1 : bmSNDTOG0; //update toggle
return( rcode ); //should be 0 in all cases
if (!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
EP_RECORD *pep = p->epinfo + ep;
if (!p->epinfo)
return USB_ERROR_EPINFO_IS_NULL;
uint8_t maxpktsize = pep->MaxPktSize;
unsigned long timeout = millis() + USB_XFER_TIMEOUT;
if (!maxpktsize) { //todo: move this check close to epinfo init. Make it 1< pktsize <64
return 0xFE;
}
regWr( rHCTL, pep->sndToggle ); //set toggle value
while( bytes_left )
{
retry_count = 0;
nak_count = 0;
bytes_tosend = ( bytes_left >= maxpktsize ) ? maxpktsize : bytes_left;
bytesWr( rSNDFIFO, bytes_tosend, data_p ); //filling output FIFO
regWr( rSNDBC, bytes_tosend ); //set number of bytes
regWr( rHXFR, ( tokOUT | ep )); //dispatch packet
while(!(regRd( rHIRQ ) & bmHXFRDNIRQ )); //wait for the completion IRQ
regWr( rHIRQ, bmHXFRDNIRQ ); //clear IRQ
rcode = ( regRd( rHRSL ) & 0x0f );
while( rcode && ( timeout > millis()))
{
switch( rcode )
{
case hrNAK:
nak_count++;
if( nak_limit && ( nak_count == USB_NAK_LIMIT ))
{
return( rcode); //return NAK
}
break;
case hrTIMEOUT:
retry_count++;
if( retry_count == USB_RETRY_LIMIT ) {
return( rcode ); //return TIMEOUT
}
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 | ep )); //dispatch packet
while(!(regRd( rHIRQ ) & bmHXFRDNIRQ )); //wait for the completion IRQ
regWr( rHIRQ, bmHXFRDNIRQ ); //clear IRQ
rcode = ( regRd( rHRSL ) & 0x0f );
}//while( rcode && ....
bytes_left -= bytes_tosend;
data_p += bytes_tosend;
}//while( bytes_left...
pep->sndToggle = ( regRd( rHRSL ) & bmSNDTOGRD ) ? 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 */
@ -285,7 +356,8 @@ void USB::Task( void ) //USB state machine
tmpdata = getVbusState();
/* modify USB task state if Vbus changed */
switch( tmpdata ) {
switch( tmpdata )
{
case SE1: //illegal state
usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL;
break;
@ -296,90 +368,399 @@ void USB::Task( void ) //USB state machine
break;
case FSHOST: //attached
case LSHOST:
//Serial.println("FSHOST");
if(( usb_task_state & USB_STATE_MASK ) == USB_STATE_DETACHED ) {
delay = millis() + USB_SETTLE_DELAY;
usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE;
}
break;
}// switch( tmpdata
//Serial.print("USB task state: ");
//Serial.println( usb_task_state, HEX );
}// switch( tmpdata
for (uint8_t i=0; i<USB_NUMDEVICES; i++)
{
if (devConfig[i])
{
rcode = devConfig[i]->Poll();
}
} //for
switch( usb_task_state ) {
case USB_DETACHED_SUBSTATE_INITIALIZE:
Serial.println("INIT");
init();
usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE;
break;
case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE: //just sit here
Serial.println("WFD");
break;
case USB_DETACHED_SUBSTATE_ILLEGAL: //just sit here
Serial.println("ILL");
break;
case USB_ATTACHED_SUBSTATE_SETTLE: //setlle time for just attached device
Serial.println("STL");
if( delay < millis() ) {
usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE;
}
break;
case USB_ATTACHED_SUBSTATE_RESET_DEVICE:
regWr( rHCTL, bmBUSRST ); //issue bus reset
Serial.println("RES");
regWr( rHCTL, bmBUSRST ); //issue bus reset
usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE;
break;
case USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE:
if(( regRd( rHCTL ) & bmBUSRST ) == 0 ) {
Serial.println("RCOMP");
if(( regRd( rHCTL ) & bmBUSRST ) == 0 )
{
tmpdata = regRd( rMODE ) | bmSOFKAENAB; //start SOF generation
regWr( rMODE, tmpdata );
// regWr( rMODE, bmSOFKAENAB );
usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF;
delay = millis() + 20; //20ms wait after reset per USB spec
}
break;
case USB_ATTACHED_SUBSTATE_WAIT_SOF: //todo: change check order
Serial.println("WSOF");
if( regRd( rHIRQ ) & bmFRAMEIRQ ) { //when first SOF received we can continue
if( delay < millis() ) { //20ms passed
usb_task_state = USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE;
if( delay < millis() ) { //20ms passed
usb_task_state = USB_STATE_ADDRESSING;
//usb_task_state = USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE;
}
}
break;
case USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE:
// toggle( BPNT_0 );
devtable[ 0 ].epinfo->MaxPktSize = 8; //set max.packet size to min.allowed
rcode = getDevDescr( 0, 0, 8, (uint8_t*)&buf );
if( rcode == 0 ) {
devtable[ 0 ].epinfo->MaxPktSize = buf.bMaxPacketSize0;
usb_task_state = USB_STATE_ADDRESSING;
}
else {
usb_error = USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE;
usb_task_state = USB_STATE_ERROR;
}
break;
case USB_STATE_ADDRESSING:
for( i = 1; i < USB_NUMDEVICES; i++ ) {
if( devtable[ i ].epinfo == NULL ) {
devtable[ i ].epinfo = devtable[ 0 ].epinfo; //set correct MaxPktSize
//temporary record
//until plugged with real device endpoint structure
rcode = setAddr( 0, 0, i );
if( rcode == 0 ) {
tmpaddr = i;
usb_task_state = USB_STATE_CONFIGURING;
}
else {
usb_error = USB_STATE_ADDRESSING; //set address error
usb_task_state = USB_STATE_ERROR;
}
break; //break if address assigned or error occured during address assignment attempt
}
} //for( i = 1; i < USB_NUMDEVICES; i++)
Serial.println("ADR");
if( usb_task_state == USB_STATE_ADDRESSING ) { //no vacant place in devtable
usb_error = 0xfe;
usb_task_state = USB_STATE_ERROR;
}
rcode = Addressing(&tmpaddr);
if (rcode == hrSUCCESS)
usb_task_state = USB_STATE_CONFIGURING;
else
{
usb_error = rcode;
usb_task_state = USB_STATE_ERROR;
}
break;
case USB_STATE_CONFIGURING:
Serial.print("CNF");
rcode = Configuring(tmpaddr);
if (rcode)
{
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:
Serial.println("RUN");
break;
case USB_STATE_ERROR:
break;
}// switch( usb_task_state
} // switch( usb_task_state )
}
uint8_t USB::Addressing(uint8_t *address)
{
uint8_t rcode = hrSUCCESS, buf[8];
Serial.println("Adrsng");
UsbDevice *p = addrPool.GetUsbDevicePtr(0);
if (!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if (!p->epinfo)
{
Serial.println("epinfo");
return USB_ERROR_EPINFO_IS_NULL;
}
Serial.print("addr:");
Serial.println(p->address, HEX);
Serial.print("ep:");
Serial.println(p->epinfo->epAddr, HEX);
//p->epinfo->MaxPktSize = 8;
Serial.print("Max:");
Serial.println(p->epinfo->MaxPktSize, HEX);
rcode = getDevDescr( 0, 0, 8, (uint8_t*)buf );
if( rcode == 0 )
{
Serial.println("OK!");
p->epinfo->MaxPktSize = ((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
p->devclass = ((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass;
}
else
{
Serial.println("getDevDesc:");
return rcode;
}
uint8_t addr = addrPool.AllocAddress(0, (p->devclass == 0x09) ? true : false);
if (!addr)
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
Serial.print("Addr:");
Serial.println(addr,HEX);
rcode = setAddr( 0, 0, addr );
if (!rcode)
{
*address = addr;
}
else
{
Serial.print("setAddr:");
Serial.println(rcode, HEX);
return rcode;
}
return rcode;
}
uint8_t USB::Configuring(uint8_t addr)
{
static uint8_t dev_index = 0;
uint8_t rcode = 0, buf[8];
for (; devConfigIndex<USB_NUMDEVICES; devConfigIndex++)
{
rcode = devConfig[devConfigIndex]->Init(addr);
Serial.println(".");
if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED)
{
// in case of an error dev_index should be reset to 0
// in order to start from the very beginning the
// next time the program gets here
if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE)
devConfigIndex = 0;
return rcode;
}
}
// if we get here that means that the device class is not supported by any of registered classes
devConfigIndex = 0;
return 0;
}
//class UsbHub
//{
// uint8_t bNbrPorts; // Number of ports
// uint8_t portStates[HUB_MAX_PORTS]; // State of each port a hub has
//};
//
//struct HubPort
//{
// UsbDevAddress *hubAddr;
// uint8_t numPort;
// uint8_t portState;
//};
//static uint8_t USB::PortTask(HubPort *phub_port, uint8_t sig)
////static uint8_t USB::PortTask(uint8_t hub_addr, uint8_t port, uint8_t &state, uint8_t sig)
//{
// switch(state)
// {
// case USB_STATE_HUB_PORT_POWERED_OFF:
// Serial.println("POWERED_OFF");
//
// for (uint8_t j=1; j<=hubs[0].bNbrPorts; j++)
// HubPortPowerOn(hubs[0].bAddress, j);
//
// delay = millis() + USB_SETTLE_DELAY;
// usb_task_state = USB_STATE_HUB_PORT_WAIT_FOR_POWER_GOOD;
// break;
// case USB_STATE_HUB_PORT_WAIT_FOR_POWER_GOOD:
// Serial.println("WAIT_FOR_POWER_GOOD");
// if (millis() >= delay)
// usb_task_state = USB_STATE_HUB_PORT_DISCONNECTED;
//// usb_task_state = USB_STATE_HUB_PORT_DISABLED;
// break;
// case USB_STATE_HUB_PORT_DISCONNECTED:
// Serial.println("PORT_DISCONNECTED");
//
// for (uint8_t j=1; j<=hubs[0].bNbrPorts; j++)
// HubClearPortFeatures(hubs[0].bAddress, j, HUB_FEATURE_PORT_ENABLE | HUB_FEATURE_C_PORT_CONNECTION);
//
// usb_task_state = USB_STATE_HUB_PORT_DISABLED;
// break;
// case USB_STATE_HUB_PORT_DISABLED:
// Serial.println("PORT_DISABLED");
//
// for (uint8_t j=1; j<=hubs[0].bNbrPorts; j++)
// HubPortReset(hubs[0].bAddress, j);
//
// delay = millis() + HUB_PORT_RESET_DELAY;
// usb_task_state = USB_STATE_HUB_PORT_RESETTING;
// break;
// case USB_STATE_HUB_PORT_RESETTING:
// Serial.println("PORT_RESETTING");
// if (millis() >= delay)
// usb_task_state = USB_STATE_HUB_PORT_ENABLED;
// break;
// case USB_STATE_HUB_PORT_ENABLED:
// Serial.println("PORT_ENABLED");
// usb_task_state = USB_STATE_RUNNING;
// break;
// }
// return 0;
//}
uint8_t USB::HubPortPowerOn(uint8_t addr, uint8_t port)
{
uint8_t rcode = SetPortFeature(addr, 0, HUB_FEATURE_PORT_POWER, port, 0);
if (rcode)
{
Serial.print("PORT #");
Serial.print(port, DEC);
Serial.print(" pwr err:");
Serial.println(rcode,HEX);
}
return rcode;
}
uint8_t USB::HubPortReset(uint8_t addr, uint8_t port)
{
uint8_t rcode = SetPortFeature(addr, 0, HUB_FEATURE_PORT_RESET, port, 0);
if (rcode)
{
Serial.print("PORT #");
Serial.print(port, DEC);
Serial.print(" rst err:");
Serial.println(rcode,HEX);
}
return rcode;
}
uint8_t USB::HubClearPortFeatures(uint8_t addr, uint8_t port, uint8_t bm_features)
{
uint8_t rcode = ClearPortFeature(addr, 0, bm_features, port, 0);
if (rcode)
{
Serial.print("PORT #");
Serial.print(port, DEC);
Serial.print(" f.clr err:");
Serial.println(rcode,HEX);
}
return rcode;
}
#if 0
// Hub Polling
uint8_t USB::PollHub()
{
uint8_t rcode;
uint8_t buf[8];
// uint8_t inTransfer( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t* data, unsigned int nak_limit = USB_NAK_LIMIT );
//Serial.println(devtable[1].epinfo->epAddr, HEX);
rcode = inTransfer(1, 0x1 /*devtable[1].epinfo->epAddr*/, 1, buf, 1);
if (rcode)
{
Serial.print("inTransfer:");
Serial.println(rcode, HEX);
return rcode;
}
Serial.print("Int:");
Serial.println(buf[0],HEX);
//return 0;
if (buf[0] & 0x01) // Hub Status Change
{
PrintHubStatus(1);
//rcode = GetHubStatus(1, 0, 1, 4, buf);
//if (rcode)
//{
// Serial.print("GetHubStatus Error");
// Serial.println(rcode, HEX);
// return rcode;
//}
}
if (buf[0] & 0x02) // Port 1
{
rcode = GetPortStatus(1, 0, 1, 4, buf);
if (rcode)
{
Serial.print("GetPortStatus Error");
Serial.println(rcode, HEX);
return rcode;
}
if (buf[2] & bmHUB_PORT_STATUS_C_PORT_RESET)
{
Serial.println("PORT_RESET");
rcode = ClearPortFeature(1, 0, 1, HUB_FEATURE_C_PORT_RESET);
if (rcode)
{
Serial.print("ClearPortFeature Error");
Serial.println(rcode, HEX);
return rcode;
}
//usb_task_state = USB_STATE_HUB_PORT_ENABLED; //USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE;
return 0;
}
if (buf[2] & bmHUB_PORT_STATUS_C_PORT_CONNECTION)
{
Serial.println("PORT_CONNECTION");
rcode = ClearPortFeature(1, 0, 1, HUB_FEATURE_C_PORT_CONNECTION);
if (rcode)
{
Serial.print("ClearPortFeature Error");
Serial.println(rcode, HEX);
return rcode;
}
// //if (buf & bmHUB_PORT_STATUS_PORT_CONNECTION)
// // usb_task_state = USB_STATE_HUB_PORT_DISABLED;
// //else
// // usb_task_state = USB_STATE_RUNNING;
}
} // if (buf[0] & 0x02) // Port 1
}
#endif
void USB::PrintHubStatus(/*USB *usbptr,*/ uint8_t addr)
{
uint8_t rcode = 0;
uint8_t buf[4];
rcode = /*usbptr->*/GetHubStatus(addr, 0, 4, (uint8_t*)&buf);
if (rcode)
{
Serial.print("ERROR:");
Serial.println(rcode, HEX);
return;
}
Serial.println("\r\nHub");
Serial.println("\r\nStatus");
Serial.print("Local Pwr Src:\t");
Serial.println((buf[0] & bmHUB_STATUS_LOCAL_POWER_SOURCE) > 0, DEC);
Serial.print("Over-current:\t");
Serial.println((buf[0] & bmHUB_STATUS_OVER_CURRENT) > 0, DEC);
Serial.println("\r\nChanges");
Serial.print("Local Pwr Src:\t");
Serial.println((buf[2] & bmHUB_STATUS_C_LOCAL_POWER_SOURCE) > 0, DEC);
Serial.print("Over-current:\t");
Serial.println((buf[2] & bmHUB_STATUS_C_OVER_CURRENT) > 0, DEC);
Serial.println("");
}

309
Usb.h
View file

@ -7,27 +7,155 @@
#include "max3421e.h"
#include "usbhost.h"
#include "usb_ch9.h"
#include "address.h"
#include <WProgram.h>
/* Common setup data constant combinations */
#define bmREQ_GET_DESCR USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //get descriptor request type
#define bmREQ_SET USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //set request type for all but 'set feature' and 'set interface'
#define bmREQ_CL_GET_INTF USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE //get interface request type
/* HID requests */
#define bmREQ_HIDOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
#define bmREQ_HIDIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
#define bmREQ_HIDREPORT USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_INTERFACE
#define USB_XFER_TIMEOUT 5000 //USB transfer timeout in milliseconds, per section 9.2.6.1 of USB 2.0 spec
#define USB_NAK_LIMIT 32000 //NAK limit for a transfer. o meand NAKs are not counted
#define USB_RETRY_LIMIT 3 //retry limit for a transfer
#define USB_SETTLE_DELAY 200 //settle delay in milliseconds
#define USB_NAK_NOWAIT 1 //used in Richard's PS2/Wiimote code
#define USB_NUMDEVICES 2 //number of USB devices
// D7 data transfer direction (0 - host-to-device, 1 - device-to-host)
// D6-5 Type (0- standard, 1 - class, 2 - vendor, 3 - reserved)
// D4-0 Recipient (0 - device, 1 - interface, 2 - endpoint, 3 - other, 4..31 - reserved)
// USB Device Classes
#define USB_CLASS_USE_CLASS_INFO 0x00 // Use Class Info in the Interface Descriptors
#define USB_CLASS_AUDIO 0x01 // Audio
#define USB_CLASS_COM_AND_CDC_CTRL 0x02 // Communications and CDC Control
#define USB_CLASS_HID 0x03 // HID
#define USB_CLASS_PHYSICAL 0x05 // Physical
#define USB_CLASS_IMAGE 0x06 // Image
#define USB_CLASS_PRINTER 0x07 // Printer
#define USB_CLASS_MASS_STORAGE 0x08 // Mass Storage
#define USB_CLASS_HUB 0x09 // Hub
#define USB_CLASS_CDC_DATA 0x0a // CDC-Data
#define USB_CLASS_SMART_CARD 0x0b // Smart-Card
#define USB_CLASS_CONTENT_SECURITY 0x0d // Content Security
#define USB_CLASS_VIDEO 0x0e // Video
#define USB_CLASS_PERSONAL_HEALTH 0x0f // Personal Healthcare
#define USB_CLASS_DIAGNOSTIC_DEVICE 0xdc // Diagnostic Device
#define USB_CLASS_WIRELESS_CTRL 0xe0 // Wireless Controller
#define USB_CLASS_MISC 0xef // Miscellaneous
#define USB_CLASS_APP_SPECIFIC 0xfe // Application Specific
#define USB_CLASS_VENDOR_SPECIFIC 0xff // Vendor Specific
// Hub Requests
#define bmREQ_CLEAR_HUB_FEATURE USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
#define bmREQ_CLEAR_PORT_FEATURE USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
#define bmREQ_CLEAR_TT_BUFFER USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
#define bmREQ_GET_HUB_DESCRIPTOR USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
#define bmREQ_GET_HUB_STATUS USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
#define bmREQ_GET_PORT_STATUS USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
#define bmREQ_RESET_TT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
#define bmREQ_SET_HUB_DESCRIPTOR USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
#define bmREQ_SET_HUB_FEATURE USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
#define bmREQ_SET_PORT_FEATURE USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
#define bmREQ_GET_TT_STATE USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
#define bmREQ_STOP_TT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
// Hub Class Requests
#define HUB_REQUEST_CLEAR_TT_BUFFER 8
#define HUB_REQUEST_RESET_TT 9
#define HUB_REQUEST_GET_TT_STATE 10
#define HUB_REQUEST_STOP_TT 11
// Hub Features
#define HUB_FEATURE_C_HUB_LOCAL_POWER 0
#define HUB_FEATURE_C_HUB_OVER_CURRENT 1
#define HUB_FEATURE_PORT_CONNECTION 0
#define HUB_FEATURE_PORT_ENABLE 1
#define HUB_FEATURE_PORT_SUSPEND 2
#define HUB_FEATURE_PORT_OVER_CURRENT 3
#define HUB_FEATURE_PORT_RESET 4
#define HUB_FEATURE_PORT_POWER 8
#define HUB_FEATURE_PORT_LOW_SPEED 9
#define HUB_FEATURE_C_PORT_CONNECTION 16
#define HUB_FEATURE_C_PORT_ENABLE 17
#define HUB_FEATURE_C_PORT_SUSPEND 18
#define HUB_FEATURE_C_PORT_OVER_CURRENT 19
#define HUB_FEATURE_C_PORT_RESET 20
#define HUB_FEATURE_PORT_TEST 21
#define HUB_FEATURE_PORT_INDICATOR 22
// Hub Port Test Modes
#define HUB_PORT_TEST_MODE_J 1
#define HUB_PORT_TEST_MODE_K 2
#define HUB_PORT_TEST_MODE_SE0_NAK 3
#define HUB_PORT_TEST_MODE_PACKET 4
#define HUB_PORT_TEST_MODE_FORCE_ENABLE 5
// Hub Port Indicator Color
#define HUB_PORT_INDICATOR_AUTO 0
#define HUB_PORT_INDICATOR_AMBER 1
#define HUB_PORT_INDICATOR_GREEN 2
#define HUB_PORT_INDICATOR_OFF 3
// Hub Port Status Bitmasks
#define bmHUB_PORT_STATUS_PORT_CONNECTION 0x0001
#define bmHUB_PORT_STATUS_PORT_ENABLE 0x0002
#define bmHUB_PORT_STATUS_PORT_SUSPEND 0x0004
#define bmHUB_PORT_STATUS_PORT_OVER_CURRENT 0x0008
#define bmHUB_PORT_STATUS_PORT_RESET 0x0010
#define bmHUB_PORT_STATUS_PORT_POWER 0x0100
#define bmHUB_PORT_STATUS_PORT_LOW_SPEED 0x0200
#define bmHUB_PORT_STATUS_PORT_HIGH_SPEED 0x0400
#define bmHUB_PORT_STATUS_PORT_TEST 0x0800
#define bmHUB_PORT_STATUS_PORT_INDICATOR 0x1000
// Hub Port Status Change Bitmasks (used one byte instead of two)
#define bmHUB_PORT_STATUS_C_PORT_CONNECTION 0x0001
#define bmHUB_PORT_STATUS_C_PORT_ENABLE 0x0002
#define bmHUB_PORT_STATUS_C_PORT_SUSPEND 0x0004
#define bmHUB_PORT_STATUS_C_PORT_OVER_CURRENT 0x0008
#define bmHUB_PORT_STATUS_C_PORT_RESET 0x0010
// Hub Status Bitmasks (used one byte instead of two)
#define bmHUB_STATUS_LOCAL_POWER_SOURCE 0x01
#define bmHUB_STATUS_OVER_CURRENT 0x12
// Hub Status Change Bitmasks (used one byte instead of two)
#define bmHUB_STATUS_C_LOCAL_POWER_SOURCE 0x01
#define bmHUB_STATUS_C_OVER_CURRENT 0x12
// Additional Error Codes
#define USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED 0xD1
#define USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE 0xD2
#define USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS 0xD3
#define USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL 0xD4
#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL 0xD5
#define USB_ERROR_EPINFO_IS_NULL 0xD6
#define USB_ERROR_INVALID_ARGUMENT 0xD7
class USBDeviceConfig
{
public:
virtual uint8_t Init(uint8_t addr) = 0;
virtual uint8_t Release(uint8_t addr) = 0;
virtual uint8_t Poll() = 0;
};
#define USB_XFER_TIMEOUT 5000 //USB transfer timeout in milliseconds, per section 9.2.6.1 of USB 2.0 spec
#define USB_NAK_LIMIT 32000 //NAK limit for a transfer. o meand NAKs are not counted
#define USB_RETRY_LIMIT 3 //retry limit for a transfer
#define USB_SETTLE_DELAY 200 //settle delay in milliseconds
#define USB_NAK_NOWAIT 1 //used in Richard's PS2/Wiimote code
#define USB_NUMDEVICES 6 //number of USB devices
#define HUB_MAX_HUBS 5 // maximum number of hubs that can be attached to the host controller
#define HUB_PORT_RESET_DELAY 20 // hub port reset delay 10 ms recomended, can be up to 20 ms
/* USB state machine states */
#define USB_STATE_MASK 0xf0
#define USB_STATE_DETACHED 0x10
@ -44,6 +172,7 @@
#define USB_STATE_RUNNING 0x90
#define USB_STATE_ERROR 0xa0
// byte usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE
/* USB Setup Packet Structure */
@ -56,7 +185,7 @@ typedef struct {
uint8_t direction: 1; // Direction of data X-fer
};
}ReqType_u;
uint8_t bRequest; // 1 Request
uint8_t bRequest; // 1 Request
union {
unsigned int wValue; // 2 Depends on bRequest
struct {
@ -68,26 +197,38 @@ typedef struct {
unsigned int wLength; // 6 Depends on bRequest
} SETUP_PKT, *PSETUP_PKT;
/* Endpoint information structure */
/* bToggle of endpoint 0 initialized to 0xff */
/* during enumeration bToggle is set to 00 */
typedef struct {
uint8_t epAddr; //copy from endpoint descriptor. Bit 7 indicates direction ( ignored for control endpoints )
uint8_t Attr; // Endpoint transfer type.
unsigned int MaxPktSize; // Maximum packet size.
uint8_t Interval; // Polling interval in frames.
uint8_t sndToggle; //last toggle value, bitmask for HCTL toggle bits
uint8_t rcvToggle; //last toggle value, bitmask for HCTL toggle bits
/* not sure if both are necessary */
} EP_RECORD;
/* device record structure */
typedef struct {
EP_RECORD* epinfo; //device endpoint information
uint8_t devclass; //device class
typedef struct
{
EP_RECORD *epinfo; //device endpoint information
uint8_t devclass; //device class
} DEV_RECORD;
typedef MAX3421e<P10, P9> MAX3421E;
struct HubDescriptor
{
uint8_t bDescLength; // descriptor length
uint8_t bDescriptorType; // descriptor type
uint8_t bNbrPorts; // number of ports a hub equiped with
struct
{
uint16_t LogPwrSwitchMode : 2;
uint16_t CompoundDevice : 1;
uint16_t OverCurrentProtectMode : 2;
uint16_t TTThinkTime : 2;
uint16_t PortIndicatorsSupported : 1;
uint16_t Reserved : 8;
};
uint8_t bPwrOn2PwrGood;
uint8_t bHubContrCurrent;
};
//typedef MAX3421e<P6, P3> MAX3421E; // Black Widdow
typedef MAX3421e<P10, P9> MAX3421E; // Duemielanove
class USB : public MAX3421E
{
@ -101,14 +242,39 @@ class USB : public MAX3421E
//byte usb_task_state;
AddressPoolImpl<USB_NUMDEVICES> addrPool;
USBDeviceConfig* devConfig[USB_NUMDEVICES];
uint8_t devConfigIndex;
public:
USB( void );
uint8_t getUsbTaskState( void );
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev)
{
for (uint8_t i=0; i<USB_NUMDEVICES; i++)
{
if (!devConfig[i])
{
devConfig[i] = pdev;
return 0;
}
}
return USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS;
};
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc)
{
addrPool.ForEachUsbDevice(pfunc);
};
uint8_t getUsbTaskState( void );
void setUsbTaskState( uint8_t state );
EP_RECORD* getDevTableEntry( uint8_t addr, uint8_t ep );
void setDevTableEntry( uint8_t addr, EP_RECORD* eprecord_ptr );
uint8_t setDevTableEntry( uint8_t addr, EP_RECORD* eprecord_ptr );
uint8_t ctrlReq( uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, unsigned int wInd, unsigned int nbytes, uint8_t* dataptr, unsigned int nak_limit = USB_NAK_LIMIT );
/* Control requests */
/* Control requests */
uint8_t getDevDescr( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t* dataptr, unsigned int nak_limit = USB_NAK_LIMIT );
uint8_t getConfDescr( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t conf, uint8_t* dataptr, unsigned int nak_limit = USB_NAK_LIMIT );
uint8_t getStrDescr( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t index, unsigned int langid, uint8_t* dataptr, unsigned int nak_limit = USB_NAK_LIMIT );
@ -119,7 +285,7 @@ class USB : public MAX3421E
uint8_t getProto( uint8_t addr, uint8_t ep, uint8_t interface, uint8_t* dataptr, unsigned int nak_limit = USB_NAK_LIMIT );
uint8_t getReportDescr( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t* dataptr, unsigned int nak_limit = USB_NAK_LIMIT );
uint8_t setReport( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t interface, uint8_t report_type, uint8_t report_id, uint8_t* dataptr, unsigned int nak_limit = USB_NAK_LIMIT );
uint8_t getReport( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t interface, uint8_t report_type, uint8_t report_id, uint8_t* dataptr, unsigned int nak_limit = USB_NAK_LIMIT );
uint8_t getReport( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t interface, uint8_t report_type, uint8_t report_id, uint8_t* dataptr, unsigned int nak_limit = USB_NAK_LIMIT );
uint8_t getIdle( uint8_t addr, uint8_t ep, uint8_t interface, uint8_t reportID, uint8_t* dataptr, unsigned int nak_limit = USB_NAK_LIMIT );
uint8_t setIdle( uint8_t addr, uint8_t ep, uint8_t interface, uint8_t reportID, uint8_t duration, unsigned int nak_limit = USB_NAK_LIMIT );
/**/
@ -128,19 +294,46 @@ class USB : public MAX3421E
uint8_t inTransfer( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t* data, unsigned int nak_limit = USB_NAK_LIMIT );
uint8_t outTransfer( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t* data, unsigned int nak_limit = USB_NAK_LIMIT );
uint8_t dispatchPkt( uint8_t token, uint8_t ep, unsigned int nak_limit = USB_NAK_LIMIT );
// Hub Methods
uint8_t ClearHubFeature( uint8_t addr, uint8_t ep, uint8_t fid, unsigned int nak_limit = USB_NAK_LIMIT );
uint8_t ClearPortFeature( uint8_t addr, uint8_t ep, uint8_t fid, uint8_t port, uint8_t sel = 0, unsigned int nak_limit = USB_NAK_LIMIT );
uint8_t GetHubDescriptor( uint8_t addr, uint8_t ep, uint8_t index, uint16_t nbytes, uint8_t *dataptr, unsigned int nak_limit = USB_NAK_LIMIT );
uint8_t GetHubStatus( uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr, unsigned int nak_limit = USB_NAK_LIMIT );
uint8_t GetPortStatus( uint8_t addr, uint8_t ep, uint8_t port, uint16_t nbytes, uint8_t* dataptr, unsigned int nak_limit = USB_NAK_LIMIT );
uint8_t SetHubDescriptor( uint8_t addr, uint8_t ep, uint8_t port, uint16_t nbytes, uint8_t* dataptr, unsigned int nak_limit = USB_NAK_LIMIT );
uint8_t SetHubFeature( uint8_t addr, uint8_t ep, uint8_t fid, unsigned int nak_limit = USB_NAK_LIMIT );
uint8_t SetPortFeature( uint8_t addr, uint8_t ep, uint8_t fid, uint8_t port, uint8_t sel = 0, unsigned int nak_limit = USB_NAK_LIMIT );
uint8_t HubPortPowerOn(uint8_t addr, uint8_t port);
uint8_t HubPortReset(uint8_t addr, uint8_t port);
uint8_t HubClearPortFeatures(uint8_t addr, uint8_t port, uint8_t bm_features);
uint8_t GetNumDevices();
uint8_t GetNumHubs();
uint8_t PollHubs();
uint8_t PollHub();
void PrintHubStatus(/*USB *usbptr,*/ uint8_t addr);
void Task( void );
//uint8_t nit() {};
uint8_t Addressing(uint8_t *address);
uint8_t Configuring(uint8_t addr);
private:
void init();
};
//get device descriptor
inline uint8_t USB::getDevDescr( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t* dataptr, unsigned int nak_limit ) {
return( ctrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, dataptr, nak_limit ));
}
//get configuration descriptor
inline uint8_t USB::getConfDescr( uint8_t addr, uint8_t ep, unsigned int nuint8_ts, uint8_t conf, uint8_t* dataptr, unsigned int nak_limit ) {
return( ctrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nuint8_ts, dataptr, nak_limit ));
inline uint8_t USB::getConfDescr( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t conf, uint8_t* dataptr, unsigned int nak_limit ) {
return( ctrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, dataptr, nak_limit ));
}
//get string descriptor
inline uint8_t USB::getStrDescr( uint8_t addr, uint8_t ep, unsigned int nuint8_ts, uint8_t index, unsigned int langid, uint8_t* dataptr, unsigned int nak_limit ) {
@ -178,4 +371,58 @@ inline uint8_t USB::getIdle( uint8_t addr, uint8_t ep, uint8_t interface, uint8_
inline uint8_t USB::setIdle( uint8_t addr, uint8_t ep, uint8_t interface, uint8_t reportID, uint8_t duration, unsigned int nak_limit ) {
return( ctrlReq( addr, ep, bmREQ_HIDOUT, HID_REQUEST_SET_IDLE, reportID, duration, interface, 0x0000, NULL, nak_limit ));
}
// uint8_t ctrlReq(
//uint8_t addr,
//uint8_t ep,
//uint8_t bmReqType,
//uint8_t bRequest,
//uint8_t wValLo,
//uint8_t wValHi,
//unsigned int wInd,
//unsigned int nbytes,
//uint8_t* dataptr,
//unsigned int nak_limit = USB_NAK_LIMIT );
// Clear Hub Feature
inline uint8_t USB::ClearHubFeature( uint8_t addr, uint8_t ep, uint8_t fid, unsigned int nak_limit )
{
return( ctrlReq( addr, ep, bmREQ_CLEAR_HUB_FEATURE, USB_REQUEST_CLEAR_FEATURE, fid, 0, 0, 0, NULL, nak_limit ));
}
// Clear Port Feature
inline uint8_t USB::ClearPortFeature( uint8_t addr, uint8_t ep, uint8_t fid, uint8_t port, uint8_t sel, unsigned int nak_limit )
{
return( ctrlReq( addr, ep, bmREQ_CLEAR_PORT_FEATURE, USB_REQUEST_CLEAR_FEATURE, fid, 0, ((0x0000|port)|(sel<<8)), 0, NULL, nak_limit ));
}
// Get Hub Descriptor
inline uint8_t USB::GetHubDescriptor( uint8_t addr, uint8_t ep, uint8_t index, uint16_t nbytes, uint8_t *dataptr, unsigned int nak_limit )
{
return( ctrlReq( addr, ep, bmREQ_GET_HUB_DESCRIPTOR, USB_REQUEST_GET_DESCRIPTOR, index, 0x29, 0, nbytes, dataptr, nak_limit ));
}
// Get Hub Status
inline uint8_t USB::GetHubStatus( uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr, unsigned int nak_limit )
{
return( ctrlReq( addr, ep, bmREQ_GET_HUB_STATUS, USB_REQUEST_GET_STATUS, 0, 0, 0x0000, nbytes, dataptr, nak_limit ));
}
// Get Port Status
inline uint8_t USB::GetPortStatus( uint8_t addr, uint8_t ep, uint8_t port, uint16_t nbytes, uint8_t* dataptr, unsigned int nak_limit )
{
//Serial.println(bmREQ_GET_PORT_STATUS, BIN);
return( ctrlReq( addr, ep, bmREQ_GET_PORT_STATUS, USB_REQUEST_GET_STATUS, 0, 0, port, nbytes, dataptr, nak_limit ));
}
// Set Hub Descriptor
inline uint8_t USB::SetHubDescriptor( uint8_t addr, uint8_t ep, uint8_t port, uint16_t nbytes, uint8_t* dataptr, unsigned int nak_limit )
{
return( ctrlReq( addr, ep, bmREQ_SET_HUB_DESCRIPTOR, USB_REQUEST_SET_DESCRIPTOR, 0, 0, port, nbytes, dataptr, nak_limit ));
}
// Set Hub Feature
inline uint8_t USB::SetHubFeature( uint8_t addr, uint8_t ep, uint8_t fid, unsigned int nak_limit )
{
return( ctrlReq( addr, ep, bmREQ_SET_HUB_FEATURE, USB_REQUEST_SET_FEATURE, fid, 0, 0, 0, NULL, nak_limit ));
}
// Set Port Feature
inline uint8_t USB::SetPortFeature( uint8_t addr, uint8_t ep, uint8_t fid, uint8_t port, uint8_t sel, unsigned int nak_limit )
{
return( ctrlReq( addr, ep, bmREQ_SET_PORT_FEATURE, USB_REQUEST_SET_FEATURE, fid, 0, (((0x0000|sel)<<8)|port), 0, NULL, nak_limit ));
}
#endif //_usb_h_

237
address.h Normal file
View file

@ -0,0 +1,237 @@
#if !defined(__ADDRESS_H__)
#define __ADDRESS_H__
#include <inttypes.h>
#include "max3421e.h"
/* Endpoint information structure */
/* bToggle of endpoint 0 initialized to 0xff */
/* during enumeration bToggle is set to 00 */
typedef struct
{
uint8_t epAddr; //copy from endpoint descriptor. Bit 7 indicates direction ( ignored for control endpoints )
uint8_t Attr; // Endpoint transfer type.
unsigned int MaxPktSize; // Maximum packet size.
uint8_t Interval; // Polling interval in frames.
uint8_t sndToggle; //last toggle value, bitmask for HCTL toggle bits
uint8_t rcvToggle; //last toggle value, bitmask for HCTL toggle bits
/* not sure if both are necessary */
} EP_RECORD;
// 7 6 5 4 3 2 1 0
// ---------------------------------
// | | H | P | P | P | A | A | A |
// ---------------------------------
//
// H - if 1 the address is a hub address
// P - parent hub address
// A - device address / port number in case of hub
//
struct UsbDeviceAddress
{
union
{
struct
{
uint8_t bmAddress : 3; // device address/port number
uint8_t bmParent : 3; // parent hub address
uint8_t bmHub : 1; // hub flag
uint8_t bmReserved : 1; // reserved, must be zerro
};
uint8_t devAddress;
};
};
#define bmUSB_DEV_ADDR_ADDRESS 0x07
#define bmUSB_DEV_ADDR_PARENT 0x38
#define bmUSB_DEV_ADDR_HUB 0x40
struct UsbDevice
{
EP_RECORD *epinfo; // endpoint info pointer
uint8_t address; // address
uint8_t devclass; // device class
};
class AddressPool
{
public:
virtual uint8_t AllocAddress(UsbDeviceAddress parent, bool is_hub = false, uint8_t port = 0) = 0;
virtual void FreeAddress(UsbDeviceAddress addr) = 0;
};
typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev);
#define ADDR_ERROR_INVALID_INDEX 0xFF
#define ADDR_ERROR_INVALID_ADDRESS 0xFF
template <const uint8_t MAX_DEVICES_ALLOWED>
class AddressPoolImpl
{
EP_RECORD dev0ep; //Endpoint data structure used during enumeration for uninitialized device
uint8_t hubCounter; // hub counter is kept
// in order to avoid hub address duplication
UsbDevice thePool[MAX_DEVICES_ALLOWED];
// Initializes address pool entry
void InitEntry(uint8_t index)
{
thePool[index].address = 0;
thePool[index].devclass = 0;
thePool[index].epinfo = &dev0ep;
};
// Returns thePool index for a given address
uint8_t FindAddressIndex(uint8_t address = 0)
{
for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
{
if (thePool[i].address == address)
return i;
}
return 0;
};
// Returns thePool child index for a given parent
uint8_t FindChildIndex(UsbDeviceAddress addr, uint8_t start = 1)
{
for (uint8_t i=(start<1 || start>=MAX_DEVICES_ALLOWED) ? 1 : start; i<MAX_DEVICES_ALLOWED; i++)
{
if (((UsbDeviceAddress*)&thePool[i].address)->bmParent == addr.bmAddress)
return i;
}
return 0;
};
// Frees address entry specified by index parameter
void FreeAddressByIndex(uint8_t index)
{
// Zerro field is reserved and should not be affected
if (index == 0)
return;
// If a hub was switched off all port addresses should be freed
if (((UsbDeviceAddress*)&thePool[index].address)->bmHub == 1)
{
for (uint8_t i=1; i = FindChildIndex(*((UsbDeviceAddress*)&thePool[index].address), i); )
FreeAddressByIndex(i);
// If the hub had the last allocated address, hubCounter should be decremented
if (hubCounter == ((UsbDeviceAddress*)&thePool[index].address)->bmAddress)
hubCounter --;
}
InitEntry(index);
}
// Initializes the whole address pool at once
void InitAllAddresses()
{
for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
InitEntry(i);
hubCounter = 0;
};
public:
AddressPoolImpl() : hubCounter(0)
{
// Zerro address is reserved
InitEntry(0);
thePool[0].address = 0;
thePool[0].epinfo = &dev0ep;
dev0ep.epAddr = 0;
dev0ep.MaxPktSize = 8;
dev0ep.sndToggle = bmSNDTOG0; //set DATA0/1 toggles to 0
dev0ep.rcvToggle = bmRCVTOG0;
InitAllAddresses();
};
// Returns a pointer to a specified address entry
UsbDevice* GetUsbDevicePtr(uint8_t addr)
{
if (!addr)
return thePool;
uint8_t index = FindAddressIndex(addr);
return (!index) ? NULL : thePool + index;
};
// Performs an operation specified by pfunc for each addressed device
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc)
{
if (!pfunc)
return;
for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
if (thePool[i].address)
pfunc(thePool + i);
};
// Allocates new address
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0)
{
if (parent > 127 || port > 7)
return 0;
// finds first empty address entry starting from one
uint8_t index = FindAddressIndex(0);
Serial.println(index, DEC);
if (!index) // if empty entry is not found
return 0;
if (parent == 0)
{
thePool[index].address = (is_hub) ? 0x41 : 1;
return thePool[index].address;
}
UsbDeviceAddress addr;
addr.bmParent = ((UsbDeviceAddress*)&parent)->bmAddress;
if (is_hub)
{
addr.bmHub = 1;
addr.bmAddress = ++hubCounter;
}
else
{
addr.bmHub = 0;
addr.bmAddress = port;
}
thePool[index].address = *((uint8_t*)&addr);
return thePool[index].address;
};
// Empties pool entry
virtual void FreeAddress(uint8_t addr)
{
// if the root hub is disconnected all the addresses should be initialized
if (addr == 0x41)
{
InitAllAddresses();
return;
}
uint8_t index = FindAddressIndex(addr);
FreeAddressByIndex(index);
};
// Returns number of hubs attached
// It can be rather helpfull to find out if there are hubs attached than getting the exact number of hubs.
uint8_t GetNumHubs()
{
return hubCounter;
};
uint8_t GetNumDevices()
{
uint8_t counter = 0;
for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
if (thePool[i].address != 0);
counter ++;
return counter;
};
};
#endif // __ADDRESS_H__

View file

@ -106,6 +106,27 @@ MAKE_PORT(PORTD, DDRD, PIND, Portd, 'D')
#ifdef USE_PORTE
MAKE_PORT(PORTE, DDRE, PINE, Porte, 'E')
#endif
#ifdef USE_PORTF
MAKE_PORT(PORTF, DDRF, PINF, Portf, 'F')
#endif
#ifdef USE_PORTG
MAKE_PORT(PORTG, DDRG, PING, Portg, 'G')
#endif
#ifdef USE_PORTH
MAKE_PORT(PORTH, DDRH, PINH, Porth, 'H')
#endif
#ifdef USE_PORTJ
MAKE_PORT(PORTJ, DDRJ, PINJ, Portj, 'J')
#endif
#ifdef USE_PORTK
MAKE_PORT(PORTK, DDRK, PINK, Portk, 'K')
#endif
#ifdef USE_PORTQ
MAKE_PORT(PORTQ, DDRQ, PINQ, Portq, 'Q')
#endif
#ifdef USE_PORTR
MAKE_PORT(PORTR, DDRR, PINR, Portr, 'R')
#endif
#ifdef USE_TCCR0A
MAKE_TCCR(TCCR0A, Tccr0a)
@ -348,7 +369,74 @@ template<typename Tp_pin, typename Tc_bit>
//typedef Tp_Tc<Pb2, Tc1b> P10; //Arduino pin 10
//typedef Tp_Tc<Pb3, Tc2a> P11; //Arduino pin 11
//Arduino pin numbers
/* Arduino pin definitions */
#if defined(__AVR_ATmega1280__) || (__AVR_ATmega2560__)
// "Mega" Arduino pin numbers
#define P0 Pe0
#define P1 Pe1
#define P2 Pe4
#define P3 Pe5
#define P4 Pg5
#define P5 Pe5
#define P6 Ph3
#define P7 Ph4
#define P8 Ph5
#define P9 Ph6
#define P10 Pb4
#define P11 Pb5
#define P12 Pb6
#define P13 Pb7
#define P14 Pj1
#define P15 Pj0
#define P16 Ph1
#define P17 Ph0
#define P18 Pd3
#define P19 Pd2
#define P20 Pd1
#define P21 Pd0
#define P22 Pa0
#define P23 Pa1
#define P24 Pa2
#define P25 Pa3
#define P26 Pa4
#define P27 Pa5
#define P28 Pa6
#define P29 Pa7
#define P30 Pc7
#define P31 Pc6
#define P32 Pc5
#define P33 Pc4
#define P34 Pc3
#define P35 Pc2
#define P36 Pc1
#define P37 Pc0
#define P38 Pd7
#define P39 Pg2
#define P40 Pg1
#define P41 Pg0
#define P42 Pl7
#define P43 Pl6
#define P44 Pl5
#define P45 Pl4
#define P46 Pl3
#define P47 Pl2
#define P48 Pl1
#define P49 Pl0
#define P50 Pb3
#define P51 Pb2
#define P52 Pb1
#define P53 Pb0
#endif //"Mega" pin definitions
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__)
//"Classical" Arduino pin numbers
#define P0 Pd0
#define P1 Pd1
@ -373,4 +461,6 @@ template<typename Tp_pin, typename Tc_bit>
#define P18 Pc4
#define P19 Pc5
#endif
#endif //_avrpins_h_

View file

@ -9,7 +9,9 @@
/* pin numbers to port numbers */
//#define MAX_SS 10
#define MAX_INT 9
//#define MAX_INT 3 // Black Widdow
#define MAX_INT 9 // Duemielanove
#define MAX_GPX 8
//#define MAX_RESET 7
//
@ -144,7 +146,8 @@
#define bmFRAMEIRQ 0x40
#define bmHXFRDNIRQ 0x80
#define rHIEN 0xd0 //26<<3
#define rHIEN 0xd0 //26<<3
/* HIEN Bits */
#define bmBUSEVENTIE 0x01
#define bmRWUIE 0x02
@ -155,7 +158,8 @@
#define bmFRAMEIE 0x40
#define bmHXFRDNIE 0x80
#define rMODE 0xd8 //27<<3
#define rMODE 0xd8 //27<<3
/* MODE Bits */
#define bmHOST 0x01
#define bmLOWSPEED 0x02
@ -191,6 +195,7 @@
#define tokISOOUT 0x60 // HS=0, ISO=1, OUTNIN=1, SETUP=0
#define rHRSL 0xf8 //31<<3
/* HRSL Bits */
#define bmRCVTOGRD 0x10
#define bmSNDTOGRD 0x20
@ -198,6 +203,7 @@
#define bmJSTATUS 0x80
#define bmSE0 0x00 //SE0 - disconnect state
#define bmSE1 0xc0 //SE1 - illegal state
/* Host error result codes, the 4 LSB's in the HRSL register */
#define hrSUCCESS 0x00
#define hrBUSY 0x01

59
newusb.pde Normal file
View file

@ -0,0 +1,59 @@
/* new USB library tests */
//nclude <digitalWriteFast.h>
#include "usbhost.h"
MAX3421e<P10, P9> Max;
uint8_t buf[10] = {0};
void setup() {
// Max.regWr( rPINCTL,( bmFDUPSPI + bmINTLEVEL ));
// Max.regWr( rUSBCTL, bmCHIPRES ); //Chip reset. This stops the oscillator
// Max.regWr( rUSBCTL, 0x00 ); //Remove the reset
// delay( 100 );
Serial.begin( 115200 );
Serial.println("Start");
// pinModeFast2( 8, OUTPUT)
}
void loop() {
// uint16_t i;
// Max.regWr( rUSBCTL, bmCHIPRES );
// Max.regWr( rUSBCTL, 0x00 );
// for( i = 0; i < 65535; i++ ) {
// if( ( Max.regRd( rUSBIRQ ) & bmOSCOKIRQ )) {
// break;
// }
// }
Serial.println( Max.reset(), DEC );
//Max.reset();
//delay( 100 );
//Max.regRd( rREVISION );
//Serial.println( Max.regRd( rREVISION ), HEX );
//Serial.println("tick");
// uint8_t tmp;
// for( uint16_t i = 0; i < 256; i++ ) {
// tmp = Max.SPIxfer( i );
// if( tmp != i ) {
// Serial.println("error");
// }
// if( SPSR & 0x40 ) {
// Serial.println("WCOL");
// }
// }
// static bool oldintval = 0;
// if( Max.intval() != oldintval ) {
// oldintval = Max.intval();
// Serial.println( oldintval, DEC );
// }
// Max.sstoggle();
//digitalWriteFast2( 8, 0 );
//digitalWriteFast2( 8, 1 );
}

View file

@ -193,12 +193,12 @@ int8_t MAX3421e< SS, INTR >::Init()
regWr( rMODE, bmDPPULLDN|bmDMPULLDN|bmHOST ); // set pull-downs, Host
regWr( rHIEN, bmCONDETIE|bmFRAMEIE ); //connection detection
/* check if device is connected */
regWr( rHCTL,bmSAMPLEBUS ); // sample USB bus
while(!(regRd( rHCTL ) & bmSAMPLEBUS )); //wait for sample operation to finish
busprobe(); //check if anything is connected
// Serial.println(getVbusState(), HEX);
busprobe(); //check if anything is connected
regWr( rHIRQ, bmCONDETIRQ ); //clear connection detect interrupt
regWr( rCPUCTL, 0x01 ); //enable interrupt pin
@ -210,33 +210,33 @@ template< typename SS, typename INTR >
void MAX3421e< SS, INTR >::busprobe()
{
byte bus_sample;
bus_sample = regRd( rHRSL ); //Get J,K status
bus_sample &= ( bmJSTATUS|bmKSTATUS ); //zero the rest of the byte
switch( bus_sample ) { //start full-speed or low-speed host
bus_sample = regRd( rHRSL ); //Get J,K status
bus_sample &= ( bmJSTATUS|bmKSTATUS ); //zero the rest of the byte
switch( bus_sample ) { //start full-speed or low-speed host
case( bmJSTATUS ):
if(( regRd( rMODE ) & bmLOWSPEED ) == 0 ) {
regWr( rMODE, MODE_FS_HOST ); //start full-speed host
regWr( rMODE, MODE_FS_HOST ); //start full-speed host
vbusState = FSHOST;
}
else {
regWr( rMODE, MODE_LS_HOST); //start low-speed host
regWr( rMODE, MODE_LS_HOST); //start low-speed host
vbusState = LSHOST;
}
break;
case( bmKSTATUS ):
if(( regRd( rMODE ) & bmLOWSPEED ) == 0 ) {
regWr( rMODE, MODE_LS_HOST ); //start low-speed host
regWr( rMODE, MODE_LS_HOST ); //start low-speed host
vbusState = LSHOST;
}
else {
regWr( rMODE, MODE_FS_HOST ); //start full-speed host
regWr( rMODE, MODE_FS_HOST ); //start full-speed host
vbusState = FSHOST;
}
break;
case( bmSE1 ): //illegal state
case( bmSE1 ): //illegal state
vbusState = SE1;
break;
case( bmSE0 ): //disconnected state
case( bmSE0 ): //disconnected state
vbusState = SE0;
break;
}//end switch( bus_sample )

520
usbhub.cpp Normal file
View file

@ -0,0 +1,520 @@
#include "usbhub.h"
USBHub::USBHub(USB *p) :
pUsb(p),
bAddress(0),
bNbrPorts(0),
bInitState(0),
bPortResetCounter(1),
qNextPollTime(0),
bPollEnable(false)
{
epInfo[0].epAddr = 0;
epInfo[0].MaxPktSize = 8;
epInfo[0].sndToggle = bmSNDTOG0; //set DATA0/1 toggles to 0
epInfo[0].rcvToggle = bmRCVTOG0;
epInfo[1].epAddr = 1;
epInfo[1].MaxPktSize = 1;
epInfo[1].Interval = 0xff;
epInfo[1].sndToggle = bmSNDTOG0; //set DATA0/1 toggles to 0
epInfo[1].rcvToggle = bmRCVTOG0;
if (pUsb)
pUsb->RegisterDeviceClass(this);
}
uint8_t USBHub::Init(uint8_t addr)
{
uint8_t buf[8];
uint8_t rcode;
switch (bInitState)
{
case 0:
Serial.println("Init");
bAddress = addr;
rcode = pUsb->getDevDescr( addr, 0, 8, (uint8_t*)buf );
if(rcode)
goto FailGetDevDescr;
// Return if the device is not a hub
if (((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass != 0x09)
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
rcode = pUsb->setDevTableEntry(addr, epInfo);
if (rcode)
goto FailSetDevTblEntry;
bInitState = 1;
case 1:
// Get hub descriptor
rcode = pUsb->GetHubDescriptor(addr, 0, 0, 8, buf);
if (rcode)
goto FailGetHubDescr;
// Save number of ports for future use
bNbrPorts = ((HubDescriptor*)buf)->bNbrPorts;
bInitState = 2;
case 2:
// Read configuration Descriptor in Order To Obtain Proper Configuration Value
rcode = pUsb->getConfDescr(addr, 0, 8, 0, buf);
if (rcode)
goto FailGetConfDescr;
Serial.print("Conf val:");
Serial.println(buf[5], HEX);
// Set Configuration Value
rcode = pUsb->setConf(addr, 0, buf[5]);
if (rcode)
goto FailSetConfDescr;
Serial.println("Hub configured");
bInitState = 3;
case 3:
// Power on all ports
for (uint8_t j=1; j<=bNbrPorts; j++)
pUsb->HubPortPowerOn(addr, j);
Serial.println("Ports powered");
bPollEnable = true;
bInitState = 0;
// bInitState = 4;
//case 4:
// Serial.print("RC:");
// Serial.println(bPortResetCounter, DEC);
// for (; bPortResetCounter<=bNbrPorts; bPortResetCounter++)
// {
// HubEvent evt;
// rcode = pUsb->GetPortStatus(addr, 0, bPortResetCounter, 4, evt.evtBuff);
// if (rcode)
// goto FailGetPortStatus;
// Serial.print("RC:");
// Serial.println(bPortResetCounter, DEC);
// Serial.print("\tSt:");
// Serial.print(evt.bmStatus, BIN);
// Serial.print("\tCh:");
// Serial.println(evt.bmChange, BIN);
// // Initiate reset only if there is a device plugged into the port
// if (evt.bmStatus & bmHUB_PORT_STATUS_PORT_CONNECTION)
// {
// Serial.print("Con:");
// Serial.println(bPortResetCounter, DEC);
// pUsb->HubPortReset(addr, bPortResetCounter);
// bPollEnable = true;
//
// if (bPortResetCounter < bNbrPorts)
// bPortResetCounter ++;
// return USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE;
// }
// } // for
// bPortResetCounter = 1;
}
bInitState = 0;
return 0;
FailGetDevDescr:
Serial.print("getDevDescr:");
goto Fail;
FailSetDevTblEntry:
Serial.print("setDevTblEn:");
goto Fail;
FailGetHubDescr:
Serial.print("getHub:");
goto Fail;
FailGetConfDescr:
Serial.print("getConf:");
goto Fail;
FailSetConfDescr:
Serial.print("setConf:");
goto Fail;
FailGetPortStatus:
Serial.print("GetPortStatus:");
goto Fail;
Fail:
Serial.println(rcode, HEX);
return rcode;
}
uint8_t USBHub::Release(uint8_t addr)
{
bAddress = 0;
bNbrPorts = 0;
bPortResetCounter = 0;
qNextPollTime = 0;
bPollEnable = false;
return 0;
}
uint8_t USBHub::Poll()
{
uint8_t rcode = 0;
if (!bPollEnable)
return 0;
if (qNextPollTime <= millis())
{
Serial.println("Poll");
rcode = GetHubStatus(bAddress);
if (rcode)
{
Serial.print("HubStatus:");
Serial.println(rcode,HEX);
}
qNextPollTime = millis() + 10;
}
return rcode;
}
//bmHUB_PORT_STATUS_C_PORT_CONNECTION
//bmHUB_PORT_STATUS_C_PORT_ENABLE
//bmHUB_PORT_STATUS_C_PORT_SUSPEND
//bmHUB_PORT_STATUS_C_PORT_OVER_CURRENT
//bmHUB_PORT_STATUS_C_PORT_RESET
uint8_t USBHub::GetHubStatus(uint8_t addr)
{
uint8_t rcode;
uint8_t buf[8];
// uint8_t inTransfer( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t* data, unsigned int nak_limit = USB_NAK_LIMIT );
//Serial.println(devtable[1].epinfo->epAddr, HEX);
rcode = pUsb->inTransfer(addr, 1, 1, buf, 1);
if (rcode)
{
Serial.print("inTransfer:");
Serial.println(rcode, HEX);
return rcode;
}
Serial.print("Int:");
Serial.println(buf[0],HEX);
//return 0;
if (buf[0] & 0x01) // Hub Status Change
{
pUsb->PrintHubStatus(addr);
//rcode = GetHubStatus(1, 0, 1, 4, buf);
//if (rcode)
//{
// Serial.print("GetHubStatus Error");
// Serial.println(rcode, HEX);
// return rcode;
//}
}
for (uint8_t port=1,mask=0x02; port<8; mask<<=1, port++)
{
if (buf[0] & mask)
{
HubEvent evt;
evt.bmEvent = 0;
rcode = pUsb->GetPortStatus(addr, 0, port, 4, evt.evtBuff);
if (rcode)
{
Serial.print("GetPortStatus err:");
Serial.println(rcode, HEX);
Serial.print("on port:");
Serial.println(port, DEC);
continue;
}
HubPortStatusChange(addr, port, evt);
}
} // for
return 0;
}
void USBHub::HubPortStatusChange(uint8_t addr, uint8_t port, HubEvent &evt)
{
Serial.print("Prt:");
Serial.print(port,HEX);
Serial.print("\tEvt:");
Serial.println(evt.bmEvent,HEX);
Serial.print("\tSt:");
Serial.println(evt.bmStatus,HEX);
Serial.print("\tCh:");
Serial.println(evt.bmChange,HEX);
//Serial.print("Con:");
//Serial.println(bmHUB_PORT_EVENT_CONNECT, HEX);
Serial.print("Rc:");
Serial.println(bmHUB_PORT_EVENT_RESET_COMPLETE, HEX);
PrintHubPortStatus(pUsb, addr, port);
switch (evt.bmEvent)
{
//case (bmHUB_PORT_STATE_DISABLED | bmHUB_PORT_STATUS_C_PORT_CONNECTION | bmHUB_PORT_STATUS_C_PORT_SUSPEND):
// Serial.println("DIS");
// pUsb->HubClearPortFeatures(addr, port, HUB_FEATURE_PORT_ENABLE | HUB_FEATURE_C_PORT_CONNECTION);
// pUsb->HubPortReset(addr, port);
// break;
// Device connected event
case bmHUB_PORT_EVENT_CONNECT:
Serial.println("CON");
pUsb->HubClearPortFeatures(addr, port, HUB_FEATURE_C_PORT_ENABLE);
pUsb->HubClearPortFeatures(addr, port, HUB_FEATURE_C_PORT_CONNECTION);
pUsb->HubPortReset(addr, port);
break;
// Reset complete event
case bmHUB_PORT_EVENT_RESET_COMPLETE:
Serial.println("RCMPL");
pUsb->HubClearPortFeatures(addr, port, HUB_FEATURE_C_PORT_RESET | HUB_FEATURE_C_PORT_CONNECTION);
// Check if device is a low-speed device
{
uint8_t new_addr;
delay(20);
// Begin addressing
pUsb->Addressing(&new_addr);
}
//uint8_t new_addr = addrPool.AllocAddress(addr, true, port);
//rcode = pUsb->setAddr(0, 0, new_addr);
//if (rcode)
//{
// Serial.print("ERR:");
// Serial.println(rcode, HEX);
//}
break;
// Suspended or resuming state
case bmHUB_PORT_STATE_SUSPENDED:
Serial.println("SUSP");
break;
// Resume complete event
case (bmHUB_PORT_STATE_ENABLED | HUB_FEATURE_C_PORT_SUSPEND):
break;
//case bmHUB_PORT_STATE_RESUMING:
// break;
} // switch (evt.bmEvent)
}
void PrintHubPortStatus(USB *usbptr, uint8_t addr, uint8_t port)
{
uint8_t rcode = 0;
HubEvent evt;
rcode = usbptr->GetPortStatus(addr, 0, port, 4, evt.evtBuff);
if (rcode)
{
Serial.println("ERROR!!!");
return;
}
Serial.print("\r\nPort ");
Serial.println(port, DEC);
Serial.println("Status");
Serial.print("CONNECTION:\t");
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_CONNECTION) > 0, DEC);
Serial.print("ENABLE:\t\t");
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_ENABLE) > 0, DEC);
Serial.print("SUSPEND:\t");
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_SUSPEND) > 0, DEC);
Serial.print("OVER_CURRENT:\t");
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_OVER_CURRENT) > 0, DEC);
Serial.print("RESET:\t\t");
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_RESET) > 0, DEC);
Serial.print("POWER:\t\t");
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_POWER) > 0, DEC);
Serial.print("LOW_SPEED:\t");
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED) > 0, DEC);
Serial.print("HIGH_SPEED:\t");
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_HIGH_SPEED) > 0, DEC);
Serial.print("TEST:\t\t");
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_TEST) > 0, DEC);
Serial.print("INDICATOR:\t");
Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_INDICATOR) > 0, DEC);
Serial.println("\nChange");
Serial.print("CONNECTION:\t");
Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_CONNECTION) > 0, DEC);
Serial.print("ENABLE:\t\t");
Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_ENABLE) > 0, DEC);
Serial.print("SUSPEND:\t");
Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_SUSPEND) > 0, DEC);
Serial.print("OVER_CURRENT:\t");
Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_OVER_CURRENT) > 0, DEC);
Serial.print("RESET:\t\t");
Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_RESET) > 0, DEC);
}
#if 0
case USB_STATE_ADDRESSING:
Serial.println("ADRESSING");
{
UsbDevice *p = addrPool.GetUsbDevicePtr(0);
if (p)
{
uint8_t addr = addrPool.AllocAddress(0, (p->devclass == 0x09) ? true : false);
if (addr)
{
Serial.print("Addr:");
Serial.println(addr,HEX);
UsbDevice *p0 = p;
rcode = setAddr( 0, 0, addr );
if (rcode)
{
Serial.println(rcode, HEX);
break;
}
p = addrPool.GetUsbDevicePtr(addr);
usb_task_state = USB_STATE_CONFIGURING;
} // if (addr)
} // if (p)
}
// for( i = 1; i < USB_NUMDEVICES; i++ )
//{
// if ( devtable[ i ].epinfo == NULL )
// {
// devtable[ i ].epinfo = devtable[ 0 ].epinfo; //set correct MaxPktSize
// //temporary record
// //until plugged with real device endpoint structure
// devtable[ i ].devclass = devtable[ 0 ].devclass;
// rcode = setAddr( 0, 0, i );
// if( rcode == 0 )
// {
// tmpaddr = i;
// if (devtable[i].devclass == USB_CLASS_HUB)
// {
// Serial.println("USB_CLASS_HUB");
// uint8_t buf[8];
// rcode = GetHubDescriptor(i, 0, 0, 8, buf);
// if (rcode == 0)
// {
// // Increment number of hubs found
// numHubs ++;
// // Insert hub address into a first available hub array entry
// for (uint8_t j=0; j<HUB_MAX_HUBS; j++)
// {
// if (hubs[j].bAddress == 0)
// {
// hubs[j].bAddress = i;
// hubs[j].bNbrPorts = ((HubDescriptor*)buf)->bNbrPorts;
// break;
// }
// } // for
//
// } // if (rcode == 0)
// }
// usb_task_state = USB_STATE_CONFIGURING;
// }
// else
// {
// usb_error = USB_STATE_ADDRESSING; //set address error
// usb_task_state = USB_STATE_ERROR;
// }
// break; //break if address assigned or error occured during address assignment attempt
// } // if( devtable[ i ].epinfo == NULL )
// } //for( i = 1; i < USB_NUMDEVICES; i++)
if( usb_task_state == USB_STATE_ADDRESSING ) //no vacant place in devtable
{
usb_error = 0xfe;
usb_task_state = USB_STATE_ERROR;
}
break;
case USB_STATE_CONFIGURING:
Serial.print("CONFIGURING...");
//// Hub Configuration Code
//if (devtable[1].devclass == USB_CLASS_HUB)
//{
// Serial.println("HUB");
// // Read configuration Descriptor in Order To Obtain Proper Configuration Value
// uint8_t buf[8];
// rcode = getConfDescr(1, 0, 8, 0, buf);
// if (rcode)
// {
// Serial.print("getConfDescr:");
// Serial.println(rcode, HEX);
// }
// Serial.print("Conf val:");
// Serial.println(buf[5], HEX);
// // Set Configuration Value
// rcode = setConf(1, 0, buf[5]);
// if (rcode)
// {
// Serial.print("setConf:");
// Serial.println(rcode, HEX);
// }
// Serial.println("Hub configured");
// // Enter Port Configuring State
// usb_task_state = USB_STATE_HUB_PORT_POWERED_OFF;
// //usb_task_state = USB_STATE_HUB_PORT_DISABLED;
// break;
//} //if (devtable[i].devclass == USB_CLASS_HUB)
usb_task_state = USB_STATE_RUNNING;
Serial.println("Configured");
break;
#endif

105
usbhub.h Normal file
View file

@ -0,0 +1,105 @@
#if !defined(__USBHUB_H__)
#define __USBHUB_H__
#include <inttypes.h>
#include <avr/pgmspace.h>
#include "avrpins.h"
#include "max3421e.h"
#include "usbhost.h"
#include "usb_ch9.h"
#include "Usb.h"
#include <WProgram.h>
// Hub Port Configuring Substates
#define USB_STATE_HUB_PORT_CONFIGURING 0xb0
#define USB_STATE_HUB_PORT_POWERED_OFF 0xb1
#define USB_STATE_HUB_PORT_WAIT_FOR_POWER_GOOD 0xb2
#define USB_STATE_HUB_PORT_DISCONNECTED 0xb3
#define USB_STATE_HUB_PORT_DISABLED 0xb4
#define USB_STATE_HUB_PORT_RESETTING 0xb5
#define USB_STATE_HUB_PORT_ENABLED 0xb6
// The bit mask to check for all necessary state bits
#define bmHUB_PORT_STATUS_ALL_MAIN ((0UL | bmHUB_PORT_STATUS_C_PORT_CONNECTION | bmHUB_PORT_STATUS_C_PORT_ENABLE | bmHUB_PORT_STATUS_C_PORT_SUSPEND | bmHUB_PORT_STATUS_C_PORT_RESET) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION | bmHUB_PORT_STATUS_PORT_SUSPEND)
// Hub Port States
//#define bmHUB_PORT_STATE_POWERED ((0UL | bmHUB_PORT_STATUS_PORT_POWER) << 16)
#define bmHUB_PORT_STATE_DISCONNECTED ((0UL | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE) << 16)
#define bmHUB_PORT_STATE_DISABLED ((0UL | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_CONNECTION))
#define bmHUB_PORT_STATE_RESETTING ((0UL | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_RESET) << 16)
#define bmHUB_PORT_STATE_ENABLED ((0UL | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE) << 16)
#define bmHUB_PORT_STATE_SUSPENDED ((0UL | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_SUSPEND) << 16)
// Hub Port Events
#define bmHUB_PORT_EVENT_CONNECT (((0UL | bmHUB_PORT_STATUS_C_PORT_CONNECTION) << 16) | bmHUB_PORT_STATE_DISABLED)
#define bmHUB_PORT_EVENT_RESET_COMPLETE (((0UL | bmHUB_PORT_STATUS_C_PORT_RESET) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION)
#define bmHUB_PORT_EVENT_PORT_ENABLED (((0UL | bmHUB_PORT_STATUS_C_PORT_CONNECTION | bmHUB_PORT_STATUS_C_PORT_ENABLE) << 16) | bmHUB_PORT_STATUS_PORT_POWER | bmHUB_PORT_STATUS_PORT_ENABLE | bmHUB_PORT_STATUS_PORT_CONNECTION)
struct HubEvent
{
union
{
struct
{
uint16_t bmStatus; // port status bits
uint16_t bmChange; // port status change bits
};
uint32_t bmEvent;
uint8_t evtBuff[4];
};
};
class USBHub : USBDeviceConfig
{
USB *pUsb; // USB class instance pointer
EP_RECORD epInfo[2]; // interrupt endpoint info structure
uint8_t bAddress; // address
uint8_t bNbrPorts; // number of ports
uint8_t bInitState; // initialization state variable
uint8_t bPortResetCounter; // number of ports reset
uint32_t qNextPollTime; // next poll time
bool bPollEnable; // poll enable flag
uint8_t GetHubStatus(uint8_t addr);
void HubPortStatusChange(uint8_t addr, uint8_t port, HubEvent &evt);
public:
USBHub(USB *p);
virtual uint8_t Init(uint8_t addr);
virtual uint8_t Release(uint8_t addr);
virtual uint8_t Poll();
};
void PrintHubPortStatus(USB *usbptr, uint8_t addr, uint8_t port);
// ---------------------------------
// | H | H | H | P | P | P | S | S |
// ---------------------------------
// H - hub ID
// P - port number
// S - port state
struct UsbHubPortState
{
union
{
struct
{
uint8_t bmState : 2;
uint8_t bmPort : 3;
uint8_t bmHub : 3;
};
uint8_t portState;
};
};
#endif // __USBHUB_H__