/*
 ## Cypress CyAPI C++ library source file (CyAPI.cpp)
 ## =======================================================
 ##
 ##  Copyright Cypress Semiconductor Corporation, 2009-2012,
 ##  All Rights Reserved
 ##  UNPUBLISHED, LICENSED SOFTWARE.
 ##
 ##  CONFIDENTIAL AND PROPRIETARY INFORMATION
 ##  WHICH IS THE PROPERTY OF CYPRESS.
 ##
 ##  Use of this file is governed
 ##  by the license agreement included in the file
 ##
 ##  <install>/license/license.rtf
 ##
 ##  where <install> is the Cypress software
 ##  install root directory path.
 ##
 ## =======================================================
*/
#ifndef WINVER
#define WINVER 0x0500
#endif

#include <objbase.h>
#include <setupapi.h>
#include <stdio.h>
#include "cyioctl.h"
#include "CyAPI.h"
#include "UsbdStatus.h"
#include "dbt.h"

const char API_VERSION[8] = "1.3.2.0";

UINT SPI_FLASH_PAGE_SIZE_IN_BYTE = 256;
UINT SPI_FLASH_SECTOR_SIZE_IN_BYTE = (64 * 1024);
UINT CYWB_BL_MAX_BUFFER_SIZE_WHEN_USING_EP0_TRANSPORT = BUFSIZE_UPORT; //(8 * 512); // 4KB

////////////////////////////////////////////////////////////////////////////////
//
// The USB Device Class
//
////////////////////////////////////////////////////////////////////////////////

// Constructor
CCyUSBDevice::CCyUSBDevice(HANDLE hnd, GUID guid, BOOL bOpen)
{
    hDevice = INVALID_HANDLE_VALUE;
    hDevNotification = 0;
    hHndNotification = 0;

    DevNum = 0;
    CfgNum = 0;
    IntfcNum  = 0;     // The current selected interface's bInterfaceNumber
    IntfcIndex = 0;    // The entry in the Config's interfaces table matching to IntfcNum and AltSetting

    Devices = 0;
    Interfaces = 0;
    AltInterfaces = 0;
    Configs = 0;

    DrvGuid = guid;
    hWnd = hnd;
    LastError  = 0;

    EndPoints         = NULL;
    ControlEndPt      = NULL;
    IsocInEndPt       = NULL;
    IsocOutEndPt      = NULL;
    BulkInEndPt       = NULL;
    BulkOutEndPt      = NULL;
    InterruptInEndPt  = NULL;
    InterruptOutEndPt = NULL;

    USBCfgs[0] = NULL;
    USBCfgs[1] = NULL;
    USBConfigDescriptors[0] = NULL;
    USBConfigDescriptors[1] = NULL;
    pUsbBosDescriptor = NULL;
    UsbBos = NULL;

    ZeroMemory(Manufacturer, USB_STRING_MAXLEN);
    ZeroMemory(Product, USB_STRING_MAXLEN);
    ZeroMemory(SerialNumber, USB_STRING_MAXLEN);
    ZeroMemory(DeviceName, USB_STRING_MAXLEN);
    ZeroMemory(FriendlyName, USB_STRING_MAXLEN);


    if (hnd) RegisterForPnpEvents(hnd);

    if (bOpen) Open(DevNum);
}

//______________________________________________________________________________

CCyUSBDevice::~CCyUSBDevice(void)
{

    Close();

    if (hDevNotification) {
        if (! UnregisterDeviceNotification(hDevNotification))
            throw "Failed to close the device notification handle.";
        hDevNotification = 0;
    }

}


//______________________________________________________________________________
//
// It is expected that the device will only expose a single Config via the
// Windows USB HCD stack.  The driver doesn't even expose an IOCTL for setting
// the configuration.
//
// This method just initializes a bunch of important variables, most important
// of which is the call to SetAltIntfcParams( ).

void  CCyUSBDevice::SetConfig(UCHAR cfg){

    if (!USBCfgs[0]) return;

    CfgNum = 0;
    if ((USBCfgs[0]) && (USBCfgs[0]->iConfiguration == cfg)) CfgNum = cfg;
    if ((USBCfgs[1]) && (USBCfgs[1]->iConfiguration == cfg)) CfgNum = cfg;

    ConfigValue   = USBCfgs[CfgNum]->bConfigurationValue;
    ConfigAttrib  = USBCfgs[CfgNum]->bmAttributes;
    MaxPower      = USBCfgs[CfgNum]->MaxPower;
    Interfaces    = USBCfgs[CfgNum]->bNumInterfaces;
    AltInterfaces = USBCfgs[CfgNum]->AltInterfaces;
    IntfcNum      = USBCfgs[CfgNum]->Interfaces[0]->bInterfaceNumber;

    UCHAR a  = AltIntfc();  // Get the current alt setting from the device
    SetAltIntfcParams(a);   // Initializes endpts, IntfcIndex, etc. without actually setting the AltInterface

    if (USBCfgs[CfgNum]->Interfaces[IntfcIndex]) {
        IntfcClass = USBCfgs[CfgNum]->Interfaces[IntfcIndex]->bInterfaceClass;
        IntfcSubClass = USBCfgs[CfgNum]->Interfaces[IntfcIndex]->bInterfaceSubClass;
        IntfcProtocol = USBCfgs[CfgNum]->Interfaces[IntfcIndex]->bInterfaceProtocol;
    }


}

//______________________________________________________________________________


UCHAR   CCyUSBDevice::ConfigCount(void){

    if (hDevice == INVALID_HANDLE_VALUE) return (UCHAR) NULL;

    return Configs;

}

//______________________________________________________________________________

UCHAR   CCyUSBDevice::IntfcCount(void){

    if (hDevice == INVALID_HANDLE_VALUE) return (UCHAR) NULL;

    return Interfaces;

}

//______________________________________________________________________________
// This method is not currently exposed because the driver does not support
// selection of the interface.  This is because the Windows USB hub driver
// creates a new device node for each interface.
/*
void   CCyUSBDevice::SetInterface(UCHAR i){
if (i < NumInterfaces) IntfcNum = i;

if (Configs[CfgNum]) {
for (int j=0; j < Configs[CfgNum]->bAltInterfaces; j++)
if ( (Configs[CfgNum]->Interfaces[j]->bInterfaceNumber == IntfcNum) &&
(Configs[CfgNum]->Interfaces[j]->bAlternateSetting == AltSetting) ) {


// TODO: Select the specified interface via the driver



IntfcIndex = j;
return;
}
}

}

*/
//______________________________________________________________________________

UCHAR   CCyUSBDevice::AltIntfc(void){

    UCHAR alt;
    if (IoControl(IOCTL_ADAPT_GET_ALT_INTERFACE_SETTING, &alt, 1))
        return alt;
    else
        return 0xFF;
}


//______________________________________________________________________________

void   CCyUSBDevice::SetAltIntfcParams(UCHAR alt){

    // Find match of IntfcNum and alt in table of interfaces
    if (USBCfgs[CfgNum]) {
        for (int j=0; j < USBCfgs[CfgNum]->AltInterfaces; j++)
            if ( //(USBCfgs[CfgNum]->Interfaces[j]->bInterfaceNumber == IntfcNum) &&
                (USBCfgs[CfgNum]->Interfaces[j]->bAlternateSetting == alt) ) {

                    IntfcIndex = j;
                    IntfcClass = USBCfgs[CfgNum]->Interfaces[j]->bInterfaceClass;
                    IntfcSubClass = USBCfgs[CfgNum]->Interfaces[j]->bInterfaceSubClass;;
                    IntfcProtocol = USBCfgs[CfgNum]->Interfaces[j]->bInterfaceProtocol;;

                    SetEndPointPtrs();
                    return;
            }
    }

}

//______________________________________________________________________________

bool CCyUSBDevice::SetAltIntfc(UCHAR alt){

    bool bSuccess = false;

    if (alt == AltIntfc()) return true;

    // Find match of IntfcNum and alt in table of interfaces
    if (USBCfgs[CfgNum]) {
        for (int j=0; j < USBCfgs[CfgNum]->AltInterfaces; j++)
            if ( //(USBCfgs[CfgNum]->Interfaces[j]->bInterfaceNumber == IntfcNum) &&
                (USBCfgs[CfgNum]->Interfaces[j]->bAlternateSetting == alt) ) {

                    IntfcIndex = j;

                    // Actually change to the alt interface, calling the driver
                    bSuccess = IoControl(IOCTL_ADAPT_SELECT_INTERFACE, &alt, 1L);

                    IntfcClass = USBCfgs[CfgNum]->Interfaces[j]->bInterfaceClass;
                    IntfcSubClass = USBCfgs[CfgNum]->Interfaces[j]->bInterfaceSubClass;;
                    IntfcProtocol = USBCfgs[CfgNum]->Interfaces[j]->bInterfaceProtocol;;

                    SetEndPointPtrs();
                    return bSuccess;
            }
    }

    return bSuccess;

}

//______________________________________________________________________________
// Returns the total number of alternate interfaces for the current interface

UCHAR  CCyUSBDevice::AltIntfcCount(void) {

    if (USBCfgs[CfgNum])
        return USBCfgs[CfgNum]->Interfaces[IntfcIndex]->bAltSettings - 1;

    return 0;  // The primary interface is not considered an Alt interface
    // even though it does have an AltSetting value (0)

}


//______________________________________________________________________________

UCHAR  CCyUSBDevice::EndPointCount(void) {

    if (hDevice == INVALID_HANDLE_VALUE) return (UCHAR) NULL;

    if (USBCfgs[CfgNum])
        return USBCfgs[CfgNum]->Interfaces[IntfcIndex]->bNumEndpoints+1; // Include EndPt0

    return (UCHAR) NULL;
}


//______________________________________________________________________________

void  CCyUSBDevice::GetDeviceName(void) {

    ZeroMemory(DeviceName, USB_STRING_MAXLEN);

    if (hDevice == INVALID_HANDLE_VALUE) return;

    IoControl(IOCTL_ADAPT_GET_DEVICE_NAME, (PUCHAR)DeviceName, USB_STRING_MAXLEN);
}

//______________________________________________________________________________

void  CCyUSBDevice::GetFriendlyName(void) {

    ZeroMemory(FriendlyName, USB_STRING_MAXLEN);

    if (hDevice == INVALID_HANDLE_VALUE) return;

    IoControl(IOCTL_ADAPT_GET_FRIENDLY_NAME, (PUCHAR)FriendlyName, USB_STRING_MAXLEN);
}

//______________________________________________________________________________

void  CCyUSBDevice::GetUSBAddress(void) {

    if (hDevice == INVALID_HANDLE_VALUE) {
        USBAddress = 0;
        return;
    }

    bool bRetVal = IoControl(IOCTL_ADAPT_GET_ADDRESS, &USBAddress, 1L);
    if (!bRetVal || BytesXfered == 0) USBAddress = 0;
}

//______________________________________________________________________________

void  CCyUSBDevice::GetDriverVer(void) {

    if (hDevice == INVALID_HANDLE_VALUE) {
        DriverVersion = (ULONG) NULL;
        return;
    }

    bool bRetVal = IoControl(IOCTL_ADAPT_GET_DRIVER_VERSION,  (PUCHAR) &DriverVersion, sizeof(ULONG));
    if (!bRetVal || BytesXfered == 0) DriverVersion = 0;
}

//______________________________________________________________________________

void  CCyUSBDevice::GetUSBDIVer(void) {

    if (hDevice == INVALID_HANDLE_VALUE) {
        USBDIVersion = (ULONG)  NULL;
        return;
    }

    bool bRetVal = IoControl(IOCTL_ADAPT_GET_USBDI_VERSION, (PUCHAR) &USBDIVersion, sizeof(ULONG));
    if (!bRetVal || BytesXfered == 0) USBDIVersion = 0;
}

//______________________________________________________________________________

UCHAR  CCyUSBDevice::DeviceCount(void){

    //SP_DEVINFO_DATA devInfoData;
    SP_DEVICE_INTERFACE_DATA  devInterfaceData;

    //Open a handle to the plug and play dev node.
    //SetupDiGetClassDevs() returns a device information set that contains info on all
    // installed devices of a specified class which are present.
    HDEVINFO hwDeviceInfo = SetupDiGetClassDevs ( (LPGUID) &DrvGuid,
        NULL,
        NULL,
        DIGCF_PRESENT|DIGCF_INTERFACEDEVICE);

    Devices = 0;

    if (hwDeviceInfo != INVALID_HANDLE_VALUE) {

        //SetupDiEnumDeviceInterfaces() returns information about device interfaces
        // exposed by one or more devices. Each call returns information about one interface.
        //The routine can be called repeatedly to get information about several interfaces
        // exposed by one or more devices.

        devInterfaceData.cbSize = sizeof(devInterfaceData);

        // Count the number of devices
        int i=0;
        Devices = 0;
        bool bDone = false;

        while (!bDone) {
            BOOL bRetVal = SetupDiEnumDeviceInterfaces (hwDeviceInfo, 0, (LPGUID) &DrvGuid,
                i, &devInterfaceData);

            if (bRetVal)
                Devices++;
            else {
                DWORD dwLastError = GetLastError();
                if (dwLastError == ERROR_NO_MORE_ITEMS) bDone = TRUE;
            }

            i++;
        }

        SetupDiDestroyDeviceInfoList(hwDeviceInfo);
    }

    return Devices;
}

//______________________________________________________________________________

bool CCyUSBDevice::CreateHandle(UCHAR dev){

    Devices = DeviceCount();

    if (!Devices) return false;

    if (dev > (Devices - 1)) return false; //dev = Devices-1;

    SP_DEVINFO_DATA devInfoData;
    SP_DEVICE_INTERFACE_DATA  devInterfaceData;
    PSP_INTERFACE_DEVICE_DETAIL_DATA functionClassDeviceData;
    SP_INTERFACE_DEVICE_DETAIL_DATA tmpInterfaceDeviceDetailData;

    ULONG requiredLength = 0;
    int deviceNumber = dev;

    HANDLE hFile;

    //Open a handle to the plug and play dev node.
    //SetupDiGetClassDevs() returns a device information set that contains info on all
    // installed devices of a specified class which are present.
    HDEVINFO hwDeviceInfo = SetupDiGetClassDevs ( (LPGUID) &DrvGuid,
        NULL,
        NULL,
        DIGCF_PRESENT|DIGCF_INTERFACEDEVICE);

    if (hwDeviceInfo != INVALID_HANDLE_VALUE) {

        //SetupDiEnumDeviceInterfaces() returns information about device interfaces
        // exposed by one or more devices. Each call returns information about one interface.
        //The routine can be called repeatedly to get information about several interfaces
        // exposed by one or more devices.

        devInterfaceData.cbSize = sizeof(devInterfaceData);

        if (SetupDiEnumDeviceInterfaces ( hwDeviceInfo, 0, (LPGUID) &DrvGuid,
            deviceNumber, &devInterfaceData)) {
                //Allocate a function class device data structure to receive the goods about this
                // particular device.
                SetupDiGetInterfaceDeviceDetail ( hwDeviceInfo, &devInterfaceData, NULL, 0,
                    &requiredLength, NULL);

                ULONG predictedLength = requiredLength;

                functionClassDeviceData = (PSP_INTERFACE_DEVICE_DETAIL_DATA) malloc (predictedLength);
                functionClassDeviceData->cbSize =  sizeof (SP_INTERFACE_DEVICE_DETAIL_DATA);
                devInfoData.cbSize = sizeof(devInfoData);
                //Retrieve the information from Plug and Play */
                if (SetupDiGetInterfaceDeviceDetail (hwDeviceInfo,
                    &devInterfaceData,
                    functionClassDeviceData,
                    predictedLength,
                    &requiredLength,
                    &devInfoData)) {

                        /* NOTE : x64 packing issue ,requiredLength return 5byte size of the (SP_INTERFACE_DEVICE_DETAIL_DATA) and functionClassDeviceData needed sizeof functionClassDeviceData 8byte */
                        int pathLen = requiredLength - (sizeof (tmpInterfaceDeviceDetailData.cbSize)+sizeof (tmpInterfaceDeviceDetailData.DevicePath));
                        //int pathLen = requiredLength - functionClassDeviceData->cbSize;

                        memcpy (DevPath, functionClassDeviceData->DevicePath, pathLen);
                        DevPath[pathLen] = 0;

                        hFile = CreateFile (DevPath,
                            GENERIC_WRITE | GENERIC_READ,
                            FILE_SHARE_WRITE | FILE_SHARE_READ,
                            NULL,
                            OPEN_EXISTING,
                            FILE_FLAG_OVERLAPPED,
                            NULL);

                        DWORD errCode =  GetLastError();
                        free(functionClassDeviceData);
                        SetupDiDestroyDeviceInfoList(hwDeviceInfo);

                        if (hFile == INVALID_HANDLE_VALUE)
                        {
                            LastError = GetLastError();
                            return false;
                        }
                        // hDevice, DevNum, USBDeviceDescriptor, and Configs are data members
                        hDevice = hFile;

                        return true;
                }

        }

        SetupDiDestroyDeviceInfoList(hwDeviceInfo);

    }

    // Got here by failing at some point

    hDevice = INVALID_HANDLE_VALUE;
    DevNum = 0;
    return false;

}


