示例#1
0
uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed) {
        const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);

        uint8_t buf[constBufSize];
        USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
        uint8_t rcode;
        UsbDevice *p = NULL;
        EpInfo *oldep_ptr = NULL;
        uint8_t len = 0;

        uint8_t num_of_conf; // number of configurations
        //uint8_t num_of_intf; // number of interfaces

        AddressPool &addrPool = pUsb->GetAddressPool();

        USBTRACE("HU Init\r\n");

        if(bAddress)
                return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;

        // Get pointer to pseudo device with address 0 assigned
        p = addrPool.GetUsbDevicePtr(0);

        if(!p)
                return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;

        if(!p->epinfo) {
                USBTRACE("epinfo\r\n");
                return USB_ERROR_EPINFO_IS_NULL;
        }

        // Save old pointer to EP_RECORD of address 0
        oldep_ptr = p->epinfo;

        // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
        p->epinfo = epInfo;

        p->lowspeed = lowspeed;

        // Get device descriptor
        rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*)buf);

        if(!rcode)
                len = (buf[0] > constBufSize) ? constBufSize : buf[0];

        if(rcode) {
                // Restore p->epinfo
                p->epinfo = oldep_ptr;

                goto FailGetDevDescr;
        }

        // Restore p->epinfo
        p->epinfo = oldep_ptr;

        // Allocate new address according to device class
        bAddress = addrPool.AllocAddress(parent, false, port);

        if(!bAddress)
                return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;

        // Extract Max Packet Size from the device descriptor
        epInfo[0].maxPktSize = udd->bMaxPacketSize0;

        // Assign new address to the device
        rcode = pUsb->setAddr(0, 0, bAddress);

        if(rcode) {
                p->lowspeed = false;
                addrPool.FreeAddress(bAddress);
                bAddress = 0;
                USBTRACE2("setAddr:", rcode);
                return rcode;
        }

        //delay(2); //per USB 2.0 sect.9.2.6.3

        USBTRACE2("Addr:", bAddress);

        p->lowspeed = false;

        p = addrPool.GetUsbDevicePtr(bAddress);

        if(!p)
                return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;

        p->lowspeed = lowspeed;

        if(len)
                rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*)buf);

        if(rcode)
                goto FailGetDevDescr;

        VID = udd->idVendor; // Can be used by classes that inherits this class to check the VID and PID of the connected device
        PID = udd->idProduct;

        num_of_conf = udd->bNumConfigurations;

        // Assign epInfo to epinfo pointer
        rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);

        if(rcode)
                goto FailSetDevTblEntry;

        USBTRACE2("NC:", num_of_conf);

        for(uint8_t i = 0; i < num_of_conf; i++) {
                //HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
                ConfigDescParser<USB_CLASS_HID, 0, 0,
                        CP_MASK_COMPARE_CLASS> confDescrParser(this);

                //rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
                rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);

                if(rcode)
                        goto FailGetConfDescr;

                if(bNumEP > 1)
                        break;
        } // for

        if(bNumEP < 2)
                return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;

        // Assign epInfo to epinfo pointer
        rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);

        USBTRACE2("Cnf:", bConfNum);

        // Set Configuration Value
        rcode = pUsb->setConf(bAddress, 0, bConfNum);

        if(rcode)
                goto FailSetConfDescr;

        for(uint8_t i = 0; i < bNumIface; i++) {
                if(hidInterfaces[i].epIndex[epInterruptInIndex] == 0)
                        continue;

                rcode = SetIdle(hidInterfaces[i].bmInterface, 0, 0);

                if(rcode && rcode != hrSTALL)
                        goto FailSetIdle;
        }

        USBTRACE("HU configured\r\n");

        OnInitSuccessful();

        bPollEnable = true;
        return 0;

FailGetDevDescr:
#ifdef DEBUG_USB_HOST
        NotifyFailGetDevDescr();
        goto Fail;
#endif

FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
        NotifyFailSetDevTblEntry();
        goto Fail;
#endif

FailGetConfDescr:
#ifdef DEBUG_USB_HOST
        NotifyFailGetConfDescr();
        goto Fail;
#endif

FailSetConfDescr:
#ifdef DEBUG_USB_HOST
        NotifyFailSetConfDescr();
        goto Fail;
#endif


FailSetIdle:
#ifdef DEBUG_USB_HOST
        USBTRACE("SetIdle:");
#endif

#ifdef DEBUG_USB_HOST
Fail:
        NotifyFail(rcode);
