<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>i.MX RT Crossover MCUs中的主题 Re: Working Custom USB example using Bulk transfer incl code!</title>
    <link>https://community.nxp.com/t5/i-MX-RT-Crossover-MCUs/Working-Custom-USB-example-using-Bulk-transfer-incl-code/m-p/1448647#M19313</link>
    <description>&lt;P&gt;Thank you.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
    <pubDate>Mon, 25 Apr 2022 16:06:44 GMT</pubDate>
    <dc:creator>yanz</dc:creator>
    <dc:date>2022-04-25T16:06:44Z</dc:date>
    <item>
      <title>Working Custom USB example using Bulk transfer incl code!</title>
      <link>https://community.nxp.com/t5/i-MX-RT-Crossover-MCUs/Working-Custom-USB-example-using-Bulk-transfer-incl-code/m-p/1260056#M13727</link>
      <description>&lt;P&gt;I have for a long time been wanting to do a Custom USB class driver on the RT106x devices. I have been put down by the, seemingly, complex structure of the NXP USB example code. While I still don't think the samples in the SDK are "the best" out there, they do seem to work, and at least provide a starting point. Several people here have been looking for an implementation of a Custom USB class device, myself including. I have a Bulk device running on a number of NXP processors (LPC2148, LPC2458, LPC1788, LPC54628 etc) and I wanted to have the same running on a RT1064.&lt;/P&gt;&lt;P&gt;Finally that seems to be working. I got some pointers from the user &lt;a href="https://community.nxp.com/t5/user/viewprofilepage/user-id/168976"&gt;@markdodd&lt;/a&gt;&amp;nbsp;&amp;nbsp;in the process, thanks a lot!&lt;/P&gt;&lt;P&gt;Now, there is ABSOLUTELY NO GUARANTEE that the code is correct, the only guarantee I can give is that there is probably something (or a lot) that could be made much better/smarter/faster. But, this at least works for me as it is. I will continue testing and fixing stuff, when I find something that can be improved, I will post it in this thread.&lt;/P&gt;&lt;P&gt;You are absolutely free to use the code in any way you see fit (as long as you follow the rules/guidelines from NXP). However, if you spot something bad/wrong etc, PLEASE let us know so we all benefit from this!&lt;/P&gt;&lt;P&gt;PLEASE remember that ALL data that you want to receive/transmit over USB MUST be in non-cached memory !&lt;/P&gt;&lt;P&gt;This device creates a Custom USB class using VID=0xFFFF, PID=0x4712 and Class=0xFF (Vendor specific)&lt;BR /&gt;The USB class has one interface (interface 0) and one configuration (configuration 1).&lt;BR /&gt;It has 4 endpoints, 1 OUT and 3 IN endpoints. In practice, it uses the OUT and one of the IN endpoints as&amp;nbsp;a "channel" for a request/response type command interface. The two last IN endpoints are used for sending log messages and wireshark compatible frames (when the target device has a TCP/IP stack embedded that it wants to send debug traffic from).&lt;BR /&gt;&lt;BR /&gt;Tested on USB0 on i.MXRT1064. I'm not sure how much needs to be done to have it work on USB1, I have tried to leave the code that was in the CDC sample from NXP, but no guarantee!&lt;/P&gt;&lt;P&gt;On the PC side I use libusbdotnet library (and C#) for communication.&lt;/P&gt;&lt;P&gt;The two most important modules is show below, all code is in a zip file attached.&lt;/P&gt;&lt;P&gt;Previous threads about this:&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;A href="https://community.nxp.com/t5/i-MX-RT/USB-Custom-class-for-RT106x/m-p/842919" target="_blank" rel="noopener"&gt;https://community.nxp.com/t5/i-MX-RT/USB-Custom-class-for-RT106x/m-p/842919&lt;/A&gt;&lt;/P&gt;&lt;P&gt;&lt;A href="https://community.nxp.com/t5/i-MX-RT/Is-there-any-information-example-on-how-to-create-a-custom-usb/m-p/1083451" target="_blank" rel="noopener"&gt;https://community.nxp.com/t5/i-MX-RT/Is-there-any-information-example-on-how-to-create-a-custom-usb/m-p/1083451&lt;/A&gt;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="c"&gt;//-----------------------------------------------------------------------------
// BulkUSB.c                                                       20210405 CHG
//
// Based on NXP's CDC sample from SDK 2.9.2 by Carsten Groen (chg@moonbounce.dk)
//-----------------------------------------------------------------------------
// 
// This device creates a Custom USB class using VID=0xFFFF, PID=0x4712 and Class=0xFF (Vendor specific)
// The USB class has one interface (interface 0) and one configuration (configuration 1).
// It has 4 endpoints, 1 OUT and 3 IN endpoints. In practice, it uses the OUT and one of the IN endpoints as
// a "channel" for a request/response type command interface. The two last IN endpoints are used
// for sending log messages and wireshark compatible frames (when the target device has a TCP/IP stack
// embedded that it wants to send debug traffic from).
//
// Tested on USB0 on i.MXRT1064. I'm not sure how much needs to be done to have it work on USB1,
// I have tried to leave the code that was in the CDC sample from NXP, but no guarantee!
// 
// On the PC side I use libusbdotnet library (and C#) for communication.
// 
// 
//-----------------------------------------------------------------------------
// Files added/modified from original SDK example:
//
//  Large changes:
//  	BulkUSB.c/h (many changes, based on virtual.com.c/h)
//		usb_device_my_bulk.c/h (many changes, based on usb_device_cdc_acm.c/h))
//
//  Minor changes:
//		usb_device_descriptor.c/h (many changes)
//		usb_device_config.h (changes marked with "CHG")
//		usb_device_class.c/h (changes marked with "CHG")
//
//-----------------------------------------------------------------------------

#include "System.h"

#include "pin_mux.h"
#include "clock_config.h"

#include "usb_device_config.h"
#include "usb.h"
#include "usb_device.h"
#include "usb_device_class.h"
#include "usb_device_my_bulk.h"
#include "usb_device_descriptor.h"
#include "usb_device_dci.h"
#include "usb_phy.h"

#include "BulkUSB.h"

// USB PHY condfiguration
#define BOARD_USB_PHY_D_CAL     (0x0CU)
#define BOARD_USB_PHY_TXCAL45DP (0x06U)
#define BOARD_USB_PHY_TXCAL45DM (0x06U)
#define CONTROLLER_ID kUSB_ControllerEhci0 
#define USB_DEVICE_INTERRUPT_PRIORITY (3U)


// Coming from usb_device_descriptors.h file
extern usb_device_endpoint_struct_t g_UsbDeviceMyBulkEndpoints[];
extern usb_device_class_struct_t g_UsbDeviceMyBulkConfig;

// Need to define these as they are used in config structs before being implemented
usb_status_t USB_DeviceCallback(usb_device_handle handle, uint32_t event, void *param);
usb_status_t USB_DeviceBulkCallback(class_handle_t handle, uint32_t event, void *param);

// Define buffer for receiving data from the bulk OUT event
USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) static uint8_t s_RecvBufBulkOut[512];


// Define struct for our Bulk device
typedef struct {
    usb_device_handle deviceHandle; // USB device handle. 
    class_handle_t bulkHandle; 		// USB CDC ACM class handle.                                                         
    volatile uint8_t attach;     	// A flag to indicate whether a usb device is attached. 1: attached, 0: not attached 
    uint8_t speed;               	// Speed of USB device. USB_SPEED_FULL/USB_SPEED_LOW/USB_SPEED_HIGH.                 
    uint8_t currentConfiguration;	// Current configuration value. 
    uint8_t currentInterfaceAlternateSetting[1]; // Current alternate setting value for each interface.
} usb_bulk_struct_t;