//______________________________________________________________________________

bool CCyUSBDevice::Open(UCHAR dev){

    // If this CCyUSBDevice object already has the driver open, close it.
    if (hDevice != INVALID_HANDLE_VALUE)
        Close();



    if (CreateHandle(dev)) {
        DevNum = dev;

        // Important call: Gets the device descriptor data from the device
        GetDevDescriptor();

        // Gets the language IDs and selects English, if avail
        SetStringDescrLanguage();

        GetString(Manufacturer,USBDeviceDescriptor.iManufacturer);
        GetString(Product,USBDeviceDescriptor.iProduct);
        GetString(SerialNumber,USBDeviceDescriptor.iSerialNumber);

        // Get BOS descriptor
        if ((BcdUSB & BCDUSBJJMASK) == USB30MAJORVER)
        {
            if(GetInternalBosDescriptor()) // USB3.0 specific descriptor
			{
				try
				{
					UsbBos = new CCyUSBBOS(hDevice,pUsbBosDescriptor);
				}
				catch(char *Str)
				{
					char *Str1 = Str;// just to ignore warning
					MessageBox(NULL,"Please correct firmware BOS descriptor table","Wrong BOS Descriptor",(UINT) NULL);
					Close(); // Close the device handle.
					return false;
				}
			}
        }
        GetUSBAddress();
        GetDeviceName();
        GetFriendlyName();
        GetDriverVer();
        GetUSBDIVer();
        GetSpeed();

        // Gets the config (including interface and endpoint) descriptors from the device
        for (int i=0; i<Configs; i++)
		{
            GetCfgDescriptor(i);
			try
			{
				if (USBConfigDescriptors[i])
				{
					if((BcdUSB & BCDUSBJJMASK) == USB20MAJORVER)
						USBCfgs[i] = new CCyUSBConfig(hDevice,USBConfigDescriptors[i]);
					else
					{
						UCHAR usb30Dummy =1;
						USBCfgs[i] = new CCyUSBConfig(hDevice,USBConfigDescriptors[i],usb30Dummy);
					}
				}
			}
			catch(char *Str)
			{
				char *Str1 = Str; // just to ignore warning
				MessageBox(NULL,"Please correct firmware descriptor table","Wrong Device Configuration",(UINT) NULL);
				Close(); // Close the device handle.
				return false;
			}
        }

        // Manually configure the Control Endpoint (EPT 0)
        ControlEndPt = new CCyControlEndPoint(hDevice, NULL);
        ControlEndPt->DscLen     = 7;
        ControlEndPt->DscType    = 5;
        ControlEndPt->Address    = 0;
        ControlEndPt->Attributes = 0;
        ControlEndPt->MaxPktSize = MaxPacketSize;
        ControlEndPt->Interval   = 0;

        // We succeeded in openning a handle to the device.  But, the device
        // is not returning descriptors properly.  We don't call Close( ) because
        // we want to leave the hDevice intact, giving the user the opportunity
        // to call the Reset( ) method
        if (!USBCfgs[0] || !USBCfgs[0]->Interfaces[0])
            return false;

        // This call sets values for ConfigVal, ConfigAttrib, MaxPower, etc.
        SetConfig(0);

        // If we registered for device notification, also register the handle
        // This is necessary in order to receive notification of removal (allowing us to close)
        // before the device re-connects (for such things as our ReConnect method).
        if (hDevNotification) {
            DEV_BROADCAST_HANDLE hFilter;
            hFilter.dbch_size = sizeof(DEV_BROADCAST_HANDLE);
            hFilter.dbch_devicetype = DBT_DEVTYP_HANDLE;
            hFilter.dbch_handle = hDevice;

            hHndNotification = RegisterDeviceNotification(hWnd, (PVOID) &hFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
        }

        return true;
    }


    // Got here by failing at some point

    hDevice = INVALID_HANDLE_VALUE;
    DevNum = 0;
    return false;
}


//______________________________________________________________________________

void CCyUSBDevice::DestroyHandle(void){

    if ( hDevice != INVALID_HANDLE_VALUE ) {

        if (hHndNotification)
            if (! UnregisterDeviceNotification(hHndNotification))
            {
                LastError = GetLastError();
                throw "Failed to close the handle notification handle.";
            }

            if (! CloseHandle(hDevice))
            {
                LastError = GetLastError();
                throw "Failed to close handle to driver.";
            }

            hDevice = INVALID_HANDLE_VALUE;
            hHndNotification = 0;
    }

}
//______________________________________________________________________________

void CCyUSBDevice::Close(void){

    DestroyHandle();
    ZeroMemory(&USBDeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));

    if(pUsbBosDescriptor)
    {
        free(pUsbBosDescriptor);
        pUsbBosDescriptor =NULL;
    }
	if(UsbBos)
	{
		delete UsbBos ;
		UsbBos = NULL;
	}
    // Clean-up dynamically allocated objects
    for (int i=0; i<Configs; i++)
        if (USBConfigDescriptors[i]) {
            free(USBConfigDescriptors[i]);
            USBConfigDescriptors[i] = NULL;
            delete USBCfgs[i];
            USBCfgs[i] = NULL;
        }


        // Reset the private pointers
        ControlEndPt      = NULL;
        IsocInEndPt       = NULL;
        IsocOutEndPt      = NULL;
        BulkInEndPt       = NULL;
        BulkOutEndPt      = NULL;
        InterruptInEndPt  = NULL;
        InterruptOutEndPt = NULL;

        Devices = 0;
        Configs = 0;
        Interfaces = 0;
        AltInterfaces = 0;

}


//______________________________________________________________________________

bool CCyUSBDevice::IoControl(ULONG cmd, PUCHAR XferBuf, ULONG len){

    if ( hDevice == INVALID_HANDLE_VALUE ) return false;
    BOOL bDioRetVal = DeviceIoControl (hDevice, cmd, XferBuf, len, XferBuf, len, &BytesXfered, NULL);
    if(!bDioRetVal)LastError = GetLastError();
    return (bDioRetVal && (BytesXfered == len));
}


//______________________________________________________________________________

bool CCyUSBDevice::GetInternalBosDescriptor()
{
    ULONG length = sizeof(SINGLE_TRANSFER) + sizeof(USB_BOS_DESCRIPTOR);
    PUCHAR buf = new UCHAR[length];
    ZeroMemory (buf, length);

    PSINGLE_TRANSFER pSingleTransfer = (PSINGLE_TRANSFER) buf;
    pSingleTransfer->SetupPacket.bmReqType.Direction = DIR_DEVICE_TO_HOST;
    pSingleTransfer->SetupPacket.bmReqType.Type      = 0;
    pSingleTransfer->SetupPacket.bmReqType.Recipient = 0;
    pSingleTransfer->SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
    pSingleTransfer->SetupPacket.wVal.hiByte = USB_BOS_DESCRIPTOR_TYPE;
    pSingleTransfer->SetupPacket.wVal.lowByte = 0;
    pSingleTransfer->SetupPacket.wLength = sizeof(USB_BOS_DESCRIPTOR);
    pSingleTransfer->SetupPacket.ulTimeOut = 5;
    pSingleTransfer->BufferLength = pSingleTransfer->SetupPacket.wLength;
    pSingleTransfer->BufferOffset = sizeof(SINGLE_TRANSFER);

    bool bRetVal = IoControl(IOCTL_ADAPT_SEND_EP0_CONTROL_TRANSFER, buf, length);
    UsbdStatus = pSingleTransfer->UsbdStatus;
    NtStatus = pSingleTransfer->NtStatus;

    if (bRetVal) {
        PUSB_BOS_DESCRIPTOR BosDesc = (PUSB_BOS_DESCRIPTOR)((PCHAR)pSingleTransfer + pSingleTransfer->BufferOffset);
        USHORT BosDescLength= BosDesc->wTotalLength;

        length = sizeof(SINGLE_TRANSFER) + BosDescLength;
        PUCHAR buf2 = new UCHAR[length];
        ZeroMemory (buf2, length);

        pSingleTransfer = (PSINGLE_TRANSFER) buf2;
        pSingleTransfer->SetupPacket.bmReqType.Direction = DIR_DEVICE_TO_HOST;
        pSingleTransfer->SetupPacket.bmReqType.Type      = 0;
        pSingleTransfer->SetupPacket.bmReqType.Recipient = 0;
        pSingleTransfer->SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
        pSingleTransfer->SetupPacket.wVal.hiByte = USB_BOS_DESCRIPTOR_TYPE;
        pSingleTransfer->SetupPacket.wVal.lowByte = 0;
        pSingleTransfer->SetupPacket.wLength = BosDescLength;
        pSingleTransfer->SetupPacket.ulTimeOut = 5;
        pSingleTransfer->BufferLength = pSingleTransfer->SetupPacket.wLength;
        pSingleTransfer->BufferOffset = sizeof(SINGLE_TRANSFER);

        bRetVal = IoControl(IOCTL_ADAPT_SEND_EP0_CONTROL_TRANSFER, buf2, length);
        UsbdStatus = pSingleTransfer->UsbdStatus;
        NtStatus = pSingleTransfer->NtStatus;

        if (bRetVal)
        {
            pUsbBosDescriptor = (PUSB_BOS_DESCRIPTOR)malloc(BosDescLength);
            memcpy(pUsbBosDescriptor, (PVOID)((PCHAR)pSingleTransfer + pSingleTransfer->BufferOffset), BosDescLength);
        }

        delete[] buf2;

    }

    delete[] buf;
    return bRetVal;
}
void CCyUSBDevice::GetDevDescriptor(void)
{

    ULONG length = sizeof(SINGLE_TRANSFER) + sizeof(USB_DEVICE_DESCRIPTOR);
    PUCHAR buf = new UCHAR[length];
    ZeroMemory (buf, length);

    //USB_DEVICE_DESCRIPTOR devDescriptor;
    ZeroMemory (&USBDeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));

    PSINGLE_TRANSFER pSingleTransfer = (PSINGLE_TRANSFER) buf;
    pSingleTransfer->SetupPacket.bmReqType.Direction = DIR_DEVICE_TO_HOST;
    pSingleTransfer->SetupPacket.bmReqType.Type      = 0;
    pSingleTransfer->SetupPacket.bmReqType.Recipient = 0;
    pSingleTransfer->SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
    pSingleTransfer->SetupPacket.wVal.hiByte = USB_DEVICE_DESCRIPTOR_TYPE;
    pSingleTransfer->SetupPacket.wLength = sizeof(USB_DEVICE_DESCRIPTOR);
    pSingleTransfer->SetupPacket.ulTimeOut = 5;
    pSingleTransfer->BufferLength = pSingleTransfer->SetupPacket.wLength;
    pSingleTransfer->BufferOffset = sizeof(SINGLE_TRANSFER);

    bool bRetVal = IoControl(IOCTL_ADAPT_SEND_EP0_CONTROL_TRANSFER, buf, length);
    UsbdStatus = pSingleTransfer->UsbdStatus;
    NtStatus = pSingleTransfer->NtStatus;

    if (bRetVal) {
        memcpy(&USBDeviceDescriptor, (PVOID)((PCHAR)pSingleTransfer + pSingleTransfer->BufferOffset), sizeof(USB_DEVICE_DESCRIPTOR));

        BcdUSB         = USBDeviceDescriptor.bcdUSB;
        VendorID       = USBDeviceDescriptor.idVendor;
        ProductID      = USBDeviceDescriptor.idProduct;
        DevClass       = USBDeviceDescriptor.bDeviceClass;
        DevSubClass    = USBDeviceDescriptor.bDeviceSubClass;
        DevProtocol    = USBDeviceDescriptor.bDeviceProtocol;
		if((BcdUSB & BCDUSBJJMASK) == USB20MAJORVER)
			MaxPacketSize  = USBDeviceDescriptor.bMaxPacketSize0;
		else
			MaxPacketSize  = (1<<USBDeviceDescriptor.bMaxPacketSize0);

        BcdDevice      = USBDeviceDescriptor.bcdDevice;
        Configs        = USBDeviceDescriptor.bNumConfigurations;
    }

    delete[] buf;

    //return devDescriptor;
}

//______________________________________________________________________________

void CCyUSBDevice::SetStringDescrLanguage(void) {

    // Get the header to find-out the number of languages, size of lang ID list
    ULONG length = sizeof(SINGLE_TRANSFER) + sizeof(USB_COMMON_DESCRIPTOR);
    PUCHAR buf = new UCHAR[length];
    ZeroMemory (buf, length);

    USB_COMMON_DESCRIPTOR cmnDescriptor;
    ZeroMemory (&cmnDescriptor, sizeof(USB_COMMON_DESCRIPTOR));

    PSINGLE_TRANSFER pSingleTransfer = (PSINGLE_TRANSFER) buf;
    pSingleTransfer->SetupPacket.bmReqType.Direction = DIR_DEVICE_TO_HOST;
    pSingleTransfer->SetupPacket.bmReqType.Type      = 0;
    pSingleTransfer->SetupPacket.bmReqType.Recipient = 0;
    pSingleTransfer->SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
    pSingleTransfer->SetupPacket.wVal.hiByte = USB_STRING_DESCRIPTOR_TYPE;
    pSingleTransfer->SetupPacket.wVal.lowByte = 0;
    pSingleTransfer->SetupPacket.wLength = sizeof(USB_COMMON_DESCRIPTOR);
    pSingleTransfer->SetupPacket.ulTimeOut = 5;
    pSingleTransfer->BufferLength = pSingleTransfer->SetupPacket.wLength;
    pSingleTransfer->BufferOffset = sizeof(SINGLE_TRANSFER);

    bool bRetVal = IoControl(IOCTL_ADAPT_SEND_EP0_CONTROL_TRANSFER, buf, length);
    UsbdStatus = pSingleTransfer->UsbdStatus;

    if (bRetVal) {
        memcpy(&cmnDescriptor, (PVOID)((PCHAR)pSingleTransfer + pSingleTransfer->BufferOffset), sizeof(USB_COMMON_DESCRIPTOR));

        int LangIDs = (cmnDescriptor.bLength - 2 ) / 2;

        // Get the entire descriptor, all LangIDs
        length = sizeof(SINGLE_TRANSFER) + cmnDescriptor.bLength;
        PUCHAR buf2 = new UCHAR[length];
        ZeroMemory (buf2, length);

        pSingleTransfer = (PSINGLE_TRANSFER) buf2;
        pSingleTransfer->SetupPacket.bmReqType.Direction = DIR_DEVICE_TO_HOST;
        pSingleTransfer->SetupPacket.bmReqType.Type      = 0;
        pSingleTransfer->SetupPacket.bmReqType.Recipient = 0;
        pSingleTransfer->SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
        pSingleTransfer->SetupPacket.wVal.hiByte = USB_STRING_DESCRIPTOR_TYPE;
        pSingleTransfer->SetupPacket.wVal.lowByte = 0;
        pSingleTransfer->SetupPacket.wLength = cmnDescriptor.bLength;
        pSingleTransfer->SetupPacket.ulTimeOut = 5;
        pSingleTransfer->BufferLength = pSingleTransfer->SetupPacket.wLength;
        pSingleTransfer->BufferOffset = sizeof(SINGLE_TRANSFER);

        bRetVal = IoControl(IOCTL_ADAPT_SEND_EP0_CONTROL_TRANSFER, buf2, length);

        UsbdStatus = pSingleTransfer->UsbdStatus;

        if (bRetVal) {
            PUSB_STRING_DESCRIPTOR IDs = (PUSB_STRING_DESCRIPTOR) (buf2 + sizeof(SINGLE_TRANSFER));

            StrLangID =(LangIDs) ? IDs[0].bString[0] : 0;

            for (int i=0; i<LangIDs; i++) {
                USHORT id = IDs[i].bString[0];
                if (id == 0x0409) StrLangID = id;
            }

        }

        delete[] buf2;

    }

    delete[] buf;

}