#endif
        Release();
        return rcode;
}
示例#2
0
void NotifyFailGetConfDescr(uint8_t reason) {
        NotifyFailGetConfDescr();
        NotifyFail(reason);
}
uint8_t FTDI::Init(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		len = 0;
        //uint16_t	cd_len = 0;

        uint8_t num_of_conf; // number of configurations
        //uint8_t		num_of_intf;	// number of interfaces

        AddressPool &addrPool = pUsb->GetAddressPool();

        USBTRACE("FTDI Init\r\n");

        if (bAddress)
                return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;

        // Get pointer to pseudo device with address 0 assigned
        p = addrPool.GetUsbDevicePtr(0);

        if (!p)
                return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;

        if (!p->epinfo) {
                USBTRACE("epinfo\r\n");
                return USB_ERROR_EPINFO_IS_NULL;
        }

        // Save old pointer to EP_RECORD of address 0
        oldep_ptr = p->epinfo;

        // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
        p->epinfo = epInfo;

        p->lowspeed = lowspeed;

        // Get device descriptor
        rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);

        // Restore p->epinfo
        p->epinfo = oldep_ptr;

        if (rcode)
                goto FailGetDevDescr;

        if (((USB_DEVICE_DESCRIPTOR*)buf)->idVendor != FTDI_VID || ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct != FTDI_PID)
                return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;

        // Save type of FTDI chip
        wFTDIType = ((USB_DEVICE_DESCRIPTOR*)buf)->bcdDevice;

        // Allocate new address according to device class
        bAddress = addrPool.AllocAddress(parent, false, port);

        if (!bAddress)
                return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;

        // Extract Max Packet Size from the device descriptor
        epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;

        // Assign new address to the device
        rcode = pUsb->setAddr(0, 0, bAddress);

        if (rcode) {
                p->lowspeed = false;
                addrPool.FreeAddress(bAddress);
                bAddress = 0;
                USBTRACE2("setAddr:", rcode);
                return rcode;
        }

        USBTRACE2("Addr:", bAddress);

        p->lowspeed = false;

        p = addrPool.GetUsbDevicePtr(bAddress);

        if (!p)
                return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;

        p->lowspeed = lowspeed;

        num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations;

        // Assign epInfo to epinfo pointer
        rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);

        if (rcode)
                goto FailSetDevTblEntry;

        USBTRACE2("NC:", num_of_conf);

        for (uint8_t i = 0; i < num_of_conf; i++) {
                HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
                ConfigDescParser < 0xFF, 0xFF, 0xFF, CP_MASK_COMPARE_ALL> confDescrParser(this);

                rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);

                if (rcode)
                        goto FailGetConfDescr;

                rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);

                if (rcode)
                        goto FailGetConfDescr;

                if (bNumEP > 1)
                        break;
        } // for

        if (bNumEP < 2)
                return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;

        USBTRACE2("NumEP:", bNumEP);

        // Assign epInfo to epinfo pointer
        rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);

        USBTRACE2("Conf:", bConfNum);

        // Set Configuration Value
        rcode = pUsb->setConf(bAddress, 0, bConfNum);

        if (rcode)
                goto FailSetConfDescr;

        rcode = pAsync->OnInit(this);

        if (rcode)
                goto FailOnInit;

        USBTRACE("FTDI configured\r\n");

        bPollEnable = true;
        return 0;

FailGetDevDescr:
#ifdef DEBUG_USB_HOST
        NotifyFailGetDevDescr();
        goto Fail;
#endif

FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
        NotifyFailSetDevTblEntry();
        goto Fail;
#endif

FailGetConfDescr:
#ifdef DEBUG_USB_HOST
        NotifyFailGetConfDescr();
        goto Fail;
#endif

FailSetConfDescr:
#ifdef DEBUG_USB_HOST
        NotifyFailSetConfDescr();
        goto Fail;
#endif

FailOnInit:
#ifdef DEBUG_USB_HOST
        USBTRACE("OnInit:");
#endif

Fail:
#ifdef DEBUG_USB_HOST
        NotifyFail(rcode);
#endif
        Release();
        return rcode;
}
示例#4
0
uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
        uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
        uint8_t rcode;
        UsbDevice *p = NULL;
        EpInfo *oldep_ptr = NULL;
        uint16_t PID;
        uint16_t VID;

        // get memory address of USB device address pool
        AddressPool &addrPool = pUsb->GetAddressPool();
#ifdef EXTRADEBUG
        Notify(PSTR("\r\nPS3USB Init"), 0x80);
#endif
        // check if address has already been assigned to an instance
        if (bAddress) {
#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);

        if (!p) {
#ifdef DEBUG_USB_HOST
                Notify(PSTR("\r\nAddress not found"), 0x80);
#endif
                return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
        }

        if (!p->epinfo) {
#ifdef DEBUG_USB_HOST
                Notify(PSTR("\r\nepinfo is null"), 0x80);
#endif
                return USB_ERROR_EPINFO_IS_NULL;
        }

        // Save old pointer to EP_RECORD of address 0
        oldep_ptr = p->epinfo;

        // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
        p->epinfo = epInfo;

        p->lowspeed = lowspeed;

        // Get device descriptor
        rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data
        // Restore p->epinfo
        p->epinfo = oldep_ptr;

        if (rcode)
                goto FailGetDevDescr;

        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))
                goto FailUnknownDevice;

        // Allocate new address according to device class
        bAddress = addrPool.AllocAddress(parent, false, port);

        if (!bAddress)
                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;

        // Assign new address to the device
        rcode = pUsb->setAddr(0, 0, bAddress);
        if (rcode) {
                p->lowspeed = false;
                addrPool.FreeAddress(bAddress);
                bAddress = 0;
#ifdef DEBUG_USB_HOST
                Notify(PSTR("\r\nsetAddr: "), 0x80);
                D_PrintHex<uint8_t > (rcode, 0x80);
#endif
                return rcode;
        }