static usb_bulk_struct_t s_bulkDevice;	// Handle to the MyBulk device


//---------------------------------------------------------------------------------------
// USB device class information
//---------------------------------------------------------------------------------------
static usb_device_class_config_struct_t s_BulkConfig[1] = {
	{
		USB_DeviceBulkCallback,		// Class callback function to handle the device status-related event for the specified type of class
		0,                         	// The class handle of the class, filled by the common driver
		&amp;amp;g_UsbDeviceMyBulkConfig,  	// Detailed information of the class
	}
};

//---------------------------------------------------------------------------------------
// USB device class configuration information
//---------------------------------------------------------------------------------------
static usb_device_class_config_list_struct_t s_MyBulkConfigList = {
    s_BulkConfig,		 // Array of class configuration structures 
    USB_DeviceCallback,  // Device callback function
    1,                   // Number of class supported
};

//---------------------------------------------------------------------------------------
// IRQ handler for USB0
//---------------------------------------------------------------------------------------
void USB_OTG1_IRQHandler(void) {
    USB_DeviceEhciIsrFunction(s_bulkDevice.deviceHandle);
}

//---------------------------------------------------------------------------------------
// IRQ handler for USB1
//---------------------------------------------------------------------------------------
void USB_OTG2_IRQHandler(void) {
    USB_DeviceEhciIsrFunction(s_bulkDevice.deviceHandle);
}

//---------------------------------------------------------------------------------------
// Init clock to USB device
//---------------------------------------------------------------------------------------
static void USB_DeviceClockInit(void) {
    usb_phy_config_struct_t phyConfig = {
        BOARD_USB_PHY_D_CAL,
        BOARD_USB_PHY_TXCAL45DP,
        BOARD_USB_PHY_TXCAL45DM,
    };
	CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
    CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, 480000000U);
    USB_EhciPhyInit(CONTROLLER_ID, BOARD_XTAL0_CLK_HZ, &amp;amp;phyConfig);
}



//---------------------------------------------------------------------------------------
// MyBulk class specific callback function.
//	handle          The MyBulk class handle.
//	event           The MyBulk class event type.
//	param           The parameter of the class specific request.
//	return A USB error code or kStatus_USB_Success.
//---------------------------------------------------------------------------------------
usb_status_t USB_DeviceBulkCallback(class_handle_t handle, uint32_t event, void *param) {
    uint32_t len;
    usb_device_endpoint_callback_message_struct_t *epCbParam;
    usb_status_t error          = kStatus_USB_Error;
    epCbParam                   = (usb_device_endpoint_callback_message_struct_t *)param;
	
    switch (event) {
		//---------------------------------------------------------------------------------------
		// Bulk OUT request frame from PC
		// We get this event when a request frame FROM the PC has been received
		//---------------------------------------------------------------------------------------
        case kUSB_DeviceMyBulkEventRequestReceiveDone:
            if (s_bulkDevice.attach) {
				// epCbParam-&amp;gt;length has the length of received bytes, s_RecvBufBulkOut has the data
				// Schedule buffer for next receive event
				error = USB_DeviceMyBulkRecv(handle, BULK_OUT_EP, s_RecvBufBulkOut, g_UsbDeviceMyBulkEndpoints[0].maxPacketSize);
            }
			break;
		
		//---------------------------------------------------------------------------------------
		// Bulk IN response to PC
		// We get this event when the response frame we sent TO the PC has been received by the PC (and ACK'ed)
		// Here we can signal the "upper layers", f.ex with a semaphore that we are ready to send another frame	
		//---------------------------------------------------------------------------------------
		case kUSB_DeviceMyBulkEventResponseTransmitDone:
			if (s_bulkDevice.attach) {
				// This is not needed in my example
				if ((epCbParam-&amp;gt;length != 0) &amp;amp;&amp;amp; (!(epCbParam-&amp;gt;length % g_UsbDeviceMyBulkEndpoints[0].maxPacketSize))) {
					// If the last packet is the size of endpoint, then send also zero-ended packet, meaning that we want to inform the host that we do not have any additional
					// data, so it can flush the output.
					//error = USB_DeviceMyBulkSend(handle, BULK_IN_EP, NULL, 0);
				} else {
				}
            }
			break;

		//---------------------------------------------------------------------------------------
		// Bulk IN Log message to PC
		// We get this event when the Log frame we sent TO the PC has been received by the PC (and ACK'ed)
		//---------------------------------------------------------------------------------------
		case kUSB_DeviceMyBulkEventLogTransmitDone:
			if (s_bulkDevice.attach) {
				// This is not needed in my example
				if ((epCbParam-&amp;gt;length != 0) &amp;amp;&amp;amp; (!(epCbParam-&amp;gt;length % g_UsbDeviceMyBulkEndpoints[0].maxPacketSize))) {
					// If the last packet is the size of endpoint, then send also zero-ended packet, meaning that we want to inform the host that we do not have any additional
					// data, so it can flush the output.
					//error = USB_DeviceMyBulkSend(handle, BULK_IN_EP, NULL, 0);
				} else {
				}
            }
			break;

		//---------------------------------------------------------------------------------------
		// Bulk IN Wireshark message to PC
		// We get this event when the Wireshark frame we sent TO the PC has been received by the PC (and ACK'ed)
		//---------------------------------------------------------------------------------------
		case kUSB_DeviceMyBulkEventWiresharkTransmitDone:
			if (s_bulkDevice.attach) {
				// This is not needed in my example
				if ((epCbParam-&amp;gt;length != 0) &amp;amp;&amp;amp; (!(epCbParam-&amp;gt;length % g_UsbDeviceMyBulkEndpoints[0].maxPacketSize))) {
					// If the last packet is the size of endpoint, then send also zero-ended packet, meaning that we want to inform the host that we do not have any additional
					// data, so it can flush the output.
					//error = USB_DeviceMyBulkSend(handle, BULK_IN_EP, NULL, 0);
				} else {
				}
            }
			break;
			
        default:
            break;
    }
    return error;
}


