From 600e5c3a07d35d8e3834de53714d9af2088d71a1 Mon Sep 17 00:00:00 2001 From: Oleg Mazurov Date: Tue, 1 Mar 2011 11:26:31 -0700 Subject: [PATCH] avrpins with mega1280/2560 support --- Usb.cpp | 683 +++++++++++++++++++++++++++++++++++++++++------------ Usb.h | 309 +++++++++++++++++++++--- address.h | 237 +++++++++++++++++++ avrpins.h | 94 +++++++- max3421e.h | 12 +- newusb.pde | 59 +++++ usb_ch9.h | 336 +++++++++++++------------- usbhost.h | 26 +- usbhub.cpp | 520 ++++++++++++++++++++++++++++++++++++++++ usbhub.h | 105 ++++++++ 10 files changed, 2013 insertions(+), 368 deletions(-) create mode 100644 address.h create mode 100644 newusb.pde create mode 100644 usbhub.cpp create mode 100644 usbhub.h diff --git a/Usb.cpp b/Usb.cpp index 2b5408b2..10fcc935 100644 --- a/Usb.cpp +++ b/Usb.cpp @@ -5,33 +5,38 @@ #include "usbhost.h" #include "Usb.h" #include "WProgram.h" +//#include 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 */ -USB::USB () +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; + + UsbDevice *p = addrPool.GetUsbDevicePtr(addr); + + 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; - if (!maxpktsize) { //todo: move this check close to epinfo init. Make it 1< pktsize <64 - return 0xFE; - } + unsigned long timeout = millis() + USB_XFER_TIMEOUT; - 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 (!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; iPoll(); + } + } //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"); + + rcode = Addressing(&tmpaddr); - if( usb_task_state == USB_STATE_ADDRESSING ) { //no vacant place in devtable - usb_error = 0xfe; - usb_task_state = USB_STATE_ERROR; - } + 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 (; devConfigIndexInit(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(""); +} diff --git a/Usb.h b/Usb.h index b7bcc779..7287d8d9 100644 --- a/Usb.h +++ b/Usb.h @@ -7,27 +7,155 @@ #include "max3421e.h" #include "usbhost.h" #include "usb_ch9.h" +#include "address.h" #include /* 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 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 MAX3421E; // Black Widdow +typedef MAX3421e MAX3421E; // Duemielanove class USB : public MAX3421E { @@ -101,14 +242,39 @@ class USB : public MAX3421E //byte usb_task_state; + + AddressPoolImpl 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 +#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 +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) ? 1 : start; ibmParent == 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 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 //typedef Tp_Tc P10; //Arduino pin 10 //typedef Tp_Tc 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 #define P18 Pc4 #define P19 Pc5 -#endif //_avrpins_h_ +#endif + +#endif //_avrpins_h_ diff --git a/max3421e.h b/max3421e.h index 34d8bcab..b4320886 100644 --- a/max3421e.h +++ b/max3421e.h @@ -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 diff --git a/newusb.pde b/newusb.pde new file mode 100644 index 00000000..0fd7d701 --- /dev/null +++ b/newusb.pde @@ -0,0 +1,59 @@ +/* new USB library tests */ + +//nclude +#include "usbhost.h" + +MAX3421e 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 ); +} + + + diff --git a/usb_ch9.h b/usb_ch9.h index e2b413c1..33bc2f61 100644 --- a/usb_ch9.h +++ b/usb_ch9.h @@ -1,169 +1,169 @@ -/* USB chapter 9 structures */ -#ifndef _ch9_h_ -#define _ch9_h_ - -#include - -/* Misc.USB constants */ -#define DEV_DESCR_LEN 18 //device descriptor length -#define CONF_DESCR_LEN 9 //configuration descriptor length -#define INTR_DESCR_LEN 9 //interface descriptor length -#define EP_DESCR_LEN 7 //endpoint descriptor length - -/* Standard Device Requests */ - -#define USB_REQUEST_GET_STATUS 0 // Standard Device Request - GET STATUS -#define USB_REQUEST_CLEAR_FEATURE 1 // Standard Device Request - CLEAR FEATURE -#define USB_REQUEST_SET_FEATURE 3 // Standard Device Request - SET FEATURE -#define USB_REQUEST_SET_ADDRESS 5 // Standard Device Request - SET ADDRESS -#define USB_REQUEST_GET_DESCRIPTOR 6 // Standard Device Request - GET DESCRIPTOR -#define USB_REQUEST_SET_DESCRIPTOR 7 // Standard Device Request - SET DESCRIPTOR -#define USB_REQUEST_GET_CONFIGURATION 8 // Standard Device Request - GET CONFIGURATION -#define USB_REQUEST_SET_CONFIGURATION 9 // Standard Device Request - SET CONFIGURATION -#define USB_REQUEST_GET_INTERFACE 10 // Standard Device Request - GET INTERFACE -#define USB_REQUEST_SET_INTERFACE 11 // Standard Device Request - SET INTERFACE -#define USB_REQUEST_SYNCH_FRAME 12 // Standard Device Request - SYNCH FRAME - -#define USB_FEATURE_ENDPOINT_HALT 0 // CLEAR/SET FEATURE - Endpoint Halt -#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // CLEAR/SET FEATURE - Device remote wake-up -#define USB_FEATURE_TEST_MODE 2 // CLEAR/SET FEATURE - Test mode - -/* Setup Data Constants */ - -#define USB_SETUP_HOST_TO_DEVICE 0x00 // Device Request bmRequestType transfer direction - host to device transfer -#define USB_SETUP_DEVICE_TO_HOST 0x80 // Device Request bmRequestType transfer direction - device to host transfer -#define USB_SETUP_TYPE_STANDARD 0x00 // Device Request bmRequestType type - standard -#define USB_SETUP_TYPE_CLASS 0x20 // Device Request bmRequestType type - class -#define USB_SETUP_TYPE_VENDOR 0x40 // Device Request bmRequestType type - vendor -#define USB_SETUP_RECIPIENT_DEVICE 0x00 // Device Request bmRequestType recipient - device -#define USB_SETUP_RECIPIENT_INTERFACE 0x01 // Device Request bmRequestType recipient - interface -#define USB_SETUP_RECIPIENT_ENDPOINT 0x02 // Device Request bmRequestType recipient - endpoint -#define USB_SETUP_RECIPIENT_OTHER 0x03 // Device Request bmRequestType recipient - other - -/* USB descriptors */ - -#define USB_DESCRIPTOR_DEVICE 0x01 // bDescriptorType for a Device Descriptor. -#define USB_DESCRIPTOR_CONFIGURATION 0x02 // bDescriptorType for a Configuration Descriptor. -#define USB_DESCRIPTOR_STRING 0x03 // bDescriptorType for a String Descriptor. -#define USB_DESCRIPTOR_INTERFACE 0x04 // bDescriptorType for an Interface Descriptor. -#define USB_DESCRIPTOR_ENDPOINT 0x05 // bDescriptorType for an Endpoint Descriptor. -#define USB_DESCRIPTOR_DEVICE_QUALIFIER 0x06 // bDescriptorType for a Device Qualifier. -#define USB_DESCRIPTOR_OTHER_SPEED 0x07 // bDescriptorType for a Other Speed Configuration. -#define USB_DESCRIPTOR_INTERFACE_POWER 0x08 // bDescriptorType for Interface Power. -#define USB_DESCRIPTOR_OTG 0x09 // bDescriptorType for an OTG Descriptor. - -/* OTG SET FEATURE Constants */ -#define OTG_FEATURE_B_HNP_ENABLE 3 // SET FEATURE OTG - Enable B device to perform HNP -#define OTG_FEATURE_A_HNP_SUPPORT 4 // SET FEATURE OTG - A device supports HNP -#define OTG_FEATURE_A_ALT_HNP_SUPPORT 5 // SET FEATURE OTG - Another port on the A device supports HNP - -/* USB Endpoint Transfer Types */ -#define USB_TRANSFER_TYPE_CONTROL 0x00 // Endpoint is a control endpoint. -#define USB_TRANSFER_TYPE_ISOCHRONOUS 0x01 // Endpoint is an isochronous endpoint. -#define USB_TRANSFER_TYPE_BULK 0x02 // Endpoint is a bulk endpoint. -#define USB_TRANSFER_TYPE_INTERRUPT 0x03 // Endpoint is an interrupt endpoint. -#define bmUSB_TRANSFER_TYPE 0x03 // bit mask to separate transfer type from ISO attributes - - -/* Standard Feature Selectors for CLEAR_FEATURE Requests */ -#define USB_FEATURE_ENDPOINT_STALL 0 // Endpoint recipient -#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // Device recipient -#define USB_FEATURE_TEST_MODE 2 // Device recipient - -/* HID constants. Not part of chapter 9 */ -/* Class-Specific Requests */ -#define HID_REQUEST_GET_REPORT 0x01 -#define HID_REQUEST_GET_IDLE 0x02 -#define HID_REQUEST_GET_PROTOCOL 0x03 -#define HID_REQUEST_SET_REPORT 0x09 -#define HID_REQUEST_SET_IDLE 0x0A -#define HID_REQUEST_SET_PROTOCOL 0x0B - -/* Class Descriptor Types */ -#define HID_DESCRIPTOR_HID 0x21 -#define HID_DESCRIPTOR_REPORT 0x22 -#define HID_DESRIPTOR_PHY 0x23 - -/* Protocol Selection */ -#define BOOT_PROTOCOL 0x00 -#define RPT_PROTOCOL 0x01 -/* HID Interface Class Code */ -#define HID_INTF 0x03 -/* HID Interface Class SubClass Codes */ -#define BOOT_INTF_SUBCLASS 0x01 -/* HID Interface Class Protocol Codes */ -#define HID_PROTOCOL_NONE 0x00 -#define HID_PROTOCOL_KEYBOARD 0x01 -#define HID_PROTOCOL_MOUSE 0x02 - - -/* descriptor data structures */ - -/* Device descriptor structure */ -typedef struct { - uint8_t bLength; // Length of this descriptor. - uint8_t bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE). - uint16_t bcdUSB; // USB Spec Release Number (BCD). - uint8_t bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. - uint8_t bDeviceSubClass; // Subclass code (assigned by the USB-IF). - uint8_t bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. - uint8_t bMaxPacketSize0; // Maximum packet size for endpoint 0. - uint16_t idVendor; // Vendor ID (assigned by the USB-IF). - uint16_t idProduct; // Product ID (assigned by the manufacturer). - uint16_t bcdDevice; // Device release number (BCD). - uint8_t iManufacturer; // Index of String Descriptor describing the manufacturer. - uint8_t iProduct; // Index of String Descriptor describing the product. - uint8_t iSerialNumber; // Index of String Descriptor with the device's serial number. - uint8_t bNumConfigurations; // Number of possible configurations. -} USB_DEVICE_DESCRIPTOR; - -/* Configuration descriptor structure */ -typedef struct -{ - uint8_t bLength; // Length of this descriptor. - uint8_t bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION). - uint16_t wTotalLength; // Total length of all descriptors for this configuration. - uint8_t bNumInterfaces; // Number of interfaces in this configuration. - uint8_t bConfigurationValue; // Value of this configuration (1 based). - uint8_t iConfiguration; // Index of String Descriptor describing the configuration. - uint8_t bmAttributes; // Configuration characteristics. - uint8_t bMaxPower; // Maximum power consumed by this configuration. -} USB_CONFIGURATION_DESCRIPTOR; - -/* Interface descriptor structure */ -typedef struct -{ - uint8_t bLength; // Length of this descriptor. - uint8_t bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE). - uint8_t bInterfaceNumber; // Number of this interface (0 based). - uint8_t bAlternateSetting; // Value of this alternate interface setting. - uint8_t bNumEndpoints; // Number of endpoints in this interface. - uint8_t bInterfaceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. - uint8_t bInterfaceSubClass; // Subclass code (assigned by the USB-IF). - uint8_t bInterfaceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. - uint8_t iInterface; // Index of String Descriptor describing the interface. -} USB_INTERFACE_DESCRIPTOR; - -/* Endpoint descriptor structure */ -typedef struct -{ - uint8_t bLength; // Length of this descriptor. - uint8_t bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT). - uint8_t bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN). - uint8_t bmAttributes; // Endpoint transfer type. - uint16_t wMaxPacketSize; // Maximum packet size. - uint8_t bInterval; // Polling interval in frames. -} USB_ENDPOINT_DESCRIPTOR; - -/* HID descriptor */ -typedef struct { - uint8_t bLength; - uint8_t bDescriptorType; - uint16_t bcdHID; - uint8_t bCountryCode; - uint8_t bNumDescriptors; - uint8_t bDescrType; - uint16_t wDescriptorLength; -} USB_HID_DESCRIPTOR; - +/* USB chapter 9 structures */ +#ifndef _ch9_h_ +#define _ch9_h_ + +#include + +/* Misc.USB constants */ +#define DEV_DESCR_LEN 18 //device descriptor length +#define CONF_DESCR_LEN 9 //configuration descriptor length +#define INTR_DESCR_LEN 9 //interface descriptor length +#define EP_DESCR_LEN 7 //endpoint descriptor length + +/* Standard Device Requests */ + +#define USB_REQUEST_GET_STATUS 0 // Standard Device Request - GET STATUS +#define USB_REQUEST_CLEAR_FEATURE 1 // Standard Device Request - CLEAR FEATURE +#define USB_REQUEST_SET_FEATURE 3 // Standard Device Request - SET FEATURE +#define USB_REQUEST_SET_ADDRESS 5 // Standard Device Request - SET ADDRESS +#define USB_REQUEST_GET_DESCRIPTOR 6 // Standard Device Request - GET DESCRIPTOR +#define USB_REQUEST_SET_DESCRIPTOR 7 // Standard Device Request - SET DESCRIPTOR +#define USB_REQUEST_GET_CONFIGURATION 8 // Standard Device Request - GET CONFIGURATION +#define USB_REQUEST_SET_CONFIGURATION 9 // Standard Device Request - SET CONFIGURATION +#define USB_REQUEST_GET_INTERFACE 10 // Standard Device Request - GET INTERFACE +#define USB_REQUEST_SET_INTERFACE 11 // Standard Device Request - SET INTERFACE +#define USB_REQUEST_SYNCH_FRAME 12 // Standard Device Request - SYNCH FRAME + +#define USB_FEATURE_ENDPOINT_HALT 0 // CLEAR/SET FEATURE - Endpoint Halt +#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // CLEAR/SET FEATURE - Device remote wake-up +#define USB_FEATURE_TEST_MODE 2 // CLEAR/SET FEATURE - Test mode + +/* Setup Data Constants */ + +#define USB_SETUP_HOST_TO_DEVICE 0x00 // Device Request bmRequestType transfer direction - host to device transfer +#define USB_SETUP_DEVICE_TO_HOST 0x80 // Device Request bmRequestType transfer direction - device to host transfer +#define USB_SETUP_TYPE_STANDARD 0x00 // Device Request bmRequestType type - standard +#define USB_SETUP_TYPE_CLASS 0x20 // Device Request bmRequestType type - class +#define USB_SETUP_TYPE_VENDOR 0x40 // Device Request bmRequestType type - vendor +#define USB_SETUP_RECIPIENT_DEVICE 0x00 // Device Request bmRequestType recipient - device +#define USB_SETUP_RECIPIENT_INTERFACE 0x01 // Device Request bmRequestType recipient - interface +#define USB_SETUP_RECIPIENT_ENDPOINT 0x02 // Device Request bmRequestType recipient - endpoint +#define USB_SETUP_RECIPIENT_OTHER 0x03 // Device Request bmRequestType recipient - other + +/* USB descriptors */ + +#define USB_DESCRIPTOR_DEVICE 0x01 // bDescriptorType for a Device Descriptor. +#define USB_DESCRIPTOR_CONFIGURATION 0x02 // bDescriptorType for a Configuration Descriptor. +#define USB_DESCRIPTOR_STRING 0x03 // bDescriptorType for a String Descriptor. +#define USB_DESCRIPTOR_INTERFACE 0x04 // bDescriptorType for an Interface Descriptor. +#define USB_DESCRIPTOR_ENDPOINT 0x05 // bDescriptorType for an Endpoint Descriptor. +#define USB_DESCRIPTOR_DEVICE_QUALIFIER 0x06 // bDescriptorType for a Device Qualifier. +#define USB_DESCRIPTOR_OTHER_SPEED 0x07 // bDescriptorType for a Other Speed Configuration. +#define USB_DESCRIPTOR_INTERFACE_POWER 0x08 // bDescriptorType for Interface Power. +#define USB_DESCRIPTOR_OTG 0x09 // bDescriptorType for an OTG Descriptor. + +/* OTG SET FEATURE Constants */ +#define OTG_FEATURE_B_HNP_ENABLE 3 // SET FEATURE OTG - Enable B device to perform HNP +#define OTG_FEATURE_A_HNP_SUPPORT 4 // SET FEATURE OTG - A device supports HNP +#define OTG_FEATURE_A_ALT_HNP_SUPPORT 5 // SET FEATURE OTG - Another port on the A device supports HNP + +/* USB Endpoint Transfer Types */ +#define USB_TRANSFER_TYPE_CONTROL 0x00 // Endpoint is a control endpoint. +#define USB_TRANSFER_TYPE_ISOCHRONOUS 0x01 // Endpoint is an isochronous endpoint. +#define USB_TRANSFER_TYPE_BULK 0x02 // Endpoint is a bulk endpoint. +#define USB_TRANSFER_TYPE_INTERRUPT 0x03 // Endpoint is an interrupt endpoint. +#define bmUSB_TRANSFER_TYPE 0x03 // bit mask to separate transfer type from ISO attributes + + +/* Standard Feature Selectors for CLEAR_FEATURE Requests */ +#define USB_FEATURE_ENDPOINT_STALL 0 // Endpoint recipient +#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // Device recipient +#define USB_FEATURE_TEST_MODE 2 // Device recipient + +/* HID constants. Not part of chapter 9 */ +/* Class-Specific Requests */ +#define HID_REQUEST_GET_REPORT 0x01 +#define HID_REQUEST_GET_IDLE 0x02 +#define HID_REQUEST_GET_PROTOCOL 0x03 +#define HID_REQUEST_SET_REPORT 0x09 +#define HID_REQUEST_SET_IDLE 0x0A +#define HID_REQUEST_SET_PROTOCOL 0x0B + +/* Class Descriptor Types */ +#define HID_DESCRIPTOR_HID 0x21 +#define HID_DESCRIPTOR_REPORT 0x22 +#define HID_DESRIPTOR_PHY 0x23 + +/* Protocol Selection */ +#define BOOT_PROTOCOL 0x00 +#define RPT_PROTOCOL 0x01 +/* HID Interface Class Code */ +#define HID_INTF 0x03 +/* HID Interface Class SubClass Codes */ +#define BOOT_INTF_SUBCLASS 0x01 +/* HID Interface Class Protocol Codes */ +#define HID_PROTOCOL_NONE 0x00 +#define HID_PROTOCOL_KEYBOARD 0x01 +#define HID_PROTOCOL_MOUSE 0x02 + + +/* descriptor data structures */ + +/* Device descriptor structure */ +typedef struct { + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE). + uint16_t bcdUSB; // USB Spec Release Number (BCD). + uint8_t bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t bDeviceSubClass; // Subclass code (assigned by the USB-IF). + uint8_t bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t bMaxPacketSize0; // Maximum packet size for endpoint 0. + uint16_t idVendor; // Vendor ID (assigned by the USB-IF). + uint16_t idProduct; // Product ID (assigned by the manufacturer). + uint16_t bcdDevice; // Device release number (BCD). + uint8_t iManufacturer; // Index of String Descriptor describing the manufacturer. + uint8_t iProduct; // Index of String Descriptor describing the product. + uint8_t iSerialNumber; // Index of String Descriptor with the device's serial number. + uint8_t bNumConfigurations; // Number of possible configurations. +} USB_DEVICE_DESCRIPTOR; + +/* Configuration descriptor structure */ +typedef struct +{ + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION). + uint16_t wTotalLength; // Total length of all descriptors for this configuration. + uint8_t bNumInterfaces; // Number of interfaces in this configuration. + uint8_t bConfigurationValue; // Value of this configuration (1 based). + uint8_t iConfiguration; // Index of String Descriptor describing the configuration. + uint8_t bmAttributes; // Configuration characteristics. + uint8_t bMaxPower; // Maximum power consumed by this configuration. +} USB_CONFIGURATION_DESCRIPTOR; + +/* Interface descriptor structure */ +typedef struct +{ + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE). + uint8_t bInterfaceNumber; // Number of this interface (0 based). + uint8_t bAlternateSetting; // Value of this alternate interface setting. + uint8_t bNumEndpoints; // Number of endpoints in this interface. + uint8_t bInterfaceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t bInterfaceSubClass; // Subclass code (assigned by the USB-IF). + uint8_t bInterfaceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t iInterface; // Index of String Descriptor describing the interface. +} USB_INTERFACE_DESCRIPTOR; + +/* Endpoint descriptor structure */ +typedef struct +{ + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT). + uint8_t bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN). + uint8_t bmAttributes; // Endpoint transfer type. + uint16_t wMaxPacketSize; // Maximum packet size. + uint8_t bInterval; // Polling interval in frames. +} USB_ENDPOINT_DESCRIPTOR; + +/* HID descriptor */ +typedef struct { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdHID; + uint8_t bCountryCode; + uint8_t bNumDescriptors; + uint8_t bDescrType; + uint16_t wDescriptorLength; +} USB_HID_DESCRIPTOR; + #endif // _ch9_h_ diff --git a/usbhost.h b/usbhost.h index 5702210e..91939dfd 100644 --- a/usbhost.h +++ b/usbhost.h @@ -66,8 +66,8 @@ MAX3421e< SS, INTR >::MAX3421e() /* pin and peripheral setup */ SS::SetDirWrite(); SS::Set(); - /* For shield rev.1.xx uncomment following two lines */ - P7::SetDirWrite(); + /* For shield rev.1.xx uncomment following two lines */ + P7::SetDirWrite(); P7::Set(); spi::init(); @@ -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 ) diff --git a/usbhub.cpp b/usbhub.cpp new file mode 100644 index 00000000..dd45a895 --- /dev/null +++ b/usbhub.cpp @@ -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; jbNbrPorts; + // 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 \ No newline at end of file diff --git a/usbhub.h b/usbhub.h new file mode 100644 index 00000000..3f13fbe5 --- /dev/null +++ b/usbhub.h @@ -0,0 +1,105 @@ +#if !defined(__USBHUB_H__) +#define __USBHUB_H__ + +#include +#include +#include "avrpins.h" +#include "max3421e.h" +#include "usbhost.h" +#include "usb_ch9.h" +#include "Usb.h" +#include + +// 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__ \ No newline at end of file