#ifdef EXTRADEBUG
        Notify(PSTR("\r\nAddr: "), 0x80);
        D_PrintHex<uint8_t > (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)
                return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;

        p->lowspeed = lowspeed;

        // Assign epInfo to epinfo pointer - only EP0 is known
        rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
        if (rcode)
                goto FailSetDevTblEntry;


        /* The application will work in reduced host mode, so we can save program and data
           memory space. After verifying the PID and VID we will use known values for the
           configuration values for device, interface, endpoints and HID for the PS3 Controllers */

        /* Initialize data structures for endpoints of device */
        epInfo[ PS3_OUTPUT_PIPE ].epAddr = 0x02; // PS3 output endpoint
        epInfo[ PS3_OUTPUT_PIPE ].epAttribs = EP_INTERRUPT;
        epInfo[ PS3_OUTPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
        epInfo[ PS3_OUTPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE;
        epInfo[ PS3_OUTPUT_PIPE ].bmSndToggle = bmSNDTOG0;
        epInfo[ PS3_OUTPUT_PIPE ].bmRcvToggle = bmRCVTOG0;
        epInfo[ PS3_INPUT_PIPE ].epAddr = 0x01; // PS3 report endpoint
        epInfo[ PS3_INPUT_PIPE ].epAttribs = EP_INTERRUPT;
        epInfo[ PS3_INPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
        epInfo[ PS3_INPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE;
        epInfo[ PS3_INPUT_PIPE ].bmSndToggle = bmSNDTOG0;
        epInfo[ PS3_INPUT_PIPE ].bmRcvToggle = bmRCVTOG0;

        rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
        if (rcode)
                goto FailSetDevTblEntry;

        delay(200); //Give time for address change

        rcode = pUsb->setConf(bAddress, epInfo[ PS3_CONTROL_PIPE ].epAddr, 1);
        if (rcode)
                goto FailSetConfDescr;

        if (PID == PS3_PID || PID == PS3NAVIGATION_PID) {
                if (PID == PS3_PID) {
#ifdef DEBUG_USB_HOST
                        Notify(PSTR("\r\nDualshock 3 Controller Connected"), 0x80);
#endif
                        PS3Connected = true;
                } else { // must be a navigation controller
#ifdef DEBUG_USB_HOST
                        Notify(PSTR("\r\nNavigation Controller Connected"), 0x80);
#endif
                        PS3NavigationConnected = true;
                }
                enable_sixaxis(); // The PS3 controller needs a special command before it starts sending data

                // Needed for PS3 Dualshock and Navigation commands to work
                for (uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++)
                        writeBuf[i] = pgm_read_byte(&PS3_REPORT_BUFFER[i]);

                for (uint8_t i = 6; i < 10; i++)
                        readBuf[i] = 0x7F; // Set the analog joystick values to center position
        } else { // must be a Motion controller
#ifdef DEBUG_USB_HOST
                Notify(PSTR("\r\nMotion Controller Connected"), 0x80);
#endif
                PS3MoveConnected = true;
                writeBuf[0] = 0x02; // Set report ID, this is needed for Move commands to work
        }
        if (my_bdaddr[0] != 0x00 || my_bdaddr[1] != 0x00 || my_bdaddr[2] != 0x00 || my_bdaddr[3] != 0x00 || my_bdaddr[4] != 0x00 || my_bdaddr[5] != 0x00) {
                if (PS3MoveConnected)
                        setMoveBdaddr(my_bdaddr); // Set internal Bluetooth address
                else
                        setBdaddr(my_bdaddr); // Set internal Bluetooth address

#ifdef DEBUG_USB_HOST
                Notify(PSTR("\r\nBluetooth Address was set to: "), 0x80);
                for (int8_t i = 5; i > 0; i--) {
                        D_PrintHex<uint8_t > (my_bdaddr[i], 0x80);
                        Notify(PSTR(":"), 0x80);
                }
                D_PrintHex<uint8_t > (my_bdaddr[0], 0x80);
#endif
        }
        onInit();

        bPollEnable = true;
        Notify(PSTR("\r\n"), 0x80);
        timer = millis();
        return 0; // successful configuration

        /* diagnostic messages */
FailGetDevDescr:
#ifdef DEBUG_USB_HOST
        NotifyFailGetDevDescr();
        goto Fail;
#endif
FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
        NotifyFailSetDevTblEntry();
        goto Fail;
#endif

FailSetConfDescr:
#ifdef DEBUG_USB_HOST
        NotifyFailSetConfDescr();
#endif
        goto Fail;
FailUnknownDevice:
#ifdef DEBUG_USB_HOST
        NotifyFailUnknownDevice(VID, PID);
#endif
        rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
Fail:

#ifdef DEBUG_USB_HOST
        Notify(PSTR("\r\nPS3 Init Failed, error code: "), 0x80);
        NotifyFail(rcode);
#endif
        Release();
        return rcode;
}
示例#5
0
void NotifyFailSetDevTblEntry(uint8_t reason) {
        NotifyFailSetDevTblEntry();
        NotifyFail(reason);

}
示例#6
0
uint8_t XR21B1411::Init(uint8_t parent, uint8_t port, bool lowspeed) {
        const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);

        uint8_t buf[constBufSize];
        USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);

        uint8_t rcode;
        UsbDevice *p = NULL;
        EpInfo *oldep_ptr = NULL;
        uint8_t num_of_conf; // number of configurations

        AddressPool &addrPool = pUsb->GetAddressPool();

        USBTRACE("XR Init\r\n");

        if(bAddress)
                return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;

        // Get pointer to pseudo device with address 0 assigned
        p = addrPool.GetUsbDevicePtr(0);

        if(!p)
                return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;

        if(!p->epinfo) {
                USBTRACE("epinfo\r\n");
                return USB_ERROR_EPINFO_IS_NULL;
        }

        // Save old pointer to EP_RECORD of address 0
        oldep_ptr = p->epinfo;

        // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
        p->epinfo = epInfo;

        p->lowspeed = lowspeed;

        // Get device descriptor
        rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf);

        // Restore p->epinfo
        p->epinfo = oldep_ptr;

        if(rcode)
                goto FailGetDevDescr;

        // Allocate new address according to device class
        bAddress = addrPool.AllocAddress(parent, false, port);

        if(!bAddress)
                return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;

        // Extract Max Packet Size from the device descriptor
        epInfo[0].maxPktSize = udd->bMaxPacketSize0;

        // Assign new address to the device
        rcode = pUsb->setAddr(0, 0, bAddress);

        if(rcode) {
                p->lowspeed = false;
                addrPool.FreeAddress(bAddress);
                bAddress = 0;
                USBTRACE2("setAddr:", rcode);
                return rcode;
        }

        USBTRACE2("Addr:", bAddress);

        p->lowspeed = false;

        p = addrPool.GetUsbDevicePtr(bAddress);

        if(!p)
                return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;

        p->lowspeed = lowspeed;

        num_of_conf = udd->bNumConfigurations;

        if((((udd->idVendor != 0x2890U) || (udd->idProduct != 0x0201U)) && ((udd->idVendor != 0x04e2U) || (udd->idProduct != 0x1411U))))
                return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;

        // Assign epInfo to epinfo pointer
        rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);

        if(rcode)
                goto FailSetDevTblEntry;

        USBTRACE2("NC:", num_of_conf);

        for(uint8_t i = 0; i < num_of_conf; i++) {
                ConfigDescParser< USB_CLASS_COM_AND_CDC_CTRL,
                        CDC_SUBCLASS_ACM,
                        CDC_PROTOCOL_ITU_T_V_250,
                        CP_MASK_COMPARE_CLASS |
                        CP_MASK_COMPARE_SUBCLASS |
                        CP_MASK_COMPARE_PROTOCOL > CdcControlParser(this);

                ConfigDescParser<USB_CLASS_CDC_DATA, 0, 0,
                        CP_MASK_COMPARE_CLASS> CdcDataParser(this);

                rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcControlParser);

                if(rcode)
                        goto FailGetConfDescr;

                rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcDataParser);

                if(rcode)
                        goto FailGetConfDescr;

                if(bNumEP > 1)
                        break;
        } // for

        if(bNumEP < 4)
                return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;

        // Assign epInfo to epinfo pointer
        rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);

        USBTRACE2("Conf:", bConfNum);

        // Set Configuration Value
        rcode = pUsb->setConf(bAddress, 0, bConfNum);

        if(rcode)
                goto FailSetConfDescr;

        // Set up features status
        _enhanced_status = enhanced_features();
        half_duplex(false);
        autoflowRTS(false);
        autoflowDSR(false);
        autoflowXON(false);
        wide(false); // Always false, because this is only available in custom mode.

        rcode = pAsync->OnInit(this);

        if(rcode)
                goto FailOnInit;

        USBTRACE("XR configured\r\n");

        ready = true;

        //bPollEnable = true;

        //USBTRACE("Poll enabled\r\n");
        return 0;