//---------------------------------------------------------------------------------------
// USB device callback function.
// 	handle          The USB device handle.
//	event           The USB device event type.
//	param           The parameter of the device specific request.
// 	return A USB error code or kStatus_USB_Success.
//---------------------------------------------------------------------------------------
usb_status_t USB_DeviceCallback(usb_device_handle handle, uint32_t event, void *param) {
    usb_status_t error = kStatus_USB_Error;
    uint16_t *temp16   = (uint16_t *)param;
    uint8_t *temp8     = (uint8_t *)param;

    switch (event) {
		
		// USB bus reset signal detected
        case kUSB_DeviceEventBusReset:
            s_bulkDevice.attach               = 0;
            s_bulkDevice.currentConfiguration = 0U;
			#if (defined(USB_DEVICE_CONFIG_EHCI) &amp;amp;&amp;amp; (USB_DEVICE_CONFIG_EHCI &amp;gt; 0U)) || \
				(defined(USB_DEVICE_CONFIG_LPCIP3511HS) &amp;amp;&amp;amp; (USB_DEVICE_CONFIG_LPCIP3511HS &amp;gt; 0U))
						/* Get USB speed to configure the device, including max packet size and interval of the endpoints. */
						if (kStatus_USB_Success == USB_DeviceClassGetSpeed(CONTROLLER_ID, &amp;amp;s_bulkDevice.speed)) {
							USB_DeviceSetSpeed(handle, s_bulkDevice.speed);
						}
			#endif
			break;
						
		// Set configuration
        case kUSB_DeviceEventSetConfiguration:
            if (0U == (*temp8)) {
                s_bulkDevice.attach               = 0;
                s_bulkDevice.currentConfiguration = 0U;
            } else if (USB_DEVICE_CONFIGURE_INDEX  == (*temp8)) {
                s_bulkDevice.attach               = 1;
                s_bulkDevice.currentConfiguration = *temp8;
                // Schedule buffers for receive
                USB_DeviceMyBulkRecv(s_bulkDevice.bulkHandle, BULK_OUT_EP, s_RecvBufBulkOut, g_UsbDeviceMyBulkEndpoints[0].maxPacketSize);
				
            } else {
                error = kStatus_USB_InvalidRequest;
            }
            break;
			
		// Set interface
        case kUSB_DeviceEventSetInterface:
            if (s_bulkDevice.attach) {
                uint8_t interface        = (uint8_t)((*temp16 &amp;amp; 0xFF00U) &amp;gt;&amp;gt; 0x08U);
                uint8_t alternateSetting = (uint8_t)(*temp16 &amp;amp; 0x00FFU);
                if (interface &amp;lt; 1) {
                    s_bulkDevice.currentInterfaceAlternateSetting[interface] = alternateSetting;
                }
            }
            break;
	
		// Get configuration
        case kUSB_DeviceEventGetConfiguration:
            break;

		// Get interface number
        case kUSB_DeviceEventGetInterface:
            break;
		
		// Set Descriptor/Get Descriptor is used to return the specified descriptor in wValue. 
		// A request for the configuration descriptor will return the device descriptor and all interface and endpoint descriptors in the one request.
        case kUSB_DeviceEventGetDeviceDescriptor:
            if (param)
                error = USB_DeviceGetDeviceDescriptor(handle, (usb_device_get_device_descriptor_struct_t *)param);
            break;
		
		// Get device configuration structure
        case kUSB_DeviceEventGetConfigurationDescriptor:
            if (param)
                error = USB_DeviceGetConfigurationDescriptor(handle, (usb_device_get_configuration_descriptor_struct_t *)param);
            break;
		
		// Get a specific string
        case kUSB_DeviceEventGetStringDescriptor:
            if (param)
                error = USB_DeviceGetStringDescriptor(handle, (usb_device_get_string_descriptor_struct_t *)param);
            break;
			
        default:
            break;
    }
    return error;
}


//---------------------------------------------------------------------------------------
// Enable interrupt for USB device
//---------------------------------------------------------------------------------------
static void USB_DeviceIsrEnable(void) {
    uint8_t irqNumber;

    uint8_t usbDeviceEhciIrq[] = USBHS_IRQS;
    irqNumber                  = usbDeviceEhciIrq[CONTROLLER_ID - kUSB_ControllerEhci0];

    // Install isr, set priority, and enable IRQ
    NVIC_SetPriority((IRQn_Type)irqNumber, USB_DEVICE_INTERRUPT_PRIORITY);
    EnableIRQ((IRQn_Type)irqNumber);
}


//---------------------------------------------------------------------------------------
// Test stuff, called from main thread
//---------------------------------------------------------------------------------------
void xxx(void) {
	static char buffer[512];
	for (int i=0; i&amp;lt;sizeof(buffer); i++)
		buffer[i]=i;
	
	// Send message on all 3 IN endpoints
	// Actually, we are allowed to specify lengths up to 16 KByte in a transmission, these will then be sent as several 512 byte packets!
	USB_DeviceMyBulkSend(s_bulkDevice.bulkHandle, BULK_IN_EP, (unsigned char*)buffer, sizeof(buffer));
	USB_DeviceMyBulkSend(s_bulkDevice.bulkHandle, BULK_IN_EP_LOG, (unsigned char*)buffer, sizeof(buffer));
	USB_DeviceMyBulkSend(s_bulkDevice.bulkHandle, BULK_IN_EP_WSHARK, (unsigned char*)buffer, sizeof(buffer));
}


