I have implemented 3 of the many functions which are needed for communicating with a USB device. These are GetDeviceDescriptor
, BulkRead
, & BulkWrite
. Here is the code:
Usb::UsbDeviceDescriptor* GetDeviceDescriptor()
{
BOOLEAN success;
ULONG nBytes;
PUSB_DEVICE_DESCRIPTOR pDeviceDiscriptor = new USB_DEVICE_DESCRIPTOR();
if( _hEzUsb == INVALID_HANDLE_VALUE )
{
ReportError( "Driver not open." );
}
else
{
success = DeviceIoControl( _hEzUsb,
IOCTL_Ezusb_GET_DEVICE_DESCRIPTOR,
NULL,
0,
pDeviceDiscriptor,
sizeof(USB_DEVICE_DESCRIPTOR),
&nBytes,
NULL );
if( success == FALSE )
{
CheckWin32Error();
}
}
UsbDeviceDescriptor* DeviceDiscriptor = new UsbDeviceDescriptor();
DeviceDiscriptor = (UsbDeviceDescriptor*)Marshal::PtrToStructure(
pDeviceDiscriptor, DeviceDiscriptor->GetType() );
delete pDeviceDiscriptor;
return( DeviceDiscriptor );
}
System::Byte BulkRead( int pipe ) []
{
if( _hEzUsb == INVALID_HANDLE_VALUE )
{
ReportError( "Driver not open." );
return( 0 );
}
char lpOutBuffer[MaxBlkSize];
BULK_TRANSFER_CONTROL btc;
btc.pipeNum = pipe;
BOOL success;
int nBytes;
success = DeviceIoControl( _hEzUsb,
IOCTL_EZUSB_BULK_READ,
&btc,
sizeof (BULK_TRANSFER_CONTROL),
lpOutBuffer,
MaxBlkSize,
(unsigned long *)&nBytes,
NULL);
if( success == FALSE )
{
CheckWin32Error();
return( 0 );
}
System::Byte buffer __gc[] = new System::Byte[nBytes];
IntPtr ptr( lpOutBuffer );
Marshal::Copy( ptr, buffer, 0, nBytes );
return( buffer );
}
int BulkWrite( System::Byte buffer __gc[], int pipe )
{
if( _hEzUsb == INVALID_HANDLE_VALUE )
{
ReportError( "Driver not open." );
return( 0 );
}
char* lpOutBuffer = new char[buffer->Length];
Marshal::Copy( buffer, 0, lpOutBuffer, buffer->Length );
BULK_TRANSFER_CONTROL btc;
BOOLEAN success;
int nBytes;
btc.pipeNum = pipe;
success = DeviceIoControl( _hEzUsb,
IOCTL_EZUSB_BULK_WRITE,
&btc,
sizeof (BULK_TRANSFER_CONTROL),
lpOutBuffer,
buffer->Length,
(unsigned long *)&nBytes,
NULL);
if( !success )
{
CheckWin32Error();
}
delete lpOutBuffer;
return( nBytes );
}
In the GetDeviceDescriptor
function, an unmanaged version of the USB_DEVICE_DESCRIPTOR
data structure is create. A pointer to the data structure is used in the DeviceIoControl
, which fills the data structure with data. When using DeviceIoControl
, you need to use macros to define what function you want to call in the device driver. If you were calling DeviceIoControl
, directly from C#, you would need a wrapper function for the macros written in C++, or duplicate their functionality it C#. These techniques are documented in John Mueller's book. To pass the data structure back to the managed world, I create a managed structure, then use Marshal::PtrToStructure
to copy the data over.
When calling DeviceIoControl
to perform a bulk read, you need to pass it a pointer to a buffer where it can place the data. I use a char array. I then copy the data to a managed Byte array, using Marshal::Copy
.
System::Byte buffer __gc[] = new System::Byte[nBytes];
IntPtr ptr( lpOutBuffer );
Marshal::Copy( ptr, buffer, 0, nBytes );
In the call to the bulk BulkWrite
function, a System::Byte buffer __gc[]
, is passed in. The data in this array is copied to an unmanaged buffer using Marshal::Copy
.
char* lpOutBuffer = new char[buffer->Length];
Marshal::Copy( buffer, 0, lpOutBuffer, buffer->Length );
Comments