FailGetDevDescr:
#ifdef DEBUG_USB_HOST
        NotifyFailGetDevDescr();
        goto Fail;
#endif

FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
        NotifyFailSetDevTblEntry();
        goto Fail;
#endif

FailGetConfDescr:
#ifdef DEBUG_USB_HOST
        NotifyFailGetConfDescr();
        goto Fail;
#endif

FailSetConfDescr:
#ifdef DEBUG_USB_HOST
        NotifyFailSetConfDescr();
        goto Fail;
#endif

FailOnInit:
#ifdef DEBUG_USB_HOST
        USBTRACE("OnInit:");
#endif

#ifdef DEBUG_USB_HOST
Fail:
        NotifyFail(rcode);
#endif
        Release();
        return rcode;
}
示例#7
0
/**
 *
 * @param parent (not used)
 * @param port (not used)
 * @param lowspeed true if device is low speed
 * @return 0 for success
 */
uint8_t BulkOnly::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;
        USBTRACE("MS Init\r\n");

        AddressPool &addrPool = pUsb->GetAddressPool();
        UsbDevice *p = addrPool.GetUsbDevicePtr(bAddress);

        if(!p)
                return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;

        // Assign new address to the device
        delay(2000);
        rcode = pUsb->setAddr(0, 0, bAddress);

        if(rcode) {
                p->lowspeed = false;
                addrPool.FreeAddress(bAddress);
                bAddress = 0;
                USBTRACE2("setAddr:", rcode);
                return rcode;
        }

        USBTRACE2("Addr:", bAddress);

        p->lowspeed = false;

        p = addrPool.GetUsbDevicePtr(bAddress);

        if(!p)
                return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;

        p->lowspeed = lowspeed;

        // Assign epInfo to epinfo pointer
        rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);

        if(rcode)
                goto FailSetDevTblEntry;

        USBTRACE2("NC:", num_of_conf);

        for(uint8_t i = 0; i < num_of_conf; i++) {
                ConfigDescParser< USB_CLASS_MASS_STORAGE,
                        MASS_SUBCLASS_SCSI,
                        MASS_PROTO_BBB,
                        CP_MASK_COMPARE_CLASS |
                        CP_MASK_COMPARE_SUBCLASS |
                        CP_MASK_COMPARE_PROTOCOL > BulkOnlyParser(this);

                rcode = pUsb->getConfDescr(bAddress, 0, i, &BulkOnlyParser);

                if(rcode)
                        goto FailGetConfDescr;

                if(bNumEP > 1)
                        break;
        }

        if(bNumEP < 3)
                return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;

        // Assign epInfo to epinfo pointer
        pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);

        USBTRACE2("Conf:", bConfNum);

        // Set Configuration Value
        rcode = pUsb->setConf(bAddress, 0, bConfNum);

        if(rcode)
                goto FailSetConfDescr;

        //Linux does a 1sec delay after this.
        delay(1000);

        rcode = GetMaxLUN(&bMaxLUN);
        if(rcode)
                goto FailGetMaxLUN;

        if(bMaxLUN >= MASS_MAX_SUPPORTED_LUN) bMaxLUN = MASS_MAX_SUPPORTED_LUN - 1;
        ErrorMessage<uint8_t > (PSTR("MaxLUN"), bMaxLUN);

        delay(1000); // Delay a bit for slow firmware.

        for(uint8_t lun = 0; lun <= bMaxLUN; lun++) {
                InquiryResponse response;
                rcode = Inquiry(lun, sizeof (InquiryResponse), (uint8_t*) & response);
                if(rcode) {
                        ErrorMessage<uint8_t > (PSTR("Inquiry"), rcode);
                } else {
#if 0
                        printf("LUN %i `", lun);
                        uint8_t *buf = response.VendorID;
                        for(int i = 0; i < 28; i++) printf("%c", buf[i]);
                        printf("'\r\nQualifier %1.1X ", response.PeripheralQualifier);
                        printf("Device type %2.2X ", response.DeviceType);
                        printf("RMB %1.1X ", response.Removable);
                        printf("SSCS %1.1X ", response.SCCS);
                        uint8_t sv = response.Version;
                        printf("SCSI version %2.2X\r\nDevice conforms to ", sv);
                        switch(sv) {
                                case 0:
                                        printf("No specific");
                                        break;
                                case 1:
                                        printf("ANSI X3.131-1986 (ANSI 1)");
                                        break;
                                case 2:
                                        printf("ANSI X3.131-1994 (ANSI 2)");
                                        break;
                                case 3:
                                        printf("ANSI INCITS 301-1997 (SPC)");
                                        break;
                                case 4:
                                        printf("ANSI INCITS 351-2001 (SPC-2)");
                                        break;
                                case 5:
                                        printf("ANSI INCITS 408-2005 (SPC-4)");
                                        break;
                                case 6:
                                        printf("T10/1731-D (SPC-4)");
                                        break;
                                default:
                                        printf("unknown");
                        }
                        printf(" standards.\r\n");
#endif
                        uint8_t tries = 0xf0;
                        while((rcode = TestUnitReady(lun))) {
                                if(rcode == 0x08) break; // break on no media, this is OK to do.
                                // try to lock media and spin up
                                if(tries < 14) {
                                        LockMedia(lun, 1);
                                        MediaCTL(lun, 1); // I actually have a USB stick that needs this!
                                } else delay(2 * (tries + 1));
                                tries++;
                                if(!tries) break;
                        }
                        if(!rcode) {
                                delay(1000);
                                LUNOk[lun] = CheckLUN(lun);
                                if(!LUNOk[lun]) LUNOk[lun] = CheckLUN(lun);
                        }
                }
        }


        CheckMedia();

        rcode = OnInit();

        if(rcode)
                goto FailOnInit;