//______________________________________________________________________________

void CCyUSBDevice::GetString(wchar_t *str, UCHAR sIndex)
{
    // Get the header to find-out the number of languages, size of lang ID list
    ULONG length = sizeof(SINGLE_TRANSFER) + sizeof(USB_COMMON_DESCRIPTOR);
    PUCHAR buf = new UCHAR[length];
    ZeroMemory (buf, length);

    USB_COMMON_DESCRIPTOR cmnDescriptor;
    ZeroMemory (&cmnDescriptor, sizeof(USB_COMMON_DESCRIPTOR));

    PSINGLE_TRANSFER pSingleTransfer = (PSINGLE_TRANSFER) buf;
    pSingleTransfer->SetupPacket.bmReqType.Direction = DIR_DEVICE_TO_HOST;
    pSingleTransfer->SetupPacket.bmReqType.Type      = 0;
    pSingleTransfer->SetupPacket.bmReqType.Recipient = 0;
    pSingleTransfer->SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
    pSingleTransfer->SetupPacket.wVal.hiByte = USB_STRING_DESCRIPTOR_TYPE;
    pSingleTransfer->SetupPacket.wVal.lowByte = sIndex;
    pSingleTransfer->SetupPacket.wIndex = StrLangID;
    pSingleTransfer->SetupPacket.wLength = sizeof(USB_COMMON_DESCRIPTOR);
    pSingleTransfer->SetupPacket.ulTimeOut = 5;
    pSingleTransfer->BufferLength = pSingleTransfer->SetupPacket.wLength;
    pSingleTransfer->BufferOffset = sizeof(SINGLE_TRANSFER);

    bool bRetVal = IoControl(IOCTL_ADAPT_SEND_EP0_CONTROL_TRANSFER, buf, length);
    UsbdStatus = pSingleTransfer->UsbdStatus;
    NtStatus = pSingleTransfer->NtStatus;

    if (bRetVal) {
        memcpy(&cmnDescriptor, (PVOID)((PCHAR)pSingleTransfer + pSingleTransfer->BufferOffset), sizeof(USB_COMMON_DESCRIPTOR));

        // Get the entire descriptor
        length = sizeof(SINGLE_TRANSFER) + cmnDescriptor.bLength;
        PUCHAR buf2 = new UCHAR[length];
        ZeroMemory (buf2, length);

        pSingleTransfer = (PSINGLE_TRANSFER) buf2;
        pSingleTransfer->SetupPacket.bmReqType.Direction = DIR_DEVICE_TO_HOST;
        pSingleTransfer->SetupPacket.bmReqType.Type      = 0;
        pSingleTransfer->SetupPacket.bmReqType.Recipient = 0;
        pSingleTransfer->SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
        pSingleTransfer->SetupPacket.wVal.hiByte = USB_STRING_DESCRIPTOR_TYPE;
        pSingleTransfer->SetupPacket.wVal.lowByte = sIndex;
        pSingleTransfer->SetupPacket.wIndex = StrLangID;
        pSingleTransfer->SetupPacket.wLength = cmnDescriptor.bLength;
        pSingleTransfer->SetupPacket.ulTimeOut = 5;
        pSingleTransfer->BufferLength = pSingleTransfer->SetupPacket.wLength;
        pSingleTransfer->BufferOffset = sizeof(SINGLE_TRANSFER);

        bRetVal = IoControl(IOCTL_ADAPT_SEND_EP0_CONTROL_TRANSFER, buf2, length);
        UsbdStatus = pSingleTransfer->UsbdStatus;
        NtStatus = pSingleTransfer->NtStatus;

        UCHAR bytes = (buf2[sizeof(SINGLE_TRANSFER)]);
        UCHAR signature = (buf2[sizeof(SINGLE_TRANSFER)+1]);

        if (bRetVal && (bytes>2) && (signature == 0x03)) {
            ZeroMemory (str, USB_STRING_MAXLEN);
            memcpy(str, (PVOID)((PCHAR)pSingleTransfer + pSingleTransfer->BufferOffset+2), bytes-2);
        }

        delete[] buf2;

    }

    delete[] buf;
}

//______________________________________________________________________________

void CCyUSBDevice::GetCfgDescriptor(int descIndex)
{

    ULONG length = sizeof(SINGLE_TRANSFER) + sizeof(USB_CONFIGURATION_DESCRIPTOR);
    PUCHAR buf = new UCHAR[length];
    ZeroMemory (buf, length);

    PSINGLE_TRANSFER pSingleTransfer = (PSINGLE_TRANSFER) buf;
    pSingleTransfer->SetupPacket.bmReqType.Direction = DIR_DEVICE_TO_HOST;
    pSingleTransfer->SetupPacket.bmReqType.Type      = 0;
    pSingleTransfer->SetupPacket.bmReqType.Recipient = 0;
    pSingleTransfer->SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
    pSingleTransfer->SetupPacket.wVal.hiByte = USB_CONFIGURATION_DESCRIPTOR_TYPE;
    pSingleTransfer->SetupPacket.wVal.lowByte = descIndex;
    pSingleTransfer->SetupPacket.wLength = sizeof(USB_CONFIGURATION_DESCRIPTOR);
    pSingleTransfer->SetupPacket.ulTimeOut = 5;
    pSingleTransfer->BufferLength = pSingleTransfer->SetupPacket.wLength;
    pSingleTransfer->BufferOffset = sizeof(SINGLE_TRANSFER);

    bool bRetVal = IoControl(IOCTL_ADAPT_SEND_EP0_CONTROL_TRANSFER, buf, length);
    UsbdStatus = pSingleTransfer->UsbdStatus;
    NtStatus = pSingleTransfer->NtStatus;

    if (bRetVal) {
        PUSB_CONFIGURATION_DESCRIPTOR configDesc = (PUSB_CONFIGURATION_DESCRIPTOR)((PCHAR)pSingleTransfer + pSingleTransfer->BufferOffset);
        USHORT configDescLength= configDesc->wTotalLength;

        length = sizeof(SINGLE_TRANSFER) + configDescLength;
        PUCHAR buf2 = new UCHAR[length];
        ZeroMemory (buf2, length);

        pSingleTransfer = (PSINGLE_TRANSFER) buf2;
        pSingleTransfer->SetupPacket.bmReqType.Direction = DIR_DEVICE_TO_HOST;
        pSingleTransfer->SetupPacket.bmReqType.Type      = 0;
        pSingleTransfer->SetupPacket.bmReqType.Recipient = 0;
        pSingleTransfer->SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
        pSingleTransfer->SetupPacket.wVal.hiByte = USB_CONFIGURATION_DESCRIPTOR_TYPE;
        pSingleTransfer->SetupPacket.wVal.lowByte = descIndex;
        pSingleTransfer->SetupPacket.wLength = configDescLength;
        pSingleTransfer->SetupPacket.ulTimeOut = 5;
        pSingleTransfer->BufferLength = pSingleTransfer->SetupPacket.wLength;
        pSingleTransfer->BufferOffset = sizeof(SINGLE_TRANSFER);

        bRetVal = IoControl(IOCTL_ADAPT_SEND_EP0_CONTROL_TRANSFER, buf2, length);
        UsbdStatus = pSingleTransfer->UsbdStatus;
        NtStatus = pSingleTransfer->NtStatus;

        if (bRetVal){
            USBConfigDescriptors[descIndex] = (PUSB_CONFIGURATION_DESCRIPTOR)malloc(configDescLength);
            memcpy(USBConfigDescriptors[descIndex], (PVOID)((PCHAR)pSingleTransfer + pSingleTransfer->BufferOffset), configDescLength);
        }

        delete[] buf2;

    }

    delete[] buf;
}

//______________________________________________________________________________

bool CCyUSBDevice::Reset()
{
    return IoControl(IOCTL_ADAPT_RESET_PARENT_PORT, NULL, 0);
}

//______________________________________________________________________________

bool CCyUSBDevice::ReConnect()
{
    return IoControl(IOCTL_ADAPT_CYCLE_PORT, NULL, 0);
}


//______________________________________________________________________________

bool CCyUSBDevice::Suspend()
{
    if (PowerState() == 4) return true;

    ULONG state = 4;
    bool ret = IoControl(IOCTL_ADAPT_SET_DEVICE_POWER_STATE, (PUCHAR) &state, sizeof(state));

    if ( 0 == state) return ret;

    return true;

}


//______________________________________________________________________________

bool CCyUSBDevice::Resume()
{
    if (PowerState() == 1) return true;

    ULONG state = 1;
    bool ret = IoControl(IOCTL_ADAPT_SET_DEVICE_POWER_STATE, (PUCHAR) &state, sizeof(state));

    if ( 0 == state) return ret;

    return true;
}


//______________________________________________________________________________

void CCyUSBDevice::GetSpeed()
{
    ULONG speed = 0;
    bHighSpeed = false;
    bSuperSpeed = false;

    IoControl(IOCTL_ADAPT_GET_DEVICE_SPEED, (PUCHAR) &speed, sizeof(speed));

    bHighSpeed = (speed == DEVICE_SPEED_HIGH);
    bSuperSpeed = (speed == DEVICE_SPEED_SUPER);
}


//______________________________________________________________________________

UCHAR CCyUSBDevice::PowerState()
{
    ULONG state;
    bool rval = IoControl(IOCTL_ADAPT_GET_DEVICE_POWER_STATE, (PUCHAR) &state, sizeof(state));

    UCHAR s = (UCHAR) NULL;

    if (rval) s = (UCHAR) state;

    return s;

}


//______________________________________________________________________________

CCyUSBEndPoint * CCyUSBDevice::EndPointOf(UCHAR addr) //throw(...)
{

    if (addr == 0) return ControlEndPt;

    CCyUSBEndPoint *ept;

    int n = EndPointCount();

    for (int i=0; i<n; i++) {
        ept = USBCfgs[CfgNum]->Interfaces[IntfcIndex]->EndPoints[i];

        if (ept)
        {
            if (addr == ept->Address) return ept; }
        else
            throw "Failed to find endpoint.";
    }

    return NULL; // Error

}
//______________________________________________________________________________

bool CCyUSBDevice::GetBosDescriptor(PUSB_BOS_DESCRIPTOR descr)
{
    if ((BcdUSB & BCDUSBJJMASK) == USB30MAJORVER)
    {
        if(UsbBos!=NULL)
        {
            descr->bLength =  UsbBos->bLength;
            descr->bDescriptorType =  UsbBos->bDescriptorType;
            descr->bNumDeviceCaps =  UsbBos->bNumDeviceCaps;
            descr->wTotalLength =  UsbBos->wTotalLength;
            return true;
        }
        return false;
    }
    else
        return false;
}
bool CCyUSBDevice::GetBosUSB20DeviceExtensionDescriptor(PUSB_BOS_USB20_DEVICE_EXTENSION descr)
{
    if ((BcdUSB & BCDUSBJJMASK) == USB30MAJORVER)
    {
        if(UsbBos->pUSB20_DeviceExt != NULL)
        {
            descr->bLength = UsbBos->pUSB20_DeviceExt->bLength;
            descr->bDescriptorType =  UsbBos->pUSB20_DeviceExt->bDescriptorType;
            descr->bDevCapabilityType =  UsbBos->pUSB20_DeviceExt->bDevCapabilityType;
            descr->bmAttribute =  UsbBos->pUSB20_DeviceExt->bmAttribute;
            return true;
        }
        return false;
    }
    else
        return false;
}
bool CCyUSBDevice::GetBosContainedIDDescriptor(PUSB_BOS_CONTAINER_ID descr)
{
    if ((BcdUSB & BCDUSBJJMASK) == USB30MAJORVER)
    {
        if(UsbBos->pContainer_ID != NULL)
        {
            descr->bLength = UsbBos->pContainer_ID->bLength;
            descr->bDescriptorType =  UsbBos->pContainer_ID->bDescriptorType;
            descr->bDevCapabilityType =  UsbBos->pContainer_ID->bDevCapabilityType;
            descr->bReserved =  UsbBos->pContainer_ID->bReserved;
            for (int i=0;i<USB_BOS_CAPABILITY_TYPE_CONTAINER_ID_SIZE;i++)
                descr->ContainerID[i] = UsbBos->pContainer_ID->ContainerID[i];

            return true;
        }
        return false;
    }
    else
        return false;
}
bool CCyUSBDevice::GetBosSSCapabilityDescriptor(PUSB_BOS_SS_DEVICE_CAPABILITY descr)
{
    if ((BcdUSB & BCDUSBJJMASK) == USB30MAJORVER)
    {
        if(UsbBos->pSS_DeviceCap != NULL)
        {
            descr->bLength = UsbBos->pSS_DeviceCap->bLength;
            descr->bDescriptorType =  UsbBos->pSS_DeviceCap->bDescriptorType;
            descr->bDevCapabilityType =  UsbBos->pSS_DeviceCap->bDevCapabilityType;
            descr->bFunctionalitySupporte =  UsbBos->pSS_DeviceCap->bFunctionalitySupporte;
            descr->bmAttribute =  UsbBos->pSS_DeviceCap->bmAttribute;
            descr->bU1DevExitLat =  UsbBos->pSS_DeviceCap->bU1DevExitLat;
            descr->wSpeedsSuported =  UsbBos->pSS_DeviceCap->SpeedsSuported;
            descr->bU2DevExitLat =  UsbBos->pSS_DeviceCap->bU2DevExitLat;
            return true;
        }
        return false;
    }
    else
        return false;
}
//______________________________________________________________________________

void CCyUSBDevice::GetDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR descr)
{
    // Copy the internal private data to the passed parameter
    *descr = USBDeviceDescriptor;
}

//______________________________________________________________________________

void CCyUSBDevice::GetConfigDescriptor(PUSB_CONFIGURATION_DESCRIPTOR descr)
{
    // Copy the internal private data to the passed parameter
    *descr = *USBConfigDescriptors[CfgNum];
}

//______________________________________________________________________________

void CCyUSBDevice::GetIntfcDescriptor(PUSB_INTERFACE_DESCRIPTOR descr)
{
    CCyUSBInterface *i = USBCfgs[CfgNum]->Interfaces[IntfcIndex];

    // Copy the internal private data to the passed parameter
    descr->bLength            = i->bLength;
    descr->bDescriptorType    = i->bDescriptorType;
    descr->bInterfaceNumber   = i->bInterfaceNumber;
    descr->bAlternateSetting  = i->bAlternateSetting;
    descr->bNumEndpoints      = i->bNumEndpoints;
    descr->bInterfaceClass    = i->bInterfaceClass;
    descr->bInterfaceSubClass = i->bInterfaceSubClass;
    descr->bInterfaceProtocol = i->bInterfaceProtocol;
    descr->iInterface         = i->iInterface;
}

//______________________________________________________________________________

CCyUSBConfig CCyUSBDevice::GetUSBConfig(int index)
{
    // Rarely (i.e. never) have more than 1 Configuration
    int i = (index > (Configs-1)) ? 0 : index;

    return *USBCfgs[i];   // Invoke the copy constructor
}

