diff --git a/BTD.cpp b/BTD.cpp index 254f104e..a714b5d6 100755 --- a/BTD.cpp +++ b/BTD.cpp @@ -34,45 +34,37 @@ qNextPollTime(0), // Reset NextPollTime pollInterval(0), bPollEnable(false) // Don't start polling before dongle is connected { - uint8_t i; - for (i = 0; i < BTD_MAX_ENDPOINTS; i++) { - epInfo[i].epAddr = 0; - epInfo[i].maxPktSize = (i) ? 0 : 8; - epInfo[i].epAttribs = 0; - epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER; - } - for (i = 0; i < BTD_NUMSERVICES; i++) + for (uint8_t i = 0; i < BTD_NUMSERVICES; i++) btService[i] = NULL; - if (pUsb) // register in USB subsystem - pUsb->RegisterDeviceClass(this); //set devConfig[] entry + clearAllVariables(); // Set all variables, endpoint structs etc. to default values + + if (pUsb) // Register in USB subsystem + pUsb->RegisterDeviceClass(this); // Set devConfig[] entry } -uint8_t BTD::Init(uint8_t parent, uint8_t port, bool lowspeed) { - uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)]; +uint8_t BTD::ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) { + const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR); + uint8_t buf[constBufSize]; uint8_t rcode; UsbDevice *p = NULL; EpInfo *oldep_ptr = NULL; - uint8_t num_of_conf; // number of configurations - uint16_t PID; - uint16_t VID; - // get memory address of USB device address pool - AddressPool &addrPool = pUsb->GetAddressPool(); + clearAllVariables(); // Set all variables, endpoint structs etc. to default values + + AddressPool &addrPool = pUsb->GetAddressPool(); // Get memory address of USB device address pool #ifdef EXTRADEBUG - Notify(PSTR("\r\nBTD Init"), 0x80); + Notify(PSTR("\r\nBTD ConfigureDevice"), 0x80); #endif - // check if address has already been assigned to an instance - if (bAddress) { + + if (bAddress) { // Check if address has already been assigned to an instance #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nAddress in use"), 0x80); #endif return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; } - // Get pointer to pseudo device with address 0 assigned - p = addrPool.GetUsbDevicePtr(0); - + p = addrPool.GetUsbDevicePtr(0); // Get pointer to pseudo device with address 0 assigned if (!p) { #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nAddress not found"), 0x80); @@ -87,66 +79,95 @@ uint8_t BTD::Init(uint8_t parent, uint8_t port, bool lowspeed) { return USB_ERROR_EPINFO_IS_NULL; } - // Save old pointer to EP_RECORD of address 0 - oldep_ptr = p->epinfo; - - // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence - p->epinfo = epInfo; - + oldep_ptr = p->epinfo; // Save old pointer to EP_RECORD of address 0 + p->epinfo = epInfo; // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence p->lowspeed = lowspeed; + rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data - // Get device descriptor - rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data - - // Restore p->epinfo - p->epinfo = oldep_ptr; + p->epinfo = oldep_ptr; // Restore p->epinfo if (rcode) goto FailGetDevDescr; - // Allocate new address according to device class - bAddress = addrPool.AllocAddress(parent, false, port); + bAddress = addrPool.AllocAddress(parent, false, port); // Allocate new address according to device class - if (!bAddress) + if (!bAddress) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nOut of address space"), 0x80); +#endif return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; + } - // Extract Max Packet Size from device descriptor - epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0; + epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0; // Extract Max Packet Size from device descriptor + epInfo[1].epAddr = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations; // Steal and abuse from epInfo structure to save memory - // Assign new address to the device - rcode = pUsb->setAddr(0, 0, bAddress); + VID = ((USB_DEVICE_DESCRIPTOR*)buf)->idVendor; + PID = ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct; + + return USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET; + +FailGetDevDescr: +#ifdef DEBUG_USB_HOST + NotifyFailGetDevDescr(rcode); +#endif + if (rcode != hrJERR) + rcode = USB_ERROR_FailGetDevDescr; + Release(); + return rcode; +}; + +uint8_t BTD::Init(uint8_t parent, uint8_t port, bool lowspeed) { + uint8_t rcode; + uint8_t num_of_conf = epInfo[1].epAddr; // Number of configurations + epInfo[1].epAddr = 0; + + AddressPool &addrPool = pUsb->GetAddressPool(); +#ifdef EXTRADEBUG + Notify(PSTR("\r\nBTD Init"), 0x80); +#endif + UsbDevice *p = addrPool.GetUsbDevicePtr(bAddress); // Get pointer to assigned address record + + if (!p) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nAddress not found"), 0x80); +#endif + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + } + + delay(300); // Assign new address to the device + + rcode = pUsb->setAddr(0, 0, bAddress); // Assign new address to the device if (rcode) { #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nsetAddr: "), 0x80); D_PrintHex (rcode, 0x80); #endif + p->lowspeed = false; goto Fail; } #ifdef EXTRADEBUG Notify(PSTR("\r\nAddr: "), 0x80); D_PrintHex (bAddress, 0x80); #endif - delay(300); // Spec says you should wait at least 200ms p->lowspeed = false; - //get pointer to assigned address record - p = addrPool.GetUsbDevicePtr(bAddress); - if (!p) + p = addrPool.GetUsbDevicePtr(bAddress); // Get pointer to assigned address record + if (!p) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nAddress not found"), 0x80); +#endif return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + } p->lowspeed = lowspeed; - // Assign epInfo to epinfo pointer - only EP0 is known - rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); + rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); // Assign epInfo to epinfo pointer - only EP0 is known if (rcode) goto FailSetDevTblEntry; - VID = ((USB_DEVICE_DESCRIPTOR*)buf)->idVendor; - PID = ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct; if (VID == PS3_VID && (PID == PS3_PID || PID == PS3NAVIGATION_PID || PID == PS3MOVE_PID)) { - /* We only need the Control endpoint, so we don't have to initialize the other endpoints of device */ - rcode = pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, 1); + rcode = pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, 1); // We only need the Control endpoint, so we don't have to initialize the other endpoints of device if (rcode) goto FailSetConfDescr; @@ -184,8 +205,6 @@ uint8_t BTD::Init(uint8_t parent, uint8_t port, bool lowspeed) { Release(); // Release device return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; // Return } else { - num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations; - // Check if attached device is a Bluetooth dongle and fill endpoint data structure // First interface in the configuration must have Bluetooth assigned Class/Subclass/Protocol // And 3 endpoints - interrupt-IN, bulk-IN, bulk-OUT, not necessarily in this order @@ -211,8 +230,6 @@ uint8_t BTD::Init(uint8_t parent, uint8_t port, bool lowspeed) { if (rcode) goto FailSetDevTblEntry; - delay(200); // Give time for address change - // Set Configuration Value rcode = pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, bConfNum); if (rcode) @@ -270,6 +287,28 @@ Fail: return rcode; } +void BTD::clearAllVariables() { + uint8_t i; + for (i = 0; i < BTD_MAX_ENDPOINTS; i++) { + epInfo[i].epAddr = 0; + epInfo[i].maxPktSize = (i) ? 0 : 8; + epInfo[i].epAttribs = 0; + epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER; + } + for (i = 0; i < BTD_NUMSERVICES; i++) { + if (btService[i]) + btService[i]->Reset(); // Reset all Bluetooth services + } + + connectToWii = false; + incomingWii = false; + bAddress = 0; // Clear device address + bNumEP = 1; // Must have to be reset to 1 + qNextPollTime = 0; // Reset next poll time + pollInterval = 0; + bPollEnable = false; // Don't start polling before dongle is connected +} + /* Extracts interrupt-IN, bulk-IN, bulk-OUT endpoint information from config descriptor */ void BTD::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) { //ErrorMessage(PSTR("Conf.Val"),conf); @@ -323,15 +362,8 @@ void BTD::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) { /* Performs a cleanup after failed Init() attempt */ uint8_t BTD::Release() { - for (uint8_t i = 0; i < BTD_NUMSERVICES; i++) { - if (btService[i]) - btService[i]->Reset(); // Reset all Bluetooth services - } - + clearAllVariables(); // Set all variables, endpoint structs etc. to default values pUsb->GetAddressPool().FreeAddress(bAddress); - bAddress = 0; - bPollEnable = false; - bNumEP = 1; // must have to be reset to 1 return 0; } @@ -382,7 +414,7 @@ void BTD::HCI_event_task() { break; case EV_INQUIRY_COMPLETE: - if (inquiry_counter >= 5) { + if (inquiry_counter >= 5 && pairWithWii) { inquiry_counter = 0; #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nCouldn't find Wiimote"), 0x80); @@ -435,7 +467,7 @@ void BTD::HCI_event_task() { hci_handle = hcibuf[3] | ((hcibuf[4] & 0x0F) << 8); // store the handle for the ACL connection hci_event_flag |= HCI_FLAG_CONN_COMPLETE; // set connection complete flag } -#ifdef EXTRADEBUG +#ifdef DEBUG_USB_HOST else { Notify(PSTR("\r\nConnection Failed"), 0x80); hci_state = HCI_CHECK_WII_SERVICE; @@ -780,6 +812,10 @@ void BTD::HCI_task() { for (uint8_t i = 0; i < BULK_MAXPKTSIZE; i++) l2capinbuf[i] = 0; + connectToWii = false; + incomingWii = false; + pairWithWii = false; + hci_state = HCI_SCANNING_STATE; } break; diff --git a/BTD.h b/BTD.h index 097b66f6..a2e3d62d 100755 --- a/BTD.h +++ b/BTD.h @@ -162,6 +162,14 @@ public: BTD(USB *p); /** @name USBDeviceConfig implementation */ + /** + * Address assignment and basic initilization is done here. + * @param parent Hub number. + * @param port Port number on the hub. + * @param lowspeed Speed of the device. + * @return 0 on success. + */ + virtual uint8_t ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed); /** * Initialize the Bluetooth dongle. * @param parent Hub number. @@ -455,8 +463,11 @@ protected: void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr); private: + void clearAllVariables(); // Set all variables, endpoint structs etc. to default values BluetoothService* btService[BTD_NUMSERVICES]; + uint16_t PID, VID; // PID and VID of device connected + bool bPollEnable; uint8_t pollInterval; diff --git a/README.md b/README.md index e2ce776a..f282ce5c 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ Currently the following boards are supported by the library: The following boards need to be activated manually in [settings.h](settings.h): * Arduino Mega ADK + * If you are using Arduino 1.5.5 or newer there is no need to activate the Arduino Mega ADK manually * Black Widdow Simply set the corresponding value to 1 instead of 0. diff --git a/Usb.cpp b/Usb.cpp index 122420bc..6bcf092e 100644 --- a/Usb.cpp +++ b/Usb.cpp @@ -475,7 +475,7 @@ void USB::Task(void) //USB state machine case USB_ATTACHED_SUBSTATE_SETTLE: //settle time for just attached device if (delay < millis()) usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE; - break; + else break; // don't fall through case USB_ATTACHED_SUBSTATE_RESET_DEVICE: regWr(rHCTL, bmBUSRST); //issue bus reset usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE; @@ -501,7 +501,7 @@ void USB::Task(void) //USB state machine break; case USB_ATTACHED_SUBSTATE_WAIT_RESET: if (delay < millis()) usb_task_state = USB_STATE_CONFIGURING; - break; + else break; // don't fall through case USB_STATE_CONFIGURING: //Serial.print("\r\nConf.LS: "); @@ -566,10 +566,10 @@ uint8_t USB::DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed) { }; uint8_t USB::AttemptConfig(uint8_t driver, uint8_t parent, uint8_t port, bool lowspeed) { - uint8_t rcode = 0; //printf("AttemptConfig: parent = %i, port = %i\r\n", parent, port); - rcode = devConfig[driver]->ConfigureDevice(parent, port, lowspeed); +again: + uint8_t rcode = devConfig[driver]->ConfigureDevice(parent, port, lowspeed); if (rcode == USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET) { if (parent == 0) { // Send a bus reset on the root interface. @@ -579,9 +579,18 @@ uint8_t USB::AttemptConfig(uint8_t driver, uint8_t parent, uint8_t port, bool lo // reset parent port devConfig[parent]->ResetHubPort(port); } - } + } else if (rcode == hrJERR) { // Some devices returns this when plugged in - trying to initialize the device again usually works + delay(100); + goto again; + } else if (rcode) + return rcode; + rcode = devConfig[driver]->Init(parent, port, lowspeed); - if(rcode) { + if (rcode == hrJERR) { // Some devices returns this when plugged in - trying to initialize the device again usually works + delay(100); + goto again; + } + if (rcode) { // Issue a bus reset, because the device may be in a limbo state if (parent == 0) { // Send a bus reset on the root interface. @@ -591,7 +600,6 @@ uint8_t USB::AttemptConfig(uint8_t driver, uint8_t parent, uint8_t port, bool lo // reset parent port devConfig[parent]->ResetHubPort(port); } - } return rcode; } @@ -651,7 +659,7 @@ uint8_t USB::Configuring(uint8_t parent, uint8_t port, bool lowspeed) { epInfo.epAttribs = 0; epInfo.bmNakPower = USB_NAK_MAX_POWER; - delay(2000); + //delay(2000); AddressPool &addrPool = GetAddressPool(); // Get pointer to pseudo device with address 0 assigned p = addrPool.GetUsbDevicePtr(0); diff --git a/XBOXOLD.cpp b/XBOXOLD.cpp index f766e329..4c9bcb20 100644 --- a/XBOXOLD.cpp +++ b/XBOXOLD.cpp @@ -299,9 +299,11 @@ bool XBOXOLD::getButtonClick(Button b) { uint8_t button; if (b == A || b == B || b == X || b == Y || b == BLACK || b == WHITE || b == L1 || b == R1) { // A, B, X, Y, BLACK, WHITE, L1, and R1 are analog buttons button = pgm_read_byte(&XBOXOLDBUTTONS[(uint8_t)b]); - if (buttonClicked[button]) + if (buttonClicked[button]) { buttonClicked[button] = false; - return buttonClicked[button]; + return true; + } + return false; } button = pgm_read_byte(&XBOXOLDBUTTONS[(uint8_t)b]); // Digital buttons diff --git a/avrpins.h b/avrpins.h index 566b2dc9..fd4fdf39 100644 --- a/avrpins.h +++ b/avrpins.h @@ -28,7 +28,7 @@ e-mail : support@circuitsathome.com #define pgm_read_pointer(p) pgm_read_word(p) // Support for these boards needs to be manually activated in settings.h or in a makefile -#if !defined(BOARD_MEGA_ADK) && defined(__AVR_ATmega2560__) && USE_UHS_MEGA_ADK +#if !defined(BOARD_MEGA_ADK) && defined(__AVR_ATmega2560__) && (USE_UHS_MEGA_ADK || defined(ARDUINO_AVR_ADK)) #define BOARD_MEGA_ADK #elif !defined(BOARD_BLACK_WIDDOW) && USE_UHS_BLACK_WIDDOW #define BOARD_BLACK_WIDDOW diff --git a/settings.h b/settings.h index d22361a0..add3ee03 100644 --- a/settings.h +++ b/settings.h @@ -29,11 +29,14 @@ //////////////////////////////////////////////////////////////////////////////// /* Set this to 1 if you are using an Arduino Mega ADK board with MAX3421e built-in */ -#define USE_UHS_MEGA_ADK 0 +#define USE_UHS_MEGA_ADK 0 // If you are using Arduino 1.5.5 or newer there is no need to do this manually /* Set this to 1 if you are using a Black Widdow */ #define USE_UHS_BLACK_WIDDOW 0 +/* Set this to a one to use the xmem2 lock. This is needed for multitasking and threading */ +#define USE_XMEM_SPI_LOCK 0 + //////////////////////////////////////////////////////////////////////////////// // MASS STORAGE //////////////////////////////////////////////////////////////////////////////// @@ -61,8 +64,16 @@ #else #include // I am not sure what WProgram.h does not include, so these are here. --xxxajk +#include #include #include #endif +#if USE_XMEM_SPI_LOCK | defined(USE_MULTIPLE_APP_API) +#include +#else +#define XMEM_ACQUIRE_SPI() (void(0)) +#define XMEM_RELEASE_SPI() (void(0)) +#endif + #endif /* SETTINGS_H */ diff --git a/usbhost.h b/usbhost.h index f0981f90..04341923 100644 --- a/usbhost.h +++ b/usbhost.h @@ -94,31 +94,26 @@ template< typename SS, typename INTR > /* constructor */ template< typename SS, typename INTR > MAX3421e< SS, INTR >::MAX3421e() { - /* pin and peripheral setup */ - SS::SetDirWrite(); - SS::Set(); - spi::init(); - INTR::SetDirRead(); +// Leaving ADK hardware setup in here, for now. This really belongs with the other parts. #ifdef BOARD_MEGA_ADK /* For Mega ADK, which has Max3421e on-board, set MAX_RESET to Output mode, and pull Reset to HIGH */ DDRJ |= _BV(PJ2); PORTJ &= ~_BV(PJ2); PORTJ |= _BV(PJ2); #endif - - /* MAX3421E - full-duplex SPI, level interrupt */ - regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL | GPX_VBDET)); }; /* write single byte into MAX3421 register */ template< typename SS, typename INTR > void MAX3421e< SS, INTR >::regWr(uint8_t reg, uint8_t data) { + XMEM_ACQUIRE_SPI(); SS::Clear(); SPDR = (reg | 0x02); while(!(SPSR & (1 << SPIF))); SPDR = data; while(!(SPSR & (1 << SPIF))); SS::Set(); + XMEM_RELEASE_SPI(); return; }; /* multiple-byte write */ @@ -126,6 +121,7 @@ void MAX3421e< SS, INTR >::regWr(uint8_t reg, uint8_t data) { /* returns a pointer to memory position after last written */ template< typename SS, typename INTR > uint8_t* MAX3421e< SS, INTR >::bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p) { + XMEM_ACQUIRE_SPI(); SS::Clear(); SPDR = (reg | 0x02); //set WR bit and send register number while(nbytes--) { @@ -135,6 +131,7 @@ uint8_t* MAX3421e< SS, INTR >::bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* dat } while(!(SPSR & (1 << SPIF))); SS::Set(); + XMEM_RELEASE_SPI(); return( data_p); } /* GPIO write */ @@ -152,19 +149,23 @@ void MAX3421e< SS, INTR >::gpioWr(uint8_t data) { /* single host register read */ template< typename SS, typename INTR > uint8_t MAX3421e< SS, INTR >::regRd(uint8_t reg) { + XMEM_ACQUIRE_SPI(); SS::Clear(); SPDR = reg; while(!(SPSR & (1 << SPIF))); SPDR = 0; //send empty byte while(!(SPSR & (1 << SPIF))); SS::Set(); - return( SPDR); + uint8_t rv = SPDR; + XMEM_RELEASE_SPI(); + return(rv); } /* multiple-byte register read */ /* returns a pointer to a memory position after last read */ template< typename SS, typename INTR > uint8_t* MAX3421e< SS, INTR >::bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p) { + XMEM_ACQUIRE_SPI(); SS::Clear(); SPDR = reg; while(!(SPSR & (1 << SPIF))); //wait @@ -185,6 +186,7 @@ uint8_t* MAX3421e< SS, INTR >::bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* dat } #endif SS::Set(); + XMEM_RELEASE_SPI(); return( data_p); } /* GPIO read. See gpioWr for explanation */ @@ -217,13 +219,24 @@ uint16_t MAX3421e< SS, INTR >::reset() { /* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */ template< typename SS, typename INTR > int8_t MAX3421e< SS, INTR >::Init() { + XMEM_ACQUIRE_SPI(); + // Moved here. + // you really should not init hardware in the constructor when it involves locks. + // Also avoids the vbus flicker issue confusing some devices. + /* pin and peripheral setup */ + SS::SetDirWrite(); + SS::Set(); + spi::init(); + INTR::SetDirRead(); + XMEM_RELEASE_SPI(); + /* MAX3421E - full-duplex SPI, level interrupt */ + // GPX pin on. Moved here, otherwise we flicker the vbus. + regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL)); + if(reset() == 0) { //OSCOKIRQ hasn't asserted in time return( -1); } - // GPX pin on. - regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL)); - regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host regWr(rHIEN, bmCONDETIE | bmFRAMEIE); //connection detection @@ -243,6 +256,19 @@ int8_t MAX3421e< SS, INTR >::Init() { /* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */ template< typename SS, typename INTR > int8_t MAX3421e< SS, INTR >::Init(int mseconds) { + XMEM_ACQUIRE_SPI(); + // Moved here. + // you really should not init hardware in the constructor when it involves locks. + // Also avoids the vbus flicker issue confusing some devices. + /* pin and peripheral setup */ + SS::SetDirWrite(); + SS::Set(); + spi::init(); + INTR::SetDirRead(); + XMEM_RELEASE_SPI(); + /* MAX3421E - full-duplex SPI, level interrupt, vbus off */ + regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL | GPX_VBDET)); + if(reset() == 0) { //OSCOKIRQ hasn't asserted in time return( -1); }