828 lines
31 KiB
Plaintext
828 lines
31 KiB
Plaintext
|
|
using System;
|
||
|
|
using Microsoft.Win32.SafeHandles;
|
||
|
|
using System.Runtime.InteropServices;
|
||
|
|
using DTS.Common.USBFramework;
|
||
|
|
using DTS.Common.Utilities.Logging;
|
||
|
|
|
||
|
|
namespace DTS.Common.WINUSBConnection
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// Routines for the WinUsb driver supported by Windows Vista and Windows XP.
|
||
|
|
/// </summary>
|
||
|
|
///
|
||
|
|
internal sealed partial class WinUsbDevice : IDisposable
|
||
|
|
{
|
||
|
|
private volatile bool _bDisposed;
|
||
|
|
|
||
|
|
~WinUsbDevice()
|
||
|
|
{
|
||
|
|
if (!_bDisposed)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
APILogger.Log("WinUSBDevice not disposed before finalizer. Disposing now");
|
||
|
|
}
|
||
|
|
catch { }
|
||
|
|
Dispose();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
internal struct DevInfo
|
||
|
|
{
|
||
|
|
internal SafeFileHandle DeviceHandle;
|
||
|
|
internal IntPtr WinUSBHandle;
|
||
|
|
internal Byte BulkInPipe;
|
||
|
|
internal Byte BulkOutPipe;
|
||
|
|
internal Byte InterruptInPipe;
|
||
|
|
internal Byte InterruptOutPipe;
|
||
|
|
internal UInt32 DeviceSpeed;
|
||
|
|
internal bool UseHybridBulkIntMode;
|
||
|
|
}
|
||
|
|
|
||
|
|
internal DevInfo MyDevInfo;
|
||
|
|
|
||
|
|
public void Dispose()
|
||
|
|
{
|
||
|
|
if (_bDisposed) return;
|
||
|
|
_bDisposed = true;
|
||
|
|
CloseDeviceHandle();
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Closes the device handle obtained with CreateFile and frees resources.
|
||
|
|
/// </summary>
|
||
|
|
///
|
||
|
|
internal void CloseDeviceHandle()
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
if (MyDevInfo.WinUSBHandle != IntPtr.Zero)
|
||
|
|
{
|
||
|
|
WinUsb_Free(MyDevInfo.WinUSBHandle);
|
||
|
|
MyDevInfo.WinUSBHandle = IntPtr.Zero;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (AccessViolationException)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
try
|
||
|
|
{
|
||
|
|
if (MyDevInfo.DeviceHandle == null || MyDevInfo.DeviceHandle.IsInvalid) return;
|
||
|
|
if (MyDevInfo.DeviceHandle.IsInvalid) return;
|
||
|
|
MyDevInfo.DeviceHandle.Dispose();
|
||
|
|
MyDevInfo.DeviceHandle = null;
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Initiates a Control Read transfer. Data stage is device to host.
|
||
|
|
/// </summary>
|
||
|
|
///
|
||
|
|
/// <param name="dataStage"> The received data. </param>
|
||
|
|
///
|
||
|
|
/// <returns>
|
||
|
|
/// True on success, False on failure.
|
||
|
|
/// </returns>
|
||
|
|
|
||
|
|
internal bool Do_Control_Read_Transfer(ref byte[] dataStage)
|
||
|
|
{
|
||
|
|
// Vendor-specific request to an interface with device-to-host Data stage.
|
||
|
|
WinUSBSetupPacket setupPacket;
|
||
|
|
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 = 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.
|
||
|
|
// WinUSBSetupPacket 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.
|
||
|
|
// ***
|
||
|
|
|
||
|
|
uint bytesReturned = 0;
|
||
|
|
var success = WinUsb_ControlTransfer(MyDevInfo.WinUSBHandle,
|
||
|
|
setupPacket,
|
||
|
|
dataStage,
|
||
|
|
Convert.ToUInt16(dataStage.Length),
|
||
|
|
ref bytesReturned,
|
||
|
|
IntPtr.Zero);
|
||
|
|
return success;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Initiates a Control Write transfer. Data stage is host to device.
|
||
|
|
/// </summary>
|
||
|
|
///
|
||
|
|
/// <param name="dataStage"> The data to send. </param>
|
||
|
|
///
|
||
|
|
/// <returns>
|
||
|
|
/// True on success, False on failure.
|
||
|
|
/// </returns>
|
||
|
|
|
||
|
|
internal bool Do_Control_Write_Transfer(byte[] dataStage)
|
||
|
|
{
|
||
|
|
// Vendor-specific request to an interface with host-to-device Data stage.
|
||
|
|
WinUSBSetupPacket setupPacket;
|
||
|
|
setupPacket.RequestType = 0X41;
|
||
|
|
|
||
|
|
// The request number that identifies the specific request.
|
||
|
|
setupPacket.Request = 1;
|
||
|
|
|
||
|
|
// Command-specific value to send to the device.
|
||
|
|
var index = Convert.ToUInt16(0);
|
||
|
|
setupPacket.Index = index;
|
||
|
|
|
||
|
|
// Number of bytes in the request's Data stage.
|
||
|
|
setupPacket.Length = Convert.ToUInt16(dataStage.Length);
|
||
|
|
|
||
|
|
// Command-specific value to send to the device.
|
||
|
|
var value = Convert.ToUInt16(0);
|
||
|
|
setupPacket.Value = value;
|
||
|
|
|
||
|
|
// ***
|
||
|
|
// winusb function
|
||
|
|
// summary
|
||
|
|
// Initiates a control transfer.
|
||
|
|
// parameters
|
||
|
|
// Device handle returned by WinUsb_Initialize.
|
||
|
|
// WinUSBSetupPacket 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.
|
||
|
|
// ***
|
||
|
|
uint bytesReturned = 0;
|
||
|
|
var success = WinUsb_ControlTransfer(MyDevInfo.WinUSBHandle,
|
||
|
|
setupPacket,
|
||
|
|
dataStage,
|
||
|
|
Convert.ToUInt16(dataStage.Length),
|
||
|
|
ref bytesReturned,
|
||
|
|
IntPtr.Zero);
|
||
|
|
return success;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Requests a handle with CreateFile.
|
||
|
|
/// </summary>
|
||
|
|
///
|
||
|
|
/// <param name="devicePathName"> Returned by SetupDiGetDeviceInterfaceDetail
|
||
|
|
/// in an SP_DEVICE_INTERFACE_DETAIL_DATA structure. </param>
|
||
|
|
///
|
||
|
|
/// <returns>
|
||
|
|
/// The handle.
|
||
|
|
/// </returns>
|
||
|
|
|
||
|
|
internal bool GetDeviceHandle(string devicePathName)
|
||
|
|
{
|
||
|
|
var security = new FileIO.SECURITY_ATTRIBUTES
|
||
|
|
{
|
||
|
|
lpSecurityDescriptor = IntPtr.Zero,
|
||
|
|
bInheritHandle = Convert.ToInt32(true)
|
||
|
|
};
|
||
|
|
|
||
|
|
security.nLength = Marshal.SizeOf(security);
|
||
|
|
|
||
|
|
System.Diagnostics.Trace.Assert(null == MyDevInfo.DeviceHandle || MyDevInfo.DeviceHandle.IsClosed);
|
||
|
|
// ***
|
||
|
|
// 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,
|
||
|
|
ref security,
|
||
|
|
FileIO.OPEN_EXISTING,
|
||
|
|
FileIO.FILE_ATTRIBUTE_NORMAL | FileIO.FILE_FLAG_OVERLAPPED,
|
||
|
|
0);
|
||
|
|
|
||
|
|
if (!MyDevInfo.DeviceHandle.IsInvalid)
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
FileIODeclarations.GetLastError();
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var w32 = new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
|
||
|
|
APILogger.Log("GetDeviceHandle(", devicePathName, ") - error - ", w32.Message);
|
||
|
|
}
|
||
|
|
catch { }
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Initializes a device interface and obtains information about it.
|
||
|
|
/// Calls these winusb API functions:
|
||
|
|
/// WinUsb_Initialize
|
||
|
|
/// WinUsb_QueryInterfaceSettings
|
||
|
|
/// WinUsb_QueryPipe
|
||
|
|
/// </summary>
|
||
|
|
/// <returns>
|
||
|
|
/// True on success, False on failure.
|
||
|
|
/// </returns>
|
||
|
|
internal bool InitializeDevice()
|
||
|
|
{
|
||
|
|
USBInterfaceDescriptor ifaceDescriptor;
|
||
|
|
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;
|
||
|
|
|
||
|
|
WinUSBPipeInformation pipeInfo;
|
||
|
|
pipeInfo.PipeTypes = 0;
|
||
|
|
pipeInfo.PipeId = 0;
|
||
|
|
pipeInfo.MaximumPacketSize = 0;
|
||
|
|
pipeInfo.Interval = 0;
|
||
|
|
|
||
|
|
MyDevInfo.UseHybridBulkIntMode = false;
|
||
|
|
|
||
|
|
// ***
|
||
|
|
// 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.
|
||
|
|
// ***
|
||
|
|
var success = WinUsb_Initialize(MyDevInfo.DeviceHandle, ref MyDevInfo.WinUSBHandle);
|
||
|
|
|
||
|
|
if (!success) return false;
|
||
|
|
// ***
|
||
|
|
// winusb function
|
||
|
|
// summary
|
||
|
|
// Get a structure with information about the device interface.
|
||
|
|
// parameters
|
||
|
|
// handle returned by WinUsb_Initialize
|
||
|
|
// alternate interface setting number
|
||
|
|
// USBInterfaceDescriptor structure to be returned.
|
||
|
|
// returns
|
||
|
|
// True on success.
|
||
|
|
|
||
|
|
success = 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.)
|
||
|
|
// WinUSBPipeInformation structure to be returned
|
||
|
|
// returns
|
||
|
|
// True on success
|
||
|
|
// ***
|
||
|
|
var pipeTimeout = Convert.ToUInt32(0);
|
||
|
|
for (var i = 0; i <= ifaceDescriptor.bNumEndpoints - 1; i++)
|
||
|
|
{
|
||
|
|
WinUsb_QueryPipe(MyDevInfo.WinUSBHandle,
|
||
|
|
0,
|
||
|
|
Convert.ToByte(i),
|
||
|
|
ref pipeInfo);
|
||
|
|
|
||
|
|
if (pipeInfo.PipeTypes == USBDPipeTypes.UsbdPipeTypeBulk && UsbEndpointDirectionIn(pipeInfo.PipeId))
|
||
|
|
{
|
||
|
|
MyDevInfo.BulkInPipe = pipeInfo.PipeId;
|
||
|
|
|
||
|
|
SetPipePolicy
|
||
|
|
(MyDevInfo.BulkInPipe,
|
||
|
|
Convert.ToUInt32(PolicyType.IgnoreShortPackets),
|
||
|
|
Convert.ToByte(false));
|
||
|
|
|
||
|
|
SetPipePolicy
|
||
|
|
(MyDevInfo.BulkInPipe,
|
||
|
|
Convert.ToUInt32(PolicyType.PipeTransferTimeout),
|
||
|
|
pipeTimeout);
|
||
|
|
|
||
|
|
}
|
||
|
|
else if (pipeInfo.PipeTypes == USBDPipeTypes.UsbdPipeTypeBulk && UsbEndpointDirectionOut(pipeInfo.PipeId))
|
||
|
|
{
|
||
|
|
MyDevInfo.BulkOutPipe = pipeInfo.PipeId;
|
||
|
|
|
||
|
|
SetPipePolicy
|
||
|
|
(MyDevInfo.BulkOutPipe,
|
||
|
|
Convert.ToUInt32(PolicyType.IgnoreShortPackets),
|
||
|
|
Convert.ToByte(false));
|
||
|
|
|
||
|
|
SetPipePolicy
|
||
|
|
(MyDevInfo.BulkOutPipe,
|
||
|
|
Convert.ToUInt32(PolicyType.PipeTransferTimeout),
|
||
|
|
pipeTimeout);
|
||
|
|
|
||
|
|
}
|
||
|
|
else if (pipeInfo.PipeTypes == USBDPipeTypes.UsbdPipeTypeInterrupt && UsbEndpointDirectionIn(pipeInfo.PipeId))
|
||
|
|
{
|
||
|
|
MyDevInfo.InterruptInPipe = pipeInfo.PipeId;
|
||
|
|
|
||
|
|
SetPipePolicy
|
||
|
|
(MyDevInfo.InterruptInPipe,
|
||
|
|
Convert.ToUInt32(PolicyType.IgnoreShortPackets),
|
||
|
|
Convert.ToByte(false));
|
||
|
|
|
||
|
|
SetPipePolicy
|
||
|
|
(MyDevInfo.InterruptInPipe,
|
||
|
|
Convert.ToUInt32(PolicyType.PipeTransferTimeout),
|
||
|
|
pipeTimeout);
|
||
|
|
|
||
|
|
}
|
||
|
|
else if (pipeInfo.PipeTypes == USBDPipeTypes.UsbdPipeTypeInterrupt && UsbEndpointDirectionOut(pipeInfo.PipeId))
|
||
|
|
{
|
||
|
|
MyDevInfo.InterruptOutPipe = pipeInfo.PipeId;
|
||
|
|
|
||
|
|
SetPipePolicy
|
||
|
|
(MyDevInfo.InterruptOutPipe,
|
||
|
|
Convert.ToUInt32(PolicyType.IgnoreShortPackets),
|
||
|
|
Convert.ToByte(false));
|
||
|
|
|
||
|
|
SetPipePolicy
|
||
|
|
(MyDevInfo.InterruptOutPipe,
|
||
|
|
Convert.ToUInt32(PolicyType.PipeTransferTimeout),
|
||
|
|
pipeTimeout);
|
||
|
|
|
||
|
|
MyDevInfo.UseHybridBulkIntMode = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return success;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Is the current operating system Windows XP or later?
|
||
|
|
/// The WinUSB driver requires Windows XP or later.
|
||
|
|
/// </summary>
|
||
|
|
///
|
||
|
|
/// <returns>
|
||
|
|
/// True if Windows XP or later, False if not.
|
||
|
|
/// </returns>
|
||
|
|
internal bool IsWindowsXpOrLater()
|
||
|
|
{
|
||
|
|
var myEnvironment = Environment.OSVersion;
|
||
|
|
|
||
|
|
// Windows XP is version 5.1.
|
||
|
|
var versionXP = new Version(5, 1);
|
||
|
|
|
||
|
|
return myEnvironment.Version >= versionXP;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Gets a value that corresponds to a USBDeviceSpeeds.
|
||
|
|
/// </summary>
|
||
|
|
internal bool QueryDeviceSpeed()
|
||
|
|
{
|
||
|
|
// ***
|
||
|
|
// 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.
|
||
|
|
// ***
|
||
|
|
uint length = 1;
|
||
|
|
var speed = new byte[1];
|
||
|
|
var success = WinUsb_QueryDeviceInformation(MyDevInfo.WinUSBHandle,
|
||
|
|
DEVICE_SPEED,
|
||
|
|
ref length,
|
||
|
|
ref speed[0]);
|
||
|
|
|
||
|
|
if (success)
|
||
|
|
{
|
||
|
|
MyDevInfo.DeviceSpeed = Convert.ToUInt32(speed[0]);
|
||
|
|
}
|
||
|
|
|
||
|
|
return success;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// see winerror.h, these are error codes that we can expect or have received from
|
||
|
|
/// read pipe
|
||
|
|
/// </summary>
|
||
|
|
private const long ERROR_GEN_FAILURE = 31L;
|
||
|
|
private const long ERROR_LOCK_VIOLATION = 33L;
|
||
|
|
private const long ERROR_INVALID_HANDLE = 6L;
|
||
|
|
private const long ERROR_OPERATION_ABORTED = 995L;
|
||
|
|
private const long ERROR_IO_INCOMPLETE = 996L;
|
||
|
|
private const long ERROR_IO_PENDING = 997L;
|
||
|
|
private const long ERROR_NOT_ENOUGH_MEMORY = 8L;
|
||
|
|
private const long ERROR_SEM_TIMEOUT = 121L;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Attempts to read data from a bulk IN endpoint.
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="pipeId"> Endpoint address. </param>
|
||
|
|
/// <param name="bytesToRead"> Number of bytes to read. </param>
|
||
|
|
/// <param name="buffer"> Buffer for storing the bytes read. </param>
|
||
|
|
/// <param name="bytesRead"> Number of bytes read. </param>
|
||
|
|
/// <param name="success"> Success or failure status. </param>
|
||
|
|
///
|
||
|
|
internal void ReadViaBulkTransfer(byte pipeId,
|
||
|
|
uint bytesToRead,
|
||
|
|
ref byte[] buffer,
|
||
|
|
ref uint bytesRead,
|
||
|
|
ref bool 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 = WinUsb_ReadPipe
|
||
|
|
(MyDevInfo.WinUSBHandle,
|
||
|
|
pipeId,
|
||
|
|
buffer,
|
||
|
|
bytesToRead,
|
||
|
|
ref bytesRead,
|
||
|
|
IntPtr.Zero);
|
||
|
|
|
||
|
|
if (success) return;
|
||
|
|
long lastError = Marshal.GetLastWin32Error();
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var w32 = new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
|
||
|
|
switch (w32.NativeErrorCode)
|
||
|
|
{
|
||
|
|
case (int)ERROR_IO_PENDING:
|
||
|
|
case (int)ERROR_IO_INCOMPLETE:
|
||
|
|
case (int)ERROR_OPERATION_ABORTED:
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
APILogger.Log(string.Format("ReadViaBulkTransfer failed Message:{0} Error: {1}", w32.Message, w32.NativeErrorCode));
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
catch { }
|
||
|
|
switch (lastError)
|
||
|
|
{
|
||
|
|
case ERROR_GEN_FAILURE:
|
||
|
|
//APILogger.LogString("WinUSBDevice::WinUsb_ReadPipe General failure - " + ERROR_GEN_FAILURE.ToString());
|
||
|
|
break;
|
||
|
|
case ERROR_LOCK_VIOLATION:
|
||
|
|
//APILogger.LogString("WinUSBDevice::WinUsb_ReadPipe Lock violation - " + ERROR_LOCK_VIOLATION.ToString());
|
||
|
|
break;
|
||
|
|
case ERROR_INVALID_HANDLE://do we clean up if the handle is invalid?
|
||
|
|
//APILogger.LogString("WinUSBDevice::WinUsb_ReadPipe Invalid Handle - " + ERROR_INVALID_HANDLE.ToString());
|
||
|
|
break;
|
||
|
|
case ERROR_IO_PENDING://this one should be okay
|
||
|
|
//APILogger.LogString("WinUSBDevice::WinUsb_ReadPipe I/O Pending - " + ERROR_IO_PENDING.ToString());
|
||
|
|
break;
|
||
|
|
case ERROR_NOT_ENOUGH_MEMORY://this we'd probably never see
|
||
|
|
//APILogger.LogString("WinUSBDevice::WinUsb_ReadPipe Not Enough Memory - " + ERROR_NOT_ENOUGH_MEMORY.ToString());
|
||
|
|
break;
|
||
|
|
case ERROR_SEM_TIMEOUT:
|
||
|
|
//APILogger.LogString("WinUSBDevice::WinUsb_ReadPipe Semaphore timeout - " + ERROR_SEM_TIMEOUT.ToString());
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var w32 = new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
|
||
|
|
APILogger.Log("ReadViaBulkTranser - error ", ex.Message, " - ", w32.Message);
|
||
|
|
}
|
||
|
|
catch { }
|
||
|
|
throw;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Attempts to read data from an interrupt IN endpoint.
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="pipeId"> Endpoint address. </param>
|
||
|
|
/// <param name="bytesToRead"> Number of bytes to read. </param>
|
||
|
|
/// <param name="buffer"> Buffer for storing the bytes read. </param>
|
||
|
|
/// <param name="bytesRead"> Number of bytes read. </param>
|
||
|
|
/// <param name="success"> Success or failure status. </param>
|
||
|
|
///
|
||
|
|
internal void ReadViaInterruptTransfer(byte pipeId,
|
||
|
|
uint bytesToRead,
|
||
|
|
ref byte[] buffer,
|
||
|
|
ref uint bytesRead,
|
||
|
|
ref bool 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 = WinUsb_ReadPipe(MyDevInfo.WinUSBHandle,
|
||
|
|
pipeId,
|
||
|
|
buffer,
|
||
|
|
bytesToRead,
|
||
|
|
ref bytesRead,
|
||
|
|
IntPtr.Zero);
|
||
|
|
|
||
|
|
if (success) return;
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var w32 = new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
|
||
|
|
APILogger.Log("ReadViaInterruptTransfer failed, ", w32.Message);
|
||
|
|
}
|
||
|
|
catch { }
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
var w32 = new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
|
||
|
|
APILogger.Log("ReadViaInterruptTransfer failed, ", ex.Message, " - ", w32.Message);
|
||
|
|
throw;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Attempts to send data via a bulk OUT endpoint.
|
||
|
|
/// </summary>
|
||
|
|
///
|
||
|
|
/// <param name="buffer"> Buffer containing the bytes to write. </param>
|
||
|
|
/// <param name="bytesToWrite"> Number of bytes to write. </param>
|
||
|
|
///
|
||
|
|
/// <returns>
|
||
|
|
/// True on success, False on failure.
|
||
|
|
/// </returns>
|
||
|
|
internal bool SendViaBulkTransfer(ref byte[] buffer, uint bytesToWrite)
|
||
|
|
{
|
||
|
|
uint bytesWritten = 0;
|
||
|
|
|
||
|
|
// ***
|
||
|
|
// 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.
|
||
|
|
// ***
|
||
|
|
System.Threading.Thread.Sleep(5);
|
||
|
|
var success = WinUsb_WritePipe
|
||
|
|
(MyDevInfo.WinUSBHandle,
|
||
|
|
MyDevInfo.BulkOutPipe,
|
||
|
|
buffer,
|
||
|
|
bytesToWrite,
|
||
|
|
ref bytesWritten,
|
||
|
|
IntPtr.Zero);
|
||
|
|
|
||
|
|
if (success) return true;
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var w32 = new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
|
||
|
|
APILogger.Log("WritePipe failed, buffer[", BitConverter.ToString(buffer, 0, Convert.ToInt32(bytesToWrite)), "], bytes: ", bytesToWrite, ", ", w32.Message);
|
||
|
|
}
|
||
|
|
catch { }
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Attempts to send data via an interrupt OUT endpoint.
|
||
|
|
/// </summary>
|
||
|
|
///
|
||
|
|
/// <param name="buffer"> Buffer containing the bytes to write. </param>
|
||
|
|
/// <param name="bytesToWrite"> Number of bytes to write. </param>
|
||
|
|
///
|
||
|
|
/// <returns>
|
||
|
|
/// True on success, False on failure.
|
||
|
|
/// </returns>
|
||
|
|
internal bool SendViaInterruptTransfer(ref byte[] buffer, uint bytesToWrite)
|
||
|
|
{
|
||
|
|
uint bytesWritten = 0;
|
||
|
|
|
||
|
|
// ***
|
||
|
|
// 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.
|
||
|
|
// ***
|
||
|
|
|
||
|
|
var success = WinUsb_WritePipe
|
||
|
|
(MyDevInfo.WinUSBHandle,
|
||
|
|
MyDevInfo.InterruptOutPipe,
|
||
|
|
buffer,
|
||
|
|
bytesToWrite,
|
||
|
|
ref bytesWritten,
|
||
|
|
IntPtr.Zero);
|
||
|
|
|
||
|
|
if (success) return true;
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var w32 = new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
|
||
|
|
APILogger.Log("SendViaInterruptTransfer failed - bytes[", BitConverter.ToString(buffer, 0, Convert.ToInt32(bytesToWrite)), "] - ", w32.Message);
|
||
|
|
}
|
||
|
|
catch { }
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Sets pipe policy.
|
||
|
|
/// Used when the value parameter is a Byte (all except PIPE_TRANSFER_TIMEOUT).
|
||
|
|
/// </summary>
|
||
|
|
///
|
||
|
|
/// <param name="pipeId"> Pipe to set a policy for. </param>
|
||
|
|
/// <param name="policyType"> POLICY_TYPE member. </param>
|
||
|
|
/// <param name="value"> Policy value. </param>
|
||
|
|
///
|
||
|
|
/// <returns>
|
||
|
|
/// True on success, False on failure.
|
||
|
|
/// </returns>
|
||
|
|
///
|
||
|
|
private bool SetPipePolicy(byte pipeId, uint policyType, byte value)
|
||
|
|
{
|
||
|
|
// ***
|
||
|
|
// 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
|
||
|
|
// ***
|
||
|
|
|
||
|
|
var success = WinUsb_SetPipePolicy
|
||
|
|
(MyDevInfo.WinUSBHandle,
|
||
|
|
pipeId,
|
||
|
|
policyType,
|
||
|
|
Convert.ToUInt32(1),
|
||
|
|
ref value);
|
||
|
|
|
||
|
|
return success;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Sets pipe policy.
|
||
|
|
/// Used when the value parameter is a UInt32 (PIPE_TRANSFER_TIMEOUT only).
|
||
|
|
/// </summary>
|
||
|
|
///
|
||
|
|
/// <param name="pipeId"> Pipe to set a policy for. </param>
|
||
|
|
/// <param name="policyType"> POLICY_TYPE member. </param>
|
||
|
|
/// <param name="value"> Policy value. </param>
|
||
|
|
///
|
||
|
|
/// <returns>
|
||
|
|
/// True on success, False on failure.
|
||
|
|
/// </returns>
|
||
|
|
///
|
||
|
|
private bool SetPipePolicy(byte pipeId, uint policyType, uint value)
|
||
|
|
{
|
||
|
|
// ***
|
||
|
|
// 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
|
||
|
|
// ***
|
||
|
|
|
||
|
|
var success = WinUsb_SetPipePolicy1
|
||
|
|
(MyDevInfo.WinUSBHandle,
|
||
|
|
pipeId,
|
||
|
|
policyType,
|
||
|
|
Convert.ToUInt32(4),
|
||
|
|
ref value);
|
||
|
|
|
||
|
|
return success;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Is the endpoint's direction IN (device to host)?
|
||
|
|
/// </summary>
|
||
|
|
///
|
||
|
|
/// <param name="addr"> The endpoint address. </param>
|
||
|
|
/// <returns>
|
||
|
|
/// True if IN (device to host), False if OUT (host to device)
|
||
|
|
/// </returns>
|
||
|
|
private static bool UsbEndpointDirectionIn(int addr)
|
||
|
|
{
|
||
|
|
var usbEndpointDirectionInReturn = (addr & 0X80) == 0X80;
|
||
|
|
return usbEndpointDirectionInReturn;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Is the endpoint's direction OUT (host to device)?
|
||
|
|
/// </summary>
|
||
|
|
///
|
||
|
|
/// <param name="addr"> The endpoint address. </param>
|
||
|
|
///
|
||
|
|
/// <returns>
|
||
|
|
/// True if OUT (host to device, False if IN (device to host)
|
||
|
|
/// </returns>
|
||
|
|
private static bool UsbEndpointDirectionOut(int addr)
|
||
|
|
{
|
||
|
|
var usbEndpointDirectionOutReturn = (addr & 0X80) == 0;
|
||
|
|
return usbEndpointDirectionOutReturn;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|