//______________________________________________________________________________

void  CCyUSBDevice::UsbdStatusString(ULONG stat, PCHAR str)
{
    //CString tmp;  // MFC Version
    //String tmp;

    char StateStr[24];
    char StatusStr[64];
    ZeroMemory(StateStr,24);
    ZeroMemory(StatusStr,64);

    if (! USBD_STATUS(stat)) {
        sprintf(StateStr,"[state=SUCCESS ");
        sprintf(StatusStr,"status=USBD_STATUS_SUCCESS]");
    } else {

        switch(USBD_STATE(stat)) {
       case USBD_STATUS_SUCCESS: sprintf(StateStr," [state=SUCCESS "); break;
       case USBD_STATUS_PENDING: sprintf(StateStr," [state=PENDING "); break;
       case USBD_STATUS_HALTED:	 sprintf(StateStr," [state=STALLED "); break;
       case USBD_STATUS_ERROR: 	 sprintf(StateStr," [state=ERROR   "); break;
       default: break;
        }

        switch(stat|0xC0000000L) { // Note: error typedefs have both error and stall bit set
       case USBD_STATUS_CRC:		        sprintf(StatusStr,"status=USBD_STATUS_CRC]"); break;
       case USBD_STATUS_BTSTUFF:	        sprintf(StatusStr,"status=USBD_STATUS_BTSTUFF]"); break;
       case USBD_STATUS_DATA_TOGGLE_MISMATCH:	sprintf(StatusStr,"status=USBD_STATUS_DATA_TOGGLE_MISMATCH]"); break;
       case USBD_STATUS_STALL_PID:		sprintf(StatusStr,"status=USBD_STATUS_STALL_PID]"); break;
       case USBD_STATUS_DEV_NOT_RESPONDING:     sprintf(StatusStr,"status=USBD_STATUS_DEV_NOT_RESPONDING]"); break;
       case USBD_STATUS_PID_CHECK_FAILURE:	sprintf(StatusStr,"status=USBD_STATUS_PID_CHECK_FAILURE]"); break;
       case USBD_STATUS_UNEXPECTED_PID:	        sprintf(StatusStr,"status=USBD_STATUS_UNEXPECTED_PID]"); break;
       case USBD_STATUS_DATA_OVERRUN:		sprintf(StatusStr,"status=USBD_STATUS_DATA_OVERRUN]"); break;
       case USBD_STATUS_DATA_UNDERRUN:		sprintf(StatusStr,"status=USBD_STATUS_DATA_UNDERRUN]"); break;
       case USBD_STATUS_RESERVED1:		sprintf(StatusStr,"status=USBD_STATUS_RESERVED1]"); break;
       case USBD_STATUS_RESERVED2:		sprintf(StatusStr,"status=USBD_STATUS_RESERVED2]"); break;
       case USBD_STATUS_BUFFER_OVERRUN:	        sprintf(StatusStr,"status=USBD_STATUS_BUFFER_OVERRUN]"); break;
       case USBD_STATUS_BUFFER_UNDERRUN:	sprintf(StatusStr,"status=USBD_STATUS_BUFFER_UNDERRUN]"); break;
       case USBD_STATUS_NOT_ACCESSED:		sprintf(StatusStr,"status=USBD_STATUS_NOT_ACCESSED]"); break;
       case USBD_STATUS_FIFO:			sprintf(StatusStr,"status=USBD_STATUS_FIFO]"); break;

       case USBD_STATUS_ENDPOINT_HALTED:	sprintf(StatusStr,"status=USBD_STATUS_ENDPOINT_HALTED]"); break;
       case USBD_STATUS_NO_MEMORY:		sprintf(StatusStr,"status=USBD_STATUS_NO_MEMORY]"); break;
       case USBD_STATUS_INVALID_URB_FUNCTION:	sprintf(StatusStr,"status=USBD_STATUS_INVALID_URB_FUNCTION]"); break;
       case USBD_STATUS_INVALID_PARAMETER:	sprintf(StatusStr,"status=USBD_STATUS_INVALID_PARAMETER]"); break;
       case USBD_STATUS_ERROR_BUSY:		sprintf(StatusStr,"status=USBD_STATUS_ERROR_BUSY]"); break;
       case USBD_STATUS_REQUEST_FAILED:	        sprintf(StatusStr,"status=USBD_STATUS_REQUEST_FAILED]"); break;
       case USBD_STATUS_INVALID_PIPE_HANDLE:	sprintf(StatusStr,"status=USBD_STATUS_INVALID_PIPE_HANDLE]"); break;
       case USBD_STATUS_NO_BANDWIDTH:		sprintf(StatusStr,"status=USBD_STATUS_NO_BANDWIDTH]"); break;
       case USBD_STATUS_INTERNAL_HC_ERROR:	sprintf(StatusStr,"status=USBD_STATUS_INTERNAL_HC_ERROR]"); break;
       case USBD_STATUS_ERROR_SHORT_TRANSFER:	sprintf(StatusStr,"status=USBD_STATUS_ERROR_SHORT_TRANSFER]"); break;
       case USBD_STATUS_BAD_START_FRAME:	sprintf(StatusStr,"status=USBD_STATUS_BAD_START_FRAME]"); break;
       case USBD_STATUS_ISOCH_REQUEST_FAILED:	sprintf(StatusStr,"status=USBD_STATUS_ISOCH_REQUEST_FAILED]"); break;
       case USBD_STATUS_FRAME_CONTROL_OWNED:	sprintf(StatusStr,"status=USBD_STATUS_FRAME_CONTROL_OWNED]"); break;
       case USBD_STATUS_FRAME_CONTROL_NOT_OWNED:sprintf(StatusStr,"status=USBD_STATUS_FRAME_CONTROL_NOT_OWNED]"); break;
       case USBD_STATUS_CANCELED:		sprintf(StatusStr,"status=USBD_STATUS_CANCELED]"); break;
       case USBD_STATUS_CANCELING:		sprintf(StatusStr,"status=USBD_STATUS_CANCELING]"); break;

       default: sprintf(StatusStr,"status=UNKNOWN]"); break;
        }
    }

    sprintf(str, "%s%s", StateStr, StatusStr);

}

//______________________________________________________________________________

// This method is called from Open, just after ControlEndPt has been instantiated
// It also gets called whenever a different Alt Interface setting is made
void CCyUSBDevice::SetEndPointPtrs(void)
{
    if (Configs == 0) return;
    if (Interfaces == 0) return;

    EndPoints = USBCfgs[CfgNum]->Interfaces[IntfcIndex]->EndPoints;
    EndPoints[0] = ControlEndPt;
    int eptCount = EndPointCount() - 1;

    IsocInEndPt       = NULL;
    IsocOutEndPt      = NULL;
    BulkInEndPt       = NULL;
    BulkOutEndPt      = NULL;
    InterruptInEndPt  = NULL;
    InterruptOutEndPt = NULL;

    for (int i=0; i<eptCount; i++) {
        UCHAR bIn = EndPoints[i+1]->Address & 0x80;
        UCHAR attrib = EndPoints[i+1]->Attributes;


        EndPoints[i+1]->XferMode = XMODE_DIRECT;

        if ((IsocInEndPt == NULL) && (attrib == 1) && bIn) IsocInEndPt = (CCyIsocEndPoint *)EndPoints[i+1];
        if ((BulkInEndPt == NULL) && (attrib == 2) && bIn) BulkInEndPt = (CCyBulkEndPoint *)EndPoints[i+1];
        if ((InterruptInEndPt == NULL) && (attrib == 3) && bIn) InterruptInEndPt = (CCyInterruptEndPoint *)EndPoints[i+1];

        if ((IsocOutEndPt == NULL) && (attrib == 1) && !bIn) IsocOutEndPt = (CCyIsocEndPoint *)EndPoints[i+1];
        if ((BulkOutEndPt == NULL) && (attrib == 2) && !bIn) BulkOutEndPt = (CCyBulkEndPoint *)EndPoints[i+1];
        if ((InterruptOutEndPt == NULL) && (attrib == 3) && !bIn) InterruptOutEndPt = (CCyInterruptEndPoint *)EndPoints[i+1];
    }

}

//______________________________________________________________________________