#ifdef DEBUG_USB_HOST
        USBTRACE("MS configured\r\n\r\n");
#endif

        bPollEnable = true;

        //USBTRACE("Poll enabled\r\n");
        return 0;

FailSetConfDescr:
#ifdef DEBUG_USB_HOST
        NotifyFailSetConfDescr();
        goto Fail;
#endif

FailOnInit:
#ifdef DEBUG_USB_HOST
        USBTRACE("OnInit:");
        goto Fail;
#endif

FailGetMaxLUN:
#ifdef DEBUG_USB_HOST
        USBTRACE("GetMaxLUN:");
        goto Fail;
#endif

        //#ifdef DEBUG_USB_HOST
        //FailInvalidSectorSize:
        //        USBTRACE("Sector Size is NOT VALID: ");
        //        goto Fail;
        //#endif

FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
        NotifyFailSetDevTblEntry();
        goto Fail;
#endif

FailGetConfDescr:
#ifdef DEBUG_USB_HOST
        NotifyFailGetConfDescr();
#endif

#ifdef DEBUG_USB_HOST
Fail:
        NotifyFail(rcode);
#endif
        Release();
        return rcode;
}
示例#8
0
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<uint8_t > (rcode, 0x80);
#endif
        p->lowspeed = false;
        goto Fail;
    }
