using System;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
namespace WinUsb
{
///
/// Routines for the WinUsb driver supported by Windows Vista and Windows XP.
///
///
public partial class WinUsbDevice
{
public struct devInfo
{
internal SafeFileHandle deviceHandle;
internal IntPtr winUsbHandle;
public Byte bulkInPipe;
internal Byte bulkOutPipe;
internal Byte interruptInPipe;
internal Byte interruptOutPipe;
internal UInt32 devicespeed;
}
public devInfo myDevInfo = new devInfo();
///
/// Closes the device handle obtained with CreateFile and frees resources.
///
///
public void CloseDeviceHandle()
{
try
{
if (myDevInfo.winUsbHandle != null)
{
SafeNativeMethods.WinUsb_Free(myDevInfo.winUsbHandle);
myDevInfo.winUsbHandle = System.IntPtr.Zero;
}
if (!(myDevInfo.deviceHandle == null))
{
if (!(myDevInfo.deviceHandle.IsInvalid))
{
myDevInfo.deviceHandle.Close();
myDevInfo.deviceHandle = null;
}
}
}
catch (Exception ex)
{
string strEx;
strEx = ex.Message;
throw;
}
}
///
/// Initiates a Control Read transfer. Data stage is device to host.
///
///
/// The received data.
///
///
/// True on success, False on failure.
///
internal Boolean Do_Control_Read_Transfer(ref Byte[] dataStage)
{
UInt32 bytesReturned = 0;
SafeNativeMethods.WINUSB_SETUP_PACKET setupPacket;
Boolean success;
try
{
// Vendor-specific request to an interface with device-to-host Data stage.
setupPacket.RequestType = 0XC1;
// The request number that identifies the specific request.
setupPacket.Request = 2;
// Command-specific value to send to the device.
setupPacket.Index = 0;
// Number of bytes in the request's Data stage.
setupPacket.Length = System.Convert.ToUInt16(dataStage.Length);
// Command-specific value to send to the device.
setupPacket.Value = 0;
// ***
// winusb function
// summary
// Initiates a control transfer.
// paramaters
// Device handle returned by WinUsb_Initialize.
// WINUSB_SETUP_PACKET structure
// Buffer to hold the returned Data-stage data.
// Number of data bytes to read in the Data stage.
// Number of bytes read in the Data stage.
// Null pointer for non-overlapped.
// returns
// True on success.
// ***
success = SafeNativeMethods.WinUsb_ControlTransfer(myDevInfo.winUsbHandle, setupPacket, dataStage, System.Convert.ToUInt16(dataStage.Length), ref bytesReturned, IntPtr.Zero);
return success;
}
catch (Exception ex)
{
string strEx;
strEx = ex.Message;
throw;
}
}
///
/// Initiates a Control Write transfer. Data stage is host to device.
///
///
/// The data to send.
///
///
/// True on success, False on failure.
///
internal Boolean Do_Control_Write_Transfer(Byte[] dataStage)
{
UInt32 bytesReturned = 0;
ushort index = System.Convert.ToUInt16(0);
SafeNativeMethods.WINUSB_SETUP_PACKET setupPacket;
Boolean success;
ushort value = System.Convert.ToUInt16(0);
try
{
// Vendor-specific request to an interface with host-to-device Data stage.
setupPacket.RequestType = 0X41;
// The request number that identifies the specific request.
setupPacket.Request = 1;
// Command-specific value to send to the device.
setupPacket.Index = index;
// Number of bytes in the request's Data stage.
setupPacket.Length = System.Convert.ToUInt16(dataStage.Length);
// Command-specific value to send to the device.
setupPacket.Value = value;
// ***
// winusb function
// summary
// Initiates a control transfer.
// parameters
// Device handle returned by WinUsb_Initialize.
// WINUSB_SETUP_PACKET structure
// Buffer containing the Data-stage data.
// Number of data bytes to send in the Data stage.
// Number of bytes sent in the Data stage.
// Null pointer for non-overlapped.
// Returns
// True on success.
// ***
success = SafeNativeMethods.WinUsb_ControlTransfer
(myDevInfo.winUsbHandle,
setupPacket,
dataStage,
System.Convert.ToUInt16(dataStage.Length),
ref bytesReturned,
IntPtr.Zero);
return success;
}
catch (Exception ex)
{
string strEx;
strEx = ex.Message;
throw;
}
}
///
/// Requests a handle with CreateFile.
///
///
/// Returned by SetupDiGetDeviceInterfaceDetail
/// in an SP_DEVICE_INTERFACE_DETAIL_DATA structure.
///
///
/// The handle.
///
public Boolean GetDeviceHandle(String devicePathName)
{
// ***
// API function
// summary
// Retrieves a handle to a device.
// parameters
// Device path name returned by SetupDiGetDeviceInterfaceDetail
// Type of access requested (read/write).
// FILE_SHARE attributes to allow other processes to access the device while this handle is open.
// Security structure. Using Null for this may cause problems under Windows XP.
// Creation disposition value. Use OPEN_EXISTING for devices.
// Flags and attributes for files. The winsub driver requires FILE_FLAG_OVERLAPPED.
// Handle to a template file. Not used.
// Returns
// A handle or INVALID_HANDLE_VALUE.
// ***
myDevInfo.deviceHandle = FileIO.CreateFile
(devicePathName,
(FileIO.GENERIC_WRITE | FileIO.GENERIC_READ),
FileIO.FILE_SHARE_READ | FileIO.FILE_SHARE_WRITE,
IntPtr.Zero,
FileIO.OPEN_EXISTING,
FileIO.FILE_ATTRIBUTE_NORMAL | FileIO.FILE_FLAG_OVERLAPPED,
0);
if (!(myDevInfo.deviceHandle.IsInvalid))
{
return true;
}
else
{
return false;
}
}
///
/// Initializes a device interface and obtains information about it.
/// Calls these winusb API functions:
/// WinUsb_Initialize
/// WinUsb_QueryInterfaceSettings
/// WinUsb_QueryPipe
///
///
/// A handle obtained in a call to winusb_initialize.
///
///
/// True on success, False on failure.
///
public Boolean InitializeDevice()
{
SafeNativeMethods.USB_INTERFACE_DESCRIPTOR ifaceDescriptor;
SafeNativeMethods.WINUSB_PIPE_INFORMATION pipeInfo;
UInt32 pipeTimeout = 2000;
Boolean success;
try
{
ifaceDescriptor.bLength = 0;
ifaceDescriptor.bDescriptorType = 0;
ifaceDescriptor.bInterfaceNumber = 0;
ifaceDescriptor.bAlternateSetting = 0;
ifaceDescriptor.bNumEndpoints = 0;
ifaceDescriptor.bInterfaceClass = 0;
ifaceDescriptor.bInterfaceSubClass = 0;
ifaceDescriptor.bInterfaceProtocol = 0;
ifaceDescriptor.iInterface = 0;
pipeInfo.PipeType = 0;
pipeInfo.PipeId = 0;
pipeInfo.MaximumPacketSize = 0;
pipeInfo.Interval = 0;
// ***
// winusb function
// summary
// get a handle for communications with a winusb device '
// parameters
// Handle returned by CreateFile.
// Device handle to be returned.
// returns
// True on success.
// ***
success = SafeNativeMethods.WinUsb_Initialize
(myDevInfo.deviceHandle,
ref myDevInfo.winUsbHandle);
if (success)
{
// ***
// winusb function
// summary
// Get a structure with information about the device interface.
// parameters
// handle returned by WinUsb_Initialize
// alternate interface setting number
// USB_INTERFACE_DESCRIPTOR structure to be returned.
// returns
// True on success.
success = SafeNativeMethods.WinUsb_QueryInterfaceSettings
(myDevInfo.winUsbHandle,
0,
ref ifaceDescriptor);
if (success)
{
// Get the transfer type, endpoint number, and direction for the interface's
// bulk and interrupt endpoints. Set pipe policies.
// ***
// winusb function
// summary
// returns information about a USB pipe (endpoint address)
// parameters
// Handle returned by WinUsb_Initialize
// Alternate interface setting number
// Number of an endpoint address associated with the interface.
// (The values count up from zero and are NOT the same as the endpoint address
// in the endpoint descriptor.)
// WINUSB_PIPE_INFORMATION structure to be returned
// returns
// True on success
// ***
for (Int32 i = 0; i <= ifaceDescriptor.bNumEndpoints - 1; i++)
{
SafeNativeMethods.WinUsb_QueryPipe
(myDevInfo.winUsbHandle,
0,
System.Convert.ToByte(i),
ref pipeInfo);
if (((pipeInfo.PipeType ==
SafeNativeMethods.USBD_PIPE_TYPE.UsbdPipeTypeBulk) &
UsbEndpointDirectionIn(pipeInfo.PipeId)))
{
myDevInfo.bulkInPipe = pipeInfo.PipeId;
SetPipePolicy
(myDevInfo.bulkInPipe,
Convert.ToUInt32(SafeNativeMethods.POLICY_TYPE.IGNORE_SHORT_PACKETS),
Convert.ToByte(false));
SetPipePolicy
(myDevInfo.bulkInPipe,
Convert.ToUInt32(SafeNativeMethods.POLICY_TYPE.PIPE_TRANSFER_TIMEOUT),
pipeTimeout);
}
else if (((pipeInfo.PipeType ==
SafeNativeMethods.USBD_PIPE_TYPE.UsbdPipeTypeBulk) &
UsbEndpointDirectionOut(pipeInfo.PipeId)))
{
myDevInfo.bulkOutPipe = pipeInfo.PipeId;
SetPipePolicy
(myDevInfo.bulkOutPipe,
Convert.ToUInt32(SafeNativeMethods.POLICY_TYPE.IGNORE_SHORT_PACKETS),
Convert.ToByte(false));
SetPipePolicy
(myDevInfo.bulkOutPipe,
Convert.ToUInt32(SafeNativeMethods.POLICY_TYPE.PIPE_TRANSFER_TIMEOUT),
pipeTimeout);
}
else if ((pipeInfo.PipeType ==
SafeNativeMethods.USBD_PIPE_TYPE.UsbdPipeTypeInterrupt) &
UsbEndpointDirectionIn(pipeInfo.PipeId))
{
myDevInfo.interruptInPipe = pipeInfo.PipeId;
SetPipePolicy
(myDevInfo.interruptInPipe,
Convert.ToUInt32(SafeNativeMethods.POLICY_TYPE.IGNORE_SHORT_PACKETS),
Convert.ToByte(false));
SetPipePolicy
(myDevInfo.interruptInPipe,
Convert.ToUInt32(SafeNativeMethods.POLICY_TYPE.PIPE_TRANSFER_TIMEOUT),
pipeTimeout);
}
else if ((pipeInfo.PipeType ==
SafeNativeMethods.USBD_PIPE_TYPE.UsbdPipeTypeInterrupt) &
UsbEndpointDirectionOut(pipeInfo.PipeId))
{
myDevInfo.interruptOutPipe = pipeInfo.PipeId;
SetPipePolicy
(myDevInfo.interruptOutPipe,
Convert.ToUInt32(SafeNativeMethods.POLICY_TYPE.IGNORE_SHORT_PACKETS),
Convert.ToByte(false));
SetPipePolicy
(myDevInfo.interruptOutPipe,
Convert.ToUInt32(SafeNativeMethods.POLICY_TYPE.PIPE_TRANSFER_TIMEOUT),
pipeTimeout);
}
}
}
else
{
success = false;
}
}
return success;
}
catch (Exception ex)
{
string strEx;
strEx = ex.Message;
throw;
}
}
///
/// Is the current operating system Windows XP or later?
/// The WinUSB driver requires Windows XP or later.
///
///
///
/// True if Windows XP or later, False if not.
///
internal Boolean IsWindowsXpOrLater()
{
try
{
OperatingSystem myEnvironment = Environment.OSVersion;
// Windows XP is version 5.1.
System.Version versionXP = new System.Version(5, 1);
if (myEnvironment.Version >= versionXP)
{
return true;
}
else
{
return false;
}
}
catch (Exception ex)
{
string strEx;
strEx = ex.Message;
throw;
}
}
///
/// Gets a value that corresponds to a USB_DEVICE_SPEED.
///
internal Boolean QueryDeviceSpeed()
{
UInt32 length = 1;
Byte[] speed = new Byte[1];
Boolean success;
// ***
// winusb function
// summary
// Get the device speed.
// (Normally not required but can be nice to know.)
// parameters
// Handle returned by WinUsb_Initialize
// Requested information type.
// Number of bytes to read.
// Information to be returned.
// returns
// True on success.
// ***
success = SafeNativeMethods.WinUsb_QueryDeviceInformation
(myDevInfo.winUsbHandle,
SafeNativeMethods.DEVICE_SPEED,
ref length,
ref speed[0]);
if (success)
{
myDevInfo.devicespeed = System.Convert.ToUInt32(speed[0]);
}
return success;
}
///
/// Attempts to read data from a bulk IN endpoint.
///
///
/// Device interface handle.
/// Endpoint address.
/// Number of bytes to read.
/// Buffer for storing the bytes read.
/// Number of bytes read.
/// Success or failure status.
///
public void ReadViaBulkTransfer(Byte pipeID, UInt32 bytesToRead, ref Byte[] buffer, ref UInt32 bytesRead, ref Boolean success)
{
try
{
// ***
// winusb function
// summary
// Attempts to read data from a device interface.
// parameters
// Device handle returned by WinUsb_Initialize.
// Endpoint address.
// Buffer to store the data.
// Maximum number of bytes to return.
// Number of bytes read.
// Null pointer for non-overlapped.
// Returns
// True on success.
// ***
success = SafeNativeMethods.WinUsb_ReadPipe
(myDevInfo.winUsbHandle,
pipeID,
buffer,
bytesToRead,
ref bytesRead,
IntPtr.Zero);
if (!(success))
{
CloseDeviceHandle();
}
}
catch (Exception ex)
{
string strEx;
strEx = ex.Message;
throw;
}
}
///
/// Attempts to read data from an interrupt IN endpoint.
///
///
/// Device interface handle.
/// Endpoint address.
/// Number of bytes to read.
/// Buffer for storing the bytes read.
/// Number of bytes read.
/// Success or failure status.
///
internal void ReadViaInterruptTransfer
(Byte pipeID,
UInt32 bytesToRead,
ref Byte[] buffer,
ref UInt32 bytesRead,
ref Boolean success)
{
try
{
// ***
// winusb function
// summary
// Attempts to read data from a device interface.
// parameters
// Device handle returned by WinUsb_Initialize.
// Endpoint address.
// Buffer to store the data.
// Maximum number of bytes to return.
// Number of bytes read.
// Null pointer for non-overlapped.
// Returns
// True on success.
// ***
success = SafeNativeMethods.WinUsb_ReadPipe
(myDevInfo.winUsbHandle,
pipeID,
buffer,
bytesToRead,
ref bytesRead,
IntPtr.Zero);
if (!(success))
{
CloseDeviceHandle();
}
}
catch (Exception ex)
{
string strEx;
strEx = ex.Message;
throw;
}
}
///
/// Attempts to send data via a bulk OUT endpoint.
///
///
/// Buffer containing the bytes to write.
/// Number of bytes to write.
///
///
/// True on success, False on failure.
///
public Boolean SendViaBulkTransfer(ref Byte[] buffer, UInt32 bytesToWrite)
{
UInt32 bytesWritten = 0;
Boolean success;
try
{
// ***
// winusb function
// summary
// Attempts to write data to a device interface.
// parameters
// Device handle returned by WinUsb_Initialize.
// Endpoint address.
// Buffer with data to write.
// Number of bytes to write.
// Number of bytes written.
// IntPtr.Zero for non-overlapped I/O.
// Returns
// True on success.
// ***
success = SafeNativeMethods.WinUsb_WritePipe
(myDevInfo.winUsbHandle,
myDevInfo.bulkOutPipe,
buffer,
bytesToWrite,
ref bytesWritten,
IntPtr.Zero);
if (!(success))
{
CloseDeviceHandle();
}
return success;
}
catch (Exception ex)
{
string strEx;
strEx = ex.Message;
throw;
}
}
///
/// Attempts to send data via an interrupt OUT endpoint.
///
///
/// Buffer containing the bytes to write.
/// Number of bytes to write.
///
///
/// True on success, False on failure.
///
internal Boolean SendViaInterruptTransfer(ref Byte[] buffer, UInt32 bytesToWrite)
{
UInt32 bytesWritten = 0;
Boolean success;
try
{
// ***
// winusb function
// summary
// Attempts to write data to a device interface.
// parameters
// Device handle returned by WinUsb_Initialize.
// Endpoint address.
// Buffer with data to write.
// Number of bytes to write.
// Number of bytes written.
// IntPtr.Zero for non-overlapped I/O.
// Returns
// True on success.
// ***
success = SafeNativeMethods.WinUsb_WritePipe
(myDevInfo.winUsbHandle,
myDevInfo.interruptOutPipe,
buffer,
bytesToWrite,
ref bytesWritten,
IntPtr.Zero);
if (!(success))
{
CloseDeviceHandle();
}
return success;
}
catch (Exception ex)
{
string strEx;
strEx = ex.Message;
throw;
}
}
///
/// Sets pipe policy.
/// Used when the value parameter is a Byte (all except PIPE_TRANSFER_TIMEOUT).
///
///
/// Pipe to set a policy for.
/// POLICY_TYPE member.
/// Policy value.
///
///
/// True on success, False on failure.
///
///
private Boolean SetPipePolicy(Byte pipeId, UInt32 policyType, Byte value)
{
Boolean success;
try
{
// ***
// winusb function
// summary
// sets a pipe policy
// parameters
// handle returned by WinUsb_Initialize
// identifies the pipe
// POLICY_TYPE member.
// length of value in bytes
// value to set for the policy.
// returns
// True on success
// ***
success = SafeNativeMethods.WinUsb_SetPipePolicy
(myDevInfo.winUsbHandle,
pipeId,
policyType,
1,
ref value);
return success;
}
catch (Exception ex)
{
string strEx;
strEx = ex.Message;
throw;
}
}
///
/// Sets pipe policy.
/// Used when the value parameter is a UInt32 (PIPE_TRANSFER_TIMEOUT only).
///
///
/// Pipe to set a policy for.
/// POLICY_TYPE member.
/// Policy value.
///
///
/// True on success, False on failure.
///
///
private Boolean SetPipePolicy(Byte pipeId, UInt32 policyType, UInt32 value)
{
Boolean success;
try
{
// ***
// winusb function
// summary
// sets a pipe policy
// parameters
// handle returned by WinUsb_Initialize
// identifies the pipe
// POLICY_TYPE member.
// length of value in bytes
// value to set for the policy.
// returns
// True on success
// ***
success = SafeNativeMethods.WinUsb_SetPipePolicy1
(myDevInfo.winUsbHandle,
pipeId,
policyType,
4,
ref value);
return success;
}
catch (Exception ex)
{
string strEx;
strEx = ex.Message;
throw;
}
}
///
/// Is the endpoint's direction IN (device to host)?
///
///
/// The endpoint address.
///
/// True if IN (device to host), False if OUT (host to device)
///
private Boolean UsbEndpointDirectionIn(Int32 addr)
{
Boolean directionIn;
try
{
if (((addr & 0X80) == 0X80))
{
directionIn = true;
}
else
{
directionIn = false;
}
}
catch (Exception ex)
{
string strEx;
strEx = ex.Message;
throw;
}
return directionIn;
}
///
/// Is the endpoint's direction OUT (host to device)?
///
///
/// The endpoint address.
///
///
/// True if OUT (host to device, False if IN (device to host)
///
private Boolean UsbEndpointDirectionOut(Int32 addr)
{
Boolean directionOut;
try
{
if (((addr & 0X80) == 0))
{
directionOut = true;
}
else
{
directionOut = false;
}
}
catch (Exception ex)
{
string strEx;
strEx = ex.Message;
throw;
}
return directionOut;
}
}
}