BOOL USBHostChargerEventHandler( BYTE address, USB_EVENT event, void *data, DWORD size ) { // Make sure the event is for a connected device if (!_USBHostCharger_FindDevice( address )) { return FALSE; } // Handle specific events. switch (event) { case EVENT_DETACH: // Notify that application that the device has been detached. USB_HOST_APP_EVENT_HANDLER(usbChargingDevices[currentChargingRecord].ID.deviceAddress, EVENT_CHARGER_DETACH, &usbChargingDevices[currentChargingRecord].ID.deviceAddress, sizeof(BYTE) ); usbChargingDevices[currentChargingRecord].flags.val = 0; usbChargingDevices[currentChargingRecord].ID.deviceAddress = 0; #ifdef DEBUG_MODE UART2PrintString( "USB Charging Client Device Detached: address=" ); UART2PutDec( address ); UART2PrintString( "\r\n" ); #endif return TRUE; break; case EVENT_SUSPEND: case EVENT_RESUME: case EVENT_BUS_ERROR: default: break; } return FALSE; } // USBHostChargerEventHandler
BOOL USBHostBluetoothInit ( BYTE address, DWORD flags, BYTE clientDriverID ) { BYTE *pDesc; // Initialize state gc_DevData.rxEvtLength = 0; gc_DevData.rxAclLength = 0; gc_DevData.flags.val = 0; // Save device the address, VID, & PID gc_DevData.ID.deviceAddress = address; pDesc = USBHostGetDeviceDescriptor(address); pDesc += 8; gc_DevData.ID.vid = (WORD)*pDesc; pDesc++; gc_DevData.ID.vid |= ((WORD)*pDesc) << 8; pDesc++; gc_DevData.ID.pid = (WORD)*pDesc; pDesc++; gc_DevData.ID.pid |= ((WORD)*pDesc) << 8; pDesc++; // Save the Client Driver ID gc_DevData.clientDriverID = clientDriverID; #ifdef USBHOSTBT_DEBUG SIOPrintString( "GEN: USB Generic Client Initalized: flags=0x" ); SIOPutHex( flags ); SIOPrintString( " address=" ); SIOPutDec( address ); SIOPrintString( " VID=0x" ); SIOPutHex( gc_DevData.ID.vid >> 8 ); SIOPutHex( gc_DevData.ID.vid & 0xFF ); SIOPrintString( " PID=0x" ); SIOPutHex( gc_DevData.ID.pid >> 8 ); SIOPutHex( gc_DevData.ID.pid & 0xFF ); SIOPrintString( "\r\n" ); #endif // Generic Client Driver Init Complete. gc_DevData.flags.initialized = 1; // Notify that application that we've been attached to a device. USB_HOST_APP_EVENT_HANDLER(address, EVENT_BLUETOOTH_ATTACH, &(gc_DevData.ID), sizeof(BLUETOOTH_DEVICE_ID) ); return TRUE; } // USBHostBluetoothInit
BOOL USBHostChargerInitialize( BYTE address, DWORD flags, BYTE clientDriverID ) { BYTE *pDesc; // Find a new entry for (currentChargingRecord=0; currentChargingRecord<USB_MAX_CHARGING_DEVICES; currentChargingRecord++) { if (!usbChargingDevices[currentChargingRecord].flags.inUse) break; } if (currentChargingRecord == USB_MAX_CHARGING_DEVICES) { #ifdef DEBUG_MODE UART2PrintString( "CHG: No more space\r\n" ); #endif return FALSE; // We have no more room for a new device. } // Initialize state - set the inUse flag. usbChargingDevices[currentChargingRecord].flags.val = 1; // Save device the address, VID, & PID usbChargingDevices[currentChargingRecord].ID.deviceAddress = address; usbChargingDevices[currentChargingRecord].ID.clientDriverID = clientDriverID; pDesc = USBHostGetDeviceDescriptor(address); pDesc += 8; usbChargingDevices[currentChargingRecord].ID.vid = (WORD)*pDesc; pDesc++; usbChargingDevices[currentChargingRecord].ID.vid |= ((WORD)*pDesc) << 8; pDesc++; usbChargingDevices[currentChargingRecord].ID.pid = (WORD)*pDesc; pDesc++; usbChargingDevices[currentChargingRecord].ID.pid |= ((WORD)*pDesc) << 8; pDesc++; VID = usbChargingDevices[currentChargingRecord].ID.vid; PID = usbChargingDevices[currentChargingRecord].ID.pid; // Notify that application that we've been attached to a device. USB_HOST_APP_EVENT_HANDLER(address, EVENT_CHARGER_ATTACH, &(usbChargingDevices[currentChargingRecord].ID), sizeof(USB_CHARGING_DEVICE_ID) ); return TRUE; } // USBHostChargerInit
/**************************************************************************** Function: BOOL AndroidAppDataEventHandler_Pv1( BYTE address, USB_EVENT event, void *data, DWORD size ) Summary: Handles data events from the host stack Description: Handles data events from the host stack Precondition: None Parameters: BYTE address - the address of the device that caused the event USB_EVENT event - the event that occured void* data - the data for the event DWORD size - the size of the data in bytes Return Values: TRUE - the event was handled FALSE - the event was not handled Remarks: This is a internal API only. This should not be called by anything other than the USB host stack via the client driver table ***************************************************************************/ BOOL AndroidAppDataEventHandler_Pv1( BYTE address, USB_EVENT event, void *data, DWORD size ) { BYTE i; switch (event) { case EVENT_SOF: // Start of frame - NOT NEEDED return TRUE; case EVENT_1MS: // 1ms timer for(i=0;i<NUM_ANDROID_DEVICES_SUPPORTED;i++) { if(devices_pv1[i].state == WAITING_FOR_ACCESSORY_RETURN) { switch(devices_pv1[i].countDown) { case 0: //do nothing break; case 1: USB_HOST_APP_EVENT_HANDLER(devices_pv1[i].address,EVENT_ANDROID_DETACH,&devices_pv1[i],sizeof(ANDROID_PROTOCOL_V1_DEVICE_DATA*)); //Device has timed out. Destroy its info. memset(&devices_pv1[i],0x00,sizeof(ANDROID_PROTOCOL_V1_DEVICE_DATA)); break; default: //for every other number, decrement the count devices_pv1[i].countDown--; break; } } } return TRUE; default: break; } return FALSE; }
/**************************************************************************** Function: BOOL AndroidAppEventHandler( BYTE address, USB_EVENT event, void *data, DWORD size ) Summary: Handles events from the host stack Description: Handles events from the host stack Precondition: None Parameters: BYTE address - the address of the device that caused the event USB_EVENT event - the event that occured void* data - the data for the event DWORD size - the size of the data in bytes Return Values: TRUE - the event was handled FALSE - the event was not handled Remarks: This is a internal API only. This should not be called by anything other than the USB host stack via the client driver table ***************************************************************************/ BOOL AndroidAppEventHandler( BYTE address, USB_EVENT event, void *data, DWORD size ) { HOST_TRANSFER_DATA* transfer_data = data ; BYTE i,j; //Throw the message to the protocol handlers if they match the address // and are ready. for(i=0;i<NUM_ANDROID_DEVICES_SUPPORTED;i++) { if((devices[i].state == READY) && (devices[i].address == address)) { for(j=0;j<(sizeof(protocolVersions)/sizeof(ANDROID_PROTOCOL_VERSION));j++) { if(devices[i].protocol == protocolVersions[j].versionNumber) { protocolVersions[j].handler(address, event, data, size); //Force exit both for loops i=NUM_ANDROID_DEVICES_SUPPORTED; break; } } } } switch (event) { case EVENT_DETACH: // USB cable has been detached (data: BYTE, address of device) for(i=0;i<NUM_ANDROID_DEVICES_SUPPORTED;i++) { if(devices[i].address == address) { if(devices[i].state == READY) { switch(devices[i].protocol) { case 1: devices[i].countDown = ANDROID_DEVICE_ATTACH_TIMEOUT; break; default: //USB_HOST_APP_EVENT_HANDLER(address,event,devices[i].protocolHandle,sizeof(ANDROID_DEVICE_DATA*)); break; } } else { USB_HOST_APP_EVENT_HANDLER(address,event,devices[i].protocolHandle,sizeof(ANDROID_DEVICE_DATA*)); //Device has timed out. Destroy its info. memset(&devices[i],0x00,sizeof(ANDROID_DEVICE_DATA)); } } } return TRUE; case EVENT_TRANSFER: for(i=0;i<NUM_ANDROID_DEVICES_SUPPORTED;i++) { if((transfer_data->bEndpointAddress == 0x00) && (devices[i].state == GET_PROTOCOL_SENT)) { for(j=0;j<(sizeof(protocolVersions)/sizeof(ANDROID_PROTOCOL_VERSION));j++) { if(devices[i].protocol == protocolVersions[j].versionNumber) { //From this level standpoint, we are done. The rest is // protocol layer specific devices[i].state = READY; devices[i].protocolHandle = protocolVersions[j].init(devices[i].address, devices[i].flags, devices[i].clientDriverID); break; } } if(j >= (sizeof(protocolVersions)/sizeof(ANDROID_PROTOCOL_VERSION))) { //If we don't support that protocol version, use the next best version //Override the protocol version specified by the device devices[i].protocol = protocolVersions[j-1].versionNumber; devices[i].state = READY; devices[i].protocolHandle = protocolVersions[j-1].init(devices[i].address, devices[i].flags, devices[i].clientDriverID); } return TRUE; } } return TRUE; case EVENT_NONE: // No event occured (NULL event) //Fall through case EVENT_HUB_ATTACH: // USB hub has been attached //Fall through case EVENT_RESUME: // Device-mode resume received //Fall through case EVENT_SUSPEND: // Device-mode suspend/idle event received //Fall through case EVENT_RESET: // Device-mode bus reset received //Fall through case EVENT_STALL: // A stall has occured //Fall through case EVENT_BUS_ERROR: // BUS error has occurred return TRUE; default: break; } return FALSE; }
BOOL USBHostBluetoothEventHandler ( BYTE address, USB_EVENT event, void *data, DWORD size ) { // Make sure it was for our device if ( address != gc_DevData.ID.deviceAddress) { return FALSE; } // Handle specific events. switch (event) { case EVENT_DETACH: // Notify that application that the device has been detached. USB_HOST_APP_EVENT_HANDLER(gc_DevData.ID.deviceAddress, EVENT_BLUETOOTH_DETACH, &gc_DevData.ID.deviceAddress, sizeof(BYTE) ); gc_DevData.flags.val = 0; gc_DevData.ID.deviceAddress = 0; #ifdef USBHOSTBT_DEBUG SIOPrintString( "USB Host Bluetooth Device Detached: address=%d\n", address ); #endif return TRUE; case EVENT_TRANSFER: if ( (data != NULL) && (size == sizeof(HOST_TRANSFER_DATA)) ) { DWORD dataCount = ((HOST_TRANSFER_DATA *)data)->dataCount; if ( ((HOST_TRANSFER_DATA *)data)->bEndpointAddress == (USB_IN_EP|USB_EP1) ) //GVG { //SIOPrintString( "E\n" ); gc_DevData.flags.rxEvtBusy = 0; gc_DevData.rxEvtLength = dataCount; if(!dataCount) return FALSE; USB_HOST_APP_EVENT_HANDLER(gc_DevData.ID.deviceAddress, EVENT_BLUETOOTH_RX1_DONE, &dataCount, sizeof(DWORD) ); } else if ( ((HOST_TRANSFER_DATA *)data)->bEndpointAddress == (USB_IN_EP|USB_EP2) ) //GVG { //if(!dataCount) return FALSE; gc_DevData.flags.rxAclBusy = 0; gc_DevData.rxAclLength = dataCount; USB_HOST_APP_EVENT_HANDLER(gc_DevData.ID.deviceAddress, EVENT_BLUETOOTH_RX2_DONE, &dataCount, sizeof(DWORD) ); } else if ( ((HOST_TRANSFER_DATA *)data)->bEndpointAddress == (USB_OUT_EP|USB_EP2) ) //GVG { gc_DevData.flags.txAclBusy = 0; USB_HOST_APP_EVENT_HANDLER(gc_DevData.ID.deviceAddress, EVENT_BLUETOOTH_TX2_DONE, &dataCount, sizeof(DWORD) ); } else { return FALSE; } return TRUE; } return FALSE; case EVENT_SUSPEND: case EVENT_RESUME: case EVENT_BUS_ERROR: default: break; } return FALSE; } // USBHostBluetoothEventHandler
/**************************************************************************** Function: BOOL AndroidAppEventHandler_Pv1( BYTE address, USB_EVENT event, void *data, DWORD size ) Summary: Handles events from the host stack Description: Handles events from the host stack Precondition: None Parameters: BYTE address - the address of the device that caused the event USB_EVENT event - the event that occured void* data - the data for the event DWORD size - the size of the data in bytes Return Values: TRUE - the event was handled FALSE - the event was not handled Remarks: This is a internal API only. This should not be called by anything other than the USB host stack via the client driver table ***************************************************************************/ BOOL AndroidAppEventHandler_Pv1( BYTE address, USB_EVENT event, void *data, DWORD size ) { HOST_TRANSFER_DATA* transfer_data = data ; ANDROID_PROTOCOL_V1_DEVICE_DATA *device = NULL; BYTE i; switch (event) { case EVENT_NONE: // No event occured (NULL event) return TRUE; case EVENT_DETACH: // USB cable has been detached (data: BYTE, address of device) for(i=0;i<NUM_ANDROID_DEVICES_SUPPORTED;i++) { if(devices_pv1[i].address == address) { if(devices_pv1[i].state == ACCESSORY_STARTING) { devices_pv1[i].state = WAITING_FOR_ACCESSORY_RETURN; } if(devices_pv1[i].state != WAITING_FOR_ACCESSORY_RETURN) { device = &devices_pv1[i]; USBHostTerminateTransfer( device->address, device->OUTEndpointNum ); USBHostTerminateTransfer( device->address, device->INEndpointNum ); USB_HOST_APP_EVENT_HANDLER(device->address,EVENT_ANDROID_DETACH,device,sizeof(ANDROID_PROTOCOL_V1_DEVICE_DATA*)); //Device has timed out. Destroy its info. memset(&devices_pv1[i],0x00,sizeof(ANDROID_PROTOCOL_V1_DEVICE_DATA)); } //If we are WAITING_FOR_ACCESSORY_RETURN, then we will timeout in data handler instead } } return TRUE; case EVENT_HUB_ATTACH: // USB hub has been attached return TRUE; case EVENT_TRANSFER: // A USB transfer has completed - NOT USED for(i=0;i<NUM_ANDROID_DEVICES_SUPPORTED;i++) { if(devices_pv1[i].address == address) { device = &devices_pv1[i]; } } //If this is for a device that we don't know about, get rid of it. if(device == NULL) { return FALSE; } //Otherwise, handle the data if(transfer_data->bEndpointAddress == 0x00) { //If the transfer was EP0, just clear the pending bit and // we will handle the rest in the tasks function so we don't // duplicate state machine changes both here and there device->status.EP0TransferPending = 0; } return TRUE; case EVENT_RESUME: // Device-mode resume received return TRUE; case EVENT_SUSPEND: // Device-mode suspend/idle event received return TRUE; case EVENT_RESET: // Device-mode bus reset received return TRUE; case EVENT_STALL: // A stall has occured return TRUE; case EVENT_BUS_ERROR: // BUS error has occurred return TRUE; default: break; } return FALSE; }
/**************************************************************************** Function: void AndroidTasks_Pv1(void) Summary: Tasks function that keeps the Android client driver moving Description: Tasks function that keeps the Android client driver moving. Keeps the driver processing requests and handling events. This function should be called periodically (the same frequency as USBHostTasks() would be helpful). Precondition: AndroidAppStart() function has been called before the first calling of this function Parameters: None Return Values: None Remarks: This function should be called periodically to keep the Android driver moving. ***************************************************************************/ void AndroidTasks_Pv1(void) { BYTE i; ANDROID_PROTOCOL_V1_DEVICE_DATA* device; BYTE errorCode; DWORD byteCount; //See if any of the devices need to do something for(i=0;i<NUM_ANDROID_DEVICES_SUPPORTED;i++) { device = &devices_pv1[i]; switch(device->state) { case DEVICE_ATTACHED: //Fall through case SEND_MANUFACTUER_STRING: //Check to see if something else is going on with EP0 //TODO: should switch this to use the transfer events instead. It is safer. if(AndroidIsLastCommandComplete(device->address, &errorCode, &byteCount) == TRUE) { //If not, then let's send the manufacturer's string AndroidCommandSendString_Pv1(device, ANDROID_ACCESSORY_STRING_MANUFACTURER, accessoryInfo->manufacturer, accessoryInfo->manufacturer_size); device->status.EP0TransferPending = 1; device->state = SEND_MODEL_STRING; } break; case SEND_MODEL_STRING: if(device->status.EP0TransferPending == 0) { //The manufacturing string is sent. Now try to send the model string //TODO: should switch this to use the transfer events instead. It is safer. if(AndroidIsLastCommandComplete(device->address, &errorCode, &byteCount) == TRUE) { //If not, then let's send the manufacturer's string AndroidCommandSendString_Pv1(device, ANDROID_ACCESSORY_STRING_MODEL, accessoryInfo->model, accessoryInfo->model_size); device->status.EP0TransferPending = 1; device->state = SEND_DESCRIPTION_STRING; } } break; case SEND_DESCRIPTION_STRING: if(device->status.EP0TransferPending == 0) { //The manufacturing string is sent. Now try to send the model string //TODO: should switch this to use the transfer events instead. It is safer. if(AndroidIsLastCommandComplete(device->address, &errorCode, &byteCount) == TRUE) { //If not, then let's send the manufacturer's string AndroidCommandSendString_Pv1(device, ANDROID_ACCESSORY_STRING_DESCRIPTION, accessoryInfo->description, accessoryInfo->description_size); device->status.EP0TransferPending = 1; device->state = SEND_VERSION_STRING; } } break; case SEND_VERSION_STRING: if(device->status.EP0TransferPending == 0) { //The manufacturing string is sent. Now try to send the model string //TODO: should switch this to use the transfer events instead. It is safer. if(AndroidIsLastCommandComplete(device->address, &errorCode, &byteCount) == TRUE) { //If not, then let's send the manufacturer's string AndroidCommandSendString_Pv1(device, ANDROID_ACCESSORY_STRING_VERSION, accessoryInfo->version, accessoryInfo->version_size); device->status.EP0TransferPending = 1; device->state = SEND_URI_STRING; } } break; case SEND_URI_STRING: if(device->status.EP0TransferPending == 0) { //The manufacturing string is sent. Now try to send the model string //TODO: should switch this to use the transfer events instead. It is safer. if(AndroidIsLastCommandComplete(device->address, &errorCode, &byteCount) == TRUE) { //If not, then let's send the manufacturer's string AndroidCommandSendString_Pv1(device, ANDROID_ACCESSORY_STRING_URI, accessoryInfo->URI, accessoryInfo->URI_size); device->status.EP0TransferPending = 1; device->state = SEND_SERIAL_STRING; } } break; case SEND_SERIAL_STRING: if(device->status.EP0TransferPending == 0) { //The manufacturing string is sent. Now try to send the model string //TODO: should switch this to use the transfer events instead. It is safer. if(AndroidIsLastCommandComplete(device->address, &errorCode, &byteCount) == TRUE) { //If not, then let's send the manufacturer's string AndroidCommandSendString_Pv1(device, ANDROID_ACCESSORY_STRING_SERIAL, accessoryInfo->serial, accessoryInfo->serial_size); device->status.EP0TransferPending = 1; device->state = START_ACCESSORY; } } break; case START_ACCESSORY: if(device->status.EP0TransferPending == 0) { //The manufacturing string is sent. Now try to send the model string //TODO: should switch this to use the transfer events instead. It is safer. if(AndroidIsLastCommandComplete(device->address, &errorCode, &byteCount) == TRUE) { //Set up a timer to remove the device if it hasn't returned to us as an // accessory mode device in a specified time, we kill the device device->countDown = ANDROID_DEVICE_ATTACH_TIMEOUT; //If not, then let's send the manufacturer's string AndroidCommandStart_Pv1(device); device->status.EP0TransferPending = 1; device->state = ACCESSORY_STARTING; } } break; case ACCESSORY_STARTING: if(device->status.EP0TransferPending == 0) { device->state = WAITING_FOR_ACCESSORY_RETURN; } break; case WAITING_FOR_ACCESSORY_RETURN: break; case RETURN_OF_THE_ACCESSORY: //The accessory has returned and has been initialialized. It is now ready to use. device->state = READY; USB_HOST_APP_EVENT_HANDLER(device->address,EVENT_ANDROID_ATTACH,device,sizeof(ANDROID_PROTOCOL_V1_DEVICE_DATA*)); break; case READY: break; default: //Don't know what state the device is in. Do some recovery here? break; } } }
BOOL USBHostMIDIEventHandler ( BYTE address, USB_EVENT event, void *data, DWORD size ) { unsigned char i; // Make sure it was for one of our devices for( i = 0; i < USB_MAX_MIDI_DEVICES; i++) { if ( address == devices[i].deviceAddress) { break; } } if(i == USB_MAX_MIDI_DEVICES) { return FALSE; } // Handle specific events switch (event) { case EVENT_DETACH: // Notify that application that the device has been detached. USB_HOST_APP_EVENT_HANDLER(devices[i].deviceAddress, EVENT_MIDI_DETACH, &devices[i], sizeof(MIDI_DEVICE) ); devices[i].deviceAddress = 0; free(devices[i].endpoints); devices[i].endpoints = NULL; #ifdef DEBUG_MODE UART2PrintString( "USB MIDI Client Device Detached: address=" ); UART2PutDec( address ); UART2PrintString( "\r\n" ); #endif return TRUE; #ifdef USB_ENABLE_TRANSFER_EVENT case EVENT_TRANSFER: if ( (data != NULL) && (size == sizeof(HOST_TRANSFER_DATA)) ) { unsigned char currentEndpoint; //DWORD dataCount = ((HOST_TRANSFER_DATA *)data)->dataCount; for(currentEndpoint = 0; currentEndpoint < devices[i].numEndpoints; currentEndpoint++) { if ( ((HOST_TRANSFER_DATA *)data)->bEndpointAddress == devices[i].endpoints[currentEndpoint].endpointAddress ) { devices[i].endpoints[currentEndpoint].busy = 0; USB_HOST_APP_EVENT_HANDLER(devices[i].deviceAddress, EVENT_MIDI_TRANSFER_DONE, &devices[i].endpoints[currentEndpoint], sizeof(MIDI_ENDPOINT_DATA)); return TRUE; } } } return FALSE; #endif case EVENT_SUSPEND: case EVENT_RESUME: case EVENT_BUS_ERROR: default: break; } return FALSE; } // USBHostMIDIEventHandler
BOOL USBHostMIDIInit ( BYTE address, DWORD flags, BYTE clientDriverID ) { BYTE *config_descriptor; BYTE *ptr; BYTE bDescriptorType; BYTE bLength; BYTE bNumEndpoints; BYTE bNumInterfaces; BYTE bInterfaceNumber; BYTE bAlternateSetting; BYTE Class; BYTE SubClass; BYTE Protocol; BYTE currentEndpoint; WORD wTotalLength; BYTE index = 0; BOOL error = FALSE; MIDI_DEVICE *device = &devices[0]; config_descriptor = USBHostGetCurrentConfigurationDescriptor(address); ptr = config_descriptor; // Load up the values from the Configuration Descriptor bLength = *ptr++; bDescriptorType = *ptr++; wTotalLength = *ptr++; // In case these are not word aligned wTotalLength += (*ptr++) << 8; bNumInterfaces = *ptr++; // Skip over the rest of the Configuration Descriptor index += bLength; ptr = &config_descriptor[index]; while (!error && (index < wTotalLength)) { // Check the descriptor length and type bLength = *ptr++; bDescriptorType = *ptr++; // Find an interface descriptor if (bDescriptorType != USB_DESCRIPTOR_INTERFACE) { // Skip over the rest of the Descriptor index += bLength; ptr = &config_descriptor[index]; } else { // Read some data from the interface descriptor bInterfaceNumber = *ptr++; bAlternateSetting = *ptr++; bNumEndpoints = *ptr++; Class = *ptr++; SubClass = *ptr++; Protocol = *ptr++; // Check to see if this is a MIDI inteface descripter if (Class != AUDIO_CLASS || SubClass != MIDI_SUB_CLASS || Protocol != MIDI_PROTOCOL) { // If we cannot support this interface, skip it. index += bLength; ptr = &config_descriptor[index]; continue; } // Initialize the device device->deviceAddress = address; device->clientDriverID = clientDriverID; device->numEndpoints = bNumEndpoints; // Allocate enough memory for each endpoint if ((device->endpoints = (MIDI_ENDPOINT_DATA*)malloc( sizeof(MIDI_ENDPOINT_DATA) * bNumEndpoints)) == NULL) { // Out of memory error = TRUE; } if (!error) { // Skip over the rest of the Interface Descriptor index += bLength; ptr = &config_descriptor[index]; // Find the Endpoint Descriptors. There might be Class and Vendor descriptors in here currentEndpoint = 0; while (!error && (index < wTotalLength) && (currentEndpoint < bNumEndpoints)) { bLength = *ptr++; bDescriptorType = *ptr++; if (bDescriptorType != USB_DESCRIPTOR_ENDPOINT) { // Skip over the rest of the Descriptor index += bLength; ptr = &config_descriptor[index]; } else { device->endpoints[currentEndpoint].endpointAddress = *ptr++; ptr++; device->endpoints[currentEndpoint].endpointSize = *ptr++; device->endpoints[currentEndpoint].endpointSize += (*ptr++) << 8; device->endpoints[currentEndpoint].busy = FALSE; if(device->endpoints[currentEndpoint].endpointSize > 64) { // For full speed bulk endpoints, only 8, 16, 32, and 64 byte packets are supported // But we will accept anything less than or equal to 64. error = TRUE; } // Get ready for the next endpoint. currentEndpoint++; index += bLength; ptr = &config_descriptor[index]; } } } // Ensure that we found all the endpoints for this interface. if (currentEndpoint != bNumEndpoints) { error = TRUE; } } } if (error) { // Destroy whatever list of interfaces, settings, and endpoints we created. // The "new" variables point to the current node we are trying to remove. if (device->endpoints != NULL) { free( device->endpoints ); device->endpoints = NULL; } return FALSE; } #ifdef DEBUG_MODE UART2PrintString( "USB MIDI Client Initalized: " ); UART2PrintString( " address=" ); UART2PutDec( address ); UART2PrintString( " Number of Endpoings=" ); UART2PutHex( bNumEndpoints ); UART2PrintString( "\r\n" ); #endif // Notify that application that we've been attached to a device. USB_HOST_APP_EVENT_HANDLER(address, EVENT_MIDI_ATTACH, device, sizeof(MIDI_DEVICE) ); return TRUE; } // USBHostMIDIInit