#ifdef EXTRADEBUG
    Notify(PSTR("\r\nAddr: "), 0x80);
    D_PrintHex<uint8_t > (bAddress, 0x80);
#endif

    p->lowspeed = false;

    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;

    rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); // Assign epInfo to epinfo pointer - only EP0 is known
    if(rcode)
        goto FailSetDevTblEntry;

    if(VID == PS3_VID && (PID == PS3_PID || PID == PS3NAVIGATION_PID || PID == PS3MOVE_PID)) {
        delay(100);
        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;

#ifdef DEBUG_USB_HOST
        if(PID == PS3_PID || PID == PS3NAVIGATION_PID) {
            if(PID == PS3_PID)
                Notify(PSTR("\r\nDualshock 3 Controller Connected"), 0x80);
            else // It must be a navigation controller
                Notify(PSTR("\r\nNavigation Controller Connected"), 0x80);
        } else // It must be a Motion controller
            Notify(PSTR("\r\nMotion Controller Connected"), 0x80);
#endif

        if(my_bdaddr[0] == 0x00 && my_bdaddr[1] == 0x00 && my_bdaddr[2] == 0x00 && my_bdaddr[3] == 0x00 && my_bdaddr[4] == 0x00 && my_bdaddr[5] == 0x00) {
#ifdef DEBUG_USB_HOST
            Notify(PSTR("\r\nPlease plug in the dongle before trying to pair with the PS3 Controller\r\nor set the Bluetooth address in the constructor of the PS3BT class"), 0x80);
#endif
        } else {
            if(PID == PS3_PID || PID == PS3NAVIGATION_PID)
                setBdaddr(my_bdaddr); // Set internal Bluetooth address
            else
                setMoveBdaddr(my_bdaddr); // Set internal Bluetooth address
#ifdef DEBUG_USB_HOST
            Notify(PSTR("\r\nBluetooth Address was set to: "), 0x80);
            for(int8_t i = 5; i > 0; i--) {
                D_PrintHex<uint8_t > (my_bdaddr[i], 0x80);
                Notify(PSTR(":"), 0x80);
            }
            D_PrintHex<uint8_t > (my_bdaddr[0], 0x80);
#endif
        }

        pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, 0); // Reset configuration value
        pUsb->setAddr(bAddress, 0, 0); // Reset address
        Release(); // Release device
        return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; // Return
    } else {
        // 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
        for(uint8_t i = 0; i < num_of_conf; i++) {
            if(VID == IOGEAR_GBU521_VID && PID == IOGEAR_GBU521_PID) {
                ConfigDescParser<USB_CLASS_VENDOR_SPECIFIC, WI_SUBCLASS_RF, WI_PROTOCOL_BT, CP_MASK_COMPARE_ALL> confDescrParser(this); // Needed for the IOGEAR GBU521
                rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
            } else {
                ConfigDescParser<USB_CLASS_WIRELESS_CTRL, WI_SUBCLASS_RF, WI_PROTOCOL_BT, CP_MASK_COMPARE_ALL> confDescrParser(this);
                rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
            }
            if(rcode) // Check error code
                goto FailGetConfDescr;
            if(bNumEP >= BTD_MAX_ENDPOINTS) // All endpoints extracted
                break;
        }

        if(bNumEP < BTD_MAX_ENDPOINTS)
            goto FailUnknownDevice;

        // Assign epInfo to epinfo pointer - this time all 3 endpoins
        rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
        if(rcode)
            goto FailSetDevTblEntry;

        // Set Configuration Value
        rcode = pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, bConfNum);
        if(rcode)
            goto FailSetConfDescr;

        hci_num_reset_loops = 100; // only loop 100 times before trying to send the hci reset command
        hci_counter = 0;
        hci_state = HCI_INIT_STATE;
        watingForConnection = false;
        bPollEnable = true;

#ifdef DEBUG_USB_HOST
        Notify(PSTR("\r\nBluetooth Dongle Initialized"), 0x80);
#endif
    }
    return 0; // Successful configuration

    /* Diagnostic messages */
FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
    NotifyFailSetDevTblEntry();
    goto Fail;
#endif

FailGetConfDescr:
#ifdef DEBUG_USB_HOST
    NotifyFailGetConfDescr();
    goto Fail;
#endif

FailSetConfDescr:
#ifdef DEBUG_USB_HOST
    NotifyFailSetConfDescr();
#endif
    goto Fail;

FailUnknownDevice:
#ifdef DEBUG_USB_HOST
    NotifyFailUnknownDevice(VID, PID);
#endif
    pUsb->setAddr(bAddress, 0, 0); // Reset address
    rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
Fail:
#ifdef DEBUG_USB_HOST
    Notify(PSTR("\r\nBTD Init Failed, error code: "), 0x80);
    NotifyFail(rcode);