bool CCyUSBDevice::RegisterForPnpEvents(HANDLE Handle)
{
    DEV_BROADCAST_DEVICEINTERFACE dFilter = {0};
    dFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
    dFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
    dFilter.dbcc_classguid = DrvGuid;

    hDevNotification = RegisterDeviceNotification(Handle, (PVOID) &dFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
    if (!hDevNotification)
    {
        LastError = GetLastError();
        return false;
    }

    return true;
}


////////////////////////////////////////////////////////////////////////////////
//
// The USB Interface Class
//
////////////////////////////////////////////////////////////////////////////////


// The Copy Constructor
CCyUSBInterface::CCyUSBInterface(CCyUSBInterface &ifc)
{
    bLength            = ifc.bLength;
    bDescriptorType    = ifc.bDescriptorType;
    bInterfaceNumber   = ifc.bInterfaceNumber;
    bAlternateSetting  = ifc.bAlternateSetting;
    bNumEndpoints      = ifc.bNumEndpoints;
    bInterfaceClass    = ifc.bInterfaceClass;
    bInterfaceSubClass = ifc.bInterfaceSubClass;
    bInterfaceProtocol = ifc.bInterfaceProtocol;
    iInterface         = ifc.iInterface;

    wTotalLength       = ifc.wTotalLength;

    int i;

    for (i=0; i<MAX_ENDPTS; i++) EndPoints[i] = NULL;

    for (i=0; i<MAX_ENDPTS; i++)
        if (ifc.EndPoints[i]){

            if (ifc.EndPoints[i]->Attributes == 0) {
                CCyControlEndPoint *e = (CCyControlEndPoint*)ifc.EndPoints[i];
                EndPoints[i] = new CCyControlEndPoint(*e);
            }

            if (ifc.EndPoints[i]->Attributes == 1) {
                CCyIsocEndPoint *e = (CCyIsocEndPoint*)ifc.EndPoints[i];
                EndPoints[i] = new CCyIsocEndPoint(*e);
            }

            if (ifc.EndPoints[i]->Attributes == 2) {
                CCyBulkEndPoint *e = (CCyBulkEndPoint*)ifc.EndPoints[i];
                EndPoints[i] = new CCyBulkEndPoint(*e);
            }

            if (ifc.EndPoints[i]->Attributes == 3) {
                CCyInterruptEndPoint *e = (CCyInterruptEndPoint*)ifc.EndPoints[i];
                EndPoints[i] = new CCyInterruptEndPoint(*e);
            }

        }

}


CCyUSBInterface::CCyUSBInterface(HANDLE handle, PUSB_INTERFACE_DESCRIPTOR pIntfcDescriptor)
{

    PUSB_ENDPOINT_DESCRIPTOR endPtDesc;

    bLength            = pIntfcDescriptor->bLength;
    bDescriptorType    = pIntfcDescriptor->bDescriptorType;
    bInterfaceNumber   = pIntfcDescriptor->bInterfaceNumber;
    bAlternateSetting  = pIntfcDescriptor->bAlternateSetting;
    bNumEndpoints      = pIntfcDescriptor->bNumEndpoints;
    bInterfaceClass    = pIntfcDescriptor->bInterfaceClass;
    bInterfaceSubClass = pIntfcDescriptor->bInterfaceSubClass;
    bInterfaceProtocol = pIntfcDescriptor->bInterfaceProtocol;
    iInterface         = pIntfcDescriptor->iInterface;

    bAltSettings = 0;
    wTotalLength = bLength;

    PUCHAR desc = (PUCHAR)pIntfcDescriptor  + pIntfcDescriptor->bLength;

    int i;
    int unexpected = 0;

    for (i=0; i<MAX_ENDPTS; i++) EndPoints[i] = NULL;

    for (i=0; i<bNumEndpoints; i++) {

        endPtDesc = (PUSB_ENDPOINT_DESCRIPTOR) (desc);
        wTotalLength += endPtDesc->bLength;

        // We leave slot [0] empty to hold THE obligatory EndPoint Zero control endpoint
        if (endPtDesc->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE) {
            switch (endPtDesc->bmAttributes ) {
       case 0:
           EndPoints[i+1] = new CCyControlEndPoint(handle, endPtDesc);
           break;
       case 1:
           EndPoints[i+1] = new CCyIsocEndPoint(handle, endPtDesc);
           break;
       case 2:
           EndPoints[i+1] = new CCyBulkEndPoint(handle, endPtDesc);
           break;
       case 3:
           EndPoints[i+1] = new CCyInterruptEndPoint(handle, endPtDesc);
           break;
            }

            desc += endPtDesc->bLength;
        } else {

            unexpected++;
            if (unexpected < 12) {  // Sanity check - prevent infinite loop

                // This may have been a class-specific descriptor (like HID).  Skip it.
                desc += endPtDesc->bLength;

                // Stay in the loop, grabbing the next descriptor
                i--;
            }

        }

    }


}

CCyUSBInterface::CCyUSBInterface(HANDLE handle, PUSB_INTERFACE_DESCRIPTOR pIntfcDescriptor,UCHAR usb30Dummy)
{

    PUSB_ENDPOINT_DESCRIPTOR endPtDesc;

    bLength            = pIntfcDescriptor->bLength;
    bDescriptorType    = pIntfcDescriptor->bDescriptorType;
    bInterfaceNumber   = pIntfcDescriptor->bInterfaceNumber;
    bAlternateSetting  = pIntfcDescriptor->bAlternateSetting;
    bNumEndpoints      = pIntfcDescriptor->bNumEndpoints;
    bInterfaceClass    = pIntfcDescriptor->bInterfaceClass;
    bInterfaceSubClass = pIntfcDescriptor->bInterfaceSubClass;
    bInterfaceProtocol = pIntfcDescriptor->bInterfaceProtocol;
    iInterface         = pIntfcDescriptor->iInterface;

    bAltSettings = 0;
    wTotalLength = bLength;

    PUCHAR desc = (PUCHAR)pIntfcDescriptor  + pIntfcDescriptor->bLength;

    int i;
    int unexpected = 0;

    for (i=0; i<MAX_ENDPTS; i++) EndPoints[i] = NULL;

    for (i=0; i<bNumEndpoints; i++)
    {
        bool bSSDec = false;
        endPtDesc = (PUSB_ENDPOINT_DESCRIPTOR) (desc);
        desc += endPtDesc->bLength;

        PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR ssendPtDesc = (PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR)desc;
        wTotalLength += endPtDesc->bLength;

        // We leave slot [0] empty to hold THE obligatory EndPoint Zero control endpoint
        if (ssendPtDesc != NULL)
            bSSDec = (ssendPtDesc->bDescriptorType == USB_SUPERSPEED_ENDPOINT_COMPANION);

        if ((endPtDesc->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE) && bSSDec)
        {
            switch (endPtDesc->bmAttributes )
            {
            case 0:
                EndPoints[i+1] = new CCyControlEndPoint(handle, endPtDesc);
                break;
            case 1:
                EndPoints[i+1] = new CCyIsocEndPoint(handle, endPtDesc,ssendPtDesc);
                break;
            case 2:
                EndPoints[i+1] = new CCyBulkEndPoint(handle, endPtDesc,ssendPtDesc);
                break;
            case 3:
                EndPoints[i+1] = new CCyInterruptEndPoint(handle, endPtDesc,ssendPtDesc);
                break;
            }

            desc += ssendPtDesc->bLength;
            wTotalLength += ssendPtDesc->bLength;

        }
        else if (endPtDesc->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE)
        {
            switch (endPtDesc->bmAttributes )
            {
            case 0:
                EndPoints[i+1] = new CCyControlEndPoint(handle, endPtDesc);
                break;
            case 1:
                EndPoints[i+1] = new CCyIsocEndPoint(handle, endPtDesc);
                break;
            case 2:
                EndPoints[i+1] = new CCyBulkEndPoint(handle, endPtDesc);
                break;
            case 3:
                EndPoints[i+1] = new CCyInterruptEndPoint(handle, endPtDesc);
                break;
            }

            //desc += endPtDesc->bLength; // THis a bug for the composite device

        }
        else
        {

            unexpected++;
            if (unexpected < 12) {  // Sanity check - prevent infinite loop

                // This may have been a class-specific descriptor (like HID).  Skip it.
                desc += endPtDesc->bLength;

                // Stay in the loop, grabbing the next descriptor
                i--;
            }

        }

    }


}

//______________________________________________________________________________

CCyUSBInterface::~CCyUSBInterface(void) {

    for (int i=0; i<MAX_ENDPTS; i++)
        if (EndPoints[i])
        {
            delete EndPoints[i];
            EndPoints[i] = NULL;
        }

}


////////////////////////////////////////////////////////////////////////////////
//
// The USB Config Class
//
////////////////////////////////////////////////////////////////////////////////

CCyUSBConfig::CCyUSBConfig(void)
{
    bLength             = 0;
    bDescriptorType     = 0;
    wTotalLength        = 0;
    bNumInterfaces      = 0;
    AltInterfaces       = 0;
    bConfigurationValue = 0;
    iConfiguration      = 0;
    bmAttributes        = 0;
    MaxPower            = 0;

    for (int i=0; i<MAX_INTERFACES; i++) Interfaces[i] = NULL;

}


// The Copy Constructor
CCyUSBConfig::CCyUSBConfig(CCyUSBConfig &cfg)
{
    bLength             = cfg.bLength;
    bDescriptorType     = cfg.bDescriptorType;
    wTotalLength        = cfg.wTotalLength;
    bNumInterfaces      = cfg.bNumInterfaces;
    AltInterfaces       = cfg.AltInterfaces;
    bConfigurationValue = cfg.bConfigurationValue;
    iConfiguration      = cfg.iConfiguration;
    bmAttributes        = cfg.bmAttributes;
    MaxPower            = cfg.MaxPower;
    AltInterfaces       = cfg.AltInterfaces;

    int i;

    for (i=0; i<MAX_INTERFACES; i++) Interfaces[i] = NULL;

    for (i=0; i<AltInterfaces; i++)
        Interfaces[i] = new CCyUSBInterface(*cfg.Interfaces[i]);

}


CCyUSBConfig::CCyUSBConfig(HANDLE handle, PUSB_CONFIGURATION_DESCRIPTOR pConfigDescr){

    PUSB_INTERFACE_DESCRIPTOR interfaceDesc;
    int i;

    bLength             = pConfigDescr->bLength;
    bDescriptorType     = pConfigDescr->bDescriptorType;
    wTotalLength        = pConfigDescr->wTotalLength;
    bNumInterfaces      = pConfigDescr->bNumInterfaces;
    AltInterfaces       = 0;
    bConfigurationValue = pConfigDescr->bConfigurationValue;
    iConfiguration      = pConfigDescr->iConfiguration;
    bmAttributes        = pConfigDescr->bmAttributes;
    MaxPower            = pConfigDescr->MaxPower;

    int tLen = pConfigDescr->wTotalLength;

    PUCHAR desc = (PUCHAR)pConfigDescr  + pConfigDescr->bLength;
    int bytesConsumed = pConfigDescr->bLength;

    for (i=0; i<MAX_INTERFACES; i++) Interfaces[i] = NULL;

    i = 0;
    do {
        interfaceDesc = (PUSB_INTERFACE_DESCRIPTOR) (desc);

        if (interfaceDesc->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE) {
            Interfaces[i] = new CCyUSBInterface(handle, interfaceDesc);
            i++;
            AltInterfaces++;  // Actually the total number of interfaces for the config
            bytesConsumed += Interfaces[i-1]->wTotalLength;
        } else {
            // Unexpected descriptor type
            // Just skip it and go on  - could have thrown an exception instead
            // since this indicates that the descriptor structure is invalid.
            bytesConsumed += interfaceDesc->bLength;
        }


        desc = (PUCHAR) pConfigDescr + bytesConsumed;

    } while ((bytesConsumed < tLen) && (i<MAX_INTERFACES)); // Only support 8 total interfaces


    // Count the alt interfaces for each interface number
    for (i=0; i<AltInterfaces; i++) {

        Interfaces[i]->bAltSettings = 0;

        for (int j=0; j<AltInterfaces; j++) // Walk the list looking for identical bInterfaceNumbers
            if (Interfaces[i]->bInterfaceNumber == Interfaces[j]->bInterfaceNumber)
                Interfaces[i]->bAltSettings++;

    }

}


CCyUSBConfig::CCyUSBConfig(HANDLE handle, PUSB_CONFIGURATION_DESCRIPTOR pConfigDescr,UCHAR usb30Dummy)
{

    PUSB_INTERFACE_DESCRIPTOR interfaceDesc;
    int i;

    bLength             = pConfigDescr->bLength;
    bDescriptorType     = pConfigDescr->bDescriptorType;
    wTotalLength        = pConfigDescr->wTotalLength;
    bNumInterfaces      = pConfigDescr->bNumInterfaces;
    AltInterfaces       = 0;
    bConfigurationValue = pConfigDescr->bConfigurationValue;
    iConfiguration      = pConfigDescr->iConfiguration;
    bmAttributes        = pConfigDescr->bmAttributes;
    MaxPower            = pConfigDescr->MaxPower;

    int tLen = pConfigDescr->wTotalLength;

    PUCHAR desc = (PUCHAR)pConfigDescr  + pConfigDescr->bLength;
    int bytesConsumed = pConfigDescr->bLength;

    for (i=0; i<MAX_INTERFACES; i++) Interfaces[i] = NULL;

    i = 0;
    do {
        interfaceDesc = (PUSB_INTERFACE_DESCRIPTOR) (desc);

        if (interfaceDesc->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE) {
            Interfaces[i] = new CCyUSBInterface(handle, interfaceDesc,usb30Dummy);
            i++;
            AltInterfaces++;  // Actually the total number of interfaces for the config
            bytesConsumed += Interfaces[i-1]->wTotalLength;
        } else {
            // Unexpected descriptor type
            // Just skip it and go on  - could have thrown an exception instead
            // since this indicates that the descriptor structure is invalid.
            bytesConsumed += interfaceDesc->bLength;
        }


        desc = (PUCHAR) pConfigDescr + bytesConsumed;

    } while ((bytesConsumed < tLen) && (i<MAX_INTERFACES)); // Only support 8 total interfaces


    // Count the alt interfaces for each interface number
    for (i=0; i<AltInterfaces; i++) {

        Interfaces[i]->bAltSettings = 0;

        for (int j=0; j<AltInterfaces; j++) // Walk the list looking for identical bInterfaceNumbers
            if (Interfaces[i]->bInterfaceNumber == Interfaces[j]->bInterfaceNumber)
                Interfaces[i]->bAltSettings++;

    }

}


//______________________________________________________________________________

CCyUSBConfig::~CCyUSBConfig(void){

    for (int i=0; i<MAX_INTERFACES; i++)
        if (Interfaces[i]) {

            // Detect the first non-zero EndPoints[0] - the control endpoint -
            // and delete it.  Then, make sure all other interfaces have 0 as
            // the value for EndPoints[0], as anything else would be a redundant
            // reference to the control endpoint and cause an error when trying
            // to delete it a second time.

            if (Interfaces[i]->EndPoints[0] != 0)
            {
                delete Interfaces[i]->EndPoints[0];

                for (int j=0; j<MAX_INTERFACES; j++)
                    if (Interfaces[j])
                        Interfaces[j]->EndPoints[0] = NULL;
            }

            delete Interfaces[i];
            Interfaces[i] = NULL;
        }

}

////////////////////////////////////////////////////////////////////////////////
//
// The CCyEndPoint ABSTRACT Class
//
////////////////////////////////////////////////////////////////////////////////

CCyUSBEndPoint::CCyUSBEndPoint(void)
{
    hDevice    = INVALID_HANDLE_VALUE;

    DscLen     = 0;
    DscType    = 0;
    Address    = 0;
    Attributes = 0;
    MaxPktSize = 0;
    Interval   = 0;
    TimeOut    = 10000;  // 10 Sec timeout is default
    bIn        = false;
    XferMode   = XMODE_DIRECT;
    LastError  = 0;
    // Initialize the SS companion descriptor with zero, as this constructore will be called for usb2.0 device
    ssdscLen =0;
    ssdscType =0;
    ssmaxburst=0; /* Maximum number of packets endpoint can send in one burst*/
    ssbmAttribute=0; // store endpoint attribute like for bulk it will be number of streams
    ssbytesperinterval=0;
}

// Copy constructor
CCyUSBEndPoint::CCyUSBEndPoint(CCyUSBEndPoint& ept)
{
    hDevice    = ept.hDevice;

    DscLen     = ept.DscLen;
    DscType    = ept.DscType;
    Address    = ept.Address;
    Attributes = ept.Attributes;
    MaxPktSize = ept.MaxPktSize;
    Interval   = ept.Interval;
    TimeOut    = ept.TimeOut;
    bIn        = ept.bIn;
    XferMode   = ept.XferMode;
    ssdscLen =ept.ssdscLen;
    ssdscType =ept.ssdscType;
    ssmaxburst=ept.ssmaxburst; /* Maximum number of packets endpoint can send in one burst*/
    ssbmAttribute=ept.ssbmAttribute; // store endpoint attribute like for bulk it will be number of streams
    ssbytesperinterval=ept.ssbytesperinterval;
    LastError  = 0;
}

CCyUSBEndPoint::CCyUSBEndPoint(HANDLE hDev, PUSB_ENDPOINT_DESCRIPTOR pEndPtDescriptor)
{

    hDevice    = hDev;

    if (pEndPtDescriptor) {
        PktsPerFrame = (pEndPtDescriptor->wMaxPacketSize & 0x1800) >> 11;
        PktsPerFrame++;

        DscLen     = pEndPtDescriptor->bLength;
        DscType    = pEndPtDescriptor->bDescriptorType;
        Address    = pEndPtDescriptor->bEndpointAddress;
        Attributes = pEndPtDescriptor->bmAttributes;
        MaxPktSize = (pEndPtDescriptor->wMaxPacketSize & 0x7ff) * PktsPerFrame;
        Interval   = pEndPtDescriptor->bInterval;
        bIn        = ((Address & 0x80) == 0x80);
    }

    TimeOut   = 10000;  // 10 Sec timeout is default

    XferMode  = XMODE_DIRECT;  // Normally, use Direct xfers

    // Initialize the SS companion descriptor with zero, as this constructore will be called for usb2.0 device
    ssdscLen =0;
    ssdscType =0;
    ssmaxburst=0; /* Maximum number of packets endpoint can send in one burst*/
    ssbmAttribute=0; // store endpoint attribute like for bulk it will be number of streams
    ssbytesperinterval=0;

}


CCyUSBEndPoint::CCyUSBEndPoint(HANDLE hDev, PUSB_ENDPOINT_DESCRIPTOR pEndPtDescriptor,USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR* SSEndPtDescriptor)
{

    hDevice    = hDev;

    if (pEndPtDescriptor) {
        PktsPerFrame = (pEndPtDescriptor->wMaxPacketSize & 0x1800) >> 11;
        PktsPerFrame++;

        DscLen     = pEndPtDescriptor->bLength;
        DscType    = pEndPtDescriptor->bDescriptorType;
        Address    = pEndPtDescriptor->bEndpointAddress;
        Attributes = pEndPtDescriptor->bmAttributes;
        MaxPktSize = (pEndPtDescriptor->wMaxPacketSize & 0x7ff) * PktsPerFrame;
        Interval   = pEndPtDescriptor->bInterval;
        bIn        = ((Address & 0x80) == 0x80);
    }

    TimeOut   = 10000;  // 10 Sec timeout is default

    XferMode  = XMODE_DIRECT;  // Normally, use Direct xfers

    if(SSEndPtDescriptor != NULL)
    {
        ssdscLen =SSEndPtDescriptor->bLength;
        ssdscType =SSEndPtDescriptor->bDescriptorType;
        ssmaxburst=SSEndPtDescriptor->bMaxBurst; /* Maximum number of packets endpoint can send in one burst*/
        MaxPktSize *=(ssmaxburst+1);
        ssbmAttribute=SSEndPtDescriptor->bmAttributes; // store endpoint attribute like for bulk it will be number of streams
        if((Attributes & 0x03) ==1) // MULT is valid for Isochronous transfer only
            MaxPktSize*=((SSEndPtDescriptor->bmAttributes & 0x03)+1); // Adding the MULT fields.

        ssbytesperinterval=SSEndPtDescriptor->bBytesPerInterval;

    }
    else
    {
        // Initialize the SS companion descriptor with zero
        ssdscLen =0;
        ssdscType =0;
        ssmaxburst=0; /* Maximum number of packets endpoint can send in one burst*/
        ssbmAttribute=0; // store endpoint attribute like for bulk it will be number of streams
        ssbytesperinterval=0;
    }

}


//______________________________________________________________________________

bool CCyUSBEndPoint::Reset(void)
{
    DWORD dwBytes = 0;
    bool  RetVal = false;

    RetVal  =  (DeviceIoControl(hDevice,
        IOCTL_ADAPT_RESET_PIPE,
        &Address,
        sizeof(UCHAR),
        NULL,
        0,
        &dwBytes,
        0) !=0);

    if(!RetVal) LastError = GetLastError();
    return RetVal;
}

//______________________________________________________________________________

bool CCyUSBEndPoint::Abort(void)
{
	DWORD dwBytes = 0;
	bool  RetVal = false;
	OVERLAPPED ov;

	memset(&ov,0,sizeof(ov));
	ov.hEvent = CreateEvent(NULL,false,false,NULL);

	RetVal  =    (DeviceIoControl(hDevice,
		IOCTL_ADAPT_ABORT_PIPE,
		&Address,
		sizeof(UCHAR),
		NULL,
		0,
		&dwBytes,
		&ov)!=0);
	if(!RetVal)
	{
		DWORD LastError = GetLastError();
		if(LastError == ERROR_IO_PENDING)
			WaitForSingleObject(ov.hEvent,1000);
	}
	CloseHandle(ov.hEvent);
	return true;

}
//______________________________________________________________________________

bool CCyUSBEndPoint::XferData(PUCHAR buf, LONG &bufLen, CCyIsoPktInfo* pktInfos)
{

    OVERLAPPED ovLapStatus;
    memset(&ovLapStatus,0,sizeof(OVERLAPPED));

    ovLapStatus.hEvent = CreateEvent(NULL, false, false, NULL);

    PUCHAR context = BeginDataXfer(buf, bufLen, &ovLapStatus);
    bool   wResult = WaitForIO(&ovLapStatus);
    bool   fResult = FinishDataXfer(buf, bufLen, &ovLapStatus, context, pktInfos);

    CloseHandle(ovLapStatus.hEvent);

    return wResult && fResult;
}

//______________________________________________________________________________

bool CCyUSBEndPoint::XferData(PUCHAR buf, LONG &bufLen, CCyIsoPktInfo* pktInfos, bool pktMode)
{
    if ((bIn == false) || (pktMode == false))
    {
        return XferData(buf, bufLen);
    }
    else
    {
        int size = 0;
        LONG xferLen = (LONG)MaxPktSize;
        bool status = true;
        PUCHAR ptr = buf;

        while (status && (size < bufLen))
        {
            if ((bufLen - size) < MaxPktSize)
                xferLen = bufLen - size;

            status = XferData(ptr, xferLen);
            if (status)
            {
                ptr += xferLen;
                size += xferLen;

                if (xferLen < MaxPktSize)
                    break;
            }
        }

        bufLen = size;
        if (bufLen > 0)
            return true;
        return status;
    }
}

//______________________________________________________________________________

bool CCyUSBEndPoint::FinishDataXfer(PUCHAR buf, LONG &bufLen, OVERLAPPED *ov, PUCHAR pXmitBuf, CCyIsoPktInfo* pktInfos)
{
    DWORD bytes = 0;
    bool rResult = (GetOverlappedResult(hDevice, ov, &bytes, FALSE)!=0);

    PSINGLE_TRANSFER pTransfer = (PSINGLE_TRANSFER) pXmitBuf;
    bufLen = (bytes) ? bytes - pTransfer->BufferOffset : 0;
    bytesWritten = bufLen;

    UsbdStatus = pTransfer->UsbdStatus;
    NtStatus   = pTransfer->NtStatus;

    if (bIn && (XferMode == XMODE_BUFFERED) && (bufLen > 0)) {
        UCHAR *ptr = (PUCHAR)pTransfer + pTransfer->BufferOffset;
        memcpy (buf, ptr, bufLen);
    }

    // If a buffer was provided, pass-back the Isoc packet info records
    if (pktInfos && (bufLen > 0)) {
        //ZeroMemory(pktInfos, pTransfer->IsoPacketLength);
        PUCHAR pktPtr = pXmitBuf + pTransfer->IsoPacketOffset;
        memcpy(pktInfos, pktPtr, pTransfer->IsoPacketLength);
    }

//    delete[] pXmitBuf;     // [] Changed in 1.5.1.3

    return rResult && (UsbdStatus == 0) && (NtStatus == 0);
}

//______________________________________________________________________________

PUCHAR CCyUSBEndPoint::BeginBufferedXfer(PUCHAR buf, LONG bufLen, OVERLAPPED *ov)
{
    if ( hDevice == INVALID_HANDLE_VALUE ) return NULL;

    int iXmitBufSize = sizeof (SINGLE_TRANSFER) + bufLen;
    PUCHAR pXmitBuf = new UCHAR[iXmitBufSize];
    ZeroMemory (pXmitBuf, sizeof(SINGLE_TRANSFER));

    PSINGLE_TRANSFER pTransfer = (PSINGLE_TRANSFER) pXmitBuf;
    pTransfer->ucEndpointAddress = Address;
    pTransfer->IsoPacketLength = 0;
    pTransfer->BufferOffset = sizeof (SINGLE_TRANSFER);
    pTransfer->BufferLength = bufLen;

    // Copy buf into pXmitBuf
    UCHAR *ptr = (PUCHAR)pXmitBuf + sizeof(SINGLE_TRANSFER);
    memcpy (ptr, buf, bufLen);

    DWORD dwReturnBytes;

    DeviceIoControl (hDevice,
        IOCTL_ADAPT_SEND_NON_EP0_TRANSFER,
        pXmitBuf,
        iXmitBufSize,
        pXmitBuf,
        iXmitBufSize,
        &dwReturnBytes,
        ov);

    UsbdStatus = pTransfer->UsbdStatus;
    NtStatus   = pTransfer->NtStatus;

    LastError = GetLastError();
    return pXmitBuf;
}



//______________________________________________________________________________
PUCHAR CCyUSBEndPoint::BeginDirectXfer(PUCHAR buf, LONG bufLen, OVERLAPPED *ov)
{
    if ( hDevice == INVALID_HANDLE_VALUE ) return NULL;

    int iXmitBufSize = sizeof (SINGLE_TRANSFER);
    PUCHAR pXmitBuf = (PUCHAR)ov + sizeof(OVERLAPPED);
    ZeroMemory (pXmitBuf, iXmitBufSize);

    PSINGLE_TRANSFER pTransfer = (PSINGLE_TRANSFER) pXmitBuf;
    pTransfer->ucEndpointAddress = Address;
    pTransfer->IsoPacketLength = 0;
    pTransfer->BufferOffset = 0;
    pTransfer->BufferLength = 0;

    DWORD dwReturnBytes;
    DeviceIoControl (hDevice,
        IOCTL_ADAPT_SEND_NON_EP0_DIRECT,
        pXmitBuf,
        iXmitBufSize,
        buf,
        bufLen,
        &dwReturnBytes,
        ov);

    UsbdStatus = pTransfer->UsbdStatus;
    NtStatus   = pTransfer->NtStatus;

    LastError = GetLastError();
    return pXmitBuf;
}



//______________________________________________________________________________
// Unlike WaitForIO, this method does not record the bytes written or reset the
// endpoint if errors occurred.  This method is called from the application level
// in conjunction with BeginDataXfer and FinishDataXfer

bool CCyUSBEndPoint::WaitForXfer(OVERLAPPED *ov, ULONG tOut)
{

    //if (LastError == ERROR_SUCCESS) return true;  // The command completed

    //if (LastError == ERROR_IO_PENDING)
    {
        DWORD waitResult = WaitForSingleObject(ov->hEvent,tOut);

        if (waitResult == WAIT_TIMEOUT)  return false;

        if (waitResult == WAIT_OBJECT_0) return true;
    }

    return false;
}

//______________________________________________________________________________

bool CCyUSBEndPoint::WaitForIO(OVERLAPPED *ovLapStatus)
{
    LastError = GetLastError();
	DWORD retcode =1;

    if (LastError == ERROR_SUCCESS) return true;  // The command completed

    if (LastError == ERROR_IO_PENDING) {
        DWORD waitResult = WaitForSingleObject(ovLapStatus->hEvent,TimeOut);

        if (waitResult == WAIT_OBJECT_0) return true;

        if (waitResult == WAIT_TIMEOUT)
		{
			Abort();
			//// Wait for the stalled command to complete - should be done already
			//retcode = WaitForSingleObject(ovLapStatus->hEvent,50); // Wait for 50 milisecond
            Sleep(50);

			//if(retcode == WAIT_TIMEOUT || retcode==WAIT_FAILED)
			//{// Worst case condition , in multithreaded environment if user set time out to ZERO and cancel the IO the requiest, rarely first Abort() fail to cancel the IO, so reissueing second Abort(0.
				//Abort();
				//retcode = WaitForSingleObject(ovLapStatus->hEvent,INFINITE);

			//}
        }
    }

	return (retcode==0) ? true:false;
}

//______________________________________________________________________________

ULONG  CCyUSBEndPoint::GetXferSize(void){

    ULONG ulTransferSize;
    DWORD BytesXfered;

    if (hDevice == INVALID_HANDLE_VALUE) return (ULONG) NULL;

    SET_TRANSFER_SIZE_INFO SetTransferInfo;

    ulTransferSize = 0;
    SetTransferInfo.EndpointAddress = Address;
    SetTransferInfo.TransferSize = ulTransferSize;

    BOOL bRetVal = DeviceIoControl(hDevice,
        IOCTL_ADAPT_GET_TRANSFER_SIZE,
        &SetTransferInfo, sizeof(SET_TRANSFER_SIZE_INFO),
        &SetTransferInfo, sizeof(SET_TRANSFER_SIZE_INFO),
        &BytesXfered,
        NULL);

    if (bRetVal && BytesXfered >= sizeof(SET_TRANSFER_SIZE_INFO))
        ulTransferSize = SetTransferInfo.TransferSize;
    else
        LastError = GetLastError();

    return ulTransferSize;
}

//______________________________________________________________________________

void   CCyUSBEndPoint::SetXferSize(ULONG xfer){

    if (hDevice == INVALID_HANDLE_VALUE) return;

    DWORD BytesXfered;
    SET_TRANSFER_SIZE_INFO SetTransferInfo;

	if(MaxPktSize==0)
		return;
    // Force a multiple of MaxPktSize
    ULONG pkts = (xfer % MaxPktSize) ? 1+(xfer / MaxPktSize) : (xfer / MaxPktSize);
    ULONG xferSize = pkts * MaxPktSize;

    SetTransferInfo.EndpointAddress = Address;
    SetTransferInfo.TransferSize = xferSize;

    if(DeviceIoControl(hDevice,
        IOCTL_ADAPT_SET_TRANSFER_SIZE,
        &SetTransferInfo, sizeof(SET_TRANSFER_SIZE_INFO),
        &SetTransferInfo, sizeof(SET_TRANSFER_SIZE_INFO),
        &BytesXfered,
        NULL)==false)
    {
        LastError = GetLastError();
    }

}



////////////////////////////////////////////////////////////////////////////////
//
// The CCyControlEndPoint Class
//
////////////////////////////////////////////////////////////////////////////////

CCyControlEndPoint::CCyControlEndPoint(void):CCyUSBEndPoint()
{

    Target = TGT_DEVICE;
    ReqType = REQ_VENDOR;
    Direction = DIR_TO_DEVICE;

    ReqCode = 0;
    Value = 0;
    Index = 0;

    XferMode = XMODE_BUFFERED;

}

// Copy Constructor
CCyControlEndPoint::CCyControlEndPoint(CCyControlEndPoint& ept):CCyUSBEndPoint(ept)
{

    Target = ept.Target;
    ReqType = ept.ReqType;
    Direction = ept.Direction;

    ReqCode = ept.ReqCode;
    Value = ept.Value;
    Index = ept.Index;

    XferMode = ept.XferMode;
}


CCyControlEndPoint::CCyControlEndPoint(HANDLE h, PUSB_ENDPOINT_DESCRIPTOR pEndPtDescriptor) :
CCyUSBEndPoint(h, pEndPtDescriptor)
{
    Target = TGT_DEVICE;
    ReqType = REQ_VENDOR;
    Direction = DIR_TO_DEVICE;

    ReqCode = 0;
    Value = 0;
    Index = 0;

    XferMode = XMODE_BUFFERED;

}

//______________________________________________________________________________

bool CCyControlEndPoint::Read(PUCHAR buf, LONG &bufLen)
{
    Direction = DIR_FROM_DEVICE;
    return XferData(buf, bufLen);
}


//______________________________________________________________________________

bool CCyControlEndPoint::Write(PUCHAR buf, LONG &bufLen)
{
    Direction = DIR_TO_DEVICE;
    return XferData(buf, bufLen);
}


//______________________________________________________________________________

PUCHAR CCyControlEndPoint::BeginDataXfer(PUCHAR buf, LONG bufLen, OVERLAPPED *ov)
{
    union {
        struct {
            UCHAR Recipient:5;
            UCHAR Type:2;
            UCHAR Direction:1;
        } bmRequest;

        UCHAR bmReq;
    };

    if ( hDevice == INVALID_HANDLE_VALUE ) return NULL;

    bmRequest.Recipient = Target;
    bmRequest.Type      = ReqType;
    bmRequest.Direction = Direction;

    bIn = (Direction == DIR_FROM_DEVICE);

    int iXmitBufSize = sizeof (SINGLE_TRANSFER) + bufLen;
    UCHAR *pXmitBuf = new UCHAR[iXmitBufSize];
    ZeroMemory (pXmitBuf, sizeof(SINGLE_TRANSFER));

    // The Control Endpoint has a 1 sec resolution on its timeout
    // But, TimeOut is in milliseconds.
    ULONG tmo = ((TimeOut > 0) && (TimeOut < 1000)) ? 1 : TimeOut / 1000;

    PSINGLE_TRANSFER pTransfer = (PSINGLE_TRANSFER) pXmitBuf;
    pTransfer->SetupPacket.bmRequest = bmReq;
    pTransfer->SetupPacket.bRequest = ReqCode;
    pTransfer->SetupPacket.wValue = Value;
    pTransfer->SetupPacket.wIndex = Index;
    pTransfer->SetupPacket.wLength = (USHORT)bufLen;
    pTransfer->SetupPacket.ulTimeOut = tmo;  // Seconds, not milliseconds
    pTransfer->ucEndpointAddress = 0x00;     // control pipe
    pTransfer->IsoPacketLength = 0;
    pTransfer->BufferOffset = sizeof (SINGLE_TRANSFER);
    pTransfer->BufferLength = bufLen;

    // Copy buf into pXmitBuf
    UCHAR *ptr = pXmitBuf + sizeof (SINGLE_TRANSFER);
    memcpy (ptr, buf, bufLen);

    DWORD dwReturnBytes;
    DeviceIoControl (hDevice,
        IOCTL_ADAPT_SEND_EP0_CONTROL_TRANSFER,
        pXmitBuf,
        iXmitBufSize,
        pXmitBuf,
        iXmitBufSize,
        &dwReturnBytes,
        ov);

    // Note that this method leaves pXmitBuf allocated.  It will get deleted in
    // FinishDataXfer.

    LastError = GetLastError();
    return pXmitBuf;

}

////////////////////////////////////////////////////////////////////////////////
//
// The CCyIsocEndPoint Class
//
////////////////////////////////////////////////////////////////////////////////

CCyIsocEndPoint::CCyIsocEndPoint(void) : CCyUSBEndPoint()
{
}

CCyIsocEndPoint::CCyIsocEndPoint(HANDLE h, PUSB_ENDPOINT_DESCRIPTOR pEndPtDescriptor) :
CCyUSBEndPoint(h, pEndPtDescriptor)
{
}
CCyIsocEndPoint::CCyIsocEndPoint(HANDLE h, PUSB_ENDPOINT_DESCRIPTOR pEndPtDescriptor,USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR* SSEndPtDescriptor) :
CCyUSBEndPoint(h, pEndPtDescriptor,SSEndPtDescriptor)
{
}

//______________________________________________________________________________

PUCHAR CCyIsocEndPoint::BeginDataXfer(PUCHAR buf, LONG bufLen, OVERLAPPED *ov)
{
    if ( hDevice == INVALID_HANDLE_VALUE ) return NULL;

    if (XferMode == XMODE_DIRECT)
        return BeginDirectXfer(buf, bufLen, ov);
    else
        return BeginBufferedXfer(buf, bufLen, ov);

}

//______________________________________________________________________________

PUCHAR CCyIsocEndPoint::BeginBufferedXfer(PUCHAR buf, LONG bufLen, OVERLAPPED *ov)
{
    if ( hDevice == INVALID_HANDLE_VALUE ) return NULL;

    int pkts;
    if(MaxPktSize)
        pkts = bufLen / MaxPktSize;       // Number of packets implied by bufLen & pktSize
    else
    {
        pkts = 0;
        return NULL;
    }

    if (bufLen % MaxPktSize) pkts++;

    if (pkts == 0) return NULL;

    int iXmitBufSize = sizeof (SINGLE_TRANSFER) + (pkts * sizeof(ISO_PACKET_INFO)) + bufLen;
    UCHAR *pXmitBuf = new UCHAR[iXmitBufSize];
    ZeroMemory (pXmitBuf, sizeof(SINGLE_TRANSFER) + (pkts * sizeof(ISO_PACKET_INFO)));

    PSINGLE_TRANSFER pTransfer = (PSINGLE_TRANSFER) pXmitBuf;
    pTransfer->ucEndpointAddress = Address;
    pTransfer->IsoPacketOffset = sizeof (SINGLE_TRANSFER);
    pTransfer->IsoPacketLength = pkts * sizeof(ISO_PACKET_INFO);
    pTransfer->BufferOffset = sizeof (SINGLE_TRANSFER) + pTransfer->IsoPacketLength;
    pTransfer->BufferLength = bufLen;

    // Copy buf into pXmitBuf
    UCHAR *ptr = pXmitBuf + pTransfer->BufferOffset;
    memcpy (ptr, buf, bufLen);

    DWORD dwReturnBytes = 0;

    DeviceIoControl (hDevice,
        IOCTL_ADAPT_SEND_NON_EP0_TRANSFER,
        pXmitBuf,
        iXmitBufSize,
        pXmitBuf,
        iXmitBufSize,
        &dwReturnBytes,
        ov);

    // Note that this method leaves pXmitBuf allocated.  It will get deleted in
    // FinishDataXfer.

    UsbdStatus = pTransfer->UsbdStatus;
    NtStatus   = pTransfer->NtStatus;

    LastError = GetLastError();
    return pXmitBuf;
}

//______________________________________________________________________________

PUCHAR CCyIsocEndPoint::BeginDirectXfer(PUCHAR buf, LONG bufLen, OVERLAPPED *ov)
{
    if ( hDevice == INVALID_HANDLE_VALUE ) return NULL;

    int pkts;
    if(MaxPktSize)
        pkts = bufLen / MaxPktSize;       // Number of packets implied by bufLen & pktSize
    else
    {
        pkts = 0;
        return NULL;
    }

    if (bufLen % MaxPktSize) pkts++;

    if (pkts == 0) return NULL;

    int iXmitBufSize = sizeof (SINGLE_TRANSFER) + (pkts * sizeof(ISO_PACKET_INFO));
    UCHAR *pXmitBuf = new UCHAR[iXmitBufSize];
    ZeroMemory (pXmitBuf, iXmitBufSize);

    PSINGLE_TRANSFER pTransfer = (PSINGLE_TRANSFER) pXmitBuf;
    pTransfer->ucEndpointAddress = Address;
    pTransfer->IsoPacketOffset = sizeof (SINGLE_TRANSFER);
    pTransfer->IsoPacketLength = pkts * sizeof(ISO_PACKET_INFO);
    pTransfer->BufferOffset = 0;
    pTransfer->BufferLength = 0;

    DWORD dwReturnBytes = 0;
    DeviceIoControl (hDevice,
        IOCTL_ADAPT_SEND_NON_EP0_DIRECT,
        pXmitBuf,
        iXmitBufSize,
        buf,
        bufLen,
        &dwReturnBytes,
        ov);

    // Note that this method leaves pXmitBuf allocated.  It will get deleted in
    // FinishDataXfer.

    UsbdStatus = pTransfer->UsbdStatus;
    NtStatus   = pTransfer->NtStatus;

    LastError = GetLastError();
    return pXmitBuf;
}

////////////////////////////////////////////////////////////////////////////////
//
// The CCyFX3Device Class
//
////////////////////////////////////////////////////////////////////////////////
CCyFX3Device::CCyFX3Device()
{
}
CCyFX3Device::~CCyFX3Device()
{
}
bool CCyFX3Device::Ep0VendorCommand(vendorCmdData cmdData)
{
    ControlEndPt->Target    = TGT_DEVICE ;
    ControlEndPt->ReqType   = REQ_VENDOR ;
    ControlEndPt->ReqCode   = cmdData.opCode ;
    ControlEndPt->Direction = (cmdData.isRead) ? DIR_FROM_DEVICE : DIR_TO_DEVICE ;

    ControlEndPt->Value     = (cmdData.addr & 0xFFFF);
    ControlEndPt->Index     = ((cmdData.addr >> 16) & 0xFFFF);

    int maxpkt = ControlEndPt->MaxPktSize;

    long len = cmdData.size;

    /* Handle the case where transfer length is 0 (used to send the Program Entry) */
    if (cmdData.size == 0)
        return ControlEndPt->XferData(cmdData.buf, len, NULL);
    else
    {
        bool bRetCode = false;
        long Stagelen = 0;
        int BufIndex = 0;
        while (len > 0)
        {
            if (len >= 65535)
                Stagelen = 65535;
            else
                Stagelen = (len) % 65535;

            /* Allocate the buffer */
            PUCHAR StageBuf = new UCHAR[Stagelen];

            if (!cmdData.isRead)
            {
                /*write operation */
                for (int i = 0; i < Stagelen; i++)
                    StageBuf[i] = cmdData.buf[BufIndex + i];
            }

            bRetCode = ControlEndPt->XferData(StageBuf, Stagelen, NULL);
            if (!bRetCode)
			{
				if(StageBuf)
				  delete[] StageBuf;

				return false;
			}

            if (cmdData.isRead)
            {
                /*read operation */
                for (int i = 0; i < Stagelen; i++)
                    cmdData.buf[BufIndex + i] = StageBuf[i];
            }

			if(StageBuf)
				  delete[] StageBuf;

            len -= Stagelen;
            BufIndex += Stagelen;
        }

    }

    return true;
}

//______________________________________________________________________________

/* Function to transmit data on the control endpoint. */
bool CCyFX3Device::DownloadBufferToDevice(UINT start_addr, USHORT count, UCHAR *data_buf, UCHAR opCode)
{
    vendorCmdData cmdData;
    cmdData.addr = start_addr;

    cmdData.isRead = 0;
    cmdData.buf = data_buf;
    cmdData.opCode = opCode;
    cmdData.size = count;

    return Ep0VendorCommand(cmdData);
}

//______________________________________________________________________________

/* Function to read data using control endpoint. */
bool CCyFX3Device::UploadBufferFromDevice(UINT start_addr, USHORT count, UCHAR *data_buf, UCHAR opCode)
{
    vendorCmdData cmdData;
    cmdData.addr = start_addr;

    cmdData.isRead = 1;
    cmdData.buf = data_buf;
    cmdData.opCode = opCode;
    cmdData.size = count;

    return Ep0VendorCommand(cmdData);
}

//______________________________________________________________________________

/* This function sends out the 0xA0 vendor request for transferring the control to
program entry point.
*/
bool CCyFX3Device::SetProgramEntry (UCHAR opCode,UINT start_addr)
{
    vendorCmdData cmdData;
    cmdData.addr = ((start_addr >> 16) | (start_addr << 16)); /* swap LSB and MSB */

    cmdData.isRead = 0;
    cmdData.buf = NULL;
    cmdData.opCode = opCode;
    cmdData.size = 0;

    return Ep0VendorCommand(cmdData);
}

//______________________________________________________________________________

bool CCyFX3Device::IsBootLoaderRunning()
{
    /*Dire : in, Target : Device, ReqCode:0xA0,wValue:0x0000,wIndex:0x0000 */
    /* This function checks for bootloader,it will return false if it is not running. */
    UCHAR buf[1];
    long len = 1;
    bool ret;
	UCHAR opCode = 0xA0; // Vendore command

    vendorCmdData cmdData;

    cmdData.addr = 0x0000;

    cmdData.isRead = true;
    cmdData.buf = buf;
    cmdData.opCode = opCode;
    cmdData.size = len;

    /* Value = isErase, index = sector number */
    ret = Ep0VendorCommand(cmdData);
    return ret;
}

//______________________________________________________________________________

FX3_FWDWNLOAD_ERROR_CODE CCyFX3Device::EraseSectorOfSPIFlash(UINT SectorNumber, UCHAR opCode)
{
    vendorCmdData cmdData;
    bool ret;
    UCHAR buf[1];
    UINT buflen = 0;
    buf[0] = 1;

    cmdData.addr = (1 + (SectorNumber << 16));

    cmdData.isRead = false;
    cmdData.buf = buf;
    cmdData.opCode = opCode;
    cmdData.size = buflen;

    /* Value = isErase, index = sector number */
    ret = Ep0VendorCommand(cmdData);
    if (ret)
    {
        /* Check the status of erase. Value should be 0 */
        buflen = 1;
		cmdData.size = buflen;
        while (buf[0] != 0)
        {
            cmdData.isRead = true;
            cmdData.addr = (0 + (SectorNumber << 16));
            if (!Ep0VendorCommand(cmdData))
                return FAILED;
        }
    }
    else
        return FAILED;

    return SUCCESS;
}

//______________________________________________________________________________

bool CCyFX3Device::WriteToSPIFlash(PUCHAR Buf, UINT buflen, UINT ByteAddress, UCHAR opCode)
{
    vendorCmdData cmdData;
    cmdData.addr = ((ByteAddress / SPI_FLASH_PAGE_SIZE_IN_BYTE) << 16); // swap LSB and MSB

    cmdData.isRead = 0;
    cmdData.buf = Buf;
    cmdData.opCode = opCode;
    cmdData.size = buflen;

    return Ep0VendorCommand(cmdData);
}

//______________________________________________________________________________

FX3_FWDWNLOAD_ERROR_CODE CCyFX3Device::DownloadUserIMGtoSPIFLASH(PUCHAR buffer_p, UINT fw_size, UCHAR opCode)
{
    /* The size of the image needs to be rounded to a multiple of the SPI page size. */
    UINT ImageSizeInPage = (fw_size + SPI_FLASH_PAGE_SIZE_IN_BYTE - 1) / SPI_FLASH_PAGE_SIZE_IN_BYTE;
    UINT TotalNumOfByteToWrote = ImageSizeInPage * SPI_FLASH_PAGE_SIZE_IN_BYTE;
    /* Sectors needs to be erased in case of SPI. Sector size = 64k. Page Size = 256 bytes. 1 Sector = 256 pages. */
    /* Calculate the number of sectors needed to write firmware image and erase them. */
    UINT NumOfSector = fw_size / SPI_FLASH_SECTOR_SIZE_IN_BYTE;
    if ((fw_size % SPI_FLASH_SECTOR_SIZE_IN_BYTE) != 0)
        NumOfSector++;

    /* Erase the sectors */
    for (UINT i = 0; i < NumOfSector; i++)
    {
        if (EraseSectorOfSPIFlash(i, opCode) != SUCCESS)
            return SPILASH_ERASE_FAILED;
    }

    /*Write the firmware to the SPI flash */
    UINT numberOfBytesLeftToWrite = TotalNumOfByteToWrote; /* Current number of bytes left to write */

    UINT FwFilePointer = 0;
    UINT massStorageByteAddress = 0; /* Current Mass Storage Byte Address  */

    PUCHAR WriteBuf = new UCHAR[CYWB_BL_MAX_BUFFER_SIZE_WHEN_USING_EP0_TRANSPORT];

    while (numberOfBytesLeftToWrite > 0)
    {
        UINT numberOfBytesToWrite = CYWB_BL_MAX_BUFFER_SIZE_WHEN_USING_EP0_TRANSPORT;

        if (numberOfBytesLeftToWrite < CYWB_BL_MAX_BUFFER_SIZE_WHEN_USING_EP0_TRANSPORT)
        {
            numberOfBytesToWrite = numberOfBytesLeftToWrite;
        }

        /* Trigger a mass storage write... */
        for (UINT i = 0; i < numberOfBytesToWrite; i++)
        {
            if ((FwFilePointer + i) < fw_size)
                WriteBuf[i] = buffer_p[i + FwFilePointer];
        }
		opCode = 0xC2; // Operation code to Write to SPI
        if (WriteToSPIFlash(WriteBuf, numberOfBytesToWrite, massStorageByteAddress, opCode) == false)
		{
			if(WriteBuf)
				delete[] WriteBuf;

            return FAILED;
		}

        /* Adjust pointers */
        numberOfBytesLeftToWrite -= numberOfBytesToWrite;
        FwFilePointer += numberOfBytesToWrite;
        massStorageByteAddress += numberOfBytesToWrite;
    }

	if(WriteBuf)
				delete[] WriteBuf;

    return SUCCESS;
}

//______________________________________________________________________________

FX3_FWDWNLOAD_ERROR_CODE CCyFX3Device::DownloadUserIMGtoI2CE2PROM(PUCHAR buffer_p, UINT fw_size, UCHAR opCode)
{
    int STAGE_SIZE = BUFSIZE_UPORT;
    PUCHAR downloadbuf = new UCHAR[STAGE_SIZE];

    int NoOfStage = ((int)fw_size / STAGE_SIZE);
    long LastStage = ((int)fw_size % STAGE_SIZE);
    UINT DownloadAddress = 0;
    long FwImagePtr = 0;
    long StageSize = STAGE_SIZE;

	//Get the I2C addressing size
    UCHAR ImgI2CSizeByte = buffer_p[2]; // the 2nd byte of the IMG file will tell us the I2EPROM internal addressing.
    UINT AddresingStageSize = 0;
    ImgI2CSizeByte = ((ImgI2CSizeByte >> 1) & 0x07); // Bit3:1 represent the addressing
    bool IsMicroShipE2Prom = false;

    switch (ImgI2CSizeByte)
    {
        case 0:
        case 1:
            return I2CE2PROM_UNKNOWN_I2C_SIZE;
        case 2:
            AddresingStageSize = (4 * 1024); // 4KByte
            break;
        case 3:
            AddresingStageSize = (8 * 1024); // 8KByte
            break;
        case 4:
            AddresingStageSize = (16 * 1024); // 16KByte
            break;
        case 5:
            AddresingStageSize = (32 * 1024); // 32KByte
            break;
        case 6:
            AddresingStageSize = (64 * 1024); // 64KByte
            break;
        case 7:
            IsMicroShipE2Prom = true; // 128KByte Addressing for Microchip.
            AddresingStageSize = (64 * 1024); // 64KByte // case 7 represent 128Kbyte but it follow 64Kbyte addressing
            break;
        default:
			{
				if(downloadbuf)
					delete[] downloadbuf;

				return I2CE2PROM_UNKNOWN_I2C_SIZE;
			}
    }


    ControlEndPt->Target    = TGT_DEVICE ;
    ControlEndPt->ReqType   = REQ_VENDOR ;
    ControlEndPt->ReqCode   = opCode ;
    ControlEndPt->Direction = DIR_TO_DEVICE ;

    ControlEndPt->Value     = (DownloadAddress & 0xFFFF);
    ControlEndPt->Index     = ((DownloadAddress >> 16) & 0xFFFF);
    int maxpkt = ControlEndPt->MaxPktSize;

    for (int i = 0; i < NoOfStage; i++)
    {
        /* Copy data from main buffer to tmp buffer */
        for (long j = 0; j < STAGE_SIZE; j++)
            downloadbuf[j] = buffer_p[FwImagePtr + j];

        if (!ControlEndPt->XferData(downloadbuf, StageSize, NULL))
		{
			if(downloadbuf)
					delete[] downloadbuf;

            return FAILED;
		}

        FwImagePtr += STAGE_SIZE;
        ControlEndPt->Index += (WORD)StageSize;

		/////
		// Address calculation done in the below box
        if (IsMicroShipE2Prom)
        {//Microchip Addressing(0-(1-64),4(64 to 128),1(128 to 192 ),5(192 to 256))
            if (FwImagePtr >= (128 * 1024))
            {
                if ((FwImagePtr % AddresingStageSize) == 0)
                {
                    if (ControlEndPt->Value == 0x04)
                        ControlEndPt->Value = 0x01;
                    else
                        ControlEndPt->Value = 0x05;

                    ControlEndPt->Index = 0;
                }
            }
            else if ((FwImagePtr % AddresingStageSize) == 0)
            {
                ControlEndPt->Value = 0x04;
                ControlEndPt->Index = 0;
            }
        }
        else
        {//ATMEL addressing sequential
            if ((FwImagePtr % AddresingStageSize)==0)
            {// Increament the Value field to represent the address and reset the Index value to zero.
                ControlEndPt->Value += 0x01;
                if(ControlEndPt->Value>=8)
                    ControlEndPt->Value = 0x0; //reset the Address to ZERO

                ControlEndPt->Index = 0;
            }
        }
		/////


    }

    if (LastStage != 0)
    {
        /*check for last stage */

        for (long j = 0; j < LastStage; j++)
            downloadbuf[j] = buffer_p[FwImagePtr + j];

        if ((LastStage % maxpkt) != 0)
        {
            /* make it multiple of max packet size */
            int diff = (maxpkt - (LastStage % maxpkt));
            for (int j = LastStage; j < (LastStage + diff); j++)
                downloadbuf[j] = 0;

            LastStage += diff;
        }

        if (!ControlEndPt->XferData(downloadbuf, LastStage, NULL))
		{
			if(downloadbuf)
					delete[] downloadbuf;

            return FAILED;
		}

		/*Failure Case:
                 The device does not return failure message when file size is more than 128KByte and only one 128Byte E2PROM on the DVK.
                 Solution:
                 Read back the last stage data to confirm that all data transferred successfully.*/
         ControlEndPt->ReqCode = 0xBB;
         ControlEndPt->Direction = DIR_FROM_DEVICE;
         if (!ControlEndPt->XferData(downloadbuf, LastStage, NULL))
         {
			 if(downloadbuf)
					delete[] downloadbuf;

               return FAILED;
         }
    }

	if(downloadbuf)
		delete[] downloadbuf;

    return SUCCESS;
}

//______________________________________________________________________________

FX3_FWDWNLOAD_ERROR_CODE CCyFX3Device::DownloadFwToRam(const UCHAR *buffer_p, UINT fw_size, UCHAR opCode)
{
    UCHAR downloadBuffer[BUFSIZE_UPORT];
    UCHAR uploadbuffer[BUFSIZE_UPORT];
    bool isTrue = true;
    UINT ComputeCheckSum = 0;
    UINT ExpectedCheckSum = 0;
    INT fwImagePtr = 0;
    UINT SectionLength = 0;
    UINT SectionAddress;
    UINT DownloadAddress;
    UINT ProgramEntry;

    /* Initialize computed checksum */
    ComputeCheckSum = 0;

    /* Check "CY" signature (0x43,0x59) and download the firmware image */
    if ((buffer_p[fwImagePtr] != 0x43) || (buffer_p[fwImagePtr + 1] != 0x59))
    {	/*signature doesn't match */
        return INVALID_FWSIGNATURE;
    }

    /* Skip the two bytes signature and the following two bytes */
    fwImagePtr += 4;

    /* Download one section at a time to the device, compute checksum, and upload-verify it */
    while (isTrue)
    {
        /* Get section length (4 bytes) and convert it from 32-bit word count to byte count */
        CYWB_BL_4_BYTES_COPY(&SectionLength, &buffer_p[fwImagePtr]);
        fwImagePtr += 4;

        SectionLength = SectionLength << 2;

        /* If length = 0, the transfer is complete */
        if (SectionLength == 0) break;

        /* Get section address (4 bytes) */
        CYWB_BL_4_BYTES_COPY(&SectionAddress, &buffer_p[fwImagePtr]);
        fwImagePtr += 4;

        /* Download BUFSIZE_UPORT maximum bytes at a time */
        INT bytesLeftToDownload = SectionLength;
        DownloadAddress = SectionAddress;

        while (bytesLeftToDownload > 0)
        {
            INT bytesToTransfer = BUFSIZE_UPORT;
            if (bytesLeftToDownload < BUFSIZE_UPORT)
                bytesToTransfer = bytesLeftToDownload;

            /* sanity check for incomplete fw with valid signatures.
            Note: bytesToTransfer should never be greater then fw length i.e buflen */
            if (bytesToTransfer > (INT)fw_size)
                return CORRUPT_FIRMWARE_IMAGE_FILE;

            memcpy(downloadBuffer, (void *)(buffer_p + fwImagePtr), bytesToTransfer);

            /* Compute checksum: Here transferLength is assumed to be a multiple of 4. If it is not, the checksum will fail anyway */
            for (INT index = 0; index < bytesToTransfer; index += 4)
            {
                UINT buf32bits = 0;
                CYWB_BL_4_BYTES_COPY(&buf32bits, &downloadBuffer[index]);
                ComputeCheckSum += buf32bits;
            }

            /*The FPGA does not seem to always be reliable: if an error is encountered, try again twice */
            INT maxTryCount = 3;
            for (INT tryCount = 1; tryCount <= maxTryCount; tryCount++)
            {
                /* Download one buffer worth of data to the device */
                if (!DownloadBufferToDevice(DownloadAddress, bytesToTransfer, downloadBuffer, opCode))
                {
                    /* Check if we exceeded the max try count */
                    if (tryCount == maxTryCount)
                    {
                        /* Failure while downloading firmware to the device. Abort */
                        return FAILED;
                    }
                    else
                    {
                        /* F/W buffer download failure. Trying writing/verifying current buffer again... */
                        continue;
                    }
                }

                memset (uploadbuffer, 0, bytesToTransfer);

                if (!UploadBufferFromDevice(DownloadAddress, bytesToTransfer, uploadbuffer, opCode))
                {
                    /* Check if we exceeded the max try count */
                    if (tryCount == maxTryCount)
                    {
                        /* Failure while uploading firmware from the device for verification. Abort */
                        return FAILED;
                    }
                    else
                    {
                        /*  F/W buffer upload failure. Trying writing/verifying current buffer again... */
                        continue;
                    }
                }

                for (int count = 0; count < bytesToTransfer; count++)
                {
                    if (downloadBuffer[count] != uploadbuffer[count])
                    {
                        /* Check if we exceeded the max try count */
                        if (tryCount == maxTryCount)
                        {
                            /* Uploaded firmware data does not match downloaded data. Abort */
                            return FAILED;
                        }
                        else
                        {
                            /* Uploaded data does not match downloaded data. Trying writing/verifying current buffer again...*/
                            continue;
                        }
                    }
                }
            }

            DownloadAddress += bytesToTransfer;
            fwImagePtr += bytesToTransfer;
            bytesLeftToDownload -= bytesToTransfer;

            /* Sanity check */
            if (fwImagePtr > (INT)fw_size)
                return INCORRECT_IMAGE_LENGTH;
        }
    }

    /* Get Program Entry Address(4 bytes) */
    CYWB_BL_4_BYTES_COPY(&ProgramEntry, &buffer_p[fwImagePtr]);
    fwImagePtr += 4;

    /* Get expected checksum (4 bytes) */
    CYWB_BL_4_BYTES_COPY(&ExpectedCheckSum, &buffer_p[fwImagePtr]);
    fwImagePtr += 4;

    /* Compare computed checksum against expected value */
    if (ComputeCheckSum != ExpectedCheckSum)
    {
        /* CheckSum mismatch. Expected=0x" << std::hex << expectedCheckSum << " Computed=0x" << std::hex << computedCheckSum; */
    }

    /* Transfer execution to Program Entry */
    UCHAR dummyBuffer[1];
	// Few of the xHCI driver stack have issue with Control IN transfer,due to that below request fails ,
	// Control IN transfer is ZERO lenght packet , and it does not have any impact on execution of firmware.
    //if (!DownloadBufferToDevice(ProgramEntry, 0, dummyBuffer, opCode))
    //{
    //    /* Downloading Program Entry failed */
    //    return FAILED;
    //}
	DownloadBufferToDevice(ProgramEntry, 0, dummyBuffer, opCode);

    return SUCCESS;
}

//______________________________________________________________________________

FX3_FWDWNLOAD_ERROR_CODE CCyFX3Device::DownloadFw(char *fileName, FX3_FWDWNLOAD_MEDIA_TYPE enMediaType)
{
    UINT fwSize = 0;
    PUCHAR FwImage;
    FILE *FwImagePtr;
    //int error;

//  error = fopen_s(&FwImagePtr, fileName, "rb");
    FwImagePtr = fopen( fileName, "rb");
    if (FwImagePtr == NULL)
        return INVALID_FILE;

    /* Find the length of the image */
    fseek (FwImagePtr, 0, SEEK_END);
    fwSize = ftell(FwImagePtr);
    fseek (FwImagePtr, 0, SEEK_SET);

    /* Allocate memory for the image */
    FwImage =  new unsigned char[fwSize];

    if (FwImage == NULL)
        return INVALID_FILE;

    if (fwSize <= 0)
    {
        fclose (FwImagePtr);
        return INVALID_FILE;
    }

    /* Read into buffer */
    fread (FwImage, fwSize, 1, FwImagePtr);
    fclose (FwImagePtr);

	FX3_FWDWNLOAD_ERROR_CODE ErroCode = SUCCESS;
    // call api to download the image
    if (enMediaType == RAM)
        ErroCode = DownloadFwToRam(FwImage, fwSize, 0xA0);
    else if (enMediaType == I2CE2PROM)
            ErroCode = DownloadUserIMGtoI2CE2PROM(FwImage, fwSize, 0xBA);
    else if (enMediaType == SPIFLASH)
        ErroCode = DownloadUserIMGtoSPIFLASH(FwImage, fwSize, 0xC4);
    else
        ErroCode = INVALID_MEDIA_TYPE;

	if(FwImage)
		delete[] FwImage;

	return ErroCode;
}

//______________________________________________________________________________

CCyIsoPktInfo* CCyIsocEndPoint::CreatePktInfos(LONG bufLen, int &packets)
{
	if(MaxPktSize==0)
		return NULL;

    packets = bufLen / MaxPktSize;       // Number of packets implied by bufLen & pktSize
    if (bufLen % MaxPktSize) packets++;

    if (packets) {
        CCyIsoPktInfo *isoPktInfos = new CCyIsoPktInfo[packets];
        return isoPktInfos;
    } else
        return NULL;

}

////////////////////////////////////////////////////////////////////////////////
//
// The CCyBulkEndPoint Class
//
////////////////////////////////////////////////////////////////////////////////

CCyBulkEndPoint::CCyBulkEndPoint(void) : CCyUSBEndPoint()
{
}

CCyBulkEndPoint::CCyBulkEndPoint(HANDLE h, PUSB_ENDPOINT_DESCRIPTOR pEndPtDescriptor) :
CCyUSBEndPoint(h, pEndPtDescriptor)
{

}
CCyBulkEndPoint::CCyBulkEndPoint(HANDLE h, PUSB_ENDPOINT_DESCRIPTOR pEndPtDescriptor,USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR* SSEndPtDescriptor):
CCyUSBEndPoint(h, pEndPtDescriptor,SSEndPtDescriptor)
{

}
//______________________________________________________________________________

PUCHAR CCyBulkEndPoint::BeginDataXfer(PUCHAR buf, LONG bufLen, OVERLAPPED *ov)
{
    if ( hDevice == INVALID_HANDLE_VALUE ) return NULL;

    if (XferMode == XMODE_DIRECT)
        return BeginDirectXfer(buf, bufLen, ov);
    else
        return BeginBufferedXfer(buf, bufLen, ov);
}



////////////////////////////////////////////////////////////////////////////////
//
// The CCyInterruptEndPoint Class
//
////////////////////////////////////////////////////////////////////////////////

CCyInterruptEndPoint::CCyInterruptEndPoint(void) : CCyUSBEndPoint()
{
}

CCyInterruptEndPoint::CCyInterruptEndPoint(HANDLE h, PUSB_ENDPOINT_DESCRIPTOR pEndPtDescriptor) :
CCyUSBEndPoint(h, pEndPtDescriptor)
{

}
CCyInterruptEndPoint::CCyInterruptEndPoint(HANDLE h, PUSB_ENDPOINT_DESCRIPTOR pEndPtDescriptor,USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR* SSEndPtDescriptor):
CCyUSBEndPoint(h, pEndPtDescriptor,SSEndPtDescriptor)
{
}

//______________________________________________________________________________

PUCHAR CCyInterruptEndPoint::BeginDataXfer(PUCHAR buf, LONG bufLen, OVERLAPPED *ov)
{
    if ( hDevice == INVALID_HANDLE_VALUE ) return NULL;

    if (XferMode == XMODE_DIRECT)
        return BeginDirectXfer(buf, bufLen, ov);
    else
        return BeginBufferedXfer(buf, bufLen, ov);

}
CCyUSBBOS::CCyUSBBOS(void)
{
	 // initialize to null
    pUSB20_DeviceExt = NULL;
    pSS_DeviceCap = NULL;
    pContainer_ID = NULL;
}
CCyUSBBOS::~CCyUSBBOS()
{
	if(pContainer_ID)
	{
		delete pContainer_ID;
		pContainer_ID = NULL;
	}
	if(pUSB20_DeviceExt)
	{
		delete pUSB20_DeviceExt;
		pUSB20_DeviceExt = NULL;
	}
	if(pSS_DeviceCap)
	{
		delete pSS_DeviceCap;
		pSS_DeviceCap = NULL;
	}
}

CCyUSBBOS::CCyUSBBOS(HANDLE h,PUSB_BOS_DESCRIPTOR pBosDescrData)
{
    // initialize to null
    pUSB20_DeviceExt = NULL;
    pSS_DeviceCap = NULL;
    pContainer_ID = NULL;

    bLength = pBosDescrData->bLength;
    bDescriptorType = pBosDescrData->bDescriptorType;
    bNumDeviceCaps = pBosDescrData->bNumDeviceCaps;
    wTotalLength = pBosDescrData->wTotalLength;

    int totallen = wTotalLength;
    totallen -=pBosDescrData->bLength;

    if (totallen < 0)
        return;

    UCHAR*  DevCap = (byte*)((byte*)pBosDescrData + pBosDescrData->bLength); // get nex descriptor

    for (int i = 0; i < bNumDeviceCaps; i++)
    {
        //check capability type
        switch (DevCap[USB_BOS_DEVICE_CAPABILITY_TYPE_INDEX])
        {
        case USB_BOS_CAPABILITY_TYPE_USB20_EXT:
            {
                PUSB_BOS_USB20_DEVICE_EXTENSION pUSB20_ext = (PUSB_BOS_USB20_DEVICE_EXTENSION)DevCap;
                totallen -= pUSB20_ext->bLength;
                DevCap = (byte *)DevCap +pUSB20_ext->bLength;
                pUSB20_DeviceExt = new CCyBosUSB20Extesnion(h, pUSB20_ext);
                break;
            }
        case USB_BOS_CAPABILITY_TYPE_SUPERSPEED_USB:
            {
                PUSB_BOS_SS_DEVICE_CAPABILITY pSS_Capability = (PUSB_BOS_SS_DEVICE_CAPABILITY)DevCap;
                totallen -= pSS_Capability->bLength;
                DevCap = (byte*)DevCap + pSS_Capability->bLength;
                pSS_DeviceCap = new CCyBosSuperSpeedCapability(h, pSS_Capability);
                break;
            }
        case USB_BOS_CAPABILITY_TYPE_CONTAINER_ID:
            {
                PUSB_BOS_CONTAINER_ID pUSB_ContainerID = (PUSB_BOS_CONTAINER_ID)DevCap;
                totallen -= pUSB_ContainerID->bLength;
                DevCap = (byte*)DevCap + pUSB_ContainerID->bLength;
                pContainer_ID = new CCyBosContainerID(h, pUSB_ContainerID);
                break;
            }
        default:
            {
                break;
            }
        }
        if(totallen<0)
            break;
    }
}
CCyBosUSB20Extesnion::CCyBosUSB20Extesnion(void)
{}
CCyBosUSB20Extesnion::CCyBosUSB20Extesnion(HANDLE h,PUSB_BOS_USB20_DEVICE_EXTENSION pBosUsb20ExtDesc)
{
    bLength = pBosUsb20ExtDesc->bLength;
    bDescriptorType = pBosUsb20ExtDesc->bDescriptorType;
    bDevCapabilityType = pBosUsb20ExtDesc->bDevCapabilityType;
    bmAttribute = pBosUsb20ExtDesc->bmAttribute;
}
CCyBosSuperSpeedCapability::CCyBosSuperSpeedCapability(void)
{}
CCyBosSuperSpeedCapability::CCyBosSuperSpeedCapability(HANDLE h,PUSB_BOS_SS_DEVICE_CAPABILITY pUSB_SuperSpeedUsb)
{
    bLength = pUSB_SuperSpeedUsb->bLength;
    bDescriptorType = pUSB_SuperSpeedUsb->bDescriptorType;
    bDevCapabilityType = pUSB_SuperSpeedUsb->bDevCapabilityType;
    bFunctionalitySupporte = pUSB_SuperSpeedUsb->bFunctionalitySupporte;
    SpeedsSuported = pUSB_SuperSpeedUsb->wSpeedsSuported;
    bmAttribute = pUSB_SuperSpeedUsb->bmAttribute;
    bU1DevExitLat = pUSB_SuperSpeedUsb->bU1DevExitLat;
    bU2DevExitLat = pUSB_SuperSpeedUsb->bU2DevExitLat;
}
CCyBosContainerID::CCyBosContainerID(void)
{}
CCyBosContainerID::CCyBosContainerID(HANDLE handle, PUSB_BOS_CONTAINER_ID pUSB_ContainerID)
{
    bLength = pUSB_ContainerID->bLength;
    bDescriptorType = pUSB_ContainerID->bDescriptorType;
    bDevCapabilityType = pUSB_ContainerID->bDevCapabilityType;
    for (int i = 0; i < USB_BOS_CAPABILITY_TYPE_CONTAINER_ID_SIZE; i++)
        ContainerID[i] = pUSB_ContainerID->ContainerID[i];
}