//---------------------------------------------------------------------------------------
// Ínitialize USB and our bulk class
//---------------------------------------------------------------------------------------
void initUSB(void) {
    USB_DeviceClockInit();
	
    s_bulkDevice.speed        = USB_SPEED_FULL;
    s_bulkDevice.attach       = 0;
    s_bulkDevice.bulkHandle = (class_handle_t)NULL;
    s_bulkDevice.deviceHandle = NULL;

	
    if (kStatus_USB_Success != USB_DeviceClassInit(CONTROLLER_ID, &amp;amp;s_MyBulkConfigList, &amp;amp;s_bulkDevice.deviceHandle)) {
        //usb_echo("USB device init failed\r\n");
    }

    s_bulkDevice.bulkHandle = s_MyBulkConfigList.config-&amp;gt;classHandle;

    USB_DeviceIsrEnable();
	
    SDK_DelayAtLeastUs(5000, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
    USB_DeviceRun(s_bulkDevice.deviceHandle);
}&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="c"&gt;//---------------------------------------------------------------------------------------
// usb_device_my_bulk.c												   		 20210409 CHG 
//
// Modified from NXP's CDC sample from SDK 2.9.2 by Carsten Groen
//---------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------

#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;

#include "usb_device_config.h"
#include "usb.h"
#include "usb_device.h"

#include "usb_device_class.h"
#include "usb_device_descriptor.h"

#include "usb_device_my_bulk.h"

extern usb_device_endpoint_struct_t g_UsbDeviceMyBulkEndpoints[];


#define USB_MYBULK_ENTER_CRITICAL() \
    OSA_SR_ALLOC();                  \
    OSA_ENTER_CRITICAL()

#define USB_MYBULK_EXIT_CRITICAL() OSA_EXIT_CRITICAL()

// MyBulk device instance 
USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_mybulk_struct_t g_myBulkHandle[USB_DEVICE_CONFIG_MYBULK];


//---------------------------------------------------------------------------------------
// Allocates the MyBulk device handle.
//
// This function allocates the MyBulk device handle.
//
//	handle The class handle of the MyBulk class.
//  returns A USB error code or kStatus_USB_Success.
//---------------------------------------------------------------------------------------
static usb_status_t USB_DeviceMyBulkAllocateHandle(usb_device_mybulk_struct_t **handle) {
    uint32_t count;
    for (count = 0; count &amp;lt; USB_DEVICE_CONFIG_MYBULK; count++) {
        if (NULL == g_myBulkHandle[count].handle) {
            *handle = &amp;amp;g_myBulkHandle[count];
            return kStatus_USB_Success;
        }
    }
    return kStatus_USB_Busy;
}

//---------------------------------------------------------------------------------------
// Frees the MyBulk device handle.
//
//	handle The class handle of the MyBulk class.
//	returns A USB error code or kStatus_USB_Success.
//---------------------------------------------------------------------------------------
static usb_status_t USB_DeviceMyBulkFreeHandle(usb_device_mybulk_struct_t *handle) {
    handle-&amp;gt;handle        = NULL;
    handle-&amp;gt;configStruct  = NULL;
    handle-&amp;gt;configuration = 0;
    handle-&amp;gt;alternate     = 0;
    return kStatus_USB_Success;
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Handle bulk IN events. These functions gets called when a mnessage we sent to the PC has been ACK'ed by the PC
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//---------------------------------------------------------------------------------------
// Common helper function for all IN event.
//
// Responds to a bulk IN endpoint event on a specific endpoint.
// 	handle The device handle of the MyBulk device.
// 	message The pointer to the message of the endpoint callback.
// 	callbackParam The pointer to the parameter of the callback.
//  ep The IN endpoint that should be handled
//  event Hvis event to send to the BulkUSB.c module
// 	Return USB error code or kStatus_USB_Success.
//---------------------------------------------------------------------------------------
static usb_status_t handleDeviceResponseBulkIn(usb_device_handle handle, usb_device_endpoint_callback_message_struct_t *message, void *callbackParam, int ep, int event) {
    usb_device_mybulk_struct_t *myBulkHandle;
    usb_status_t status = kStatus_USB_Error;
	int i;
	
    myBulkHandle        = (usb_device_mybulk_struct_t *)callbackParam;
    if (NULL == myBulkHandle) {
        return kStatus_USB_InvalidHandle;
    }
	
	// Find our index in bulkIn[] based on the specific EP number we handle in this function
	for (i=0; i&amp;lt;BULK_NUM_ENDPOINTS_IN; i++) {
		if (myBulkHandle-&amp;gt;bulkIn[i].ep == ep) {
			break;
		}
	}
	
    myBulkHandle-&amp;gt;bulkIn[i].isBusy = 0;
    if ((NULL != myBulkHandle-&amp;gt;configStruct) &amp;amp;&amp;amp; (NULL != myBulkHandle-&amp;gt;configStruct-&amp;gt;classCallback)) {
        status = myBulkHandle-&amp;gt;configStruct-&amp;gt;classCallback((class_handle_t)myBulkHandle, event, message);
    }
    return status;
}


//---------------------------------------------------------------------------------------
// 3 handlers that responds to a bulk IN endpoint event on their specific endpoint, each
// calls a common helper function
// 	handle The device handle of the MyBulk device.
// 	message The pointer to the message of the endpoint callback.
// 	callbackParam The pointer to the parameter of the callback.
// 	A USB error code or kStatus_USB_Success.
//---------------------------------------------------------------------------------------
static usb_status_t USB_DeviceResponseBulkIn(usb_device_handle handle, usb_device_endpoint_callback_message_struct_t *message, void *callbackParam) {
	return handleDeviceResponseBulkIn(handle, message, callbackParam, BULK_IN_EP, kUSB_DeviceMyBulkEventResponseTransmitDone);
}

static usb_status_t USB_DeviceLogBulkIn(usb_device_handle handle, usb_device_endpoint_callback_message_struct_t *message, void *callbackParam) {
	return handleDeviceResponseBulkIn(handle, message, callbackParam, BULK_IN_EP_LOG, kUSB_DeviceMyBulkEventLogTransmitDone);
}

static usb_status_t USB_DeviceWiresharkBulkIn(usb_device_handle handle, usb_device_endpoint_callback_message_struct_t *message, void *callbackParam) {
	return handleDeviceResponseBulkIn(handle, message, callbackParam, BULK_IN_EP_WSHARK,kUSB_DeviceMyBulkEventWiresharkTransmitDone);
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Handle bulk OUT events. This functions gets called when a message sent by the PC has been received
// We only have 1 single OUT endpoint in this device
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//---------------------------------------------------------------------------------------
// Responds to the bulk out endpoint event
// 	handle The device handle of the MyBulk device.
//	message The pointer to the message of the endpoint callback.
//	callbackParam The pointer to the parameter of the callback.
//	return A USB error code or kStatus_USB_Success.
//---------------------------------------------------------------------------------------
static usb_status_t USB_DeviceCommandBulkOut(usb_device_handle handle, usb_device_endpoint_callback_message_struct_t *message, void *callbackParam) {
    usb_device_mybulk_struct_t *myBulkHandle;
    usb_status_t status = kStatus_USB_Error;
    myBulkHandle        = (usb_device_mybulk_struct_t *)callbackParam;

    if (NULL == myBulkHandle) {
        return kStatus_USB_InvalidHandle;
    }
    myBulkHandle-&amp;gt;bulkOut[0].isBusy = 0U;
    if ((NULL != myBulkHandle-&amp;gt;configStruct) &amp;amp;&amp;amp; (NULL != myBulkHandle-&amp;gt;configStruct-&amp;gt;classCallback)) {
        status = myBulkHandle-&amp;gt;configStruct-&amp;gt;classCallback((class_handle_t)myBulkHandle, kUSB_DeviceMyBulkEventRequestReceiveDone, message);
    }
    return status;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 
//---------------------------------------------------------------------------------------
// Initializes the endpoints in MyBulk class.
//	myBulkHandle The class handle of the MyBulk class.
//	return A USB error code or kStatus_USB_Success.
//---------------------------------------------------------------------------------------
static usb_status_t USB_DeviceMyBulkEndpointsInit(usb_device_mybulk_struct_t *myBulkHandle) {
    usb_device_interface_list_t *interfaceList;
    usb_device_interface_struct_t *interface = NULL;
    usb_status_t error                       = kStatus_USB_Error;
    uint32_t count;
    uint32_t index;
	
	
    if (NULL == myBulkHandle) {
        return error;
    }

    /* return error when configuration is invalid (0 or more than the configuration number) */
    if ((myBulkHandle-&amp;gt;configuration == 0U) ||
        (myBulkHandle-&amp;gt;configuration &amp;gt; myBulkHandle-&amp;gt;configStruct-&amp;gt;classInfomation-&amp;gt;configurations)) {
        return error;
    }

    interfaceList = &amp;amp;myBulkHandle-&amp;gt;configStruct-&amp;gt;classInfomation-&amp;gt;interfaceList[myBulkHandle-&amp;gt;configuration - 1U];

    for (count = 0; count &amp;lt; interfaceList-&amp;gt;count; count++) {
        if (USB_DEVICE_CLASS == interfaceList-&amp;gt;interfaces[count].classCode) {
            for (index = 0; index &amp;lt; interfaceList-&amp;gt;interfaces[count].count; index++) {
                if (interfaceList-&amp;gt;interfaces[count].interface[index].alternateSetting == myBulkHandle-&amp;gt;alternate) {
                    interface = &amp;amp;interfaceList-&amp;gt;interfaces[count].interface[index];
                    break;
                }
            }
            myBulkHandle-&amp;gt;interfaceNumber = interfaceList-&amp;gt;interfaces[count].interfaceNumber;
            break;
        }
    }
    if (NULL == interface) {
        return error;
    }

	
	//---------------------------------------------------------------------------------------
	// We need to populate the myBulkHandle-&amp;gt;bulkIn[] and myBulkHandle-&amp;gt;bulkOut[] arrays with
	// the correct callback functions. We look at the specific endpoint and assign the correct
	// callback handler based on that
	//---------------------------------------------------------------------------------------
	int outIndex=0; // Index into myBulkHandle-&amp;gt;bulkOut[]
	int inIndex=0;  // Index into myBulkHandle-&amp;gt;bulkIn[]

	// Loop thru all the defined endpoints
    for (count = 0; count &amp;lt; interface-&amp;gt;endpointList.count; count++) {
        usb_device_endpoint_init_struct_t epInitStruct;
        usb_device_endpoint_callback_struct_t epCallback;
        epInitStruct.zlt             = 0;
        epInitStruct.interval        = interface-&amp;gt;endpointList.endpoint[count].interval;
        epInitStruct.endpointAddress = interface-&amp;gt;endpointList.endpoint[count].endpointAddress;
        epInitStruct.maxPacketSize   = interface-&amp;gt;endpointList.endpoint[count].maxPacketSize;
        epInitStruct.transferType    = interface-&amp;gt;endpointList.endpoint[count].transferType;

		// If the endpoint is a IN endpoint, assign callback function etc to the specific myBulkHandle-&amp;gt;bulkIn[]
        if ((USB_IN == ((epInitStruct.endpointAddress &amp;amp; USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) &amp;gt;&amp;gt;
                        USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)) &amp;amp;&amp;amp;
            (USB_ENDPOINT_BULK == epInitStruct.transferType))
        {
            myBulkHandle-&amp;gt;bulkIn[inIndex].ep     		= (epInitStruct.endpointAddress &amp;amp; USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK);
            myBulkHandle-&amp;gt;bulkIn[inIndex].isBusy 		= 0;
            myBulkHandle-&amp;gt;bulkIn[inIndex].pipeDataBuffer= (uint8_t *)USB_UNINITIALIZED_VAL_32;
            myBulkHandle-&amp;gt;bulkIn[inIndex].pipeStall     = 0;
            myBulkHandle-&amp;gt;bulkIn[inIndex].pipeDataLen   = 0;
			
			// Decide whích bulk handler to call depending on endpoint number
			switch (myBulkHandle-&amp;gt;bulkIn[inIndex].ep) {
				case BULK_IN_EP: epCallback.callbackFn			= USB_DeviceResponseBulkIn; break;
				case BULK_IN_EP_LOG: epCallback.callbackFn		= USB_DeviceLogBulkIn; break;
				case BULK_IN_EP_WSHARK: epCallback.callbackFn	= USB_DeviceWiresharkBulkIn; break;
				default: epCallback.callbackFn=NULL;
			}
            
			inIndex++;
        }
		// If the endpoint is a OUT endpoint, assign callback function etc to the specific myBulkHandle-&amp;gt;bulkOut[]
		// (This is pretty simple as we only have 1 single OUT EP in this device :)
        else if ((USB_OUT == ((epInitStruct.endpointAddress &amp;amp; USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) &amp;gt;&amp;gt;
                              USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)) &amp;amp;&amp;amp;
                 (USB_ENDPOINT_BULK == epInitStruct.transferType))
        {
            myBulkHandle-&amp;gt;bulkOut[outIndex].ep     			= (epInitStruct.endpointAddress &amp;amp; USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK);
            myBulkHandle-&amp;gt;bulkOut[outIndex].isBusy 			= 0;
            myBulkHandle-&amp;gt;bulkOut[outIndex].pipeDataBuffer 	= (uint8_t *)USB_UNINITIALIZED_VAL_32;
            myBulkHandle-&amp;gt;bulkOut[outIndex].pipeStall      	= 0;
            myBulkHandle-&amp;gt;bulkOut[outIndex].pipeDataLen    	= 0;
			
			// Decide whích bulk handler to call depending on endpoint number
			switch (myBulkHandle-&amp;gt;bulkOut[outIndex].ep) {
				case BULK_OUT_EP: epCallback.callbackFn		= USB_DeviceCommandBulkOut; break;
				default: epCallback.callbackFn=NULL;
			}
			outIndex++;
        } else {
        }
        epCallback.callbackParam = myBulkHandle;
		
		// Register callback handler etc for each endpoint
        error = USB_DeviceInitEndpoint(myBulkHandle-&amp;gt;handle, &amp;amp;epInitStruct, &amp;amp;epCallback);
    }
	
    return error;
}

//-----------------------------------------------------------------------------
// De-initializes the endpoints in MyBulk class.
//
// This function de-initializes the endpoints in MyBulk class.
//
// myBulkHandle The class handle of the MyBulk class.
// returns A USB error code or kStatus_USB_Success.
//-----------------------------------------------------------------------------
static usb_status_t USB_DeviceMyBulkEndpointsDeinit(usb_device_mybulk_struct_t *myBulkHandle) {
    usb_status_t status = kStatus_USB_Error;
    uint32_t count;

    if (NULL == myBulkHandle-&amp;gt;dataInterfaceHandle) {
        return status;
    }
    for (count = 0; count &amp;lt; myBulkHandle-&amp;gt;dataInterfaceHandle-&amp;gt;endpointList.count; count++) {
        status = USB_DeviceDeinitEndpoint(myBulkHandle-&amp;gt;handle, myBulkHandle-&amp;gt;dataInterfaceHandle-&amp;gt;endpointList.endpoint[count].endpointAddress);
    }
    myBulkHandle-&amp;gt;dataInterfaceHandle = NULL;

    return status;
}

//-----------------------------------------------------------------------------
// Handles the MyBulk class event.
//
// This function responds to various events including the common device events and the class-specific events.
// For class-specific events, it calls the class callback defined in the application to deal with the class-specific event.
//
//	handle The class handle of the MyBulk class.
//	event The event type.
//	param The class handle of the MyBulk class.
//	returns:
//		A USB error code or kStatus_USB_Success.
//		kStatus_USB_Success The MyBulk class is de-initialized successfully.
//		kStatus_USB_Error The configure structure of the MyBulk class handle is invalid.
//		kStatus_USB_InvalidHandle The MyBulk device handle or the MyBulk class handle is invalid.
//		kStatus_USB_InvalidParameter The endpoint number of the MyBulk class handle is invalid.
//		Others The error code returned by class callback in application.
//-----------------------------------------------------------------------------
usb_status_t USB_DeviceMyBulkEvent(void *handle, uint32_t event, void *param) {
    usb_device_mybulk_struct_t *myBulkHandle;
    usb_device_mybulk_request_param_struct_t reqParam;
    usb_status_t error = kStatus_USB_Error;
    uint32_t count;
    uint16_t interfaceAlternate;
    uint8_t *temp8;
    uint8_t alternate;
    usb_device_class_event_t eventCode = (usb_device_class_event_t)event;
    if ((NULL == param) || (NULL == handle)) {
        return kStatus_USB_InvalidHandle;
    }

    myBulkHandle = (usb_device_mybulk_struct_t *)handle;

	// CHG: We only handle the common class events 
    switch (eventCode) {
        case kUSB_DeviceClassEventDeviceReset:
            // Bus reset, clear the configuration
            myBulkHandle-&amp;gt;configuration = 0;
            break;
		
        case kUSB_DeviceClassEventSetConfiguration:
            temp8 = ((uint8_t *)param);
            if (NULL == myBulkHandle-&amp;gt;configStruct) {
                break;
            }
            if (*temp8 == myBulkHandle-&amp;gt;configuration) {
                break;
            }

            error                       = USB_DeviceMyBulkEndpointsDeinit(myBulkHandle);
            myBulkHandle-&amp;gt;configuration = *temp8;
            myBulkHandle-&amp;gt;alternate     = 0U;
            error                       = USB_DeviceMyBulkEndpointsInit(myBulkHandle);
            if (kStatus_USB_Success != error) {
				#ifdef DEBUG
					usb_echo("kUSB_DeviceClassEventSetConfiguration, USB_DeviceInitEndpoint fail\r\n");
				#endif
            }
            break;
			
			
        case kUSB_DeviceClassEventSetInterface:
            if (NULL == myBulkHandle-&amp;gt;configStruct) {
                break;
            }

            interfaceAlternate = *((uint16_t *)param);
            alternate          = (uint8_t)(interfaceAlternate &amp;amp; 0xFFU);

            if (myBulkHandle-&amp;gt;interfaceNumber != ((uint8_t)(interfaceAlternate &amp;gt;&amp;gt; 8U))) {
                break;
            }
            if (alternate == myBulkHandle-&amp;gt;alternate) {
                break;
            }
            error                   = USB_DeviceMyBulkEndpointsDeinit(myBulkHandle);
            myBulkHandle-&amp;gt;alternate = alternate;
            error                   = USB_DeviceMyBulkEndpointsInit(myBulkHandle);
            if (kStatus_USB_Success != error) {
				#ifdef DEBUG
					usb_echo("kUSB_DeviceClassEventSetInterface, USB_DeviceInitEndpoint fail\r\n");
				#endif
            }
            break;
			
		// CHG Not used
        case kUSB_DeviceClassEventSetEndpointHalt:
            break;

		// CHG Not used
        case kUSB_DeviceClassEventClearEndpointHalt:
            break;
			
		// CHG Not used
        case kUSB_DeviceClassEventClassRequest:
			break;

        default:
            break;
    }
    return error;
}

//-----------------------------------------------------------------------------
// USB MyBulk Class Driver
//
// Initializes the MyBulk class.
//
// This function obtains a USB device handle according to the controller ID, initializes the MyBulk class
// with the class configure parameters and creates the mutex for each pipe.
//
// 	controllerId The ID of the controller. The value can be chosen from the kUSB_ControllerKhci0,
// 	kUSB_ControllerKhci1, kUSB_ControllerEhci0, or kUSB_ControllerEhci1.
// 	config The user configuration structure of type usb_device_class_config_struct_t. The user
//	populates the members of this structure and passes the pointer of this structure
//	into this function.
// 	handle  It is out parameter. The class handle of the MyBulk class.
//	returns: 
//		A USB error code or kStatus_USB_Success.
//		kStatus_USB_Success The MyBulk class is initialized successfully.
//		kStatus_USB_Busy No MyBulk device handle available for allocation.
//		kStatus_USB_InvalidHandle The MyBulk device handle allocation failure.
//		kStatus_USB_InvalidParameter The USB device handle allocation failure.
//-----------------------------------------------------------------------------
usb_status_t USB_DeviceMyBulkInit(uint8_t controllerId, usb_device_class_config_struct_t *config, class_handle_t *handle) {
    usb_device_mybulk_struct_t *myBulkHandle;
    usb_status_t error;
	int i;
    error = USB_DeviceMyBulkAllocateHandle(&amp;amp;myBulkHandle);

    if (kStatus_USB_Success != error) {
        return error;
    }

    error = USB_DeviceClassGetDeviceHandle(controllerId, &amp;amp;myBulkHandle-&amp;gt;handle);

    if (kStatus_USB_Success != error) {
        return error;
    }

    if (NULL == myBulkHandle-&amp;gt;handle) {
        return kStatus_USB_InvalidHandle;
    }
    myBulkHandle-&amp;gt;configStruct  = config;
    myBulkHandle-&amp;gt;configuration = 0;
    myBulkHandle-&amp;gt;alternate     = 0xFF;

	for (i=0; i&amp;lt;BULK_NUM_ENDPOINTS_IN; i++) {
		myBulkHandle-&amp;gt;bulkIn[i].mutex = (osa_mutex_handle_t)&amp;amp;myBulkHandle-&amp;gt;bulkIn[i].mutexBuffer[0];
		if (KOSA_StatusSuccess != OSA_MutexCreate((myBulkHandle-&amp;gt;bulkIn[i].mutex))) {
		#ifdef DEBUG
			usb_echo("mutex create error!");
		#endif
		}
	}
	
	for (i=0; i&amp;lt;BULK_NUM_ENDPOINTS_OUT; i++) {
		myBulkHandle-&amp;gt;bulkOut[i].mutex = (osa_mutex_handle_t)&amp;amp;myBulkHandle-&amp;gt;bulkOut[i].mutexBuffer[0];
		if (KOSA_StatusSuccess != OSA_MutexCreate((myBulkHandle-&amp;gt;bulkOut[i].mutex))) {
			#ifdef DEBUG
				usb_echo("mutex create error!");
			#endif
		}
	}
    *handle = (class_handle_t)myBulkHandle;
    return error;
}

//-----------------------------------------------------------------------------
//	Deinitializes the USB MyBulk class.
//
// This function destroys the mutex for each pipe, deinitializes each endpoint of the MyBulk class and frees
// the MyBulk class handle.
// 
// handle The class handle of the MyBulk class.
// 	returns:
//		A USB error code or kStatus_USB_Success.
//		kStatus_USB_Success The MyBulk class is de-initialized successfully.
//		kStatus_USB_Error The endpoint deinitialization failure.
//		kStatus_USB_InvalidHandle The MyBulk device handle or the MyBulk class handle is invalid.
//		kStatus_USB_InvalidParameter The endpoint number of the MyBulk class handle is invalid.
//-----------------------------------------------------------------------------
usb_status_t USB_DeviceMyBulkDeinit(class_handle_t handle) {
    usb_device_mybulk_struct_t *myBulkHandle;
    usb_status_t error;
	int i;
    myBulkHandle = (usb_device_mybulk_struct_t *)handle;

    if (NULL == myBulkHandle) {
        return kStatus_USB_InvalidHandle;
    }
	
	for (i=0; i&amp;lt;BULK_NUM_ENDPOINTS_IN; i++) {
		if (KOSA_StatusSuccess != OSA_MutexDestroy((myBulkHandle-&amp;gt;bulkIn[i].mutex))) {
		#ifdef DEBUG
			usb_echo("mutex destroy error!");
		#endif
		}
	}
	
	for (i=0; i&amp;lt;BULK_NUM_ENDPOINTS_OUT; i++) {
		if (KOSA_StatusSuccess != OSA_MutexDestroy((myBulkHandle-&amp;gt;bulkOut[i].mutex))) {
			#ifdef DEBUG
				usb_echo("mutex destroy error!");
			#endif
		}
	}
    error = USB_DeviceMyBulkEndpointsDeinit(myBulkHandle);
    (void)USB_DeviceMyBulkFreeHandle(myBulkHandle);
    return error;
}

//-----------------------------------------------------------------------------
// Primes the endpoint to send packet to host.
//
// This function checks whether the endpoint is sending packet, then it primes the endpoint
// with the buffer address and the buffer length if the pipe is not busy. Otherwise, it ignores this transfer by
// returning an error code.
// 
//	handle The class handle of the MyBulk class.
//	ep The endpoint number of the transfer.
//	buffer The pointer to the buffer to be transferred.
//	length The length of the buffer to be transferred.
//	returns:
//		A USB error code or kStatus_USB_Success.
//		kStatus_USB_Success Prime to send packet successfully.
//		kStatus_USB_Busy The endpoint is busy in transferring.
//		//		kStatus_USB_InvalidHandle The MyBulk device handle or the MyBulk class handle is invalid.
//		kStatus_USB_ControllerNotFound The controller interface is invalid.
//
// The function can only be called in the same context.
//-----------------------------------------------------------------------------
usb_status_t USB_DeviceMyBulkSend(class_handle_t handle, uint8_t ep, uint8_t *buffer, uint32_t length) {
    usb_device_mybulk_struct_t *myBulkHandle;
    usb_status_t status                   = kStatus_USB_Error;
    usb_device_mybulk_pipe_t *myBulkPipe = NULL;
	int i;
	
    if (NULL == handle) {
        return kStatus_USB_InvalidHandle;
    }
    myBulkHandle = (usb_device_mybulk_struct_t *)handle;

	
	// Find our index in bulkIn[] base on EP number we handle in this function
	for (i=0; i&amp;lt;BULK_NUM_ENDPOINTS_IN; i++) {
		if (myBulkHandle-&amp;gt;bulkIn[i].ep == ep) {
			break;
		}
	}
	
	// Create a pointer to this specific pipe
	myBulkPipe = &amp;amp;(myBulkHandle-&amp;gt;bulkIn[i]);
	
    if (NULL != myBulkPipe) {
        if (1U == myBulkPipe-&amp;gt;isBusy) {
            return kStatus_USB_Busy;
        }
        myBulkPipe-&amp;gt;isBusy = 1U;

        if (0u != myBulkPipe-&amp;gt;pipeStall) {
            myBulkPipe-&amp;gt;pipeDataBuffer = buffer;
            myBulkPipe-&amp;gt;pipeDataLen    = length;
            return kStatus_USB_Success;
        }

        status = USB_DeviceSendRequest(myBulkHandle-&amp;gt;handle, ep, buffer, length);
        if (kStatus_USB_Success != status) {
            myBulkPipe-&amp;gt;isBusy = 0U;
        }
    }
    return status;
}

//-----------------------------------------------------------------------------
// Primes the endpoint to receive packet from host.
//
// This function checks whether the endpoint is receiving packet, then it primes the endpoint
// with the buffer address and the buffer length if the pipe is not busy. Otherwise, it ignores this transfer by
// returning an error code.
//
// 	handle The class handle of the MyBulk class.
// 	ep The endpoint number of the transfer.
// 	buffer The pointer to the buffer to be transferred.
// 	length The length of the buffer to be transferred.
// 	returns:
//		A USB error code or kStatus_USB_Success.
//		kStatus_USB_Success Prime to receive packet successfully.
//		kStatus_USB_Busy The endpoint is busy in transferring.
//		kStatus_USB_InvalidHandle The MyBulk device handle or the MyBulk class handle is invalid.
//		kStatus_USB_ControllerNotFound The controller interface is invalid.
//
// The function can only be called in the same context.
//-----------------------------------------------------------------------------
usb_status_t USB_DeviceMyBulkRecv(class_handle_t handle, uint8_t ep, uint8_t *buffer, uint32_t length) {
    usb_device_mybulk_struct_t *myBulkHandle;
    usb_status_t status;
	int i=0;
    if (NULL == handle) {
        return kStatus_USB_InvalidHandle;
    }
    myBulkHandle = (usb_device_mybulk_struct_t *)handle;

	// Find our index in bulkOut[] base on EP number we handle in this function
	for (i=0; i&amp;lt;BULK_NUM_ENDPOINTS_OUT; i++) {
		if (myBulkHandle-&amp;gt;bulkOut[i].ep == ep) {
			break;
		}
	}
	
	
    if (1U == myBulkHandle-&amp;gt;bulkOut[i].isBusy) {
        return kStatus_USB_Busy;
    }
    myBulkHandle-&amp;gt;bulkOut[i].isBusy = 1U;

    if (0U != myBulkHandle-&amp;gt;bulkOut[i].pipeStall) {
        myBulkHandle-&amp;gt;bulkOut[i].pipeDataBuffer = buffer;
        myBulkHandle-&amp;gt;bulkOut[i].pipeDataLen    = length;
        return kStatus_USB_Success;
    }

    status = USB_DeviceRecvRequest(myBulkHandle-&amp;gt;handle, ep, buffer, length);
    if (kStatus_USB_Success != status) {
        myBulkHandle-&amp;gt;bulkOut[i].isBusy = 0U;
    }
    return status;
}&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Sun, 11 Apr 2021 08:46:49 GMT</pubDate>
      <guid>https://community.nxp.com/t5/i-MX-RT-Crossover-MCUs/Working-Custom-USB-example-using-Bulk-transfer-incl-code/m-p/1260056#M13727</guid>
      <dc:creator>carstengroen</dc:creator>
      <dc:date>2021-04-11T08:46:49Z</dc:date>
    </item>
    <item>
      <title>Re: Working Custom USB example using Bulk transfer incl code!</title>
      <link>https://community.nxp.com/t5/i-MX-RT-Crossover-MCUs/Working-Custom-USB-example-using-Bulk-transfer-incl-code/m-p/1261005#M13766</link>
      <description>&lt;P&gt;Forgot to mention that the code is based on SDK 2.9.1.&lt;/P&gt;&lt;P&gt;Also just a heads-up, I acquired a Beagle 480 USB analyser some time ago, this is highly recommended for stuff like this, makes it so much easier to see what's going on!&lt;/P&gt;</description>
      <pubDate>Tue, 13 Apr 2021 06:06:30 GMT</pubDate>
      <guid>https://community.nxp.com/t5/i-MX-RT-Crossover-MCUs/Working-Custom-USB-example-using-Bulk-transfer-incl-code/m-p/1261005#M13766</guid>
      <dc:creator>carstengroen</dc:creator>
      <dc:date>2021-04-13T06:06:30Z</dc:date>
    </item>
    <item>
      <title>Re: Working Custom USB example using Bulk transfer incl code!</title>
      <link>https://community.nxp.com/t5/i-MX-RT-Crossover-MCUs/Working-Custom-USB-example-using-Bulk-transfer-incl-code/m-p/1277346#M14238</link>
      <description>&lt;P&gt;Very nice work, this effort is much needed.&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Mon, 17 May 2021 04:53:27 GMT</pubDate>
      <guid>https://community.nxp.com/t5/i-MX-RT-Crossover-MCUs/Working-Custom-USB-example-using-Bulk-transfer-incl-code/m-p/1277346#M14238</guid>
      <dc:creator>MattInSeattle</dc:creator>
      <dc:date>2021-05-17T04:53:27Z</dc:date>
    </item>
    <item>
      <title>Re: Working Custom USB example using Bulk transfer incl code!</title>
      <link>https://community.nxp.com/t5/i-MX-RT-Crossover-MCUs/Working-Custom-USB-example-using-Bulk-transfer-incl-code/m-p/1448532#M19310</link>
      <description>&lt;P&gt;Thank a lot for this great work!&lt;/P&gt;&lt;P&gt;I have two question about it:&lt;/P&gt;&lt;P&gt;1. main() missed, is code below enough :&lt;/P&gt;&lt;P&gt;void main(void)&lt;BR /&gt;{&lt;BR /&gt;initUSB();&lt;BR /&gt;}&lt;/P&gt;&lt;P&gt;2. Is there is a driver for this example?&lt;/P&gt;</description>
      <pubDate>Mon, 25 Apr 2022 12:26:11 GMT</pubDate>
      <guid>https://community.nxp.com/t5/i-MX-RT-Crossover-MCUs/Working-Custom-USB-example-using-Bulk-transfer-incl-code/m-p/1448532#M19310</guid>
      <dc:creator>yanz</dc:creator>
      <dc:date>2022-04-25T12:26:11Z</dc:date>
    </item>
    <item>
      <title>Re: Working Custom USB example using Bulk transfer incl code!</title>
      <link>https://community.nxp.com/t5/i-MX-RT-Crossover-MCUs/Working-Custom-USB-example-using-Bulk-transfer-incl-code/m-p/1448610#M19312</link>
      <description>&lt;P&gt;&lt;a href="https://community.nxp.com/t5/user/viewprofilepage/user-id/199488"&gt;@yanz&lt;/a&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Yes, you call the function initUSB() in the first file "BulkUSB.c", this is all that there is to it.&lt;/P&gt;&lt;P&gt;I have some code in C# for the PC side, however I can not share this. You will find samples on the net for the PC&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="carstengroen_0-1650890459029.png" style="width: 400px;"&gt;&lt;img src="https://community.nxp.com/t5/image/serverpage/image-id/177877i649E367552F30C5B/image-size/medium?v=v2&amp;amp;px=400" role="button" title="carstengroen_0-1650890459029.png" alt="carstengroen_0-1650890459029.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Mon, 25 Apr 2022 14:22:31 GMT</pubDate>
      <guid>https://community.nxp.com/t5/i-MX-RT-Crossover-MCUs/Working-Custom-USB-example-using-Bulk-transfer-incl-code/m-p/1448610#M19312</guid>
      <dc:creator>carstengroen</dc:creator>
      <dc:date>2022-04-25T14:22:31Z</dc:date>
    </item>
    <item>
      <title>Re: Working Custom USB example using Bulk transfer incl code!</title>
      <link>https://community.nxp.com/t5/i-MX-RT-Crossover-MCUs/Working-Custom-USB-example-using-Bulk-transfer-incl-code/m-p/1448647#M19313</link>
      <description>&lt;P&gt;Thank you.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Mon, 25 Apr 2022 16:06:44 GMT</pubDate>
      <guid>https://community.nxp.com/t5/i-MX-RT-Crossover-MCUs/Working-Custom-USB-example-using-Bulk-transfer-incl-code/m-p/1448647#M19313</guid>
      <dc:creator>yanz</dc:creator>
      <dc:date>2022-04-25T16:06:44Z</dc:date>
    </item>
    <item>
      <title>Re: Working Custom USB example using Bulk transfer incl code!</title>
      <link>https://community.nxp.com/t5/i-MX-RT-Crossover-MCUs/Working-Custom-USB-example-using-Bulk-transfer-incl-code/m-p/1511586#M21268</link>
      <description>&lt;P&gt;Could you recommend PC software to test it?&lt;/P&gt;</description>
      <pubDate>Thu, 25 Aug 2022 08:38:36 GMT</pubDate>
      <guid>https://community.nxp.com/t5/i-MX-RT-Crossover-MCUs/Working-Custom-USB-example-using-Bulk-transfer-incl-code/m-p/1511586#M21268</guid>
      <dc:creator>kingchen2019</dc:creator>
      <dc:date>2022-08-25T08:38:36Z</dc:date>
    </item>
    <item>
      <title>Re: Working Custom USB example using Bulk transfer incl code!</title>
      <link>https://community.nxp.com/t5/i-MX-RT-Crossover-MCUs/Working-Custom-USB-example-using-Bulk-transfer-incl-code/m-p/1511699#M21271</link>
      <description>&lt;P&gt;I did the "PC end" myself using libusb and C#. works like a charm!&lt;/P&gt;</description>
      <pubDate>Thu, 25 Aug 2022 10:39:05 GMT</pubDate>
      <guid>https://community.nxp.com/t5/i-MX-RT-Crossover-MCUs/Working-Custom-USB-example-using-Bulk-transfer-incl-code/m-p/1511699#M21271</guid>
      <dc:creator>carstengroen</dc:creator>
      <dc:date>2022-08-25T10:39:05Z</dc:date>
    </item>
    <item>
      <title>Re: Working Custom USB example using Bulk transfer incl code!</title>
      <link>https://community.nxp.com/t5/i-MX-RT-Crossover-MCUs/Working-Custom-USB-example-using-Bulk-transfer-incl-code/m-p/1512690#M21305</link>
      <description>&lt;P&gt;It will be appreciated if you share the PC test software. I need to test this solution. Thank you!!&lt;/P&gt;</description>
      <pubDate>Sat, 27 Aug 2022 10:50:10 GMT</pubDate>
      <guid>https://community.nxp.com/t5/i-MX-RT-Crossover-MCUs/Working-Custom-USB-example-using-Bulk-transfer-incl-code/m-p/1512690#M21305</guid>
      <dc:creator>kingchen2019</dc:creator>
      <dc:date>2022-08-27T10:50:10Z</dc:date>
    </item>
    <item>
      <title>Re: Working Custom USB example using Bulk transfer incl code!</title>
      <link>https://community.nxp.com/t5/i-MX-RT-Crossover-MCUs/Working-Custom-USB-example-using-Bulk-transfer-incl-code/m-p/1512691#M21306</link>
      <description>&lt;P&gt;Sorry, can't do that&lt;/P&gt;&lt;P&gt;You need to do some programming &lt;LI-EMOJI id="lia_winking-face" title=":winking_face:"&gt;&lt;/LI-EMOJI&gt;&lt;/P&gt;</description>
      <pubDate>Sat, 27 Aug 2022 11:14:27 GMT</pubDate>
      <guid>https://community.nxp.com/t5/i-MX-RT-Crossover-MCUs/Working-Custom-USB-example-using-Bulk-transfer-incl-code/m-p/1512691#M21306</guid>
      <dc:creator>carstengroen</dc:creator>
      <dc:date>2022-08-27T11:14:27Z</dc:date>
    </item>
    <item>
      <title>Re: Working Custom USB example using Bulk transfer incl code!</title>
      <link>https://community.nxp.com/t5/i-MX-RT-Crossover-MCUs/Working-Custom-USB-example-using-Bulk-transfer-incl-code/m-p/1516355#M21445</link>
      <description>&lt;P&gt;I can find a test SW in keil, which can test Bulk, Hid, CDC and so on.&lt;/P&gt;</description>
      <pubDate>Fri, 02 Sep 2022 13:56:52 GMT</pubDate>
      <guid>https://community.nxp.com/t5/i-MX-RT-Crossover-MCUs/Working-Custom-USB-example-using-Bulk-transfer-incl-code/m-p/1516355#M21445</guid>
      <dc:creator>kingchen2019</dc:creator>
      <dc:date>2022-09-02T13:56:52Z</dc:date>
    </item>
    <item>
      <title>Re: Working Custom USB example using Bulk transfer incl code!</title>
      <link>https://community.nxp.com/t5/i-MX-RT-Crossover-MCUs/Working-Custom-USB-example-using-Bulk-transfer-incl-code/m-p/1516385#M21447</link>
      <description>&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;P&gt;Very nice work, this effort is much needed.&amp;nbsp;&lt;/P&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;DIV&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;</description>
      <pubDate>Fri, 02 Sep 2022 15:16:15 GMT</pubDate>
      <guid>https://community.nxp.com/t5/i-MX-RT-Crossover-MCUs/Working-Custom-USB-example-using-Bulk-transfer-incl-code/m-p/1516385#M21447</guid>
      <dc:creator>nickycruze2</dc:creator>
      <dc:date>2022-09-02T15:16:15Z</dc:date>
    </item>
  </channel>
</rss>