#endif
    Release();
    return rcode;
}
示例#9
0
uint8_t PL2303::Init(uint8_t parent, uint8_t port, bool lowspeed) {
        const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);

        uint8_t buf[constBufSize];
        USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
        uint8_t rcode;
        UsbDevice *p = NULL;
        EpInfo *oldep_ptr = NULL;
        uint8_t num_of_conf; // number of configurations
		enum pl2303_type pltype = unknown;

        AddressPool &addrPool = pUsb->GetAddressPool();

        USBTRACE("PL Init\r\n");

        if(bAddress)
                return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;

        // Get pointer to pseudo device with address 0 assigned
        p = addrPool.GetUsbDevicePtr(0);

        if(!p)
                return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;

        if(!p->epinfo) {
                USBTRACE("epinfo\r\n");
                return USB_ERROR_EPINFO_IS_NULL;
        }

        // Save old pointer to EP_RECORD of address 0
        oldep_ptr = p->epinfo;

        // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
        p->epinfo = epInfo;

        p->lowspeed = lowspeed;

        // Get device descriptor
        rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);

        // Restore p->epinfo
        p->epinfo = oldep_ptr;

        if(rcode)
                goto FailGetDevDescr;

        if(udd->idVendor != PL_VID && udd->idProduct != PL_PID)
                return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;

		/* determine chip variant */
		
		if (udd->bDeviceClass == 0x02 ) {
			pltype = type_0;
		}
		else if (udd->bMaxPacketSize0 == 0x40 ) { 
			pltype = rev_HX;
		}
		else if (udd->bDeviceClass == 0x00) {
			pltype = type_1;
		}
		else if (udd->bDeviceClass == 0xff) {
			pltype = type_1;
		}
				
        // Save type of PL chip
        wPLType = udd->bcdDevice;

        // Allocate new address according to device class
        bAddress = addrPool.AllocAddress(parent, false, port);

        if(!bAddress)
                return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;

        // Extract Max Packet Size from the device descriptor
        epInfo[0].maxPktSize = udd->bMaxPacketSize0;

        // Assign new address to the device
        rcode = pUsb->setAddr(0, 0, bAddress);

        if(rcode) {
                p->lowspeed = false;
                addrPool.FreeAddress(bAddress);
                bAddress = 0;
                USBTRACE2("setAddr:", rcode);
                return rcode;
        }

        USBTRACE2("Addr:", bAddress);

        p->lowspeed = false;

        p = addrPool.GetUsbDevicePtr(bAddress);

        if(!p)
                return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;

        p->lowspeed = lowspeed;

        num_of_conf = udd->bNumConfigurations;

        // Assign epInfo to epinfo pointer
        rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);

        if(rcode)
                goto FailSetDevTblEntry;

        USBTRACE2("NC:", num_of_conf);

        for(uint8_t i = 0; i < num_of_conf; i++) {
                HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
                ConfigDescParser < 0xFF, 0, 0, CP_MASK_COMPARE_CLASS> confDescrParser(this);

                rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);

                if(rcode)
                        goto FailGetConfDescr;

                rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);

                if(rcode)
                        goto FailGetConfDescr;

                if(bNumEP > 1)
                        break;
        } // for

        if(bNumEP < 2)
                return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;

        // Assign epInfo to epinfo pointer
        rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);

        USBTRACE2("Conf:", bConfNum);

        // Set Configuration Value
        rcode = pUsb->setConf(bAddress, 0, bConfNum);

        if(rcode)
                goto FailSetConfDescr;
				
		#if defined(PL2303_COMPAT)
			/* shamanic dance - sending Prolific init data as-is */
			vendorRead( 0x84, 0x84, 0, buf );
			vendorWrite( 0x04, 0x04, 0 );
			vendorRead( 0x84, 0x84, 0, buf );
			vendorRead( 0x83, 0x83, 0, buf );
			vendorRead( 0x84, 0x84, 0, buf );
			vendorWrite( 0x04, 0x04, 1 );
			vendorRead( 0x84, 0x84, 0, buf);
			vendorRead( 0x83, 0x83, 0, buf);
			vendorWrite( 0, 0, 1 );
			vendorWrite( 1, 0, 0 );
			if ( pltype == rev_HX ) {
				vendorWrite( 2, 0, 0x44 );
				vendorWrite( 0x06, 0x06, 0 );   //from W7 init
			}
			else {
			vendorWrite( 2, 0, 0x24 );
			}
			/* shamanic dance end */
		#endif
		
		/* calling post-init callback */
        rcode = pAsync->OnInit(this);

        if(rcode)
                goto FailOnInit;

        USBTRACE("PL configured\r\n");

        //bPollEnable = true;
        ready = true;
        return 0;

FailGetDevDescr:
#ifdef DEBUG_USB_HOST
        NotifyFailGetDevDescr();
        goto Fail;
#endif

FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
        NotifyFailSetDevTblEntry();
        goto Fail;
#endif

FailGetConfDescr:
#ifdef DEBUG_USB_HOST
        NotifyFailGetConfDescr();
        goto Fail;
#endif

FailSetConfDescr:
#ifdef DEBUG_USB_HOST
        NotifyFailSetConfDescr();
        goto Fail;
#endif

FailOnInit:
#ifdef DEBUG_USB_HOST
        USBTRACE("OnInit:");
#endif

#ifdef DEBUG_USB_HOST
Fail:
        NotifyFail(rcode);
#endif
        Release();
        return rcode;
}
/**
 *
 * @param parent (not used)
 * @param port (not used)
 * @param lowspeed true if device is low speed
 * @return 0 for success
 */
uint8_t BulkOnly::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;
        USBTRACE("MS Init\r\n");

        AddressPool &addrPool = pUsb->GetAddressPool();
        UsbDevice *p = addrPool.GetUsbDevicePtr(bAddress);

        if (!p)
                return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;

        // Assign new address to the device
        delay(2000);
        rcode = pUsb->setAddr(0, 0, bAddress);

        if (rcode) {
                p->lowspeed = false;
                addrPool.FreeAddress(bAddress);
                bAddress = 0;
                USBTRACE2("setAddr:", rcode);
                return rcode;
        }

        USBTRACE2("Addr:", bAddress);

        p->lowspeed = false;

        p = addrPool.GetUsbDevicePtr(bAddress);

        if (!p)
                return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;

        p->lowspeed = lowspeed;

        // Assign epInfo to epinfo pointer
        rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);

        if (rcode)
                goto FailSetDevTblEntry;

        USBTRACE2("NC:", num_of_conf);

        for (uint8_t i = 0; i < num_of_conf; i++) {
                ConfigDescParser< USB_CLASS_MASS_STORAGE,
                        MASS_SUBCLASS_SCSI,
                        MASS_PROTO_BBB,
                        CP_MASK_COMPARE_CLASS |
                        CP_MASK_COMPARE_SUBCLASS |
                        CP_MASK_COMPARE_PROTOCOL > BulkOnlyParser(this);

                rcode = pUsb->getConfDescr(bAddress, 0, i, &BulkOnlyParser);

                if (rcode)
                        goto FailGetConfDescr;

                if (bNumEP > 1)
                        break;
        } // for

        if (bNumEP < 3)
                return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;

        // Assign epInfo to epinfo pointer
        pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);

        USBTRACE2("Conf:", bConfNum);

        // Set Configuration Value
        rcode = pUsb->setConf(bAddress, 0, bConfNum);

        if (rcode)
                goto FailSetConfDescr;

        //Linux does a 1sec delay after this.
        delay(1000);

        rcode = GetMaxLUN(&bMaxLUN);
        if (rcode)
                goto FailGetMaxLUN;

        if (bMaxLUN >= MASS_MAX_SUPPORTED_LUN) bMaxLUN = MASS_MAX_SUPPORTED_LUN - 1;
        ErrorMessage<uint8_t > (PSTR("MaxLUN"), bMaxLUN);

        delay(1000); // Delay a bit for slow firmware.

        //bTheLUN = bMaxLUN;

        for (uint8_t lun = 0; lun <= bMaxLUN; lun++) {
                InquiryResponse response;
                rcode = Inquiry(lun, sizeof (InquiryResponse), (uint8_t*) & response);
                if (rcode) {
                        ErrorMessage<uint8_t > (PSTR("Inquiry"), rcode);
                } else {
                        uint8_t tries = 0xf0;
                        while (rcode = TestUnitReady(lun)) {
                                if (rcode == 0x08) break; // break on no media, this is OK to do.
                                // try to lock media and spin up
                                if (tries < 14) {
                                        LockMedia(lun, 1);
                                        MediaCTL(lun, 1); // I actually have a USB stick that needs this!
                                } else delay(2 * (tries + 1));
                                tries++;
                                if (!tries) break;
                        }
                        if (!rcode) {
                                delay(1000);
                                LUNOk[lun] = CheckLUN(lun);
                                if (!LUNOk[lun]) LUNOk[lun] = CheckLUN(lun);
                        }
                }
        }


#if 0
        {
                bool good;
                for (uint8_t i = 1; i == 0; i++) {
                        good = false;
                        CheckMedia();
                        for (uint8_t lun = 0; lun <= bMaxLUN; lun++) good |= LUNOk[lun];
                        if (good) break;
                        delay(118); // 255 loops =~ 30 seconds to allow for spin up, as per SCSI spec.
                }
        }
#else
        CheckMedia();
#endif

        rcode = OnInit();

        if (rcode)
                goto FailOnInit;

        USBTRACE("MS configured\r\n\r\n");

        bPollEnable = true;

        //USBTRACE("Poll enabled\r\n");
        return 0;

FailSetConfDescr:
#ifdef DEBUG_USB_HOST
        NotifyFailSetConfDescr();
        goto Fail;
#endif

FailOnInit:
#ifdef DEBUG_USB_HOST
        USBTRACE("OnInit:");
        goto Fail;
#endif

FailGetMaxLUN:
#ifdef DEBUG_USB_HOST
        USBTRACE("GetMaxLUN:");
        goto Fail;
#endif

FailInvalidSectorSize:
#ifdef DEBUG_USB_HOST
        USBTRACE("Sector Size is NOT VALID: ");
        goto Fail;
#endif

FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
        NotifyFailSetDevTblEntry();
        goto Fail;
#endif

FailGetConfDescr:
#ifdef DEBUG_USB_HOST
        NotifyFailGetConfDescr();
#endif

Fail:
#ifdef DEBUG_USB_HOST
        NotifyFail(rcode);
#endif
        Release();
        return rcode;
}