Mercurial > hg > ucis.core
changeset 21:dcfec2be27c9
Added USBLib
line wrap: on
line diff
--- a/UCIS.csproj Mon Apr 15 00:43:48 2013 +0200 +++ b/UCIS.csproj Mon Apr 15 01:04:59 2013 +0200 @@ -32,6 +32,7 @@ <DefineConstants>TRACE</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> </PropertyGroup> <ItemGroup> <Reference Include="System" /> @@ -131,6 +132,31 @@ <Compile Include="Radio\Tuner.cs" /> <Compile Include="Remoting\RemotingManager.cs" /> <Compile Include="ThreadPool.cs" /> + <Compile Include="USBLib\Communication\IUsbDevice.cs" /> + <Compile Include="USBLib\Communication\IUsbDeviceRegistry.cs" /> + <Compile Include="USBLib\Communication\LibUsb0\LibUsb0Registry.cs" /> + <Compile Include="USBLib\Communication\LibUsb0\LibUsbDevice.cs" /> + <Compile Include="USBLib\Communication\LibUsb0\Support.cs" /> + <Compile Include="USBLib\Communication\LibUsb1\libusb1.cs" /> + <Compile Include="USBLib\Communication\LibUsb1\LibUsb1Device.cs" /> + <Compile Include="USBLib\Communication\LibUsb1\LibUsb1Registry.cs" /> + <Compile Include="USBLib\Communication\LibUsbDotNet.cs" /> + <Compile Include="USBLib\Communication\UsbControlRequestType.cs" /> + <Compile Include="USBLib\Communication\UsbDescriptorType.cs" /> + <Compile Include="USBLib\Communication\UsbInterface.cs" /> + <Compile Include="USBLib\Communication\UsbPipeStream.cs" /> + <Compile Include="USBLib\Communication\WindowsUsbDeviceRegistry.cs" /> + <Compile Include="USBLib\Communication\WinUsb\WinUsbDevice.cs" /> + <Compile Include="USBLib\Communication\WinUsb\WinUsbRegistry.cs" /> + <Compile Include="USBLib\Descriptor\UsbDescriptor.cs" /> + <Compile Include="USBLib\Internal\Windows\SetupApi.cs" /> + <Compile Include="USBLib\Internal\Windows\UsbApi.cs" /> + <Compile Include="USBLib\Internal\Windows\Win32Kernel.cs" /> + <Compile Include="USBLib\Windows\Devices\DeviceNode.cs" /> + <Compile Include="USBLib\Windows\USB\UsbBus.cs" /> + <Compile Include="USBLib\Windows\USB\UsbController.cs" /> + <Compile Include="USBLib\Windows\USB\UsbDevice.cs" /> + <Compile Include="USBLib\Windows\USB\UsbHub.cs" /> <Compile Include="UTF8NoPreamble.cs" /> <Compile Include="Util\ArrayUtil.cs" /> <Compile Include="Util\AsyncResultBase.cs" />
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Communication/IUsbDevice.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,32 @@ +using System; + +namespace UCIS.USBLib.Communication { + public interface IUsbDevice : IUsbInterface, IDisposable { + new Byte Configuration { get; set; } + void ClaimInterface(int interfaceID); + void ReleaseInterface(int interfaceID); + void ResetDevice(); + + IUsbDeviceRegistry Registry { get; } + + //void Close(); + } + public interface IUsbInterface : IDisposable { + Byte Configuration { get; } + void Close(); + + //int ControlTransfer(byte requestType, byte request, short value, short index, Byte[] buffer, int offset, int length); + int GetDescriptor(byte descriptorType, byte index, short langId, Byte[] buffer, int offset, int length); + String GetString(short langId, byte stringIndex); + + int BulkWrite(Byte endpoint, Byte[] buffer, int offset, int length); + int BulkRead(Byte endpoint, Byte[] buffer, int offset, int length); + int InterruptWrite(Byte endpoint, Byte[] buffer, int offset, int length); + int InterruptRead(Byte endpoint, Byte[] buffer, int offset, int length); + int ControlWrite(UsbControlRequestType requestType, byte request, short value, short index, Byte[] buffer, int offset, int length); + int ControlRead(UsbControlRequestType requestType, byte request, short value, short index, Byte[] buffer, int offset, int length); + + UsbPipeStream GetBulkStream(Byte endpoint); + UsbPipeStream GetInterruptStream(Byte endpoint); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Communication/IUsbDeviceRegistry.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using UCIS.USBLib.Communication.LibUsb; +using UCIS.USBLib.Communication.LibUsb1; +using UCIS.USBLib.Communication.WinUsb; + +namespace UCIS.USBLib.Communication { + public interface IUsbDeviceRegistry { + IDictionary<String, Object> DeviceProperties { get; } + Int32 Vid { get; } + Int32 Pid { get; } + Byte InterfaceID { get; } + + String Name { get; } //Device product name (or null if not available) + String Manufacturer { get; } //Device manufacturer name (or null if not available) + String FullName { get; } //Device manufacturer name and product name + String SymbolicName { get; } //Arbitrary string that uniquely identifies the device + + IUsbDevice Open(); + } + public static class UsbDevice { + public static IList<IUsbDeviceRegistry> AllDevices { + get { + List<IUsbDeviceRegistry> list = new List<IUsbDeviceRegistry>(); + if (Environment.OSVersion.Platform == PlatformID.Win32NT) { + foreach (IUsbDeviceRegistry reg in WinUsbRegistry.DeviceList) list.Add(reg); + foreach (IUsbDeviceRegistry reg in LibUsb0Registry.DeviceList) list.Add(reg); + } else { + foreach (IUsbDeviceRegistry reg in LibUsb1Registry.DeviceList) list.Add(reg); + } + return list; + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Communication/LibUsb0/LibUsb0Registry.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using UCIS.HWLib.Windows.Devices; + +namespace UCIS.USBLib.Communication.LibUsb { + public class LibUsb0Registry : WindowsUsbDeviceRegistry, IUsbDeviceRegistry { + private LibUsb0Registry(DeviceNode device, String interfacepath) : base(device, interfacepath) { } + public static List<LibUsb0Registry> GetDevicesByInterfaceClass(Guid classGuid) { + List<LibUsb0Registry> deviceList = new List<LibUsb0Registry>(); + IList<DeviceNode> usbdevices = DeviceNode.GetDevices(classGuid); + foreach (DeviceNode device in usbdevices) { + LibUsb0Registry regInfo = GetDeviceForDeviceNode(device, classGuid); + if (regInfo != null) deviceList.Add(regInfo); + } + return deviceList; + } + public static List<LibUsb0Registry> DeviceList { + get { + List<LibUsb0Registry> deviceList = new List<LibUsb0Registry>(); + IList<DeviceNode> usbdevices = DeviceNode.GetDevices("USB"); + foreach (DeviceNode device in usbdevices) { + LibUsb0Registry regInfo = GetDeviceForDeviceNode(device); + if (regInfo == null) continue; + deviceList.Add(regInfo); + } + return deviceList; + } + } + public static List<LibUsb0Registry> FilterDeviceList { + get { + return GetDevicesByInterfaceClass(new Guid("{F9F3FF14-AE21-48A0-8A25-8011A7A931D9}")); + } + } + public static LibUsb0Registry GetDeviceForDeviceNode(DeviceNode device, Guid classGuid) { + String[] iLibUsb = device.GetInterfaces(classGuid); + if (iLibUsb == null || iLibUsb.Length == 0) return null; + return new LibUsb0Registry(device, iLibUsb[0]); + } + public static LibUsb0Registry GetDeviceForDeviceNode(DeviceNode device) { + String deviceInterface = null; + if (deviceInterface == null) { + String[] interfaces = device.GetInterfaces("{20343A29-6DA1-4DB8-8A3C-16E774057BF5}"); + if (interfaces != null && interfaces.Length > 0) { + deviceInterface = interfaces[0]; + } + } + if (deviceInterface == null && device.Service == "libusb0") { + String[] devInterfaceGuids = device.GetCustomPropertyStringArray("DeviceInterfaceGuids"); + if (devInterfaceGuids != null && devInterfaceGuids.Length > 0) { + Guid deviceInterfaceGuid = new Guid(devInterfaceGuids[0]); + String[] interfaces = device.GetInterfaces(deviceInterfaceGuid); + if (interfaces != null && interfaces.Length > 0) { + deviceInterface = interfaces[0]; + } + } + } + /*if (deviceInterface == null) { + String[] interfaces = device.GetInterfaces("{F9F3FF14-AE21-48A0-8A25-8011A7A931D9}"); + if (interfaces != null && interfaces.Length > 0) { + deviceInterface = interfaces[0]; + } + }*/ + if (deviceInterface == null) return null; + return new LibUsb0Registry(device, deviceInterface); + } + + public LibUsb0Device Open() { + return new LibUsb0Device(DevicePath, this); + } + IUsbDevice IUsbDeviceRegistry.Open() { + return Open(); + } + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Communication/LibUsb0/LibUsbDevice.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,264 @@ +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Threading; +using Microsoft.Win32.SafeHandles; +using UCIS.USBLib.Internal.Windows; + +namespace UCIS.USBLib.Communication.LibUsb { + public class LibUsb0Device : UsbInterface, IUsbDevice { + //private readonly List<int> mClaimedInterfaces = new List<int>(); + public string DeviceFilename { get; private set; } + public IUsbDeviceRegistry Registry { get; private set; } + private SafeFileHandle DeviceHandle; + + public LibUsb0Device(String path, LibUsb0Registry registry) { + DeviceFilename = path; + this.Registry = registry; + DeviceHandle = Kernel32.CreateFile(DeviceFilename, + NativeFileAccess.SPECIAL, + NativeFileShare.NONE, + IntPtr.Zero, + NativeFileMode.OPEN_EXISTING, + NativeFileFlag.FILE_FLAG_OVERLAPPED, + IntPtr.Zero); + if (DeviceHandle.IsInvalid || DeviceHandle.IsClosed) throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not open device"); + } + public override void Close() { + if (DeviceHandle != null) DeviceHandle.Close(); + } + + public override Byte Configuration { + get { return base.Configuration; } + set { + ControlWrite( + UsbControlRequestType.EndpointOut | UsbControlRequestType.TypeStandard | UsbControlRequestType.RecipDevice, + (byte)UsbStandardRequest.SetConfiguration, + value, + 0, null, 0, 0); + } + } + + public void ClaimInterface(int interfaceID) { + LibUsbRequest req = new LibUsbRequest(); + req.Iface.ID = interfaceID; + req.Timeout = UsbConstants.DEFAULT_TIMEOUT; + int ret; + DeviceIoControl(DeviceHandle, LibUsbIoCtl.CLAIM_INTERFACE, ref req, LibUsbRequest.Size, null, 0, out ret); + } + public void ReleaseInterface(int interfaceID) { + LibUsbRequest req = new LibUsbRequest(); + req.Iface.ID = interfaceID; + req.Timeout = UsbConstants.DEFAULT_TIMEOUT; + int ret; + DeviceIoControl(DeviceHandle, LibUsbIoCtl.RELEASE_INTERFACE, ref req, LibUsbRequest.Size, null, 0, out ret); + } + public void SetAltInterface(int interfaceID, int alternateID) { + LibUsbRequest req = new LibUsbRequest(); + req.Iface.ID = interfaceID; + req.Iface.AlternateID = alternateID; + req.Timeout = UsbConstants.DEFAULT_TIMEOUT; + int ret; + DeviceIoControl(DeviceHandle, LibUsbIoCtl.SET_INTERFACE, ref req, LibUsbRequest.Size, null, 0, out ret); + } + public void ResetDevice() { + LibUsbRequest req = new LibUsbRequest(); + req.Timeout = UsbConstants.DEFAULT_TIMEOUT; + int ret; + DeviceIoControl(DeviceHandle, LibUsbIoCtl.RESET_DEVICE, ref req, LibUsbRequest.Size, null, 0, out ret); + } + public unsafe override int GetDescriptor(byte descriptorType, byte index, short langId, byte[] buffer, int offset, int length) { + if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer length"); + LibUsbRequest req = new LibUsbRequest(); + req.Descriptor.Index = index; + req.Descriptor.LangID = langId; + req.Descriptor.Recipient = (byte)UsbEndpointDirection.EndpointIn & 0x1F; + req.Descriptor.Type = descriptorType; + req.Timeout = UsbConstants.DEFAULT_TIMEOUT; + int ret; + fixed (Byte* b = buffer) { + DeviceIoControl(DeviceHandle, LibUsbIoCtl.GET_DESCRIPTOR, ref req, LibUsbRequest.Size, (IntPtr)(b + offset), length, out ret); + } + return ret; + } + public override int BulkRead(byte endpoint, byte[] buffer, int offset, int length) { + return PipeTransfer(endpoint, false, false, buffer, offset, length, 0); + } + public override int BulkWrite(byte endpoint, byte[] buffer, int offset, int length) { + return PipeTransfer(endpoint, true, false, buffer, offset, length, 0); + } + public override int InterruptRead(byte endpoint, byte[] buffer, int offset, int length) { + return PipeTransfer(endpoint, false, false, buffer, offset, length, 0); + } + public override int InterruptWrite(byte endpoint, byte[] buffer, int offset, int length) { + return PipeTransfer(endpoint, true, false, buffer, offset, length, 0); + } + public unsafe override int ControlRead(UsbControlRequestType requestType, byte request, short value, short index, byte[] buffer, int offset, int length) { + if (buffer == null) buffer = new Byte[0]; + if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer length"); + int code; + LibUsbRequest req = new LibUsbRequest(); + PrepareControlTransfer(requestType, request, value, index, length, ref req, out code); + int ret; + fixed (Byte* b = buffer) { + DeviceIoControl(DeviceHandle, code, ref req, LibUsbRequest.Size, (IntPtr)(b + offset), length, out ret); + } + return ret; + } + public unsafe override int ControlWrite(UsbControlRequestType requestType, byte request, short value, short index, byte[] buffer, int offset, int length) { + Byte[] inbuffer = new Byte[length + LibUsbRequest.Size]; + if (length > 0) Buffer.BlockCopy(buffer, offset, inbuffer, LibUsbRequest.Size, length); + int code; + fixed (Byte* inbufferp = inbuffer) + PrepareControlTransfer(requestType, request, value, index, length, ref *((LibUsbRequest*)inbufferp), out code); + int ret; + DeviceIoControl(DeviceHandle, code, inbuffer, length + LibUsbRequest.Size, null, 0, out ret); + return length; + //ret -= LibUsbRequest.Size; + //if (ret <= 0) return 0; + //return ret; + } + void PrepareControlTransfer(UsbControlRequestType requestType, byte request, short value, short index, int length, ref LibUsbRequest req, out int code) { + code = LibUsbIoCtl.CONTROL_TRANSFER; + req.Timeout = UsbConstants.DEFAULT_TIMEOUT; + req.Control.RequestType = (Byte)requestType; + req.Control.Request = request; + req.Control.Value = (ushort)value; + req.Control.Index = (ushort)index; + req.Control.Length = (ushort)length; + switch ((UsbControlRequestType)((int)requestType & (0x03 << 5))) { + case UsbControlRequestType.TypeStandard: + switch ((UsbStandardRequest)request) { + case UsbStandardRequest.GetStatus: + req.Status.Recipient = (int)requestType & 0x1F; + req.Status.Index = index; + code = LibUsbIoCtl.GET_STATUS; + break; + case UsbStandardRequest.ClearFeature: + req.Feature.Recipient = (int)requestType & 0x1F; + req.Feature.ID = value; + req.Feature.Index = index; + code = LibUsbIoCtl.CLEAR_FEATURE; + break; + case UsbStandardRequest.SetFeature: + req.Feature.Recipient = (int)requestType & 0x1F; + req.Feature.ID = value; + req.Feature.Index = index; + code = LibUsbIoCtl.SET_FEATURE; + break; + case UsbStandardRequest.GetDescriptor: + req.Descriptor.Recipient = (int)requestType & 0x1F; + req.Descriptor.Type = (value >> 8) & 0xFF; + req.Descriptor.Index = value & 0xFF; + req.Descriptor.LangID = index; + code = LibUsbIoCtl.GET_DESCRIPTOR; + break; + case UsbStandardRequest.SetDescriptor: + req.Descriptor.Recipient = (int)requestType & 0x1F; + req.Descriptor.Type = (value >> 8) & 0xFF; + req.Descriptor.Index = value & 0xFF; + req.Descriptor.LangID = index; + code = LibUsbIoCtl.SET_DESCRIPTOR; + break; + case UsbStandardRequest.GetConfiguration: + code = LibUsbIoCtl.GET_CONFIGURATION; + break; + case UsbStandardRequest.SetConfiguration: + req.Config.ID = value; + code = LibUsbIoCtl.SET_CONFIGURATION; + break; + case UsbStandardRequest.GetInterface: + req.Iface.ID = index; + code = LibUsbIoCtl.GET_INTERFACE; + break; + case UsbStandardRequest.SetInterface: + req.Iface.ID = index; + req.Iface.AlternateID = value; + code = LibUsbIoCtl.SET_INTERFACE; + break; + default: + throw new ArgumentException(String.Format("Invalid request: 0x{0:X8}", request)); + } + break; + case UsbControlRequestType.TypeVendor: + case UsbControlRequestType.TypeClass: + req.Vendor.Type = ((byte)requestType >> 5) & 0x03; + req.Vendor.Recipient = (int)requestType & 0x1F; + req.Vendor.Request = (int)request; + req.Vendor.ID = value; + req.Vendor.Index = index; + code = ((byte)requestType & 0x80) != 0 ? LibUsbIoCtl.VENDOR_READ : LibUsbIoCtl.VENDOR_WRITE; + break; + case UsbControlRequestType.TypeReserved: + default: + throw new ArgumentException(String.Format("Invalid or unsupported request type: 0x{0:X8}", requestType)); + } + } + + unsafe int PipeTransfer(Byte epnum, Boolean write, Boolean isochronous, Byte[] buffer, int offset, int length, int packetsize) { + if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer length"); + LibUsbRequest req = new LibUsbRequest(); + req.Endpoint.ID = epnum; + req.Endpoint.PacketSize = packetsize; + req.Timeout = UsbConstants.DEFAULT_TIMEOUT; + fixed (Byte* b = buffer) { + if (write) { + int cltCode = isochronous ? LibUsbIoCtl.ISOCHRONOUS_WRITE : LibUsbIoCtl.INTERRUPT_OR_BULK_WRITE; + int transfered = 0; + while (length > 0) { + int ret; + DeviceIoControl(DeviceHandle, cltCode, ref req, LibUsbRequest.Size, (IntPtr)(b + offset), Math.Min(Int16.MaxValue, length), out ret); + if (ret <= 0) throw new System.IO.EndOfStreamException(); + length -= ret; + offset += ret; + transfered += ret; + } + return transfered; + } else { + int cltCode = isochronous ? LibUsbIoCtl.ISOCHRONOUS_READ : LibUsbIoCtl.INTERRUPT_OR_BULK_READ; + int ret; + DeviceIoControl(DeviceHandle, cltCode, ref req, LibUsbRequest.Size, (IntPtr)(b + offset), Math.Min(UInt16.MaxValue, length), out ret); + return ret; + } + } + } + public void PipeReset(byte pipeID) { + LibUsbRequest req = new LibUsbRequest(); + req.Endpoint.ID = pipeID; + req.Timeout = UsbConstants.DEFAULT_TIMEOUT; + int ret; + DeviceIoControl(DeviceHandle, LibUsbIoCtl.RESET_ENDPOINT, ref req, LibUsbRequest.Size, null, 0, out ret); + } + + private unsafe void DeviceIoControl(SafeHandle hDevice, int IoControlCode, [In] ref LibUsbRequest InBuffer, int nInBufferSize, Byte[] OutBuffer, int nOutBufferSize, out int pBytesReturned) { + fixed (LibUsbRequest* InBufferPtr = &InBuffer) { + fixed (Byte* OutBufferPtr = OutBuffer) { + DeviceIoControl(hDevice, IoControlCode, (IntPtr)InBufferPtr, nInBufferSize, (IntPtr)OutBufferPtr, nOutBufferSize, out pBytesReturned); + } + } + } + private unsafe void DeviceIoControl(SafeHandle hDevice, int IoControlCode, Byte[] InBuffer, int nInBufferSize, Byte[] OutBuffer, int nOutBufferSize, out int pBytesReturned) { + fixed (Byte* InBufferPtr = InBuffer, OutBufferPtr = OutBuffer) { + DeviceIoControl(hDevice, IoControlCode, (IntPtr)InBufferPtr, nInBufferSize, (IntPtr)OutBufferPtr, nOutBufferSize, out pBytesReturned); + } + } + private unsafe void DeviceIoControl(SafeHandle hDevice, int IoControlCode, [In] ref LibUsbRequest InBuffer, int nInBufferSize, IntPtr OutBuffer, int nOutBufferSize, out int pBytesReturned) { + fixed (LibUsbRequest* InBufferPtr = &InBuffer) { + DeviceIoControl(hDevice, IoControlCode, (IntPtr)InBufferPtr, nInBufferSize, OutBuffer, nOutBufferSize, out pBytesReturned); + } + } + private unsafe void DeviceIoControl(SafeHandle hDevice, int IoControlCode, IntPtr InBuffer, int nInBufferSize, IntPtr OutBuffer, int nOutBufferSize, out int pBytesReturned) { + using (ManualResetEvent evt = new ManualResetEvent(false)) { + NativeOverlapped overlapped = new NativeOverlapped(); + overlapped.EventHandle = evt.SafeWaitHandle.DangerousGetHandle(); + if (Kernel32.DeviceIoControl(hDevice, IoControlCode, InBuffer, nInBufferSize, OutBuffer, nOutBufferSize, out pBytesReturned, &overlapped)) + return; + int err = Marshal.GetLastWin32Error(); + if (err != 997) throw new Win32Exception(err); + evt.WaitOne(); + if (!Kernel32.GetOverlappedResult(hDevice, &overlapped, out pBytesReturned, false)) + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + } + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Communication/LibUsb0/Support.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,444 @@ +using System; +using System.Runtime.InteropServices; + +namespace UCIS.USBLib.Communication.LibUsb { + /// <summary> Transfers data to the main control endpoint (Endpoint 0). + /// </summary> + /// <remarks> All USB devices respond to requests from the host on the device’s Default Control Pipe. These requests are made using control transfers. The request and the request’s parameters are sent to the device in the Setup packet. The host is responsible for establishing the values passed in the fields. Every Setup packet has eight bytes. + /// </remarks> + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct UsbSetupPacket { + /// <summary> + /// This bitmapped field identifies the characteristics of the specific request. In particular, this field identifies the direction of data transfer in the second phase of the control transfer. The state of the Direction bit is ignored if the wLength field is zero, signifying there is no Data stage. + /// The USB Specification defines a series of standard requests that all devices must support. In addition, a device class may define additional requests. A device vendor may also define requests supported by the device. + /// Requests may be directed to the device, an interface on the device, or a specific endpoint on a device. This field also specifies the intended recipient of the request. When an interface or endpoint is specified, the wIndex field identifies the interface or endpoint. + /// </summary> + /// <remarks> + /// <ul>Characteristics of request: + /// <li>D7: Data transfer direction</li> + /// <li>0 = Host-to-device</li> + /// <li>1 = Device-to-host</li> + /// <li>D6...5: Type</li> + /// <li>0 = Standard</li> + /// <li>1 = Class</li> + /// <li>2 = Vendor</li> + /// <li>3 = Reserved</li> + /// <li>D4...0: Recipient</li> + /// <li>0 = Device</li> + /// <li>1 = Interface</li> + /// <li>2 = Endpoint</li> + /// <li>3 = Other</li> + /// <li>4...31 = Reserved</li> + /// </ul> + /// </remarks> + public byte RequestType; + + /// <summary> + /// This field specifies the particular request. The Type bits in the bmRequestType field modify the meaning of this field. This specification defines values for the bRequest field only when the bits are reset to zero, indicating a standard request. + /// </summary> + public byte Request; + + /// <summary> + /// The contents of this field vary according to the request. It is used to pass a parameter to the device, specific to the request. + /// </summary> + public short Value; + + /// <summary> + /// The contents of this field vary according to the request. It is used to pass a parameter to the device, specific to the request. + /// </summary> + public short Index; + + /// <summary> + /// This field specifies the length of the data transferred during the second phase of the control transfer. The direction of data transfer (host-to-device or device-to-host) is indicated by the Direction bit of the <see cref="RequestType"/> field. If this field is zero, there is no data transfer phase. On an input request, a device must never return more data than is indicated by the wLength value; it may return less. On an output request, wLength will always indicate the exact amount of data to be sent by the host. Device behavior is undefined if the host should send more data than is specified in wLength. + /// </summary> + public short Length; + + /// <summary> + /// Creates a new instance of a <see cref="UsbSetupPacket"/> and initializes all the fields with the following parameters. + /// </summary> + /// <param name="requestType">See <see cref="UsbSetupPacket.RequestType"/>.</param> + /// <param name="request">See <see cref="UsbSetupPacket.Request"/>.</param> + /// <param name="value">See <see cref="UsbSetupPacket.Value"/>.</param> + /// <param name="index">See <see cref="UsbSetupPacket.Index"/>.</param> + /// <param name="length">See <see cref="UsbSetupPacket.Length"/>.</param> + public UsbSetupPacket(byte requestType, byte request, short value, short index, short length) { + RequestType = requestType; + Request = request; + Value = value; + Index = index; + Length = length; + } + } + /// <summary> Standard Windows registry properties for USB devices and other hardware. + /// </summary> + /// DeviceRegistryProperty or DEVICE_REGISTRY_PROPERTY on MSDN + enum DevicePropertyType { + /// <summary> + /// Requests a string describing the device, such as "Microsoft PS/2 Port Mouse", typically defined by the manufacturer. + /// </summary> + DeviceDesc = 0, + /// <summary> + /// Requests the hardware IDs provided by the device that identify the device. + /// </summary> + HardwareId = 1, + /// <summary> + /// Requests the compatible IDs reported by the device. + /// </summary> + CompatibleIds = 2, + /// <summary> + /// Requests the name of the device's setup class, in text format. + /// </summary> + Class = 5, + /// <summary> + /// Requests the GUID for the device's setup class. + /// </summary> + ClassGuid = 6, + /// <summary> + /// Requests the name of the driver-specific registry key. + /// </summary> + Driver = 7, + /// <summary> + /// Requests a string identifying the manufacturer of the device. + /// </summary> + Mfg = 8, + /// <summary> + /// Requests a string that can be used to distinguish between two similar devices, typically defined by the class installer. + /// </summary> + FriendlyName = 9, + /// <summary> + /// Requests information about the device's location on the bus; the interpretation of this information is bus-specific. + /// </summary> + LocationInformation = 10, + /// <summary> + /// Requests the name of the PDO for this device. + /// </summary> + PhysicalDeviceObjectName = 11, + /// <summary> + /// Requests the GUID for the bus that the device is connected to. + /// </summary> + BusTypeGuid = 12, + /// <summary> + /// Requests the bus type, such as PCIBus or PCMCIABus. + /// </summary> + LegacyBusType = 13, + /// <summary> + /// Requests the legacy bus number of the bus the device is connected to. + /// </summary> + BusNumber = 14, + /// <summary> + /// Requests the name of the enumerator for the device, such as "USB". + /// </summary> + EnumeratorName = 15, + /// <summary> + /// Requests the address of the device on the bus. + /// </summary> + Address = 16, + /// <summary> + /// Requests a number associated with the device that can be displayed in the user interface. + /// </summary> + UiNumber = 17, + /// <summary> + /// Windows XP and later.) Requests the device's installation state. + /// </summary> + InstallState = 18, + /// <summary> + /// (Windows XP and later.) Requests the device's current removal policy. The operating system uses this value as a hint to determine how the device is normally removed. + /// </summary> + RemovalPolicy = 19 + } + /// <summary> Various USB constants. + /// </summary> + static class UsbConstants { + /// <summary> + /// Default timeout for all USB IO operations. + /// </summary> + public const int DEFAULT_TIMEOUT = 1000; + + /// <summary> + /// Maximum size of a config descriptor. + /// </summary> + public const int MAX_CONFIG_SIZE = 4096; + + /// <summary> + /// Maximum number of USB devices. + /// </summary> + public const int MAX_DEVICES = 128; + + /// <summary> + /// Maximum number of endpoints per device. + /// </summary> + public const int MAX_ENDPOINTS = 32; + + /// <summary> + /// Endpoint direction mask. + /// </summary> + public const byte ENDPOINT_DIR_MASK = 0x80; + + /// <summary> + /// Endpoint number mask. + /// </summary> + public const byte ENDPOINT_NUMBER_MASK = 0xf; + + } + ///<summary>Endpoint direction.</summary> + /// <seealso cref="UsbCtrlFlags"/> + [Flags] + enum UsbEndpointDirection : byte { + /// <summary> + /// In Direction + /// </summary> + EndpointIn = 0x80, + /// <summary> + /// Out Direction + /// </summary> + EndpointOut = 0x00, + } + ///<summary> + /// Contains version information for the LibUsb Sys driver. + ///</summary> + /// <remarks> + /// This version is not related to LibUsbDotNet. TO get the LibUsbDotNet version use .NET reflections. + /// </remarks> + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct UsbKernelVersion { + /// <summary> + /// True if Major == 0 and Minor == 0 and Micro == 0 and Nano == 0. + /// </summary> + public bool IsEmpty { + get { + if (Major == 0 && Minor == 0 && Micro == 0 && Nano == 0) return true; + return false; + } + } + + internal UsbKernelVersion(int major, int minor, int micro, int nano, int bcdLibUsbDotNetKernelMod) { + Major = major; + Minor = minor; + Micro = micro; + Nano = nano; + BcdLibUsbDotNetKernelMod = bcdLibUsbDotNetKernelMod; + } + + /// <summary> + /// LibUsb-Win32 Major version + /// </summary> + public readonly int Major; + + /// <summary> + /// LibUsb-Win32 Minor version + /// </summary> + public readonly int Minor; + + /// <summary> + /// LibUsb-Win32 Micro version + /// </summary> + public readonly int Micro; + + /// <summary> + /// LibUsb-Win32 Nano version + /// </summary> + public readonly int Nano; + + /// <summary> + /// The LibUsbDotNet - LibUsb-Win32 binary mod code. if not running the LibUsbDotNet LibUsb-Win32 modified kernel driver, this value is 0. + /// </summary> + public readonly int BcdLibUsbDotNetKernelMod; + + ///<summary> + ///The full LibUsb-Win32 kernel driver version (libusb0.sys). + ///</summary> + /// + ///<returns> + ///A <see cref="System.String"/> containing the full LibUsb-Win32 version. + ///</returns> + public override string ToString() { return string.Format("{0}.{1}.{2}.{3}", Major, Minor, Micro, Nano); } + } + [StructLayout(LayoutKind.Explicit, Pack = 1, Size = sizeof(int) * 6)] + struct LibUsbRequest { + public static int Size = Marshal.SizeOf(typeof(LibUsbRequest)); + [FieldOffset(0)] + public int Timeout; // = UsbConstants.DEFAULT_TIMEOUT; + + #region Union Struct + + [FieldOffset(sizeof(int))] + public Control Control; + + [FieldOffset(sizeof(int))] + public Config Config; + + [FieldOffset(sizeof(int))] + public Debug Debug; + + [FieldOffset(sizeof(int))] + public Descriptor Descriptor; + + [FieldOffset(sizeof(int))] + public Endpoint Endpoint; + + [FieldOffset(sizeof(int))] + public Feature Feature; + + [FieldOffset(sizeof(int))] + public Iface Iface; + + [FieldOffset(sizeof(int))] + public Status Status; + + [FieldOffset(sizeof(int))] + public Vendor Vendor; + + [FieldOffset(sizeof(int))] + public UsbKernelVersion Version; + + [FieldOffset(sizeof(int))] + public DeviceProperty DeviceProperty; + + [FieldOffset(sizeof(int))] + public DeviceRegKey DeviceRegKey; + + [FieldOffset(sizeof(int))] + public BusQueryID BusQueryID; + #endregion + + public Byte[] Bytes { + get { + Byte[] rtn = new byte[Size]; + + for (int i = 0; i < Size; i++) + rtn[i] = Marshal.ReadByte(this, i); + + return rtn; + } + } + + + public void RequestConfigDescriptor(int index) { + Timeout = UsbConstants.DEFAULT_TIMEOUT; + + int value = ((int)UsbDescriptorType.Configuration << 8) + index; + + Descriptor.Recipient = (byte)UsbEndpointDirection.EndpointIn & 0x1F; + Descriptor.Type = (value >> 8) & 0xFF; + Descriptor.Index = value & 0xFF; + Descriptor.LangID = 0; + } + + public void RequestStringDescriptor(int index, short langid) { + Timeout = UsbConstants.DEFAULT_TIMEOUT; + + int value = ((int)UsbDescriptorType.String << 8) + index; + + Descriptor.Recipient = (byte)UsbEndpointDirection.EndpointIn & 0x1F; + Descriptor.Type = value >> 8 & 0xFF; + Descriptor.Index = value & 0xFF; + Descriptor.LangID = langid; + } + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct Descriptor { + public int Type; + public int Index; + public int LangID; + public int Recipient; + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct Config { + public int ID; + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct Control { + public byte RequestType; + public byte Request; + public ushort Value; + public ushort Index; + public ushort Length; + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct DeviceProperty { + public int ID; + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct Iface { + public int ID; + public int AlternateID; + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct Endpoint { + public int ID; + public int PacketSize; + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct Vendor { + public int Type; + public int Recipient; + public int Request; + public int ID; + public int Index; + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct Feature { + public int Recipient; + public int ID; + public int Index; + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct Status { + public int Recipient; + public int Index; + public int ID; + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct Debug { + public int Level; + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct DeviceRegKey { + public int KeyType; + public int NameOffset; + public int ValueOffset; + public int ValueLength; + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct BusQueryID { + public ushort IDType; + } + static class LibUsbIoCtl { + private const int FILE_ANY_ACCESS = 0; + private const int FILE_DEVICE_UNKNOWN = 0x00000022; + + private const int METHOD_BUFFERED = 0; + private const int METHOD_IN_DIRECT = 1; + private const int METHOD_OUT_DIRECT = 2; + private const int METHOD_NEITHER = 3; + + public static readonly int ABORT_ENDPOINT = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80F, METHOD_BUFFERED, FILE_ANY_ACCESS); + public static readonly int CLAIM_INTERFACE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x815, METHOD_BUFFERED, FILE_ANY_ACCESS); + public static readonly int CLEAR_FEATURE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x806, METHOD_BUFFERED, FILE_ANY_ACCESS); + public static readonly int CONTROL_TRANSFER = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x903, METHOD_BUFFERED, FILE_ANY_ACCESS); + + public static readonly int GET_CONFIGURATION = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS); + public static readonly int GET_CUSTOM_REG_PROPERTY = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x901, METHOD_BUFFERED, FILE_ANY_ACCESS); + public static readonly int GET_DESCRIPTOR = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x809, METHOD_BUFFERED, FILE_ANY_ACCESS); + public static readonly int GET_INTERFACE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x804, METHOD_BUFFERED, FILE_ANY_ACCESS); + public static readonly int GET_STATUS = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x807, METHOD_BUFFERED, FILE_ANY_ACCESS); + public static readonly int GET_VERSION = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x812, METHOD_BUFFERED, FILE_ANY_ACCESS); + public static readonly int GET_REG_PROPERTY = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x900, METHOD_BUFFERED, FILE_ANY_ACCESS); + public static readonly int INTERRUPT_OR_BULK_READ = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80B, METHOD_OUT_DIRECT, FILE_ANY_ACCESS); + public static readonly int INTERRUPT_OR_BULK_WRITE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80A, METHOD_IN_DIRECT, FILE_ANY_ACCESS); + public static readonly int ISOCHRONOUS_READ = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x814, METHOD_OUT_DIRECT, FILE_ANY_ACCESS); + public static readonly int ISOCHRONOUS_WRITE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x813, METHOD_IN_DIRECT, FILE_ANY_ACCESS); + public static readonly int RELEASE_INTERFACE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x816, METHOD_BUFFERED, FILE_ANY_ACCESS); + public static readonly int RESET_DEVICE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x810, METHOD_BUFFERED, FILE_ANY_ACCESS); + public static readonly int RESET_ENDPOINT = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80E, METHOD_BUFFERED, FILE_ANY_ACCESS); + public static readonly int SET_CONFIGURATION = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS); + public static readonly int SET_DEBUG_LEVEL = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x811, METHOD_BUFFERED, FILE_ANY_ACCESS); + public static readonly int SET_DESCRIPTOR = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x808, METHOD_BUFFERED, FILE_ANY_ACCESS); + public static readonly int SET_FEATURE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x805, METHOD_BUFFERED, FILE_ANY_ACCESS); + public static readonly int SET_INTERFACE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS); + public static readonly int VENDOR_READ = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80D, METHOD_BUFFERED, FILE_ANY_ACCESS); + public static readonly int VENDOR_WRITE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80C, METHOD_BUFFERED, FILE_ANY_ACCESS); + + private static int CTL_CODE(int DeviceType, int Function, int Method, int Access) { return ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method); } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Communication/LibUsb1/LibUsb1Device.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,92 @@ +using System; + +namespace UCIS.USBLib.Communication.LibUsb1 { + public unsafe class LibUsb1Device : UsbInterface, IUsbDevice { + libusb_device Device; + libusb_device_handle Handle; + //Boolean KernelDriverWasAttached = false; + public IUsbDeviceRegistry Registry { get; private set; } + internal LibUsb1Device(libusb_device device, LibUsb1Registry registry) { + this.Device = device; + this.Registry = registry; + int ret = libusb1.libusb_open(Device, out Handle); + if (ret != 0) throw new Exception("libusb_open returned " + ret.ToString()); + } + + public override void Close() { + if (Handle != null) Handle.Close(); + } + + public override int BulkWrite(byte endpoint, byte[] buffer, int offset, int length) { + return BulkTransfer(endpoint, buffer, offset, length); + } + public override int BulkRead(byte endpoint, byte[] buffer, int offset, int length) { + return BulkTransfer(endpoint, buffer, offset, length); + } + private int BulkTransfer(byte endpoint, byte[] buffer, int offset, int length) { + if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer length"); + if (length == 0) return 0; + fixed (Byte* b = buffer) { + int ret = libusb1.libusb_bulk_transfer(Handle, endpoint, b + offset, length, out length, 0); + if (ret < 0) throw new Exception("libusb_bulk_transfer returned " + ret.ToString()); + } + return length; + } + + public override int InterruptWrite(byte endpoint, byte[] buffer, int offset, int length) { + return InterruptTransfer(endpoint, buffer, offset, length); + } + public override int InterruptRead(byte endpoint, byte[] buffer, int offset, int length) { + return InterruptTransfer(endpoint, buffer, offset, length); + } + private int InterruptTransfer(byte endpoint, byte[] buffer, int offset, int length) { + if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer length"); + if (length == 0) return 0; + fixed (Byte* b = buffer) { + int ret = libusb1.libusb_interrupt_transfer(Handle, endpoint, b + offset, length, out length, 0); + if (ret < 0) throw new Exception("libusb_interrupt_transfer returned " + ret.ToString()); + } + return length; + } + + public override int ControlWrite(UsbControlRequestType requestType, byte request, short value, short index, byte[] buffer, int offset, int length) { + return ControlTransfer(requestType, request, value, index, buffer, offset, length); + } + public override int ControlRead(UsbControlRequestType requestType, byte request, short value, short index, byte[] buffer, int offset, int length) { + return ControlTransfer(requestType, request, value, index, buffer, offset, length); + } + private int ControlTransfer(UsbControlRequestType requestType, byte request, short value, short index, byte[] buffer, int offset, int length) { + if (buffer == null) buffer = new Byte[0]; + if (offset < 0 || length < 0 || length > ushort.MaxValue || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length"); + fixed (Byte* b = buffer) { + int ret = libusb1.libusb_control_transfer(Handle, (Byte)requestType, request, (ushort)value, (ushort)index, b + offset, (ushort)length, 0); + if (ret < 0) throw new Exception("libusb_control_transfer returned " + ret.ToString()); + return ret; + } + } + + public override byte Configuration { + get { return base.Configuration; } + set { + if (value == base.Configuration) return; + for (int i = 0; i < 16; i++) libusb1.libusb_detach_kernel_driver(Handle, i); + int ret = libusb1.libusb_set_configuration(Handle, value); + if (ret != 0) throw new Exception("libusb_set_configuration returned " + ret.ToString()); + } + } + public void ClaimInterface(int interfaceID) { + int ret = libusb1.libusb_detach_kernel_driver(Handle, interfaceID); + ret = libusb1.libusb_claim_interface(Handle, interfaceID); + if (ret != 0) throw new Exception("libusb_claim_interface returned " + ret.ToString()); + } + public void ReleaseInterface(int interfaceID) { + int ret = libusb1.libusb_release_interface(Handle, interfaceID); + if (ret != 0) throw new Exception("libusb_release_interface returned " + ret.ToString()); + ret = libusb1.libusb_attach_kernel_driver(Handle, interfaceID); + } + public void ResetDevice() { + int ret = libusb1.libusb_reset_device(Handle); + if (ret != 0) throw new Exception("libusb_reset_device returned " + ret.ToString()); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Communication/LibUsb1/LibUsb1Registry.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace UCIS.USBLib.Communication.LibUsb1 { + public class LibUsb1Registry : IUsbDeviceRegistry { + static libusb_context Context; + + libusb_device Device; + libusb1.libusb_device_descriptor? DeviceDescriptor = null; + + public unsafe static List<LibUsb1Registry> DeviceList { + get { + List<LibUsb1Registry> deviceList = new List<LibUsb1Registry>(); + if (Context == null) { + int ret = libusb1.libusb_init(out Context); + if (ret != 0) throw new Exception("libusb_init returned " + ret.ToString()); + } + IntPtr* list; + IntPtr count = libusb1.libusb_get_device_list(Context, out list); + for (IntPtr* item = list; *item != IntPtr.Zero; item++) { + deviceList.Add(new LibUsb1Registry(new libusb_device(*item, true))); + } + libusb1.libusb_free_device_list(list, 0); + return deviceList; + } + } + + private LibUsb1Registry(libusb_device device) { + this.Device = device; + } + private libusb1.libusb_device_descriptor GetDeviceDescriptor() { + if (DeviceDescriptor == null) { + libusb1.libusb_device_descriptor descriptor; + int ret = libusb1.libusb_get_device_descriptor(Device, out descriptor); + if (ret < 0) throw new Exception("libusb_get_device_descriptor returned " + ret.ToString()); + DeviceDescriptor = descriptor; + } + return DeviceDescriptor.Value; + } + + public int Vid { get { return GetDeviceDescriptor().idVendor; } } + public int Pid { get { return GetDeviceDescriptor().idProduct; } } + public byte InterfaceID { get { return 0; } } + + public string Name { + get { + byte iProduct = GetDeviceDescriptor().iProduct; + libusb_device_handle handle; + int ret = libusb1.libusb_open(Device, out handle); + if (ret != 0) return null; + if (ret != 0) throw new Exception("libusb_open returned " + ret.ToString()); + StringBuilder data = new StringBuilder(1024); + ret = libusb1.libusb_get_string_descriptor_ascii(handle, iProduct, data, data.Capacity); + if (ret < 0) throw new Exception("libusb_get_string_descriptor_ascii returned " + ret.ToString()); + handle.Close(); + return data.ToString(); + } + } + public string Manufacturer { + get { + byte iProduct = GetDeviceDescriptor().iManufacturer; + libusb_device_handle handle; + int ret = libusb1.libusb_open(Device, out handle); + if (ret != 0) return null; + if (ret != 0) throw new Exception("libusb_open returned " + ret.ToString()); + StringBuilder data = new StringBuilder(1024); + ret = libusb1.libusb_get_string_descriptor_ascii(handle, iProduct, data, data.Capacity); + if (ret < 0) throw new Exception("libusb_get_string_descriptor_ascii returned " + ret.ToString()); + handle.Close(); + return data.ToString(); + } + } + public string FullName { + get { + libusb1.libusb_device_descriptor descriptor = GetDeviceDescriptor(); + String mfg = null, prod = null; + libusb_device_handle handle; + int ret = libusb1.libusb_open(Device, out handle); + if (ret != 0) return null; + if (ret != 0) throw new Exception("libusb_open returned " + ret.ToString()); + if (descriptor.iManufacturer != 0) { + StringBuilder data = new StringBuilder(1024); + ret = libusb1.libusb_get_string_descriptor_ascii(handle, descriptor.iManufacturer, data, data.Capacity); + if (ret < 0) throw new Exception("libusb_get_string_descriptor_ascii returned " + ret.ToString()); + mfg = data.ToString(); + } + if (descriptor.iProduct != 0) { + StringBuilder data = new StringBuilder(1024); + ret = libusb1.libusb_get_string_descriptor_ascii(handle, descriptor.iProduct, data, data.Capacity); + if (ret < 0) throw new Exception("libusb_get_string_descriptor_ascii returned " + ret.ToString()); + prod = data.ToString(); + } + handle.Close(); + if (mfg == null && prod == null) return null; + if (mfg == null) return prod; + if (prod == null) return mfg; + return mfg + " - " + prod; + } + } + public Byte BusNumber { + get { + return libusb1.libusb_get_bus_number(Device); + } + } + public Byte DeviceAddress { + get { + return libusb1.libusb_get_device_address(Device); + } + } + public String SymbolicName { get { return String.Format("libusb;bus={0};address={1}", BusNumber, DeviceAddress); } } + IDictionary<String, Object> IUsbDeviceRegistry.DeviceProperties { get { return null; } } + public LibUsb1Device Open() { + return new LibUsb1Device(Device, this); + } + IUsbDevice IUsbDeviceRegistry.Open() { + return Open(); + } + + public override bool Equals(object obj) { + LibUsb1Registry r = obj as LibUsb1Registry; + if (r == null) return false; + return r.Device.DangerousGetHandle() == Device.DangerousGetHandle(); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Communication/LibUsb1/libusb1.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,717 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; +using Microsoft.Win32.SafeHandles; +using ssize_t = System.IntPtr; + +namespace UCIS.USBLib.Communication.LibUsb1 { + class libusb_context : SafeHandleZeroOrMinusOneIsInvalid { + public libusb_context() : base(true) { } + protected override bool ReleaseHandle() { + libusb1.libusb_exit(handle); + return true; + } + } + class libusb_device : SafeHandleZeroOrMinusOneIsInvalid { + public libusb_device() : base(true) { } + public libusb_device(IntPtr handle, Boolean ownsHandle) : base(ownsHandle) { SetHandle(handle); } + protected override bool ReleaseHandle() { + libusb1.libusb_unref_device(handle); + return true; + } + } + class libusb_device_handle : SafeHandleZeroOrMinusOneIsInvalid { + public libusb_device_handle() : base(true) { } + protected override bool ReleaseHandle() { + libusb1.libusb_close(handle); + return true; + } + } + unsafe static class libusb1 { + const CallingConvention LIBUSB1_CC = CallingConvention.Winapi; + const String LIBUSB1_DLL = "libusb-1.0.dll"; + /* Device and/or Interface Class codes */ + enum libusb_class_code { + /** In the context of a \ref libusb_device_descriptor "device descriptor", + * this bDeviceClass value indicates that each interface specifies its + * own class information and all interfaces operate independently. + */ + LIBUSB_CLASS_PER_INTERFACE = 0, + + /** Audio class */ + LIBUSB_CLASS_AUDIO = 1, + + /** Communications class */ + LIBUSB_CLASS_COMM = 2, + + /** Human Interface Device class */ + LIBUSB_CLASS_HID = 3, + + /** Physical */ + LIBUSB_CLASS_PHYSICAL = 5, + + /** Printer class */ + LIBUSB_CLASS_PRINTER = 7, + + /** Image class */ + LIBUSB_CLASS_PTP = 6, /* legacy name from libusb-0.1 usb.h */ + LIBUSB_CLASS_IMAGE = 6, + + /** Mass storage class */ + LIBUSB_CLASS_MASS_STORAGE = 8, + + /** Hub class */ + LIBUSB_CLASS_HUB = 9, + + /** Data class */ + LIBUSB_CLASS_DATA = 10, + + /** Smart Card */ + LIBUSB_CLASS_SMART_CARD = 0x0b, + + /** Content Security */ + LIBUSB_CLASS_CONTENT_SECURITY = 0x0d, + + /** Video */ + LIBUSB_CLASS_VIDEO = 0x0e, + + /** Personal Healthcare */ + LIBUSB_CLASS_PERSONAL_HEALTHCARE = 0x0f, + + /** Diagnostic Device */ + LIBUSB_CLASS_DIAGNOSTIC_DEVICE = 0xdc, + + /** Wireless class */ + LIBUSB_CLASS_WIRELESS = 0xe0, + + /** Application class */ + LIBUSB_CLASS_APPLICATION = 0xfe, + + /** Class is vendor-specific */ + LIBUSB_CLASS_VENDOR_SPEC = 0xff + } + + /* Descriptor types as defined by the USB specification. */ + enum libusb_descriptor_type { + /** Device descriptor. See libusb_device_descriptor. */ + LIBUSB_DT_DEVICE = 0x01, + + /** Configuration descriptor. See libusb_config_descriptor. */ + LIBUSB_DT_CONFIG = 0x02, + + /** String descriptor */ + LIBUSB_DT_STRING = 0x03, + + /** Interface descriptor. See libusb_interface_descriptor. */ + LIBUSB_DT_INTERFACE = 0x04, + + /** Endpoint descriptor. See libusb_endpoint_descriptor. */ + LIBUSB_DT_ENDPOINT = 0x05, + + /** HID descriptor */ + LIBUSB_DT_HID = 0x21, + + /** HID report descriptor */ + LIBUSB_DT_REPORT = 0x22, + + /** Physical descriptor */ + LIBUSB_DT_PHYSICAL = 0x23, + + /** Hub descriptor */ + LIBUSB_DT_HUB = 0x29 + } + + /* Descriptor sizes per descriptor type */ + const int LIBUSB_DT_DEVICE_SIZE = 18; + const int LIBUSB_DT_CONFIG_SIZE = 9; + const int LIBUSB_DT_INTERFACE_SIZE = 9; + const int LIBUSB_DT_ENDPOINT_SIZE = 7; + const int LIBUSB_DT_ENDPOINT_AUDIO_SIZE = 9; /* Audio extension */ + const int LIBUSB_DT_HUB_NONVAR_SIZE = 7; + + const int LIBUSB_ENDPOINT_ADDRESS_MASK = 0x0f; /* in bEndpointAddress */ + const int LIBUSB_ENDPOINT_DIR_MASK = 0x80; + + /* Endpoint direction. Values for bit 7 of the + * \ref libusb_endpoint_descriptor::bEndpointAddress "endpoint address" scheme. + */ + enum libusb_endpoint_direction { + /** In: device-to-host */ + LIBUSB_ENDPOINT_IN = 0x80, + + /** Out: host-to-device */ + LIBUSB_ENDPOINT_OUT = 0x00 + } + + const int LIBUSB_TRANSFER_TYPE_MASK = 0x03; /* in bmAttributes */ + + /* Endpoint transfer type. Values for bits 0:1 of the + * \ref libusb_endpoint_descriptor::bmAttributes "endpoint attributes" field. + */ + enum libusb_transfer_type { + /** Control endpoint */ + LIBUSB_TRANSFER_TYPE_CONTROL = 0, + + /** Isochronous endpoint */ + LIBUSB_TRANSFER_TYPE_ISOCHRONOUS = 1, + + /** Bulk endpoint */ + LIBUSB_TRANSFER_TYPE_BULK = 2, + + /** Interrupt endpoint */ + LIBUSB_TRANSFER_TYPE_INTERRUPT = 3 + } + + /* Standard requests, as defined in table 9-3 of the USB2 specifications */ + enum libusb_standard_request { + /** Request status of the specific recipient */ + LIBUSB_REQUEST_GET_STATUS = 0x00, + + /** Clear or disable a specific feature */ + LIBUSB_REQUEST_CLEAR_FEATURE = 0x01, + + /* 0x02 is reserved */ + + /** Set or enable a specific feature */ + LIBUSB_REQUEST_SET_FEATURE = 0x03, + + /* 0x04 is reserved */ + + /** Set device address for all future accesses */ + LIBUSB_REQUEST_SET_ADDRESS = 0x05, + + /** Get the specified descriptor */ + LIBUSB_REQUEST_GET_DESCRIPTOR = 0x06, + + /** Used to update existing descriptors or add new descriptors */ + LIBUSB_REQUEST_SET_DESCRIPTOR = 0x07, + + /** Get the current device configuration value */ + LIBUSB_REQUEST_GET_CONFIGURATION = 0x08, + + /** Set device configuration */ + LIBUSB_REQUEST_SET_CONFIGURATION = 0x09, + + /** Return the selected alternate setting for the specified interface */ + LIBUSB_REQUEST_GET_INTERFACE = 0x0A, + + /** Select an alternate interface for the specified interface */ + LIBUSB_REQUEST_SET_INTERFACE = 0x0B, + + /** Set then report an endpoint's synchronization frame */ + LIBUSB_REQUEST_SYNCH_FRAME = 0x0C + } + + /* Request type bits of the + * \ref libusb_control_setup::bmRequestType "bmRequestType" field in control + * transfers. */ + enum libusb_request_type { + /** Standard */ + LIBUSB_REQUEST_TYPE_STANDARD = (0x00 << 5), + + /** Class */ + LIBUSB_REQUEST_TYPE_CLASS = (0x01 << 5), + + /** Vendor */ + LIBUSB_REQUEST_TYPE_VENDOR = (0x02 << 5), + + /** Reserved */ + LIBUSB_REQUEST_TYPE_RESERVED = (0x03 << 5) + } + + /* Recipient bits of the + * \ref libusb_control_setup::bmRequestType "bmRequestType" field in control + * transfers. Values 4 through 31 are reserved. */ + enum libusb_request_recipient { + /** Device */ + LIBUSB_RECIPIENT_DEVICE = 0x00, + + /** Interface */ + LIBUSB_RECIPIENT_INTERFACE = 0x01, + + /** Endpoint */ + LIBUSB_RECIPIENT_ENDPOINT = 0x02, + + /** Other */ + LIBUSB_RECIPIENT_OTHER = 0x03 + } + + const int LIBUSB_ISO_SYNC_TYPE_MASK = 0x0C; + + /* Synchronization type for isochronous endpoints. Values for bits 2:3 of the + * \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in + * libusb_endpoint_descriptor. + */ + enum libusb_iso_sync_type { + /** No synchronization */ + LIBUSB_ISO_SYNC_TYPE_NONE = 0, + + /** Asynchronous */ + LIBUSB_ISO_SYNC_TYPE_ASYNC = 1, + + /** Adaptive */ + LIBUSB_ISO_SYNC_TYPE_ADAPTIVE = 2, + + /** Synchronous */ + LIBUSB_ISO_SYNC_TYPE_SYNC = 3 + } + const int LIBUSB_ISO_USAGE_TYPE_MASK = 0x30; + + /* Usage type for isochronous endpoints. Values for bits 4:5 of the + * \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in + * libusb_endpoint_descriptor. + */ + enum libusb_iso_usage_type { + /** Data endpoint */ + LIBUSB_ISO_USAGE_TYPE_DATA = 0, + + /** Feedback endpoint */ + LIBUSB_ISO_USAGE_TYPE_FEEDBACK = 1, + + /** Implicit feedback Data endpoint */ + LIBUSB_ISO_USAGE_TYPE_IMPLICIT = 2 + } + + /* A structure representing the standard USB device descriptor. This + * descriptor is documented in section 9.6.1 of the USB 2.0 specification. + * All multiple-byte fields are represented in host-endian format. + */ + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct libusb_device_descriptor { + /** Size of this descriptor (in bytes) */ + public Byte bLength; + + /** Descriptor type. Will have value + * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE LIBUSB_DT_DEVICE in this + * context. */ + public Byte bDescriptorType; + + /** USB specification release number in binary-coded decimal. A value of + * 0x0200 indicates USB 2.0, 0x0110 indicates USB 1.1, etc. */ + public UInt16 bcdUSB; + + /** USB-IF class code for the device. See \ref libusb_class_code. */ + public Byte bDeviceClass; + + /** USB-IF subclass code for the device, qualified by the bDeviceClass + * value */ + public Byte bDeviceSubClass; + + /** USB-IF protocol code for the device, qualified by the bDeviceClass and + * bDeviceSubClass values */ + public Byte bDeviceProtocol; + + /** Maximum packet size for endpoint 0 */ + public Byte bMaxPacketSize0; + + /** USB-IF vendor ID */ + public UInt16 idVendor; + + /** USB-IF product ID */ + public UInt16 idProduct; + + /** Device release number in binary-coded decimal */ + public UInt16 bcdDevice; + + /** Index of string descriptor describing manufacturer */ + public Byte iManufacturer; + + /** Index of string descriptor describing product */ + public Byte iProduct; + + /** Index of string descriptor containing device serial number */ + public Byte iSerialNumber; + + /** Number of possible configurations */ + public Byte bNumConfigurations; + } + + /* A structure representing the standard USB endpoint descriptor. This + * descriptor is documented in section 9.6.3 of the USB 2.0 specification. + * All multiple-byte fields are represented in host-endian format. + */ + [StructLayout(LayoutKind.Sequential)] + struct libusb_endpoint_descriptor { + /** Size of this descriptor (in bytes) */ + Byte bLength; + + /** Descriptor type. Will have value + * \ref libusb_descriptor_type::LIBUSB_DT_ENDPOINT LIBUSB_DT_ENDPOINT in + * this context. */ + Byte bDescriptorType; + + /** The address of the endpoint described by this descriptor. Bits 0:3 are + * the endpoint number. Bits 4:6 are reserved. Bit 7 indicates direction, + * see \ref libusb_endpoint_direction. + */ + Byte bEndpointAddress; + + /** Attributes which apply to the endpoint when it is configured using + * the bConfigurationValue. Bits 0:1 determine the transfer type and + * correspond to \ref libusb_transfer_type. Bits 2:3 are only used for + * isochronous endpoints and correspond to \ref libusb_iso_sync_type. + * Bits 4:5 are also only used for isochronous endpoints and correspond to + * \ref libusb_iso_usage_type. Bits 6:7 are reserved. + */ + Byte bmAttributes; + + /** Maximum packet size this endpoint is capable of sending/receiving. */ + UInt16 wMaxPacketSize; + + /** Interval for polling endpoint for data transfers. */ + Byte bInterval; + + /** For audio devices only: the rate at which synchronization feedback + * is provided. */ + Byte bRefresh; + + /** For audio devices only: the address if the synch endpoint */ + Byte bSynchAddress; + + /** Extra descriptors. If libusb encounters unknown endpoint descriptors, + * it will store them here, should you wish to parse them. */ + byte* extra; + + /** Length of the extra descriptors, in bytes. */ + int extra_length; + } + + /* A structure representing the standard USB interface descriptor. This + * descriptor is documented in section 9.6.5 of the USB 2.0 specification. + * All multiple-byte fields are represented in host-endian format. + */ + [StructLayout(LayoutKind.Sequential)] + struct libusb_interface_descriptor { + /** Size of this descriptor (in bytes) */ + Byte bLength; + + /** Descriptor type. Will have value + * \ref libusb_descriptor_type::LIBUSB_DT_INTERFACE LIBUSB_DT_INTERFACE + * in this context. */ + Byte bDescriptorType; + + /** Number of this interface */ + Byte bInterfaceNumber; + + /** Value used to select this alternate setting for this interface */ + Byte bAlternateSetting; + + /** Number of endpoints used by this interface (excluding the control + * endpoint). */ + Byte bNumEndpoints; + + /** USB-IF class code for this interface. See \ref libusb_class_code. */ + Byte bInterfaceClass; + + /** USB-IF subclass code for this interface, qualified by the + * bInterfaceClass value */ + Byte bInterfaceSubClass; + + /** USB-IF protocol code for this interface, qualified by the + * bInterfaceClass and bInterfaceSubClass values */ + Byte bInterfaceProtocol; + + /** Index of string descriptor describing this interface */ + Byte iInterface; + + /** Array of endpoint descriptors. This length of this array is determined + * by the bNumEndpoints field. */ + libusb_endpoint_descriptor* endpoint; + + /** Extra descriptors. If libusb encounters unknown interface descriptors, + * it will store them here, should you wish to parse them. */ + Byte* extra; + + /** Length of the extra descriptors, in bytes. */ + int extra_length; + } + + /* A collection of alternate settings for a particular USB interface. + */ + [StructLayout(LayoutKind.Sequential)] + struct libusb_interface { + /** Array of interface descriptors. The length of this array is determined + * by the num_altsetting field. */ + libusb_interface_descriptor* altsetting; + + /** The number of alternate settings that belong to this interface */ + int num_altsetting; + } + + /* A structure representing the standard USB configuration descriptor. This + * descriptor is documented in section 9.6.3 of the USB 2.0 specification. + * All multiple-byte fields are represented in host-endian format. + */ + struct libusb_config_descriptor { + /** Size of this descriptor (in bytes) */ + Byte bLength; + + /** Descriptor type. Will have value + * \ref libusb_descriptor_type::LIBUSB_DT_CONFIG LIBUSB_DT_CONFIG + * in this context. */ + Byte bDescriptorType; + + /** Total length of data returned for this configuration */ + Byte wTotalLength; + + /** Number of interfaces supported by this configuration */ + Byte bNumInterfaces; + + /** Identifier value for this configuration */ + Byte bConfigurationValue; + + /** Index of string descriptor describing this configuration */ + Byte iConfiguration; + + /** Configuration characteristics */ + Byte bmAttributes; + + /** Maximum power consumption of the USB device from this bus in this + * configuration when the device is fully opreation. Expressed in units + * of 2 mA. */ + Byte MaxPower; + + /** Array of interfaces supported by this configuration. The length of + * this array is determined by the bNumInterfaces field. */ + libusb_interface* @interface; + + /** Extra descriptors. If libusb encounters unknown configuration + * descriptors, it will store them here, should you wish to parse them. */ + Byte* extra; + + /** Length of the extra descriptors, in bytes. */ + int extra_length; + } + + /* Setup packet for control transfers. */ + [StructLayout(LayoutKind.Sequential, Size = 8)] + struct libusb_control_setup { + /** Request type. Bits 0:4 determine recipient, see + * \ref libusb_request_recipient. Bits 5:6 determine type, see + * \ref libusb_request_type. Bit 7 determines data transfer direction, see + * \ref libusb_endpoint_direction. + */ + Byte bmRequestType; + + /** Request. If the type bits of bmRequestType are equal to + * \ref libusb_request_type::LIBUSB_REQUEST_TYPE_STANDARD + * "LIBUSB_REQUEST_TYPE_STANDARD" then this field refers to + * \ref libusb_standard_request. For other cases, use of this field is + * application-specific. */ + Byte bRequest; + + /** Value. Varies according to request */ + UInt16 wValue; + + /** Index. Varies according to request, typically used to pass an index + * or offset */ + UInt16 wIndex; + + /** Number of bytes to transfer */ + UInt16 wLength; + } + + const int LIBUSB_CONTROL_SETUP_SIZE = 8; //sizeof(libusb_control_setup); // Marshal.SizeOf(typeof(libusb_control_setup)); + + /* Structure representing a libusb session. The concept of individual libusb + * sessions allows for your program to use two libraries (or dynamically + * load two modules) which both independently use libusb. This will prevent + * interference between the individual libusb users - for example + * libusb_set_debug() will not affect the other user of the library, and + * libusb_exit() will not destroy resources that the other user is still + * using. + * + * Sessions are created by libusb_init() and destroyed through libusb_exit(). + * If your application is guaranteed to only ever include a single libusb + * user (i.e. you), you do not have to worry about contexts: pass NULL in + * every function call where a context is required. The default context + * will be used. + * + * For more information, see \ref contexts. + */ + + /* Structure representing a USB device detected on the system. This is an + * opaque type for which you are only ever provided with a pointer, usually + * originating from libusb_get_device_list(). + * + * Certain operations can be performed on a device, but in order to do any + * I/O you will have to first obtain a device handle using libusb_open(). + * + * Devices are reference counted with libusb_device_ref() and + * libusb_device_unref(), and are freed when the reference count reaches 0. + * New devices presented by libusb_get_device_list() have a reference count of + * 1, and libusb_free_device_list() can optionally decrease the reference count + * on all devices in the list. libusb_open() adds another reference which is + * later destroyed by libusb_close(). + */ + + /* Structure representing a handle on a USB device. This is an opaque type for + * which you are only ever provided with a pointer, usually originating from + * libusb_open(). + * + * A device handle is used to perform I/O and other operations. When finished + * with a device handle, you should call libusb_close(). + */ + + /* Speed codes. Indicates the speed at which the device is operating. */ + enum libusb_speed { + /** The OS doesn't report or know the device speed. */ + LIBUSB_SPEED_UNKNOWN = 0, + + /** The device is operating at low speed (1.5MBit/s). */ + LIBUSB_SPEED_LOW = 1, + + /** The device is operating at full speed (12MBit/s). */ + LIBUSB_SPEED_FULL = 2, + + /** The device is operating at high speed (480MBit/s). */ + LIBUSB_SPEED_HIGH = 3, + + /** The device is operating at super speed (5000MBit/s). */ + LIBUSB_SPEED_SUPER = 4, + } + + /* Error codes. Most libusb functions return 0 on success or one of these + * codes on failure. + * You can call \ref libusb_error_name() to retrieve a string representation + * of an error code. + */ + enum libusb_error { + /** Success (no error) */ + LIBUSB_SUCCESS = 0, + + /** Input/output error */ + LIBUSB_ERROR_IO = -1, + + /** Invalid parameter */ + LIBUSB_ERROR_INVALID_PARAM = -2, + + /** Access denied (insufficient permissions) */ + LIBUSB_ERROR_ACCESS = -3, + + /** No such device (it may have been disconnected) */ + LIBUSB_ERROR_NO_DEVICE = -4, + + /** Entity not found */ + LIBUSB_ERROR_NOT_FOUND = -5, + + /** Resource busy */ + LIBUSB_ERROR_BUSY = -6, + + /** Operation timed out */ + LIBUSB_ERROR_TIMEOUT = -7, + + /** Overflow */ + LIBUSB_ERROR_OVERFLOW = -8, + + /** Pipe error */ + LIBUSB_ERROR_PIPE = -9, + + /** System call interrupted (perhaps due to signal) */ + LIBUSB_ERROR_INTERRUPTED = -10, + + /** Insufficient memory */ + LIBUSB_ERROR_NO_MEM = -11, + + /** Operation not supported or unimplemented on this platform */ + LIBUSB_ERROR_NOT_SUPPORTED = -12, + + /* NB! Remember to update libusb_error_name() + when adding new error codes here. */ + + /** Other error */ + LIBUSB_ERROR_OTHER = -99 + } + + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + public static extern int libusb_init(out libusb_context ctx); + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + public static extern void libusb_exit(IntPtr ctx); + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + static extern void libusb_set_debug(libusb_context ctx, int level); + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + static extern Byte* libusb_error_name(int errcode); + + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + public static extern ssize_t libusb_get_device_list(libusb_context ctx, out IntPtr* list); //libusb_device** list + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + public static extern void libusb_free_device_list(IntPtr* list, int unref_devices); + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + static extern libusb_device libusb_ref_device(libusb_device dev); + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + public static extern void libusb_unref_device(IntPtr dev); + + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + static extern int libusb_get_configuration(libusb_device_handle dev, out int config); + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + public static extern int libusb_get_device_descriptor(libusb_device dev, out libusb_device_descriptor desc); + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + static extern int libusb_get_active_config_descriptor(libusb_device dev, libusb_config_descriptor** config); + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + static extern int libusb_get_config_descriptor(libusb_device dev, Byte config_index, libusb_config_descriptor** config); + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + static extern int libusb_get_config_descriptor_by_value(libusb_device dev, Byte bConfigurationValue, libusb_config_descriptor** config); + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + static extern void libusb_free_config_descriptor(libusb_config_descriptor* config); + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + public static extern Byte libusb_get_bus_number(libusb_device dev); + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + public static extern Byte libusb_get_device_address(libusb_device dev); + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + static extern int libusb_get_device_speed(libusb_device dev); + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + static extern int libusb_get_max_packet_size(libusb_device dev, Byte endpoint); + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + static extern int libusb_get_max_iso_packet_size(libusb_device dev, Byte endpoint); + + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + public static extern int libusb_open(libusb_device dev, out libusb_device_handle handle); + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + public static extern void libusb_close(IntPtr dev_handle); + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + static extern libusb_device libusb_get_device(libusb_device_handle dev_handle); + + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + public static extern int libusb_set_configuration(libusb_device_handle dev, int configuration); + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + public static extern int libusb_claim_interface(libusb_device_handle dev, int interface_number); + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + public static extern int libusb_release_interface(libusb_device_handle dev, int interface_number); + + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + static extern libusb_device_handle libusb_open_device_with_vid_pid(libusb_context ctx, UInt16 vendor_id, UInt16 product_id); + + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + static extern int libusb_set_interface_alt_setting(libusb_device_handle dev, int interface_number, int alternate_setting); + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + static extern int libusb_clear_halt(libusb_device_handle dev, Byte endpoint); + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + public static extern int libusb_reset_device(libusb_device_handle dev); + + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + static extern int libusb_kernel_driver_active(libusb_device_handle dev, int interface_number); + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + public static extern int libusb_detach_kernel_driver(libusb_device_handle dev, int interface_number); + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + public static extern int libusb_attach_kernel_driver(libusb_device_handle dev, int interface_number); + + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + public static extern int libusb_control_transfer(libusb_device_handle dev_handle, + Byte request_type, Byte bRequest, UInt16 wValue, UInt16 wIndex, + Byte* data, UInt16 wLength, UInt32 timeout); + + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + public static extern int libusb_bulk_transfer(libusb_device_handle dev_handle, + Byte endpoint, Byte* data, int length, + out int actual_length, UInt32 timeout); + + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + public static extern int libusb_interrupt_transfer(libusb_device_handle dev_handle, + Byte endpoint, Byte* data, int length, + out int actual_length, UInt32 timeout); + + [DllImport(LIBUSB1_DLL, CallingConvention = LIBUSB1_CC)] + public static extern int libusb_get_string_descriptor_ascii(libusb_device_handle dev, + Byte desc_index, [MarshalAs(UnmanagedType.LPStr)] StringBuilder data, int length); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Communication/LibUsbDotNet.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,528 @@ +using System; +using System.Collections.ObjectModel; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Threading; +using System.Text; +using System.IO; +using LibUsbDotNet.Main; +using LibUsbDotNet.Info; +using LibUsbDotNet.Descriptors; +using UCIS.USBLib.Communication; +using LibUsb0Registry = UCIS.USBLib.Communication.LibUsb.LibUsb0Registry; +using LibUsb1Registry = UCIS.USBLib.Communication.LibUsb1.LibUsb1Registry; +using nIUsbDevice = UCIS.USBLib.Communication.IUsbDevice; +using nIUsbInterface = UCIS.USBLib.Communication.IUsbInterface; +using WinUsbRegistry = UCIS.USBLib.Communication.WinUsb.WinUsbRegistry; + +namespace LibUsbDotNet { + public class UsbDevice : IUsbDevice { + public nIUsbInterface Device { get; private set; } + public UsbDevice(nIUsbInterface dev) { + Device = dev; + } + public bool GetDescriptor(byte descriptorType, byte index, short langId, Byte[] buffer, int bufferLength, out int transferLength) { + try { + transferLength = Device.GetDescriptor(descriptorType, index, langId, buffer, 0, bufferLength); + return true; + } catch { + transferLength = 0; + return false; + } + } + public bool ControlTransfer(ref UsbSetupPacket setupPacket, Byte[] buffer, int bufferLength, out int lengthTransferred) { + if ((setupPacket.RequestType & 128) != 0) { + lengthTransferred = Device.ControlRead((UsbControlRequestType)setupPacket.RequestType, setupPacket.Request, setupPacket.Value, setupPacket.Index, buffer, 0, bufferLength); + } else { + lengthTransferred = Device.ControlWrite((UsbControlRequestType)setupPacket.RequestType, setupPacket.Request, setupPacket.Value, setupPacket.Index, buffer, 0, bufferLength); + } + return true; + } + public DriverModeType DriverMode { get { return DriverModeType.Unknown; } } + public enum DriverModeType { + Unknown, + LibUsb, + WinUsb, + MonoLibUsb, + LibUsbWinBack + } + public UsbEndpointWriter OpenEndpointWriter(WriteEndpointID writeEndpointID, EndpointType endpointType) { + return new UsbEndpointWriter(Device, (Byte)writeEndpointID, endpointType); + } + public UsbEndpointReader OpenEndpointReader(ReadEndpointID readEndpointID, int buffersize, EndpointType endpointType) { + UsbEndpointReader reader = new UsbEndpointReader(Device, (Byte)readEndpointID, endpointType); + reader.ReadBufferSize = buffersize; + return reader; + } + public void Close() { + Device.Dispose(); + } + public UsbDeviceInfo Info { get { return new UsbDeviceInfo(this); } } + public static IList<UsbRegistry> AllDevices { + get { + List<UsbRegistry> list = new List<UsbRegistry>(); + if (Environment.OSVersion.Platform == PlatformID.Win32NT) { + foreach (IUsbDeviceRegistry reg in WinUsbRegistry.DeviceList) list.Add(new UsbRegistry(reg)); + foreach (IUsbDeviceRegistry reg in LibUsb0Registry.DeviceList) list.Add(new UsbRegistry(reg)); + } else { + foreach (IUsbDeviceRegistry reg in LibUsb1Registry.DeviceList) list.Add(new UsbRegistry(reg)); + } + return list; + } + } + private SafeHandle Handle { get { return null; } } + public bool SetConfiguration(byte config) { + nIUsbDevice dev = Device as nIUsbDevice; + if (dev == null) return false; + try { + dev.Configuration = config; + return true; + } catch { + return false; + } + } + public bool ClaimInterface(int interfaceID) { + nIUsbDevice dev = Device as nIUsbDevice; + if (dev == null) return false; + try { + dev.ClaimInterface(interfaceID); + return true; + } catch { + return false; + } + } + public bool ReleaseInterface(int interfaceID) { + nIUsbDevice dev = Device as nIUsbDevice; + if (dev == null) return false; + try { + dev.ReleaseInterface(interfaceID); + return true; + } catch { + return false; + } + } + public IList<UsbConfigInfo> Configs { + get { + List<UsbConfigInfo> rtnConfigs = new List<UsbConfigInfo>(); + byte[] cfgBuffer = new byte[UsbConstants.MAX_CONFIG_SIZE]; + int iConfigs = Info.Descriptor.ConfigurationCount; + for (int iConfig = 0; iConfig < iConfigs; iConfig++) { + int iBytesTransmitted; + if (!GetDescriptor((byte)UsbDescriptorType.Configuration, 0, 0, cfgBuffer, cfgBuffer.Length, out iBytesTransmitted)) + throw new Exception("Could not read configuration descriptor"); + if (iBytesTransmitted < UsbConfigDescriptor.Size || cfgBuffer[1] != (byte)UsbDescriptorType.Configuration) + throw new Exception("GetDeviceConfigs: USB config descriptor is invalid."); + UsbConfigDescriptor configDescriptor = new UsbConfigDescriptor(); + Helper.BytesToObject(cfgBuffer, 0, Math.Min(UsbConfigDescriptor.Size, cfgBuffer[0]), configDescriptor); + if (configDescriptor.TotalLength != iBytesTransmitted) throw new Exception("GetDeviceConfigs: USB config descriptor length doesn't match the length received."); + List<byte[]> rawDescriptorList = new List<byte[]>(); + int iRawLengthPosition = configDescriptor.Length; + while (iRawLengthPosition < configDescriptor.TotalLength) { + byte[] rawDescriptor = new byte[cfgBuffer[iRawLengthPosition]]; + if (iRawLengthPosition + rawDescriptor.Length > iBytesTransmitted) throw new Exception("Descriptor length is out of range."); + Array.Copy(cfgBuffer, iRawLengthPosition, rawDescriptor, 0, rawDescriptor.Length); + rawDescriptorList.Add(rawDescriptor); + iRawLengthPosition += rawDescriptor.Length; + } + rtnConfigs.Add(new UsbConfigInfo(this, configDescriptor, ref rawDescriptorList)); + } + return rtnConfigs; + } + } + } + public interface IUsbDevice { + bool SetConfiguration(byte config); + bool ClaimInterface(int interfaceID); + bool ReleaseInterface(int interfaceID); + } + public class UsbEndpointWriter : IDisposable { + public nIUsbInterface Device { get; private set; } + public Byte EndpointID { get; private set; } + public EndpointType EndpointType { get; private set; } + public Byte EpNum { get { return EndpointID; } } + public UsbEndpointWriter(nIUsbInterface dev, byte epid, EndpointType eptype) { + Device = dev; + EndpointID = epid; + EndpointType = eptype; + } + public ErrorCode Write(byte[] buffer, int offset, int count, int timeout, out int transferLength) { + switch (EndpointType) { + case EndpointType.Bulk: transferLength = Device.BulkWrite(EndpointID, buffer, offset, count); break; + case EndpointType.Interrupt: transferLength = Device.InterruptWrite(EndpointID, buffer, offset, count); break; + default: transferLength = 0; return ErrorCode.Error; + } + return ErrorCode.Ok; + } + public void Dispose() { } + } + public class UsbEndpointReader : IDisposable { + public nIUsbInterface Device { get; private set; } + public Byte EndpointID { get; private set; } + public EndpointType EndpointType { get; private set; } + public Byte EpNum { get { return EndpointID; } } + public int ReadBufferSize { get; set; } + + public UsbEndpointReader(nIUsbInterface dev, byte epid, EndpointType eptype) { + Device = dev; + EndpointID = epid; + EndpointType = eptype; + ReadBufferSize = 4096; + } + public ErrorCode Read(byte[] buffer, int offset, int count, int timeout, out int transferLength) { + switch (EndpointType) { + case EndpointType.Bulk: transferLength = Device.BulkRead(EndpointID, buffer, offset, count); break; + case EndpointType.Interrupt: transferLength = Device.InterruptRead(EndpointID, buffer, offset, count); break; + default: transferLength = 0; return ErrorCode.Error; + } + return ErrorCode.Ok; + } + public void Dispose() { DataReceivedEnabled = false; } + + private bool mDataReceivedEnabled; + private Thread mReadThread; + + public virtual bool DataReceivedEnabled { + get { return mDataReceivedEnabled; } + set { + if (value != mDataReceivedEnabled) { + if (mDataReceivedEnabled) { + mReadThread.Abort(); + } else { + mDataReceivedEnabled = true; + mReadThread = new Thread(ReadDataProcess); + mReadThread.Start(); + } + } + } + } + + private void ReadDataProcess(object state) { + byte[] buffer = new byte[ReadBufferSize]; + try { + while (mDataReceivedEnabled) { + int transferLength; + Read(buffer, 0, buffer.Length, -1, out transferLength); + EventHandler<EndpointDataEventArgs> eh = DataReceived; + if (!ReferenceEquals(eh, null)) eh(this, new EndpointDataEventArgs(buffer, transferLength)); + } + } catch (Exception ex) { + if (ReadError != null) ReadError(this, new ErrorEventArgs(ex)); + } finally { + mDataReceivedEnabled = false; + } + } + + public event EventHandler<EndpointDataEventArgs> DataReceived; + public event ErrorEventHandler ReadError; + } +} +namespace LibUsbDotNet.Main { + public static class UsbConstants { + public const int MAX_CONFIG_SIZE = 4096; + public const int MAX_DEVICES = 128; + public const int MAX_ENDPOINTS = 32; + public const byte ENDPOINT_DIR_MASK = 0x80; + public const byte ENDPOINT_NUMBER_MASK = 0xf; + } + public static class Helper { + public static void BytesToObject(byte[] sourceBytes, int iStartIndex, int iLength, object destObject) { + GCHandle gch = GCHandle.Alloc(destObject, GCHandleType.Pinned); + IntPtr ptrDestObject = gch.AddrOfPinnedObject(); + Marshal.Copy(sourceBytes, iStartIndex, ptrDestObject, iLength); + gch.Free(); + } + public static string ToString(string sep0, string[] names, string sep1, object[] values, string sep2) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < names.Length; i++) sb.Append(sep0 + names[i] + sep1 + values[i] + sep2); + return sb.ToString(); + } + } + public class EndpointDataEventArgs : EventArgs { + internal EndpointDataEventArgs(byte[] bytes, int size) { + Buffer = bytes; + Count = size; + } + public byte[] Buffer { get; private set; } + public int Count { get; private set; } + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct UsbSetupPacket { + public byte RequestType; + public byte Request; + public short Value; + public short Index; + public short Length; + public UsbSetupPacket(byte requestType, byte request, short value, short index, short length) { + RequestType = requestType; + Request = request; + Value = value; + Index = index; + Length = length; + } + } + public enum UsbEndpointDirection : byte { + EndpointIn = 0x80, + EndpointOut = 0x00, + } + public enum UsbRequestType : byte { + TypeClass = (0x01 << 5), + TypeReserved = (0x03 << 5), + TypeStandard = (0x00 << 5), + TypeVendor = (0x02 << 5), + } + public enum WriteEndpointID : byte { + Ep01 = 0x01, + Ep02 = 0x02, + Ep03 = 0x03, + Ep04 = 0x04, + Ep05 = 0x05, + Ep06 = 0x06, + Ep07 = 0x07, + Ep08 = 0x08, + Ep09 = 0x09, + Ep10 = 0x0A, + Ep11 = 0x0B, + Ep12 = 0x0C, + Ep13 = 0x0D, + Ep14 = 0x0E, + Ep15 = 0x0F, + } + public enum ReadEndpointID : byte { + Ep01 = 0x81, + Ep02 = 0x82, + Ep03 = 0x83, + Ep04 = 0x84, + Ep05 = 0x85, + Ep06 = 0x86, + Ep07 = 0x87, + Ep08 = 0x88, + Ep09 = 0x89, + Ep10 = 0x8A, + Ep11 = 0x8B, + Ep12 = 0x8C, + Ep13 = 0x8D, + Ep14 = 0x8E, + Ep15 = 0x8F, + } + public enum UsbRequestRecipient : byte { + RecipDevice = 0x00, + RecipInterface = 0x01, + RecipEndpoint = 0x02, + RecipOther = 0x03, + } + public enum EndpointType : byte { + Control, + Isochronous, + Bulk, + Interrupt + } + public enum ErrorCode { + Ok = 0, + Error = 1, + } + public class UsbRegistry { + public IUsbDeviceRegistry Registry { get; private set; } + public UsbRegistry(IUsbDeviceRegistry reg) { + Registry = reg; + } + public int Vid { get { return Registry.Vid; } } + public int Pid { get { return Registry.Pid; } } + public int Rev { get { return 0; } } + public Boolean IsAlive { get { return true; } } + public Boolean Open(out UsbDevice hand) { + hand = new UsbDevice(Registry.Open()); + return true; + } + public IDictionary<String, Object> DeviceProperties { get { return Registry.DeviceProperties; } } + public String FullName { get { return Registry.FullName; } } + public String Name { get { return Registry.Name; } } + public String SymbolicName { get { return Registry.SymbolicName; } } + } +} +namespace LibUsbDotNet.Info { + public class UsbDeviceInfo { + private readonly UsbDeviceDescriptor mDeviceDescriptor; + internal UsbDevice mUsbDevice; + internal UsbDeviceInfo(UsbDevice usbDevice) { + mUsbDevice = usbDevice; + mDeviceDescriptor = new UsbDeviceDescriptor(); + Byte[] bytes = new Byte[UsbDeviceDescriptor.Size]; + int ret; + usbDevice.GetDescriptor((byte)UsbDescriptorType.Device, 0, 0, bytes, UsbDeviceDescriptor.Size, out ret); + Object asobj = mDeviceDescriptor; + Helper.BytesToObject(bytes, 0, ret, asobj); + mDeviceDescriptor = (UsbDeviceDescriptor)asobj; + } + public UsbDeviceDescriptor Descriptor { get { return mDeviceDescriptor; } } + public String ManufacturerString { + get { + if (Descriptor.ManufacturerStringIndex == 0) return null; + return mUsbDevice.Device.GetString(0, Descriptor.ManufacturerStringIndex); + } + } + public String ProductString { + get { + if (Descriptor.ProductStringIndex == 0) return null; + return mUsbDevice.Device.GetString(0, Descriptor.ProductStringIndex); + } + } + public String SerialString { + get { + if (Descriptor.SerialStringIndex == 0) return null; + return mUsbDevice.Device.GetString(0, Descriptor.SerialStringIndex); + } + } + } + public class UsbConfigInfo { + private readonly List<UsbInterfaceInfo> mInterfaceList = new List<UsbInterfaceInfo>(); + internal readonly UsbConfigDescriptor mUsbConfigDescriptor; + internal UsbDevice mUsbDevice; + internal UsbConfigInfo(UsbDevice usbDevice, UsbConfigDescriptor descriptor, ref List<byte[]> rawDescriptors) { + mUsbDevice = usbDevice; + mUsbConfigDescriptor = descriptor; + UsbInterfaceInfo currentInterface = null; + for (int iRawDescriptor = 0; iRawDescriptor < rawDescriptors.Count; iRawDescriptor++) { + byte[] bytesRawDescriptor = rawDescriptors[iRawDescriptor]; + switch (bytesRawDescriptor[1]) { + case (byte)UsbDescriptorType.Interface: + currentInterface = new UsbInterfaceInfo(usbDevice, bytesRawDescriptor); + mInterfaceList.Add(currentInterface); + break; + case (byte)UsbDescriptorType.Endpoint: + if (currentInterface == null) throw new Exception("Recieved and endpoint descriptor before receiving an interface descriptor."); + currentInterface.mEndpointInfo.Add(new UsbEndpointInfo(bytesRawDescriptor)); + break; + } + } + } + public UsbConfigDescriptor Descriptor { get { return mUsbConfigDescriptor; } } + public ReadOnlyCollection<UsbInterfaceInfo> InterfaceInfoList { get { return mInterfaceList.AsReadOnly(); } } + } + public class UsbInterfaceInfo { + internal readonly UsbInterfaceDescriptor mUsbInterfaceDescriptor; + internal UsbDevice mUsbDevice; + internal List<UsbEndpointInfo> mEndpointInfo = new List<UsbEndpointInfo>(); + internal UsbInterfaceInfo(UsbDevice usbDevice, byte[] descriptor) { + mUsbDevice = usbDevice; + mUsbInterfaceDescriptor = new UsbInterfaceDescriptor(); + Helper.BytesToObject(descriptor, 0, Math.Min(UsbInterfaceDescriptor.Size, descriptor[0]), mUsbInterfaceDescriptor); + } + public UsbInterfaceDescriptor Descriptor { get { return mUsbInterfaceDescriptor; } } + public ReadOnlyCollection<UsbEndpointInfo> EndpointInfoList { get { return mEndpointInfo.AsReadOnly(); } } + } + public class UsbEndpointInfo { + internal UsbEndpointDescriptor mUsbEndpointDescriptor; + internal UsbEndpointInfo(byte[] descriptor) { + mUsbEndpointDescriptor = new UsbEndpointDescriptor(); + Helper.BytesToObject(descriptor, 0, Math.Min(UsbEndpointDescriptor.Size, descriptor[0]), mUsbEndpointDescriptor); + } + public UsbEndpointDescriptor Descriptor { + get { return mUsbEndpointDescriptor; } + } + } +} +namespace LibUsbDotNet.Descriptors { + public enum DescriptorType : byte { + Device = 1, + Configuration = 2, + String = 3, + Interface = 4, + Endpoint = 5, + DeviceQualifier = 6, + OtherSpeedConfiguration = 7, + InterfacePower = 8, + OTG = 9, + Debug = 10, + InterfaceAssociation = 11, + Hid = 0x21, + HidReport = 0x22, + Physical = 0x23, + Hub = 0x29 + } + public enum ClassCodeType : byte { + PerInterface = 0, + Audio = 1, + Comm = 2, + Hid = 3, + Printer = 7, + Ptp = 6, + MassStorage = 8, + Hub = 9, + Data = 10, + VendorSpec = 0xff + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public abstract class UsbDescriptor { + public static readonly int Size = Marshal.SizeOf(typeof(UsbDescriptor)); + public byte Length; + public DescriptorType DescriptorType; + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public class UsbDeviceDescriptor : UsbDescriptor { + public new static readonly int Size = Marshal.SizeOf(typeof(UsbDeviceDescriptor)); + public short BcdUsb; + public ClassCodeType Class; + public byte SubClass; + public byte Protocol; + public byte MaxPacketSize0; + public short VendorID; + public short ProductID; + public short BcdDevice; + public byte ManufacturerStringIndex; + public byte ProductStringIndex; + public byte SerialStringIndex; + public byte ConfigurationCount; + internal UsbDeviceDescriptor() { } + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public class UsbConfigDescriptor : UsbDescriptor { + public new static readonly int Size = Marshal.SizeOf(typeof(UsbConfigDescriptor)); + public readonly short TotalLength; + public readonly byte InterfaceCount; + public readonly byte ConfigID; + public readonly byte StringIndex; + public readonly byte Attributes; + public readonly byte MaxPower; + internal UsbConfigDescriptor() { } + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public class UsbInterfaceDescriptor : UsbDescriptor { + public new static readonly int Size = Marshal.SizeOf(typeof(UsbInterfaceDescriptor)); + public readonly byte InterfaceID; + public readonly byte AlternateID; + public readonly byte EndpointCount; + public readonly ClassCodeType Class; + public readonly byte SubClass; + public readonly byte Protocol; + public readonly byte StringIndex; + internal UsbInterfaceDescriptor() { } + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public class UsbEndpointDescriptor : UsbDescriptor { + public new static readonly int Size = Marshal.SizeOf(typeof(UsbEndpointDescriptor)); + public readonly byte EndpointID; + public readonly byte Attributes; + public readonly short MaxPacketSize; + public readonly byte Interval; + public readonly byte Refresh; + public readonly byte SynchAddress; + internal UsbEndpointDescriptor() { } + } +} +namespace MonoLibUsb { + public static class MonoUsbApi { + internal const CallingConvention CC = 0; + internal const string LIBUSB_DLL = "libusb-1.0.dll"; + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_detach_kernel_driver")] + public static extern int DetachKernelDriver([In] MonoUsbDeviceHandle deviceHandle, int interfaceNumber); + public static int ControlTransfer(MonoUsbDeviceHandle deviceHandle, byte requestType, byte request, short value, short index, object data, short dataLength, int timeout) { + throw new NotImplementedException(); + } + public static int BulkTransfer(MonoUsbDeviceHandle deviceHandle, byte endpoint, object data, int length, out int actualLength, int timeout) { + throw new NotImplementedException(); + } + } + public abstract class MonoUsbDeviceHandle : SafeHandle { + public MonoUsbDeviceHandle(Boolean bOwnsHandle) : base(IntPtr.Zero, bOwnsHandle) { } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Communication/UsbControlRequestType.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,103 @@ +using System; + +namespace UCIS.USBLib.Communication { + [Flags] + public enum UsbControlRequestType : byte { + /// <summary> + /// Class specific request. + /// </summary> + TypeClass = (0x01 << 5), + /// <summary> + /// RESERVED. + /// </summary> + TypeReserved = (0x03 << 5), + /// <summary> + /// Standard request. + /// </summary> + TypeStandard = (0x00 << 5), + /// <summary> + /// Vendor specific request. + /// </summary> + TypeVendor = (0x02 << 5), + + TypeMask = 0x03 << 5, + + /// <summary> + /// Device is recipient. + /// </summary> + RecipDevice = 0x00, + /// <summary> + /// Endpoint is recipient. + /// </summary> + RecipEndpoint = 0x02, + /// <summary> + /// Interface is recipient. + /// </summary> + RecipInterface = 0x01, + /// <summary> + /// Other is recipient. + /// </summary> + RecipOther = 0x03, + + RecipMask = 0x03, + + /// <summary> + /// In Direction + /// </summary> + EndpointIn = 0x80, + /// <summary> + /// Out Direction + /// </summary> + EndpointOut = 0x00, + + EndpointMask = 0x80, + } + + [Flags] + public enum UsbStandardRequest : byte { + /// <summary> + /// Clear or disable a specific feature. + /// </summary> + ClearFeature = 0x01, + /// <summary> + /// Returns the current device Configuration value. + /// </summary> + GetConfiguration = 0x08, + /// <summary> + /// Returns the specified descriptor if the descriptor exists. + /// </summary> + GetDescriptor = 0x06, + /// <summary> + /// Returns the selected alternate setting for the specified interface. + /// </summary> + GetInterface = 0x0A, + /// <summary> + /// Returns status for the specified recipient. + /// </summary> + GetStatus = 0x00, + /// <summary> + /// Sets the device address for all future device accesses. + /// </summary> + SetAddress = 0x05, + /// <summary> + /// Sets the device Configuration. + /// </summary> + SetConfiguration = 0x09, + /// <summary> + /// Optional and may be used to update existing descriptors or new descriptors may be added. + /// </summary> + SetDescriptor = 0x07, + /// <summary> + /// used to set or enable a specific feature. + /// </summary> + SetFeature = 0x03, + /// <summary> + /// Allows the host to select an alternate setting for the specified interface. + /// </summary> + SetInterface = 0x0B, + /// <summary> + /// Used to set and then report an endpoint’s synchronization frame. + /// </summary> + SynchFrame = 0x0C, + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Communication/UsbDescriptorType.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,63 @@ +using System; + +namespace UCIS.USBLib.Communication { + [Flags] + public enum UsbDescriptorType : byte { + /// <summary> + /// Device descriptor type. + /// </summary> + Device = 1, + /// <summary> + /// Configuration descriptor type. + /// </summary> + Configuration = 2, + /// <summary> + /// String descriptor type. + /// </summary> + String = 3, + /// <summary> + /// Interface descriptor type. + /// </summary> + Interface = 4, + /// <summary> + /// Endpoint descriptor type. + /// </summary> + Endpoint = 5, + /// <summary> + /// Device Qualifier descriptor type. + /// </summary> + DeviceQualifier = 6, + /// <summary> + /// Other Speed Configuration descriptor type. + /// </summary> + OtherSpeedConfiguration = 7, + /// <summary> + /// Interface Power descriptor type. + /// </summary> + InterfacePower = 8, + /// <summary> + /// OTG descriptor type. + /// </summary> + OTG = 9, + /// <summary> + /// Debug descriptor type. + /// </summary> + Debug = 10, + /// <summary> + /// Interface Association descriptor type. + /// </summary> + InterfaceAssociation = 11, + + ///<summary> HID descriptor</summary> + Hid = 0x21, + + ///<summary> HID report descriptor</summary> + HidReport = 0x22, + + ///<summary> Physical descriptor</summary> + Physical = 0x23, + + ///<summary> Hub descriptor</summary> + Hub = 0x29 + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Communication/UsbInterface.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,61 @@ +using System; +using System.Text; +using UCIS.USBLib.Descriptor; + +namespace UCIS.USBLib.Communication { + public abstract class UsbInterface : IUsbInterface { + public virtual byte Configuration { + get { + byte[] buf = new byte[1]; + int tl = ControlRead( + UsbControlRequestType.EndpointIn | UsbControlRequestType.TypeStandard | UsbControlRequestType.RecipDevice, + (byte)UsbStandardRequest.GetConfiguration, 0, 0, + buf, 0, buf.Length); + if (tl != buf.Length) throw new Exception("Read failed"); + return buf[0]; + } + set { + throw new NotImplementedException(); + } + } + public unsafe virtual string GetString(short langId, byte stringIndex) { + Byte[] buffer = new Byte[256]; + int tl = GetDescriptor((byte)UsbDescriptorType.String, stringIndex, langId, buffer, 0, buffer.Length); + if (tl < 2) return null; + return UsbStringDescriptor.GetString(buffer, 0, tl); + } + public virtual int GetDescriptor(byte descriptorType, byte index, short langId, byte[] buffer, int offset, int length) { + return ControlRead( + UsbControlRequestType.EndpointIn | UsbControlRequestType.RecipDevice | UsbControlRequestType.TypeStandard, + (Byte)UsbStandardRequest.GetDescriptor, + (short)((descriptorType << 8) | index), langId, buffer, offset, length); + } + public virtual int ControlWrite(UsbControlRequestType requestType, byte request, short value, short index) { + return ControlWrite(requestType, request, value, index, null, 0, 0); + } + + public abstract void Close(); + + public abstract int BulkWrite(Byte endpoint, Byte[] buffer, int offset, int length); + public abstract int BulkRead(Byte endpoint, Byte[] buffer, int offset, int length); + public abstract int InterruptWrite(Byte endpoint, Byte[] buffer, int offset, int length); + public abstract int InterruptRead(Byte endpoint, Byte[] buffer, int offset, int length); + public abstract int ControlWrite(UsbControlRequestType requestType, byte request, short value, short index, byte[] buffer, int offset, int length); + public abstract int ControlRead(UsbControlRequestType requestType, byte request, short value, short index, byte[] buffer, int offset, int length); + + public UsbPipeStream GetBulkStream(Byte endpoint) { + return new UsbPipeStream(this, endpoint, false); + } + public UsbPipeStream GetInterruptStream(Byte endpoint) { + return new UsbPipeStream(this, endpoint, true); + } + + public void Dispose() { + Close(); + GC.SuppressFinalize(this); + } + ~UsbInterface() { + Close(); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Communication/UsbPipeStream.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,64 @@ +using System; +using System.IO; + +namespace UCIS.USBLib.Communication { + public class UsbPipeStream : Stream { + public IUsbInterface Device { get; private set; } + public Byte Endpoint { get; private set; } + public Boolean InterruptEndpoint { get; private set; } + + public UsbPipeStream(IUsbInterface device, Byte endpoint, Boolean interrupt) { + this.Device = device; + this.Endpoint = endpoint; + this.InterruptEndpoint = interrupt; + } + + public override bool CanRead { + get { return (Endpoint & 0x80) != 0; } + } + + public override bool CanSeek { + get { return false; } + } + + public override bool CanWrite { + get { return (Endpoint & 0x80) == 0; } + } + + public override void Flush() { + } + + public override long Length { get { return 0; } } + + public override long Position { + get { return 0; } + set { throw new NotImplementedException(); } + } + + public override int Read(byte[] buffer, int offset, int count) { + if (InterruptEndpoint) { + return Device.InterruptRead(Endpoint, buffer, offset, count); + } else { + return Device.BulkRead(Endpoint, buffer, offset, count); + } + } + + public override long Seek(long offset, SeekOrigin origin) { + throw new NotImplementedException(); + } + + public override void SetLength(long value) { + throw new NotImplementedException(); + } + + public override void Write(byte[] buffer, int offset, int count) { + int written; + if (InterruptEndpoint) { + written = Device.InterruptWrite(Endpoint, buffer, offset, count); + } else { + written = Device.BulkWrite(Endpoint, buffer, offset, count); + } + if (written != count) throw new EndOfStreamException("Could not write all data"); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Communication/WinUsb/WinUsbDevice.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,216 @@ +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Security; +using Microsoft.Win32.SafeHandles; +using UCIS.USBLib.Internal.Windows; + +namespace UCIS.USBLib.Communication.WinUsb { + class SafeWinUsbInterfaceHandle : SafeHandleZeroOrMinusOneIsInvalid { + public SafeWinUsbInterfaceHandle() : base(true) { } + protected override bool ReleaseHandle() { + if (IsInvalid) return true; + bool bSuccess = WinUsbDevice.WinUsb_Free(handle); + handle = IntPtr.Zero; + return bSuccess; + } + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct UsbSetupPacket { + public byte RequestType; + public byte Request; + public short Value; + public short Index; + public short Length; + public UsbSetupPacket(byte requestType, byte request, short value, short index, short length) { + RequestType = requestType; + Request = request; + Value = value; + Index = index; + Length = length; + } + } + [SuppressUnmanagedCodeSecurity] + public class WinUsbDevice : UsbInterface, IUsbDevice { + const string WIN_USB_DLL = "winusb.dll"; + [DllImport(WIN_USB_DLL, SetLastError = true)] + static extern bool WinUsb_Initialize(SafeFileHandle DeviceHandle, out SafeWinUsbInterfaceHandle InterfaceHandle); + [DllImport(WIN_USB_DLL, SetLastError = true)] + internal static extern bool WinUsb_GetAssociatedInterface(SafeWinUsbInterfaceHandle InterfaceHandle, byte AssociatedInterfaceIndex, out SafeWinUsbInterfaceHandle AssociatedInterfaceHandle); + [DllImport(WIN_USB_DLL, SetLastError = true)] + internal static extern bool WinUsb_Free(IntPtr InterfaceHandle); + [DllImport(WIN_USB_DLL, SetLastError = true)] + private static extern bool WinUsb_AbortPipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID); + [DllImport(WIN_USB_DLL, SetLastError = true)] + private static extern bool WinUsb_ControlTransfer(SafeWinUsbInterfaceHandle InterfaceHandle, UsbSetupPacket SetupPacket, IntPtr Buffer, int BufferLength, out int LengthTransferred, IntPtr pOVERLAPPED); + [DllImport(WIN_USB_DLL, SetLastError = true)] + private static extern bool WinUsb_FlushPipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID); + [DllImport(WIN_USB_DLL, SetLastError = true)] + private static extern bool WinUsb_GetDescriptor(SafeWinUsbInterfaceHandle InterfaceHandle, byte DescriptorType, byte Index, ushort LanguageID, IntPtr Buffer, int BufferLength, out int LengthTransferred); + [DllImport(WIN_USB_DLL, SetLastError = true)] + private static extern bool WinUsb_ReadPipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID, Byte[] Buffer, int BufferLength, out int LengthTransferred, IntPtr pOVERLAPPED); + [DllImport(WIN_USB_DLL, SetLastError = true)] + private static extern bool WinUsb_ReadPipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID, IntPtr pBuffer, int BufferLength, out int LengthTransferred, IntPtr pOVERLAPPED); + [DllImport(WIN_USB_DLL, SetLastError = true)] + private static extern bool WinUsb_ResetPipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID); + [DllImport(WIN_USB_DLL, SetLastError = true)] + private static extern bool WinUsb_WritePipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID, Byte[] Buffer, int BufferLength, out int LengthTransferred, IntPtr pOVERLAPPED); + [DllImport(WIN_USB_DLL, SetLastError = true)] + private static extern bool WinUsb_WritePipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID, IntPtr pBuffer, int BufferLength, out int LengthTransferred, IntPtr pOVERLAPPED); + //[DllImport(WIN_USB_DLL, SetLastError = true)] + //private static extern bool WinUsb_SetPipePolicy(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID, UInt32 PolicyType, UInt32 ValueLength, ref Byte Value); + SafeFileHandle DeviceHandle; + private SafeWinUsbInterfaceHandle[] InterfaceHandles = null; + private int[] EndpointToInterfaceIn = new int[0]; + private int[] EndpointToInterfaceOut = new int[0]; + public IUsbDeviceRegistry Registry { get; private set; } + + public WinUsbDevice(String path, WinUsbRegistry registry) { + this.Registry = registry; + DeviceHandle = Kernel32.CreateFile(path, + NativeFileAccess.FILE_GENERIC_WRITE | NativeFileAccess.FILE_GENERIC_READ, + NativeFileShare.FILE_SHARE_WRITE | NativeFileShare.FILE_SHARE_READ, + IntPtr.Zero, + NativeFileMode.OPEN_EXISTING, + NativeFileFlag.FILE_ATTRIBUTE_NORMAL | NativeFileFlag.FILE_FLAG_OVERLAPPED, + IntPtr.Zero); + if (DeviceHandle.IsInvalid || DeviceHandle.IsClosed) throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not open device"); + SafeWinUsbInterfaceHandle InterfaceHandle; + if (!WinUsb_Initialize(DeviceHandle, out InterfaceHandle)) throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not initialize WinUsb"); + if (InterfaceHandle.IsInvalid || InterfaceHandle.IsClosed) throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not open interface"); + InterfaceHandles = new SafeWinUsbInterfaceHandle[1] { InterfaceHandle }; + foreach (LibUsbDotNet.Info.UsbConfigInfo ci in (new LibUsbDotNet.UsbDevice(this)).Configs) { + if (ci.Descriptor.ConfigID == Configuration) { + foreach (LibUsbDotNet.Info.UsbInterfaceInfo ifinfo in ci.InterfaceInfoList) { + foreach (LibUsbDotNet.Info.UsbEndpointInfo epinfo in ifinfo.EndpointInfoList) { + int epidx = epinfo.Descriptor.EndpointID & 0x7F; + if ((epinfo.Descriptor.EndpointID & 0x80) != 0) { + if (EndpointToInterfaceIn.Length <= epidx) Array.Resize(ref EndpointToInterfaceIn, epidx + 1); + EndpointToInterfaceIn[epidx] = ifinfo.Descriptor.InterfaceID; + } else { + if (EndpointToInterfaceOut.Length <= epidx) Array.Resize(ref EndpointToInterfaceOut, epidx + 1); + EndpointToInterfaceOut[epidx] = ifinfo.Descriptor.InterfaceID; + } + } + } + } + } + } + + public void ClaimInterface(int interfaceID) { + GetInterfaceHandle(interfaceID); + } + public void ReleaseInterface(int interfaceID) { + if (interfaceID == 0) return; + if (InterfaceHandles.Length < interfaceID || InterfaceHandles[interfaceID] == null) return; + InterfaceHandles[interfaceID].Close(); + InterfaceHandles[interfaceID] = null; + } + void IUsbDevice.ResetDevice() { + throw new NotSupportedException(); + } + private SafeWinUsbInterfaceHandle GetInterfaceHandle(int interfaceID) { + if (interfaceID == 0) return InterfaceHandles[0]; + if (interfaceID < 0 || interfaceID > 255) throw new ArgumentOutOfRangeException("interfaceID"); + if (InterfaceHandles.Length > interfaceID && InterfaceHandles[interfaceID] != null) return InterfaceHandles[interfaceID]; + SafeWinUsbInterfaceHandle ih; + if (!WinUsb_GetAssociatedInterface(InterfaceHandles[0], (Byte)(interfaceID - 1), out ih) || ih.IsInvalid || ih.IsClosed) + throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not open interface"); + if (InterfaceHandles.Length <= interfaceID) Array.Resize(ref InterfaceHandles, interfaceID + 1); + InterfaceHandles[interfaceID] = ih; + return ih; + } + private SafeWinUsbInterfaceHandle GetInterfaceHandleForEndpoint(int epID) { + int epidx = epID & 0x7F; + if ((epID & 0x80) != 0) { + if (EndpointToInterfaceIn.Length <= epidx) throw new ArgumentOutOfRangeException("endpoint"); + return GetInterfaceHandle(EndpointToInterfaceIn[epidx]); + } else { + if (EndpointToInterfaceOut.Length <= epidx) throw new ArgumentOutOfRangeException("endpoint"); + return GetInterfaceHandle(EndpointToInterfaceOut[epidx]); + } + } + + public override void Close() { + foreach (SafeWinUsbInterfaceHandle ih in InterfaceHandles) ih.Close(); + InterfaceHandles = new SafeWinUsbInterfaceHandle[0]; + if (DeviceHandle != null) DeviceHandle.Close(); + } + + public override Byte Configuration { + get { return base.Configuration; } + set { + if (value == base.Configuration) return; + throw new NotSupportedException(); + } + } + + public unsafe int ControlTransfer(byte requestType, byte request, short value, short index, byte[] buffer, int offset, int length) { + if (buffer == null) buffer = new Byte[0]; + if (offset < 0 || length < 0 || length > short.MaxValue || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length"); + SafeWinUsbInterfaceHandle ih = InterfaceHandles[0]; + switch ((UsbControlRequestType)requestType & UsbControlRequestType.RecipMask) { + case UsbControlRequestType.RecipInterface: ih = GetInterfaceHandle(index & 0xff); break; + case UsbControlRequestType.RecipEndpoint: ih = GetInterfaceHandleForEndpoint(index & 0xff); break; + case UsbControlRequestType.RecipOther: break; + } + fixed (Byte* b = buffer) { + if (!WinUsb_ControlTransfer(ih, + new UsbSetupPacket(requestType, request, value, index, (short)length), + (IntPtr)(b + offset), length, out length, IntPtr.Zero)) + throw new Win32Exception(Marshal.GetLastWin32Error(), "Control transfer failed"); + return length; + } + } + + public override int ControlWrite(UsbControlRequestType requestType, byte request, short value, short index, byte[] buffer, int offset, int length) { + return ControlTransfer((byte)(requestType | UsbControlRequestType.EndpointOut), request, value, index, buffer, offset, length); + } + + public override int ControlRead(UsbControlRequestType requestType, byte request, short value, short index, byte[] buffer, int offset, int length) { + return ControlTransfer((byte)(requestType | UsbControlRequestType.EndpointIn), request, value, index, buffer, offset, length); + } + + public unsafe override int GetDescriptor(byte descriptorType, byte index, short langId, byte[] buffer, int offset, int length) { + if (length > short.MaxValue || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length"); + fixed (Byte* b = buffer) { + if (!WinUsb_GetDescriptor(InterfaceHandles[0], descriptorType, index, (ushort)langId, (IntPtr)(b + offset), length, out length)) + throw new Win32Exception(Marshal.GetLastWin32Error(), "Descriptor transfer failed"); + } + return length; + } + + public unsafe int PipeWrite(byte endpoint, byte[] buffer, int offset, int length) { + if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer length"); + SafeWinUsbInterfaceHandle ih = GetInterfaceHandleForEndpoint(endpoint); + fixed (Byte* b = buffer) { + if (!WinUsb_WritePipe(ih, endpoint, (IntPtr)(b + offset), length, out length, IntPtr.Zero)) + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + return length; + } + + public unsafe int PipeRead(byte endpoint, byte[] buffer, int offset, int length) { + if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer length"); + SafeWinUsbInterfaceHandle ih = GetInterfaceHandleForEndpoint(endpoint); + fixed (Byte* b = buffer) { + if (!WinUsb_ReadPipe(ih, endpoint, (IntPtr)(b + offset), length, out length, IntPtr.Zero)) + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + return length; + } + + public override int BulkWrite(Byte endpoint, Byte[] buffer, int offset, int length) { + return PipeWrite(endpoint, buffer, offset, length); + } + public override int BulkRead(Byte endpoint, Byte[] buffer, int offset, int length) { + return PipeRead(endpoint, buffer, offset, length); + } + public override int InterruptWrite(Byte endpoint, Byte[] buffer, int offset, int length) { + return PipeWrite(endpoint, buffer, offset, length); + } + public override int InterruptRead(Byte endpoint, Byte[] buffer, int offset, int length) { + return PipeRead(endpoint, buffer, offset, length); + } + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Communication/WinUsb/WinUsbRegistry.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using UCIS.HWLib.Windows.Devices; + +namespace UCIS.USBLib.Communication.WinUsb { + public class WinUsbRegistry : WindowsUsbDeviceRegistry, IUsbDeviceRegistry { + private WinUsbRegistry(DeviceNode device, String interfacepath) : base(device, interfacepath) { } + public IList<Guid> DeviceInterfaceGuids { get; private set; } + + public static List<WinUsbRegistry> DeviceList { + get { + List<WinUsbRegistry> deviceList = new List<WinUsbRegistry>(); + IList<DeviceNode> usbdevices = DeviceNode.GetDevices("USB"); + foreach (DeviceNode device in usbdevices) { + WinUsbRegistry regInfo = GetDeviceForDeviceNode(device); + if (regInfo != null) deviceList.Add(regInfo); + } + return deviceList; + } + } + public static WinUsbRegistry GetDeviceForDeviceNode(DeviceNode device) { + if (device.Service != "WinUSB") return null; + String[] devInterfaceGuids = device.GetCustomPropertyStringArray("DeviceInterfaceGuids"); + if (devInterfaceGuids == null || devInterfaceGuids.Length < 1) return null; + Guid deviceInterfaceGuid = new Guid(devInterfaceGuids[0]); + String[] interfaces = device.GetInterfaces(deviceInterfaceGuid); + if (interfaces == null || interfaces.Length < 1) return null; + WinUsbRegistry regInfo = new WinUsbRegistry(device, interfaces[0]); + regInfo.DeviceInterfaceGuids = Array.ConvertAll(devInterfaceGuids, delegate(String g) { return new Guid(g); }); + return regInfo; + } + + public WinUsbDevice Open() { + return new WinUsbDevice(DevicePath, this); + } + IUsbDevice IUsbDeviceRegistry.Open() { + return Open(); + } + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Communication/WindowsUsbDeviceRegistry.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text.RegularExpressions; +using UCIS.HWLib.Windows.Devices; +using UCIS.USBLib.Internal.Windows; + +namespace UCIS.USBLib.Communication { + public abstract class WindowsUsbDeviceRegistry { + public DeviceNode DeviceNode { get; private set; } + + // Parsed out of the device ID + private bool mIsDeviceIDParsed; + private byte mInterfaceID; + private ushort mVid; + private ushort mPid; + private ushort mRevision; + + private IDictionary<string, object> mDeviceProperties; + + public String DevicePath { get; private set; } + public String DeviceID { get; private set; } + public String SymbolicName { get { return DevicePath; } } + + private static Regex RegHardwareID = null; + + protected WindowsUsbDeviceRegistry(DeviceNode device, String interfacepath) { + DeviceNode = device; + DeviceID = device.DeviceID; + DevicePath = interfacepath; + } + + public IDictionary<string, object> DeviceProperties { + get { + if (mDeviceProperties == null) mDeviceProperties = SetupApi.GetSPDRPProperties(DeviceNode); + return mDeviceProperties; + } + } + + private void parseDeviceID() { + if (mIsDeviceIDParsed) return; + if (RegHardwareID == null) { + RegexOptions OPTIONS = RegexOptions.CultureInvariant | RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase; + string PATTERN = "(Vid_(?<Vid>[0-9A-F]{1,4}))|(Pid_(?<Pid>[0-9A-F]{1,4}))|(Rev_(?<Rev>[0-9]{1,4}))|(MI_(?<MI>[0-9A-F]{1,2}))"; + RegHardwareID = new Regex(PATTERN, OPTIONS); + } + String[] HardwareIDs = DeviceNode.GetPropertyStringArray(CMRDP.HARDWAREID); + String HardwareID = null; + if (HardwareIDs == null || HardwareIDs.Length < 1 || HardwareIDs[0].Length == 0) { + HardwareID = DeviceID; + } else { + HardwareID = HardwareIDs[0]; + } + foreach (Match match in RegHardwareID.Matches(HardwareID)) { + Group group = match.Groups["Vid"]; + if (group.Success) ushort.TryParse(group.Value, NumberStyles.HexNumber, null, out mVid); + group = match.Groups["Pid"]; + if (group.Success) ushort.TryParse(group.Value, NumberStyles.HexNumber, null, out mPid); + group = match.Groups["Rev"]; + if (group.Success) ushort.TryParse(group.Value, NumberStyles.Integer, null, out mRevision); + group = match.Groups["MI"]; + if (group.Success) Byte.TryParse(group.Value, NumberStyles.HexNumber, null, out mInterfaceID); + } + mIsDeviceIDParsed = true; + } + public int Vid { + get { + parseDeviceID(); + return mVid; + } + } + public int Pid { + get { + parseDeviceID(); + return mPid; + } + } + public byte InterfaceID { + get { + parseDeviceID(); + return (byte)mInterfaceID; + } + } + + public string Name { get { return DeviceNode.GetPropertyString(CMRDP.DEVICEDESC); } } + public string Manufacturer { get { return DeviceNode.GetPropertyString(CMRDP.MFG); } } + public string FullName { + get { + String desc = Name; + String mfg = Manufacturer; + if (mfg == null) return desc; + if (desc == null) return mfg; + return mfg + " - " + desc; + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Descriptor/UsbDescriptor.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,194 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using UCIS.USBLib.Communication; + +namespace UCIS.USBLib.Descriptor { + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct UsbDescriptor { + byte bmLength; + byte bType; + public Byte Length { get { return bmLength; } } + public UsbDescriptorType Type { get { return (UsbDescriptorType)bType; } } + internal static short FromLittleEndian(short value) { + if (BitConverter.IsLittleEndian) return value; + return (short)(((value & 0xFF) << 8) | ((value >> 8) & 0xFF)); + } + public unsafe static UsbDescriptor FromByteArray(Byte[] buffer, int offset, int length) { + if (length < Marshal.SizeOf(typeof(UsbDescriptor))) throw new ArgumentOutOfRangeException("length", "The data length is smaller than the descriptor length"); + if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer dimensions"); + fixed (Byte* ptr = buffer) return *(UsbDescriptor*)(ptr + offset); + } + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct UsbStringDescriptor { + public static String GetString(Byte[] buffer, int offset, int length) { + if (length < 2) throw new ArgumentOutOfRangeException("length", "The data length is smaller than the descriptor length"); + if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer dimensions"); + if (buffer[offset + 1] != (Byte)UsbDescriptorType.String) throw new InvalidOperationException("The descriptor is not a string descriptor"); + int slen = buffer[offset]; + if (slen > length) throw new InvalidOperationException("The string has been truncated"); + return Encoding.Unicode.GetString(buffer, offset + 2, slen - 2); + } + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct UsbDeviceDescriptor { + byte bmLength; + byte bType; + short bcdUSB; + byte bDeviceClass; + byte bDeviceSubClass; + byte bDeviceProtocol; + byte bMaxControlPacketSize; + short idVendor; + short idProduct; + short bcdDevice; + byte iManufacturer; + byte iProduct; + byte iSerialNumber; + byte numConfigurations; + public Byte Length { get { return bmLength; } } + public UsbDescriptorType Type { get { return (UsbDescriptorType)bType; }} + public short USBVersion { get { return UsbDescriptor.FromLittleEndian(bcdUSB); } } + public Byte DeviceClass { get { return bDeviceClass; } } + public Byte DeviceSubClass { get { return bDeviceSubClass; } } + public Byte DeviceProtocol { get { return bDeviceProtocol; } } + public short DeviceVersion { get { return UsbDescriptor.FromLittleEndian(bcdDevice); } } + public Byte MaxControlPacketSize { get { return bMaxControlPacketSize; } } + public short VendorID { get { return UsbDescriptor.FromLittleEndian(idVendor); } } + public short ProductID { get { return UsbDescriptor.FromLittleEndian(idProduct); } } + public Byte ManufacturerStringID { get { return iManufacturer; } } + public Byte ProductStringID { get { return iProduct; } } + public Byte SerialNumberStringID { get { return iSerialNumber; } } + public Byte NumConfigurations { get { return numConfigurations; } } + public unsafe static UsbDeviceDescriptor FromByteArray(Byte[] buffer, int offset, int length) { + if (length < Size) throw new ArgumentOutOfRangeException("length", "The data length is smaller than the descriptor length"); + if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer dimensions"); + fixed (Byte* ptr = buffer) return *(UsbDeviceDescriptor*)(ptr + offset); + } + public static unsafe int Size { get { return sizeof(UsbDeviceDescriptor); } } + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct UsbConfigurationDescriptor { + byte bmLength; + byte bType; + short wTotalLength; + byte bNumInterfaces; + byte bConfigurationValue; + byte bConfigurationStringID; + byte bmAttributes; + byte bMaxPower; + public Byte Length { get { return bmLength; } } + public UsbDescriptorType Type { get { return (UsbDescriptorType)bType; } } + public short TotalLength { get { return UsbDescriptor.FromLittleEndian(wTotalLength); } } + public Byte NumInterfaces { get { return bNumInterfaces; } } + public Byte ConfigurationValue { get { return bConfigurationValue; } } + public Byte ConfigurationStringID { get { return bConfigurationStringID; } } + public Boolean SelfPowered { get { return 0 != (bmAttributes & (1 << 6)); } } + public Boolean RemoteWakeup { get { return 0 != (bmAttributes & (1 << 5)); } } + public int MaxPowerMA { get { return bMaxPower * 2; } } + public unsafe static UsbConfigurationDescriptor FromByteArray(Byte[] buffer, int offset, int length) { + if (length < Size) throw new ArgumentOutOfRangeException("length", "The data length is smaller than the descriptor length"); + if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer dimensions"); + fixed (Byte* ptr = buffer) return *(UsbConfigurationDescriptor*)(ptr + offset); + } + public static unsafe int Size { get { return sizeof(UsbConfigurationDescriptor); } } + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct UsbInterfaceDescriptor { + byte bmLength; + byte bType; + byte bInterfaceNumber; + byte bAlternateSetting; + byte bNumEndpoints; + byte bInterfaceClass; + byte bInterfaceSubClass; + byte bInterfaceProtocol; + byte bInterfaceStringID; + public Byte Length { get { return bmLength; } } + public UsbDescriptorType Type { get { return (UsbDescriptorType)bType; } } + public Byte InterfaceNumber { get { return bInterfaceNumber; } } + public Byte AlternateSetting { get { return bAlternateSetting; } } + public Byte NumEndpoints { get { return bNumEndpoints; } } + public Byte InterfaceClass { get { return bInterfaceClass; } } + public Byte InterfaceSubClass { get { return bInterfaceSubClass; } } + public Byte InterfaceProtocol { get { return bInterfaceProtocol; } } + public Byte InterfaceStringID { get { return bInterfaceStringID; } } + public unsafe static UsbInterfaceDescriptor FromByteArray(Byte[] buffer, int offset, int length) { + if (length < Size) throw new ArgumentOutOfRangeException("length", "The data length is smaller than the descriptor length"); + if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer dimensions"); + fixed (Byte* ptr = buffer) return *(UsbInterfaceDescriptor*)(ptr + offset); + } + public static unsafe int Size { get { return sizeof(UsbInterfaceDescriptor); } } + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct UsbEndpointDescriptor { + byte bmLength; + byte bType; + byte bEndpointAddress; + Byte bmAttributes; + short wMaxPacketSize; + byte bInterval; + public Byte Length { get { return bmLength; } } + public UsbDescriptorType Type { get { return (UsbDescriptorType)bType; } } + public Byte EndpointAddress { get { return bEndpointAddress; } } + public Boolean IsInput { get { return 0 != (EndpointAddress & (1 << 7)); } } + public int EndpointNumber { get { return EndpointAddress & 0xF; } } + public int TransferType { get { return bmAttributes & 3; } } + public Boolean IsControl { get { return TransferType == 0; } } + public Boolean IsIsochronous { get { return TransferType == 1; } } + public Boolean IsBulk { get { return TransferType == 2; } } + public Boolean IsInterrupt { get { return TransferType == 3; } } + public int MaxPacketSize { get { return UsbDescriptor.FromLittleEndian(wMaxPacketSize) & 0x7FF; } } + public Byte Interval { get { return bInterval; } } + public unsafe static UsbEndpointDescriptor FromByteArray(Byte[] buffer, int offset, int length) { + if (length < Size) throw new ArgumentOutOfRangeException("length", "The data length is smaller than the descriptor length"); + if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer dimensions"); + fixed (Byte* ptr = buffer) return *(UsbEndpointDescriptor*)(ptr + offset); + } + public static unsafe int Size { get { return sizeof(UsbEndpointDescriptor); } } + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct UsbHIDDescriptor { + byte bmLength; + byte bType; + short bcdHID; + byte bCountryCode; + byte bNumDescriptors; + byte bDescriptorType; + short wDescriptorLength; + public Byte Length { get { return bmLength; } } + public UsbDescriptorType Type { get { return (UsbDescriptorType)bType; } } + public short HIDVersion { get { return UsbDescriptor.FromLittleEndian(bcdHID); } } + public Byte CountryCode { get { return bCountryCode; } } + public Byte NumDescriptors { get { return bNumDescriptors; } } + public UsbDescriptorType DescriptorType { get { return (UsbDescriptorType)bDescriptorType; } } + public short DescriptorLength { get { return UsbDescriptor.FromLittleEndian(wDescriptorLength); } } + public unsafe static UsbHIDDescriptor FromByteArray(Byte[] buffer, int offset, int length) { + if (length < Size) throw new ArgumentOutOfRangeException("length", "The data length is smaller than the descriptor length"); + if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer dimensions"); + fixed (Byte* ptr = buffer) return *(UsbHIDDescriptor*)(ptr + offset); + } + public static unsafe int Size { get { return sizeof(UsbHIDDescriptor); } } + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct UsbHubDescriptor { + byte bmLength; + byte bType; + byte bNumPorts; + short wHubCharacteristics; + byte bPwrOn2PwrGood; //2ms intervals + byte bHubControllerCurrent; + public Byte Length { get { return bmLength; } } + public UsbDescriptorType Type { get { return (UsbDescriptorType)bType; } } + public Byte NumPorts { get { return bNumPorts; } } + public Boolean IsCompoundDevice { get { return 0 != (wHubCharacteristics & (1 << 2)); } } + public Byte HubControllerCurrent { get { return bHubControllerCurrent; } } + public unsafe static UsbHubDescriptor FromByteArray(Byte[] buffer, int offset, int length) { + if (length < Marshal.SizeOf(typeof(UsbHubDescriptor))) throw new ArgumentOutOfRangeException("length", "The data length is smaller than the descriptor length"); + if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer dimensions"); + fixed (Byte* ptr = buffer) return *(UsbHubDescriptor*)(ptr + offset); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Internal/Windows/SetupApi.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,402 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using UCIS.HWLib.Windows.Devices; +using Microsoft.Win32; +using Microsoft.Win32.SafeHandles; + +namespace UCIS.USBLib.Internal.Windows { + class SafeDeviceInfoSetHandle : SafeHandleZeroOrMinusOneIsInvalid { + public SafeDeviceInfoSetHandle() : base(true) { } + //public SafeDeviceInfoSetHandle(IntPtr handle) : base(true) { SetHandle(handle); } + protected override bool ReleaseHandle() { + if (IsInvalid) return true; + bool bSuccess = SetupApi.SetupDiDestroyDeviceInfoList(handle); + handle = IntPtr.Zero; + return bSuccess; + } + } + class SetupApi { + [DllImport("setupapi.dll", CharSet = CharSet.Auto)] + public static extern SafeDeviceInfoSetHandle SetupDiGetClassDevs(IntPtr ClassGuid, [MarshalAs(UnmanagedType.LPTStr)] string Enumerator, IntPtr hwndParent, int Flags); + [DllImport("setupapi.dll", CharSet = CharSet.Auto)] + public static extern SafeDeviceInfoSetHandle SetupDiGetClassDevsA(ref Guid ClassGuid, [MarshalAs(UnmanagedType.LPTStr)] string Enumerator, IntPtr hwndParent, DICFG Flags); + [DllImport("setupapi.dll", CharSet = CharSet.Auto)] + public static extern SafeDeviceInfoSetHandle SetupDiGetClassDevsA(IntPtr ClassGuid, [MarshalAs(UnmanagedType.LPStr)] string Enumerator, IntPtr hwndParent, DICFG Flags); + + [DllImport("setupapi.dll", CharSet = CharSet.Auto /*, SetLastError = true*/)] + public static extern bool SetupDiDestroyDeviceInfoList(IntPtr hDevInfo); + + [DllImport("setupapi.dll", SetLastError = true)] + public static extern bool SetupDiEnumDeviceInfo(SafeDeviceInfoSetHandle DeviceInfoSet, int MemberIndex, ref SP_DEVINFO_DATA DeviceInfoData); + [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern Boolean SetupDiEnumDeviceInterfaces(SafeDeviceInfoSetHandle hDevInfo, ref SP_DEVINFO_DATA devInfo, ref Guid interfaceClassGuid, int memberIndex, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData); + [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern Boolean SetupDiEnumDeviceInterfaces(SafeDeviceInfoSetHandle hDevInfo, IntPtr devInfo, ref Guid interfaceClassGuid, int memberIndex, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData); + [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern Boolean SetupDiGetDeviceInterfaceDetail(SafeDeviceInfoSetHandle hDevInfo, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData, ref SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData, int deviceInterfaceDetailDataSize, out int requiredSize, ref SP_DEVINFO_DATA deviceInfoData); + + [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern bool SetupDiGetCustomDeviceProperty(SafeDeviceInfoSetHandle DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, string CustomPropertyName, DICUSTOMDEVPROP Flags, out RegistryValueKind PropertyRegDataType, Byte[] PropertyBuffer, int PropertyBufferSize, out int RequiredSize); + [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Ansi)] + public static extern bool SetupDiGetDeviceInstanceIdA(SafeDeviceInfoSetHandle DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, StringBuilder DeviceInstanceId, int DeviceInstanceIdSize, out int RequiredSize); + [DllImport("setupapi.dll", CharSet = CharSet.Auto)] + public static extern bool SetupDiGetDeviceInterfacePropertyKeys(SafeDeviceInfoSetHandle DeviceInfoSet, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, byte[] propKeyBuffer, int propKeyBufferElements, out int RequiredPropertyKeyCount, int Flags); + [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern bool SetupDiGetDeviceRegistryProperty(SafeDeviceInfoSetHandle DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, SPDRP Property, out RegistryValueKind PropertyRegDataType, byte[] PropertyBuffer, int PropertyBufferSize, out int RequiredSize); + [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern bool SetupDiGetDeviceRegistryProperty(SafeDeviceInfoSetHandle DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, SPDRP iProperty, out int PropertyRegDataType, IntPtr PropertyBuffer, int PropertyBufferSize, out int RequiredSize); + [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern bool SetupDiGetDeviceRegistryProperty(SafeDeviceInfoSetHandle DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, SPDRP iProperty, out int PropertyRegDataType, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder PropertyBuffer, int PropertyBufferSize, out int RequiredSize); + + [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern bool SetupDiGetDeviceInstanceId(SafeDeviceInfoSetHandle DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, StringBuilder DeviceInstanceId, int DeviceInstanceIdSize, out int RequiredSize); + + [DllImport("setupapi.dll")] + public static extern bool SetupDiSetClassInstallParams(SafeDeviceInfoSetHandle DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, ref SP_CLASSINSTALL_HEADER ClassInstallParams, int ClassInstallParamsSize); + + [DllImport("setupapi.dll")] + public static extern bool SetupDiCallClassInstaller(int InstallFunction, SafeDeviceInfoSetHandle DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData); + + [DllImport("setupapi.dll", CharSet = CharSet.Auto)] + public static extern CR CM_Get_Device_ID(UInt32 dnDevInst, StringBuilder Buffer, int BufferLen, int ulFlags); + [DllImport("setupapi.dll", CharSet = CharSet.Auto)] + public static extern CR CM_Get_Device_ID(UInt32 dnDevInst, IntPtr Buffer, int BufferLen, int ulFlags); + [DllImport("setupapi.dll", CharSet = CharSet.Auto)] + public static extern CR CM_Get_Device_ID_Size(out UInt32 pulLen, UInt32 dnDevInst, UInt32 ulFlags); + [DllImport("setupapi.dll")] + public static extern CR CM_Get_Parent(out UInt32 pdnDevInst, UInt32 dnDevInst, int ulFlags); + + [DllImport("setupapi.dll", CharSet = CharSet.Auto)] + public static extern CR CM_Locate_DevNode(out UInt32 pdnDevInst, [MarshalAs(UnmanagedType.LPWStr)] String pDeviceID, UInt32 ulFlags); + [DllImport("setupapi.dll", CharSet = CharSet.Auto)] + public static extern CR CM_Get_Sibling(out UInt32 pdnDevInst, UInt32 DevInst, UInt32 ulFlags); + [DllImport("setupapi.dll", CharSet = CharSet.Auto)] + public static extern CR CM_Get_Child(out UInt32 pdnDevInst, UInt32 dnDevInst, UInt32 ulFlags); + [DllImport("setupapi.dll", CharSet = CharSet.Auto)] + public static extern CR CM_Get_DevNode_Registry_Property(UInt32 dnDevInst, CMRDP ulProperty, out UInt32 pulRegDataType, Byte[] Buffer, ref UInt32 pulLength, UInt32 ulFlags); + [DllImport("setupapi.dll", CharSet = CharSet.Auto)] + public static extern CR CM_Get_Device_Interface_List([In] ref Guid InterfaceClassGuid, [MarshalAs(UnmanagedType.LPWStr)] String pDeviceID, Byte[] Buffer, UInt32 BufferLen, UInt32 ulFlags); + [DllImport("setupapi.dll", CharSet = CharSet.Auto)] + public static extern CR CM_Get_Device_Interface_List_Size(out UInt32 pulLen, [In] ref Guid InterfaceClassGuid, [MarshalAs(UnmanagedType.LPWStr)] String pDeviceID, UInt32 ulFlags); + [DllImport("setupapi.dll", CharSet = CharSet.Auto)] + public static extern CR CM_Enumerate_Classes(UInt32 ulClassIndex, out Guid ClassGuid, UInt32 ulFlags); + [DllImport("setupapi.dll", CharSet = CharSet.Auto)] + public static extern CR CM_Get_DevNode_Status(out UInt32 pulStatus, out UInt32 pulProblemNumber, UInt32 dnDevInst, UInt32 ulFlags); + + + //public const int DIGCF_DEFAULT = 0x00000001; // only valid with DIGCF_DEVICEINTERFACE + public const int DIGCF_PRESENT = 0x00000002; + public const int DIGCF_ALLCLASSES = 0x00000004; + public const int DIGCF_PROFILE = 0x00000008; + public const int DIGCF_DEVICEINTERFACE = 0x00000010; + + internal static Guid? GetAsGuid(byte[] buffer) { if (buffer == null) return null; else return GetAsGuid(buffer, buffer.Length); } + internal static Guid GetAsGuid(byte[] buffer, int len) { + if (len != 16) return Guid.Empty; + byte[] guidBytes = new byte[len]; + Array.Copy(buffer, guidBytes, guidBytes.Length); + return new Guid(guidBytes); + } + internal static string GetAsString(byte[] buffer) { return GetAsString(buffer, buffer.Length); } + internal static string GetAsString(byte[] buffer, int len) { + if (len <= 2) return String.Empty; + return Encoding.Unicode.GetString(buffer, 0, len).TrimEnd('\0'); + } + internal static string[] GetAsStringArray(byte[] buffer) { return GetAsStringArray(buffer, buffer.Length); } + internal static string[] GetAsStringArray(byte[] buffer, int len) { + return GetAsString(buffer, len).Split(new char[] { '\0' }, StringSplitOptions.RemoveEmptyEntries); + } + internal static Int32? GetAsInt32(byte[] buffer) { if (buffer == null) return null; else return GetAsInt32(buffer, buffer.Length); } + internal static Int32 GetAsInt32(byte[] buffer, int len) { + if (len != 4) return 0; + return buffer[0] | ((buffer[1]) << 8) | ((buffer[2]) << 16) | ((buffer[3]) << 24); + } + + public static IDictionary<String, Object> GetSPDRPProperties(DeviceNode device) { + Dictionary<string, object> deviceProperties = new Dictionary<string, object>(); + foreach (SPDRP prop in Enum.GetValues(typeof(SPDRP))) { + Byte[] propBuffer = device.GetProperty(prop); + if (propBuffer == null) continue; + int iReturnBytes = propBuffer.Length; + object oValue = null; + switch (prop) { + case SPDRP.PhysicalDeviceObjectName: + case SPDRP.LocationInformation: + case SPDRP.Class: + case SPDRP.Mfg: + case SPDRP.DeviceDesc: + case SPDRP.Driver: + case SPDRP.EnumeratorName: + case SPDRP.FriendlyName: + case SPDRP.ClassGuid: + case SPDRP.Service: + oValue = GetAsString(propBuffer, iReturnBytes); + break; + case SPDRP.HardwareId: + case SPDRP.CompatibleIds: + case SPDRP.LocationPaths: + oValue = GetAsStringArray(propBuffer, iReturnBytes); + break; + case SPDRP.BusNumber: + case SPDRP.InstallState: + case SPDRP.LegacyBusType: + case SPDRP.RemovalPolicy: + case SPDRP.UiNumber: + case SPDRP.Address: + oValue = GetAsInt32(propBuffer, iReturnBytes); + break; + case SPDRP.BusTypeGuid: + oValue = GetAsGuid(propBuffer, iReturnBytes); + break; + default: + oValue = propBuffer; + break; + } + deviceProperties.Add(prop.ToString(), oValue); + } + return deviceProperties; + } + } + + [StructLayout(LayoutKind.Sequential)] + struct SP_DEVICE_INTERFACE_DATA { + public UInt32 cbSize; + public Guid interfaceClassGuid; + public UInt32 flags; + private UIntPtr reserved; + public SP_DEVICE_INTERFACE_DATA(Boolean b) : this() { + cbSize = (uint)Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DATA)); + } + } + [StructLayout(LayoutKind.Sequential)] + struct SP_DEVINFO_DATA { + public UInt32 cbSize; + public Guid ClassGuid; + public UInt32 DevInst; + public IntPtr Reserved; + public SP_DEVINFO_DATA(Boolean b) + : this() { + cbSize = (uint)Marshal.SizeOf(typeof(SP_DEVINFO_DATA)); + } + } + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Unicode)] + struct SP_DEVICE_INTERFACE_DETAIL_DATA { + public uint cbSize; //<summary>The size, in bytes, of the fixed portion of the SP_DEVICE_INTERFACE_DETAIL_DATA structure.</summary> + //Byte[1] DevicePath + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)] + public String DevicePath; //<summary>A NULL-terminated string that contains the device interface path. This path can be passed to Win32 functions such as CreateFile.</summary> + public SP_DEVICE_INTERFACE_DETAIL_DATA(Boolean b) + : this() { + //cbSize should be sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) which is the same as the following + //if DevicePath is a 1-byte array and the structure is properly padded... is it really? + if (IntPtr.Size == 8) cbSize = 8; //Workaround for x64 + else cbSize = 4 + (uint)Marshal.SystemDefaultCharSize; + } + } + + enum CR { + SUCCESS = (0x00000000), + DEFAULT = (0x00000001), + OUT_OF_MEMORY = (0x00000002), + INVALID_POINTER = (0x00000003), + INVALID_FLAG = (0x00000004), + INVALID_DEVNODE = (0x00000005), + INVALID_DEVINST = INVALID_DEVNODE, + INVALID_RES_DES = (0x00000006), + INVALID_LOG_CONF = (0x00000007), + INVALID_ARBITRATOR = (0x00000008), + INVALID_NODELIST = (0x00000009), + DEVNODE_HAS_REQS = (0x0000000A), + DEVINST_HAS_REQS = DEVNODE_HAS_REQS, + INVALID_RESOURCEID = (0x0000000B), + DLVXD_NOT_FOUND = (0x0000000C), // WIN 95 ONLY + NO_SUCH_DEVNODE = (0x0000000D), + NO_SUCH_DEVINST = NO_SUCH_DEVNODE, + NO_MORE_LOG_CONF = (0x0000000E), + NO_MORE_RES_DES = (0x0000000F), + ALREADY_SUCH_DEVNODE = (0x00000010), + ALREADY_SUCH_DEVINST = ALREADY_SUCH_DEVNODE, + INVALID_RANGE_LIST = (0x00000011), + INVALID_RANGE = (0x00000012), + FAILURE = (0x00000013), + NO_SUCH_LOGICAL_DEV = (0x00000014), + CREATE_BLOCKED = (0x00000015), + NOT_SYSTEM_VM = (0x00000016), // WIN 95 ONLY + REMOVE_VETOED = (0x00000017), + APM_VETOED = (0x00000018), + INVALID_LOAD_TYPE = (0x00000019), + BUFFER_SMALL = (0x0000001A), + NO_ARBITRATOR = (0x0000001B), + NO_REGISTRY_HANDLE = (0x0000001C), + REGISTRY_ERROR = (0x0000001D), + INVALID_DEVICE_ID = (0x0000001E), + INVALID_DATA = (0x0000001F), + INVALID_API = (0x00000020), + DEVLOADER_NOT_READY = (0x00000021), + NEED_RESTART = (0x00000022), + NO_MORE_HW_PROFILES = (0x00000023), + DEVICE_NOT_THERE = (0x00000024), + NO_SUCH_VALUE = (0x00000025), + WRONG_TYPE = (0x00000026), + INVALID_PRIORITY = (0x00000027), + NOT_DISABLEABLE = (0x00000028), + FREE_RESOURCES = (0x00000029), + QUERY_VETOED = (0x0000002A), + CANT_SHARE_IRQ = (0x0000002B), + NO_DEPENDENT = (0x0000002C), + SAME_RESOURCES = (0x0000002D), + NO_SUCH_REGISTRY_KEY = (0x0000002E), + INVALID_MACHINENAME = (0x0000002F), // NT ONLY + REMOTE_COMM_FAILURE = (0x00000030), // NT ONLY + MACHINE_UNAVAILABLE = (0x00000031), // NT ONLY + NO_CM_SERVICES = (0x00000032), // NT ONLY + ACCESS_DENIED = (0x00000033), // NT ONLY + CALL_NOT_IMPLEMENTED = (0x00000034), + INVALID_PROPERTY = (0x00000035), + DEVICE_INTERFACE_ACTIVE = (0x00000036), + NO_SUCH_DEVICE_INTERFACE = (0x00000037), + INVALID_REFERENCE_STRING = (0x00000038), + INVALID_CONFLICT_LIST = (0x00000039), + INVALID_INDEX = (0x0000003A), + INVALID_STRUCTURE_SIZE = (0x0000003B), + NUM_CR_RESULTS = (0x0000003C) + } + [Flags] + enum DICFG { + /// <summary> + /// Return only the device that is associated with the system default device interface, if one is set, for the specified device interface classes. + /// only valid with <see cref="DEVICEINTERFACE"/>. + /// </summary> + DEFAULT = 0x00000001, + /// <summary> + /// Return only devices that are currently present in a system. + /// </summary> + PRESENT = 0x00000002, + /// <summary> + /// Return a list of installed devices for all device setup classes or all device interface classes. + /// </summary> + ALLCLASSES = 0x00000004, + /// <summary> + /// Return only devices that are a part of the current hardware profile. + /// </summary> + PROFILE = 0x00000008, + /// <summary> + /// Return devices that support device interfaces for the specified device interface classes. + /// </summary> + DEVICEINTERFACE = 0x00000010, + } + enum DICUSTOMDEVPROP { + NONE = 0, + MERGE_MULTISZ = 0x00000001, + } + public enum SPDRP { + /// <summary> + /// Requests a string describing the device, such as "Microsoft PS/2 Port Mouse", typically defined by the manufacturer. + /// </summary> + DeviceDesc = (0x00000000), + /// <summary> + /// Requests the hardware IDs provided by the device that identify the device. + /// </summary> + HardwareId = (0x00000001), + /// <summary> + /// Requests the compatible IDs reported by the device. + /// </summary> + CompatibleIds = (0x00000002), + Service = 0x00000004, + /// <summary> + /// Requests the name of the device's setup class, in text format. + /// </summary> + Class = (0x00000007), + /// <summary> + /// Requests the GUID for the device's setup class. + /// </summary> + ClassGuid = (0x00000008), + /// <summary> + /// Requests the name of the driver-specific registry key. + /// </summary> + Driver = (0x00000009), + ConfigFlags = 0x0000000A, + /// <summary> + /// Requests a string identifying the manufacturer of the device. + /// </summary> + Mfg = (0x0000000B), + /// <summary> + /// Requests a string that can be used to distinguish between two similar devices, typically defined by the class installer. + /// </summary> + FriendlyName = (0x0000000C), + /// <summary> + /// Requests information about the device's location on the bus; the interpretation of this information is bus-specific. + /// </summary> + LocationInformation = (0x0000000D), + /// <summary> + /// Requests the name of the PDO for this device. + /// </summary> + PhysicalDeviceObjectName = (0x0000000E), + Capabilities = 0x0000000F, + /// <summary> + /// Requests a number associated with the device that can be displayed in the user interface. + /// </summary> + UiNumber = (0x00000010), + UpperFilters = 0x00000011, + LowerFilters = 0x00000012, + /// <summary> + /// Requests the GUID for the bus that the device is connected to. + /// </summary> + BusTypeGuid = (0x00000013), + /// <summary> + /// Requests the bus type, such as PCIBus or PCMCIABus. + /// </summary> + LegacyBusType = (0x00000014), + /// <summary> + /// Requests the legacy bus number of the bus the device is connected to. + /// </summary> + BusNumber = (0x00000015), + /// <summary> + /// Requests the name of the enumerator for the device, such as "USB". + /// </summary> + EnumeratorName = (0x00000016), + DevType = 0x00000019, + Exclusive = 0x0000001A, + Characteristics = 0x0000001B, + /// <summary> + /// Requests the address of the device on the bus. + /// </summary> + Address = (0x0000001C), + /// <summary> + /// (Windows XP and later.) Requests the device's current removal policy. The operating system uses this value as a hint to determine how the device is normally removed. + /// </summary> + RemovalPolicy = (0x0000001F), + /// <summary> + /// Windows XP and later.) Requests the device's installation state. + /// </summary> + InstallState = (0x00000022), + /// <summary> + /// Device Location Paths (R) + /// </summary> + LocationPaths = (0x00000023), + } + public enum CMRDP : uint { + DEVICEDESC = 0x00000001, + HARDWAREID = 0x00000002, + COMPATIBLEIDS = 0x00000003, + SERVICE = 0x00000005, + CLASS = 0x00000008, + CLASSGUID = 0x00000009, + DRIVER = 0x0000000A, + CONFIGFLAGS = 0x0000000B, + MFG = 0x0000000C, + FRIENDLYNAME = 0x0000000D, + LOCATION_INFORMATION = 0x0000000E, + PHYSICAL_DEVICE_OBJECT_NAME = 0x0000000F, + CAPABILITIES = 0x00000010, + UI_NUMBER = 0x00000011, + UPPERFILTERS = 0x00000012, + LOWERFILTERS = 0x00000013, + BUSTYPEGUID = 0x00000014, + LEGACYBUSTYPE = 0x00000015, + BUSNUMBER = 0x00000016, + ENUMERATOR_NAME = 0x00000017, + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Internal/Windows/UsbApi.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,386 @@ +using System; +using System.Runtime.InteropServices; + +namespace UCIS.USBLib.Internal.Windows { + class UsbApi { + //public const int INVALID_HANDLE_VALUE = -1; + + public const int USBUSER_GET_CONTROLLER_INFO_0 = 0x00000001; + public const int USBUSER_GET_CONTROLLER_DRIVER_KEY = 0x00000002; + + public const int IOCTL_GET_HCD_DRIVERKEY_NAME = 0x220424; + public const int IOCTL_USB_GET_ROOT_HUB_NAME = 0x220408; + public const int IOCTL_USB_GET_NODE_INFORMATION = 0x220408; + public const int IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX = 0x220448; + public const int IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION = 0x220410; + public const int IOCTL_USB_GET_NODE_CONNECTION_NAME = 0x220414; + public const int IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME = 0x220420; + public const int IOCTL_STORAGE_GET_DEVICE_NUMBER = 0x2D1080; + + public const int USB_DEVICE_DESCRIPTOR_TYPE = 0x1; + public const int USB_CONFIGURATION_DESCRIPTOR_TYPE = 0x2; + public const int USB_STRING_DESCRIPTOR_TYPE = 0x3; + public const int USB_INTERFACE_DESCRIPTOR_TYPE = 0x4; + public const int USB_ENDPOINT_DESCRIPTOR_TYPE = 0x5; + + public const string GUID_DEVINTERFACE_HUBCONTROLLER = "3abf6f2d-71c4-462a-8a92-1e6861e6af27"; + public const string GUID_DEVINTERFACE_USB_HOST_CONTROLLER = "{3ABF6F2D-71C4-462A-8A92-1E6861E6AF27}"; + public const string GUID_DEVINTERFACE_USB_HUB = "{F18A0E88-C30C-11D0-8815-00A0C906BED8}"; + public const string GUID_DEVINTERFACE_USB_DEVICE = "{A5DCBF10-6530-11D2-901F-00C04FB951ED}"; + + public const int MAX_BUFFER_SIZE = 2048; + public const int MAXIMUM_USB_STRING_LENGTH = 255; + public const string REGSTR_KEY_USB = "USB"; + public const int REG_SZ = 1; + public const int DIF_PROPERTYCHANGE = 0x00000012; + public const int DICS_FLAG_GLOBAL = 0x00000001; + + + //public const int SPDRP_DRIVER = 0x9; + //public const int SPDRP_DEVICEDESC = 0x0; + + public const int DICS_ENABLE = 0x00000001; + public const int DICS_DISABLE = 0x00000002; + + //#endregion + } + + #region enumerations + + enum UsbDeviceClass : byte { + UnspecifiedDevice = 0x00, + AudioInterface = 0x01, + CommunicationsAndCDCControlBoth = 0x02, + HIDInterface = 0x03, + PhysicalInterfaceDevice = 0x5, + ImageInterface = 0x06, + PrinterInterface = 0x07, + MassStorageInterface = 0x08, + HubDevice = 0x09, + CDCDataInterface = 0x0A, + SmartCardInterface = 0x0B, + ContentSecurityInterface = 0x0D, + VidioInterface = 0x0E, + PersonalHeathcareInterface = 0x0F, + DiagnosticDeviceBoth = 0xDC, + WirelessControllerInterface = 0xE0, + MiscellaneousBoth = 0xEF, + ApplicationSpecificInterface = 0xFE, + VendorSpecificBoth = 0xFF + } + + enum HubCharacteristics : byte { + GangedPowerSwitching = 0x00, + IndividualPotPowerSwitching = 0x01, + // to do + } + + enum USB_HUB_NODE { + UsbHub, + UsbMIParent + } + + enum USB_DESCRIPTOR_TYPE : byte { + DeviceDescriptorType = 0x1, + ConfigurationDescriptorType = 0x2, + StringDescriptorType = 0x3, + InterfaceDescriptorType = 0x4, + EndpointDescriptorType = 0x5, + HubDescriptor = 0x29 + } + + [Flags] + enum USB_CONFIGURATION : byte { + RemoteWakeUp = 32, + SelfPowered = 64, + BusPowered = 128, + RemoteWakeUp_BusPowered = 160, + RemoteWakeUp_SelfPowered = 96 + } + + enum USB_TRANSFER : byte { + Control = 0x0, + Isochronous = 0x1, + Bulk = 0x2, + Interrupt = 0x3 + } + + enum USB_CONNECTION_STATUS : int { + NoDeviceConnected, + DeviceConnected, + DeviceFailedEnumeration, + DeviceGeneralFailure, + DeviceCausedOvercurrent, + DeviceNotEnoughPower, + DeviceNotEnoughBandwidth, + DeviceHubNestedTooDeeply, + DeviceInLegacyHub + } + + enum USB_DEVICE_SPEED : byte { + UsbLowSpeed = 0, + UsbFullSpeed, + UsbHighSpeed + } + + [Flags] + enum DeviceInterfaceDataFlags : uint { + Unknown = 0x00000000, + Active = 0x00000001, + Default = 0x00000002, + Removed = 0x00000004 + } + + [Flags] + enum HubPortStatus : short { + Connection = 0x0001, + Enabled = 0x0002, + Suspend = 0x0004, + OverCurrent = 0x0008, + BeingReset = 0x0010, + Power = 0x0100, + LowSpeed = 0x0200, + HighSpeed = 0x0400, + TestMode = 0x0800, + Indicator = 0x1000, + // these are the bits which cause the hub port state machine to keep moving + //kHubPortStateChangeMask = kHubPortConnection | kHubPortEnabled | kHubPortSuspend | kHubPortOverCurrent | kHubPortBeingReset + } + + enum HubStatus : byte { + LocalPowerStatus = 1, + OverCurrentIndicator = 2, + LocalPowerStatusChange = 1, + OverCurrentIndicatorChange = 2 + } + + enum PortIndicatorSlectors : byte { + IndicatorAutomatic = 0, + IndicatorAmber, + IndicatorGreen, + IndicatorOff + } + + enum PowerSwitching : byte { + SupportsGangPower = 0, + SupportsIndividualPortPower = 1, + SetPowerOff = 0, + SetPowerOn = 1 + } + + #endregion + + #region structures + + [StructLayout(LayoutKind.Sequential)] + struct SP_CLASSINSTALL_HEADER { + public int cbSize; + public int InstallFunction; //DI_FUNCTION InstallFunction; + } + + [StructLayout(LayoutKind.Sequential)] + struct SP_PROPCHANGE_PARAMS { + public SP_CLASSINSTALL_HEADER ClassInstallHeader; + public int StateChange; + public int Scope; + public int HwProfile; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + struct USB_HCD_DRIVERKEY_NAME { + public uint ActualLength; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = UsbApi.MAX_BUFFER_SIZE)] + public string DriverKeyName; //WCHAR DriverKeyName[1]; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + struct USB_ROOT_HUB_NAME { + public uint ActualLength; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = UsbApi.MAX_BUFFER_SIZE)] + public string RootHubName; //WCHAR RootHubName[1]; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct USB_HUB_DESCRIPTOR { + public byte bDescriptorLength; + public USB_DESCRIPTOR_TYPE bDescriptorType; + public byte bNumberOfPorts; + public ushort wHubCharacteristics; + public byte bPowerOnToPowerGood; + public byte bHubControlCurrent; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] + public byte[] bRemoveAndPowerMask; //UCHAR bRemoveAndPowerMask[64]; + } + + [StructLayout(LayoutKind.Sequential)] + struct USB_HUB_INFORMATION { + public USB_HUB_DESCRIPTOR HubDescriptor; + public bool HubIsBusPowered; + } + + [StructLayout(LayoutKind.Sequential)] + struct USB_NODE_INFORMATION { + //public int NodeType; + public USB_HUB_NODE NodeType; + public USB_HUB_INFORMATION HubInformation; // union { USB_HUB_INFORMATION HubInformation; USB_MI_PARENT_INFORMATION MiParentInformation; } + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct USB_NODE_CONNECTION_INFORMATION_EX { + public uint ConnectionIndex; + public USB_DEVICE_DESCRIPTOR DeviceDescriptor; + public byte CurrentConfigurationValue; + public USB_DEVICE_SPEED Speed; + public byte DeviceIsHub; //BOOLEAN DeviceIsHub; + public ushort DeviceAddress; + public uint NumberOfOpenPipes; + public USB_CONNECTION_STATUS ConnectionStatus; + //public IntPtr PipeList; //USB_PIPE_INFO PipeList[0]; + //[MarshalAs(UnmanagedType.ByValArray, SizeConst=100)] + //Byte[] PipeList; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct USB_DESCRIPTOR { + public byte bLength; + public USB_DESCRIPTOR_TYPE bDescriptorType; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + class USB_DEVICE_DESCRIPTOR { + public byte bLength; + public USB_DESCRIPTOR_TYPE bDescriptorType; + public ushort bcdUSB; + public UsbDeviceClass bDeviceClass; + public byte bDeviceSubClass; + public byte bDeviceProtocol; + public byte bMaxPacketSize0; + public ushort idVendor; + public ushort idProduct; + public ushort bcdDevice; + public byte iManufacturer; + public byte iProduct; + public byte iSerialNumber; + public byte bNumConfigurations; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct USB_ENDPOINT_DESCRIPTOR { + public byte bLength; + public USB_DESCRIPTOR_TYPE bDescriptorType; + public byte bEndpointAddress; + public USB_TRANSFER bmAttributes; + public short wMaxPacketSize; + public byte bInterval; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + struct USB_STRING_DESCRIPTOR { + public byte bLength; + public USB_DESCRIPTOR_TYPE bDescriptorType; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = UsbApi.MAXIMUM_USB_STRING_LENGTH)] + public string bString; //WCHAR bString[1]; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct USB_INTERFACE_DESCRIPTOR { + public byte bLength; + public USB_DESCRIPTOR_TYPE bDescriptorType; + public byte bInterfaceNumber; + public byte bAlternateSetting; + public byte bNumEndpoints; + public byte bInterfaceClass; + public byte bInterfaceSubClass; + public byte bInterfaceProtocol; + public byte Interface; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct USB_CONFIGURATION_DESCRIPTOR { + public byte bLength; + public USB_DESCRIPTOR_TYPE bDescriptorType; + public ushort wTotalLength; + public byte bNumInterface; + public byte bConfigurationsValue; + public byte iConfiguration; + public USB_CONFIGURATION bmAttributes; + public byte MaxPower; + } + + [StructLayout(LayoutKind.Sequential)] + struct HID_DESCRIPTOR_DESC_LIST { + public byte bReportType; + public short wReportLength; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct HID_DESCRIPTOR { + public byte bLength; + public USB_DESCRIPTOR_TYPE bDescriptorType; + public ushort bcdHID; + public byte bCountry; + public byte bNumDescriptors; + public HID_DESCRIPTOR_DESC_LIST hid_desclist; //DescriptorList [1]; + } + + [StructLayout(LayoutKind.Sequential)] + struct USB_SETUP_PACKET { + public byte bmRequest; + public byte bRequest; + public ushort wValue; + public ushort wIndex; + public ushort wLength; + } + + [StructLayout(LayoutKind.Sequential)] + struct USB_DESCRIPTOR_REQUEST { + public uint ConnectionIndex; + public USB_SETUP_PACKET SetupPacket; + //public byte[] Data; //UCHAR Data[0]; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + struct USB_NODE_CONNECTION_NAME { + public uint ConnectionIndex; + public uint ActualLength; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = UsbApi.MAX_BUFFER_SIZE)] + public string NodeName; //WCHAR NodeName[1]; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + struct USB_NODE_CONNECTION_DRIVERKEY_NAME { + public uint ConnectionIndex; + public uint ActualLength; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = UsbApi.MAX_BUFFER_SIZE)] + public string DriverKeyName; //WCHAR DriverKeyName[1]; + } + + [StructLayout(LayoutKind.Sequential)] + struct STORAGE_DEVICE_NUMBER { + public int DeviceType; //DEVICE_TYPE DeviceType; + public uint DeviceNumber; + public uint PartitionNumber; + } + + [StructLayout(LayoutKind.Sequential)] + class SP_DEVINFO_DATA1 { + public int cbSize; + public Guid ClassGuid; + public int DevInst; + public ulong Reserved; + }; + + [StructLayout(LayoutKind.Sequential)] + class RAW_ROOTPORT_PARAMETERS { + public ushort PortNumber; + public ushort PortStatus; + } + + [StructLayout(LayoutKind.Sequential)] + class USB_UNICODE_NAME { + public uint Length; + public string str; //WCHAR String[1]; + } + + #endregion +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Internal/Windows/Win32Kernel.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,114 @@ +using System; +using System.Runtime.InteropServices; +using System.Security; +using System.Threading; +using Microsoft.Win32.SafeHandles; + +namespace UCIS.USBLib.Internal.Windows { + [SuppressUnmanagedCodeSecurity] + static class Kernel32 { + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] + internal static extern SafeFileHandle CreateFile(string fileName, NativeFileAccess fileAccess, NativeFileShare fileShare, IntPtr securityAttributes, NativeFileMode creationDisposition, NativeFileFlag flags, IntPtr template); + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess, int dwShareMode, IntPtr lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)] + unsafe internal static extern bool DeviceIoControl(SafeHandle hDevice, int IoControlCode, IntPtr InBuffer, int nInBufferSize, IntPtr OutBuffer, int nOutBufferSize, out int pBytesReturned, NativeOverlapped* Overlapped); + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)] + unsafe internal static extern bool GetOverlappedResult(SafeHandle hFile, NativeOverlapped* lpOverlapped, out int lpNumberOfBytesTransferred, Boolean bWait); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern bool DeviceIoControl(SafeHandle hDevice, int dwIoControlCode, IntPtr lpInBuffer, int nInBufferSize, out USB_ROOT_HUB_NAME lpOutBuffer, int nOutBufferSize, out int lpBytesReturned, IntPtr lpOverlapped); + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern bool DeviceIoControl(SafeHandle hDevice, int dwIoControlCode, [In] ref USB_NODE_INFORMATION lpInBuffer, int nInBufferSize, out USB_NODE_INFORMATION lpOutBuffer, int nOutBufferSize, out int lpBytesReturned, IntPtr lpOverlapped); + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern bool DeviceIoControl(SafeHandle hDevice, int dwIoControlCode, [In] ref USB_DESCRIPTOR_REQUEST lpInBuffer, int nInBufferSize, IntPtr lpOutBuffer, int nOutBufferSize, out int lpBytesReturned, IntPtr lpOverlapped); + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern bool DeviceIoControl(SafeHandle hDevice, int dwIoControlCode, [In] ref USB_NODE_CONNECTION_DRIVERKEY_NAME lpInBuffer, int nInBufferSize, out USB_NODE_CONNECTION_DRIVERKEY_NAME lpOutBuffer, int nOutBufferSize, out int lpBytesReturned, IntPtr lpOverlapped); + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern bool DeviceIoControl(SafeHandle hDevice, int dwIoControlCode, [In] ref USB_NODE_CONNECTION_INFORMATION_EX lpInBuffer, int nInBufferSize, out USB_NODE_CONNECTION_INFORMATION_EX lpOutBuffer, int nOutBufferSize, out int lpBytesReturned, IntPtr lpOverlapped); + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern bool DeviceIoControl(SafeHandle hDevice, int dwIoControlCode, [In] ref USB_NODE_CONNECTION_NAME lpInBuffer, int nInBufferSize, out USB_NODE_CONNECTION_NAME lpOutBuffer, int nOutBufferSize, out int lpBytesReturned, IntPtr lpOverlapped); + + //public const uint GENERIC_READ = 0x80000000; + public const uint GENERIC_WRITE = 0x40000000; + //public const uint GENERIC_EXECUTE = 0x20000000; + //public const uint GENERIC_ALL = 0x10000000; + //public const uint FILE_FLAG_NO_BUFFERING = 0x20000000; + + //public const int FILE_SHARE_READ = 0x1; + public const int FILE_SHARE_WRITE = 0x2; + public const int OPEN_EXISTING = 0x3; + } + + [Flags] + enum NativeFileAccess : uint { + FILE_SPECIAL = 0, + FILE_APPEND_DATA = (0x0004), // file + FILE_READ_DATA = (0x0001), // file & pipe + FILE_WRITE_DATA = (0x0002), // file & pipe + FILE_READ_EA = (0x0008), // file & directory + FILE_WRITE_EA = (0x0010), // file & directory + FILE_READ_ATTRIBUTES = (0x0080), // all + FILE_WRITE_ATTRIBUTES = (0x0100), // all + DELETE = 0x00010000, + READ_CONTROL = (0x00020000), + WRITE_DAC = (0x00040000), + WRITE_OWNER = (0x00080000), + SYNCHRONIZE = (0x00100000), + STANDARD_RIGHTS_REQUIRED = (0x000F0000), + STANDARD_RIGHTS_READ = (READ_CONTROL), + STANDARD_RIGHTS_WRITE = (READ_CONTROL), + STANDARD_RIGHTS_EXECUTE = (READ_CONTROL), + STANDARD_RIGHTS_ALL = (0x001F0000), + SPECIFIC_RIGHTS_ALL = (0x0000FFFF), + FILE_GENERIC_READ = (STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE), + FILE_GENERIC_WRITE = (STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE), + SPECIAL = 0 + } + + enum NativeFileMode : uint { + CREATE_NEW = 1, + CREATE_ALWAYS = 2, + OPEN_EXISTING = 3, + OPEN_ALWAYS = 4, + TRUNCATE_EXISTING = 5, + } + + [Flags] + enum NativeFileShare : uint { + NONE = 0, + FILE_SHARE_READ = 0x00000001, + FILE_SHARE_WRITE = 0x00000002, + FILE_SHARE_DEELETE = 0x00000004, + } + + [Flags] + enum NativeFileFlag : uint { + FILE_ATTRIBUTE_READONLY = 0x00000001, + FILE_ATTRIBUTE_HIDDEN = 0x00000002, + FILE_ATTRIBUTE_SYSTEM = 0x00000004, + FILE_ATTRIBUTE_DIRECTORY = 0x00000010, + FILE_ATTRIBUTE_ARCHIVE = 0x00000020, + FILE_ATTRIBUTE_DEVICE = 0x00000040, + FILE_ATTRIBUTE_NORMAL = 0x00000080, + FILE_ATTRIBUTE_TEMPORARY = 0x00000100, + FILE_ATTRIBUTE_SPARSE_FILE = 0x00000200, + FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400, + FILE_ATTRIBUTE_COMPRESSED = 0x00000800, + FILE_ATTRIBUTE_OFFLINE = 0x00001000, + FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000, + FILE_ATTRIBUTE_ENCRYPTED = 0x00004000, + FILE_FLAG_WRITE_THROUGH = 0x80000000, + FILE_FLAG_OVERLAPPED = 0x40000000, + FILE_FLAG_NO_BUFFERING = 0x20000000, + FILE_FLAG_RANDOM_ACCESS = 0x10000000, + FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000, + FILE_FLAG_DELETE_ON_CLOSE = 0x04000000, + FILE_FLAG_BACKUP_SEMANTICS = 0x02000000, + FILE_FLAG_POSIX_SEMANTICS = 0x01000000, + FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000, + FILE_FLAG_OPEN_NO_RECALL = 0x00100000, + FILE_FLAG_FIRST_PIPE_INSTANCE = 0x00080000, + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Windows/Devices/DeviceNode.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,267 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Text; +using Microsoft.Win32; +using UCIS.USBLib.Internal.Windows; + +namespace UCIS.HWLib.Windows.Devices { + public class CMException : Exception { + internal CMException(CR result, String method) + : base(method + " returned " + result.ToString()) { + } + internal static void Throw(CR result, String method) { + if (result == CR.SUCCESS) return; + throw new CMException(result, method); + } + } + public class DeviceNode { + public static DeviceNode Root { + get { + UInt32 node; + CR ret = SetupApi.CM_Locate_DevNode(out node, null, 0); + CMException.Throw(ret, "CM_Locate_DevNode"); + return new DeviceNode(node); + } + } + public static DeviceNode GetDevice(String deviceID) { + UInt32 node; + CR ret = SetupApi.CM_Locate_DevNode(out node, deviceID, 0); + CMException.Throw(ret, "CM_Locate_DevNode"); + return new DeviceNode(node); + } + private static IList<DeviceNode> GetDevicesInSet(SafeDeviceInfoSetHandle dis) { + List<DeviceNode> list = new List<DeviceNode>(); + if (dis.IsInvalid) throw new Win32Exception(Marshal.GetLastWin32Error()); + SP_DEVINFO_DATA dd = new SP_DEVINFO_DATA(true); + for (int index = 0; ; index++) { + if (!SetupApi.SetupDiEnumDeviceInfo(dis, index, ref dd)) break; + list.Add(new DeviceNode(dd.DevInst)); + } + return list; + } + public static IList<DeviceNode> GetDevices() { + using (SafeDeviceInfoSetHandle dis = SetupApi.SetupDiGetClassDevsA(IntPtr.Zero, null, IntPtr.Zero, DICFG.PRESENT | DICFG.ALLCLASSES)) { + return GetDevicesInSet(dis); + } + } + public static IList<DeviceNode> GetDevices(Guid classGuid) { + using (SafeDeviceInfoSetHandle dis = SetupApi.SetupDiGetClassDevsA(ref classGuid, null, IntPtr.Zero, DICFG.PRESENT | DICFG.DEVICEINTERFACE)) { + return GetDevicesInSet(dis); + } + } + public static IList<DeviceNode> GetDevices(String enumerator) { + using (SafeDeviceInfoSetHandle dis = SetupApi.SetupDiGetClassDevsA(IntPtr.Zero, enumerator, IntPtr.Zero, DICFG.PRESENT | DICFG.ALLCLASSES)) { + //using (SafeDeviceInfoSetHandle dis = SetupApi.SetupDiGetClassDevsA(IntPtr.Zero, enumerator, IntPtr.Zero, DICFG.ALLCLASSES | DICFG.DEVICEINTERFACE)) { + return GetDevicesInSet(dis); + } + } + + public UInt32 DevInst { get; private set; } + private String _DeviceID = null; + internal DeviceNode(UInt32 node) { + DevInst = node; + } + public String DeviceID { + get { + if (_DeviceID == null) { + uint deviceidlen; + CR ret = SetupApi.CM_Get_Device_ID_Size(out deviceidlen, DevInst, 0); + CMException.Throw(ret, "CM_Get_Device_ID_Size"); + StringBuilder deviceid = new StringBuilder((int)deviceidlen); + ret = SetupApi.CM_Get_Device_ID(DevInst, deviceid, deviceid.MaxCapacity, 0); + CMException.Throw(ret, "CM_Get_Device_ID"); + _DeviceID = deviceid.ToString(); + } + return _DeviceID; + } + } + public Byte[] GetProperty(SPDRP property) { + using (SafeDeviceInfoSetHandle dis = SetupApi.SetupDiGetClassDevsA(IntPtr.Zero, DeviceID, IntPtr.Zero, DICFG.DEVICEINTERFACE | DICFG.ALLCLASSES)) { + if (dis.IsInvalid) throw new Win32Exception(Marshal.GetLastWin32Error()); + SP_DEVINFO_DATA dd = new SP_DEVINFO_DATA(true); + if (!SetupApi.SetupDiEnumDeviceInfo(dis, 0, ref dd)) + return null; + //throw new Win32Exception(Marshal.GetLastWin32Error()); + RegistryValueKind propertyType; + byte[] propBuffer = new byte[256]; + int requiredSize; + if (!SetupApi.SetupDiGetDeviceRegistryProperty(dis, ref dd, property, out propertyType, propBuffer, propBuffer.Length, out requiredSize)) + return null; + if (requiredSize > propBuffer.Length) { + propBuffer = new Byte[requiredSize]; + if (!SetupApi.SetupDiGetDeviceRegistryProperty(dis, ref dd, property, out propertyType, propBuffer, propBuffer.Length, out requiredSize)) + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + if (requiredSize < propBuffer.Length) Array.Resize(ref propBuffer, requiredSize); + return propBuffer; + } + } + public String GetPropertyString(SPDRP property) { + Byte[] buffer = GetProperty(property); + if (buffer == null) return null; + return SetupApi.GetAsString(buffer, buffer.Length); + } + public Byte[] GetProperty(CMRDP property) { + uint proplength = 0; + uint proptype; + CR ret = SetupApi.CM_Get_DevNode_Registry_Property(DevInst, property, out proptype, null, ref proplength, 0); + if (ret == CR.NO_SUCH_VALUE) return null; + if (ret != CR.BUFFER_SMALL) CMException.Throw(ret, "CM_Get_DevNode_Registry_Property"); + Byte[] propbuffer = new Byte[proplength]; + ret = SetupApi.CM_Get_DevNode_Registry_Property(DevInst, property, out proptype, propbuffer, ref proplength, 0); + CMException.Throw(ret, "CM_Get_DevNode_Registry_Property"); + if (propbuffer.Length > proplength) Array.Resize(ref propbuffer, (int)proplength); + return propbuffer; + } + public String GetPropertyString(CMRDP property) { + Byte[] buffer = GetProperty(property); + if (buffer == null) return null; + return SetupApi.GetAsString(buffer, buffer.Length); + } + public String[] GetPropertyStringArray(CMRDP property) { + Byte[] buffer = GetProperty(property); + if (buffer == null) return null; + return SetupApi.GetAsStringArray(buffer, buffer.Length); + } + + public Byte[] GetCustomProperty(String name) { + using (SafeDeviceInfoSetHandle dis = SetupApi.SetupDiGetClassDevsA(IntPtr.Zero, DeviceID, IntPtr.Zero, DICFG.DEVICEINTERFACE | DICFG.ALLCLASSES)) { + if (dis.IsInvalid) throw new Win32Exception(Marshal.GetLastWin32Error()); + SP_DEVINFO_DATA dd = new SP_DEVINFO_DATA(true); + if (!SetupApi.SetupDiEnumDeviceInfo(dis, 0, ref dd)) + return null; + //throw new Win32Exception(Marshal.GetLastWin32Error()); + RegistryValueKind propertyType; + byte[] propBuffer = new byte[256]; + int requiredSize; + if (!SetupApi.SetupDiGetCustomDeviceProperty(dis, ref dd, name, DICUSTOMDEVPROP.NONE, out propertyType, propBuffer, propBuffer.Length, out requiredSize)) + return null; + if (requiredSize > propBuffer.Length) { + propBuffer = new Byte[requiredSize]; + if (!SetupApi.SetupDiGetCustomDeviceProperty(dis, ref dd, name, DICUSTOMDEVPROP.NONE, out propertyType, propBuffer, propBuffer.Length, out requiredSize)) + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + if (requiredSize < propBuffer.Length) Array.Resize(ref propBuffer, requiredSize); + return propBuffer; + } + } + public String GetCustomPropertyString(String name) { + Byte[] buffer = GetCustomProperty(name); + if (buffer == null) return null; + return SetupApi.GetAsString(buffer, buffer.Length); + } + public String[] GetCustomPropertyStringArray(String name) { + Byte[] buffer = GetCustomProperty(name); + if (buffer == null) return null; + return SetupApi.GetAsStringArray(buffer, buffer.Length); + } + + public String DeviceDescription { get { return GetPropertyString(CMRDP.DEVICEDESC); } } + public String[] HardwareID { get { return GetPropertyStringArray(CMRDP.HARDWAREID); } } + public String[] CompatibleIDs { get { return GetPropertyStringArray(CMRDP.COMPATIBLEIDS); } } + public String Service { get { return GetPropertyString(CMRDP.SERVICE); } } + public String Class { get { return GetPropertyString(CMRDP.CLASS); } } + public String ClassGuid { get { return GetPropertyString(CMRDP.CLASSGUID); } } + public String DriverKey { get { return GetPropertyString(CMRDP.DRIVER); } } + public String Manufacturer { get { return GetPropertyString(CMRDP.MFG); } } + public String FriendlyName { get { return GetPropertyString(CMRDP.FRIENDLYNAME); } } + public String LocationInformation { get { return GetPropertyString(CMRDP.LOCATION_INFORMATION); } } + public String PhysicalDeviceObjectName { get { return GetPropertyString(CMRDP.PHYSICAL_DEVICE_OBJECT_NAME); } } + public Guid? BusTypeGuid { get { return SetupApi.GetAsGuid(GetProperty(CMRDP.BUSTYPEGUID)); } } + public Int32? BusNumber { get { return SetupApi.GetAsInt32(GetProperty(CMRDP.BUSNUMBER)); } } + public String EnumeratorName { get { return GetPropertyString(CMRDP.ENUMERATOR_NAME); } } + + public String[] GetInterfaces(String classGuid) { + return GetInterfaces(new Guid(classGuid)); + } + public String[] GetInterfaces(Guid classGuid) { + uint len; + CR ret = SetupApi.CM_Get_Device_Interface_List_Size(out len, ref classGuid, DeviceID, 0); + CMException.Throw(ret, "CM_Get_Device_Interface_List_Size"); + if (len <= 1) return null; + Byte[] buffer = new Byte[2 * len]; + ret = SetupApi.CM_Get_Device_Interface_List(ref classGuid, DeviceID, buffer, len, 0); + CMException.Throw(ret, "CM_Get_Device_Interface_List"); + return SetupApi.GetAsStringArray(buffer, 2 * (int)len); + } + public Boolean SupportsInterface(Guid classGuid) { + uint len; + CR ret = SetupApi.CM_Get_Device_Interface_List_Size(out len, ref classGuid, DeviceID, 0); + CMException.Throw(ret, "CM_Get_Device_Interface_List_Size"); + return len > 2; + } + + public IList<DeviceNode> GetChildren() { + UInt32 child; + CR ret = SetupApi.CM_Get_Child(out child, DevInst, 0); + if (ret == CR.NO_SUCH_DEVNODE) return null; + CMException.Throw(ret, "CM_Get_Child"); + List<DeviceNode> list = new List<DeviceNode>(); + while (true) { + list.Add(new DeviceNode(child)); + ret = SetupApi.CM_Get_Sibling(out child, child, 0); + if (ret == CR.NO_SUCH_DEVNODE) break; + CMException.Throw(ret, "CM_Get_Sibling"); + } + return list; + } + + public DeviceNode GetParent() { + UInt32 node; + CR ret = SetupApi.CM_Get_Parent(out node, DevInst, 0); + if (ret == CR.NO_SUCH_DEVNODE) return null; + CMException.Throw(ret, "CM_Get_Parent"); + return new DeviceNode(node); + } + + public Boolean Present { + get { + UInt32 status, problem; + CR ret = SetupApi.CM_Get_DevNode_Status(out status, out problem, DevInst, 0); + if (ret == CR.NO_SUCH_DEVNODE) return false; + CMException.Throw(ret, "CM_Get_DevNode_Status"); + if (status == 25174016) return false; + return true; + } + } + + public override bool Equals(object obj) { + DeviceNode other = obj as DeviceNode; + if (ReferenceEquals(other, null)) return false; + return DevInst == other.DevInst; + } + public override int GetHashCode() { + return (int)DevInst; + } + public static Boolean operator ==(DeviceNode x, DeviceNode y) { + if (ReferenceEquals(x, y)) return true; + if (ReferenceEquals(x, null)) return false; + if (ReferenceEquals(y, null)) return false; + return x.DevInst == y.DevInst; + } + public static Boolean operator !=(DeviceNode x, DeviceNode y) { + return !(x == y); + } + + public void SetEnabled(Boolean enabled) { + using (SafeDeviceInfoSetHandle dis = SetupApi.SetupDiGetClassDevsA(IntPtr.Zero, DeviceID, IntPtr.Zero, DICFG.DEVICEINTERFACE | DICFG.ALLCLASSES)) { + if (dis.IsInvalid) throw new Win32Exception(Marshal.GetLastWin32Error()); + SP_DEVINFO_DATA dd = new SP_DEVINFO_DATA(true); + if (!SetupApi.SetupDiEnumDeviceInfo(dis, 0, ref dd)) + throw new Win32Exception(Marshal.GetLastWin32Error()); + SP_PROPCHANGE_PARAMS PropChangeParams = new SP_PROPCHANGE_PARAMS(); + PropChangeParams.ClassInstallHeader.cbSize = Marshal.SizeOf(PropChangeParams.ClassInstallHeader); + PropChangeParams.ClassInstallHeader.InstallFunction = UsbApi.DIF_PROPERTYCHANGE; + PropChangeParams.Scope = UsbApi.DICS_FLAG_GLOBAL; // or use DICS_FLAG_CONFIGSPECIFIC to limit to current HW profile + PropChangeParams.HwProfile = 0; //Current hardware profile + PropChangeParams.StateChange = enabled ? UsbApi.DICS_ENABLE : UsbApi.DICS_DISABLE; + if (!SetupApi.SetupDiSetClassInstallParams(dis, ref dd, ref PropChangeParams.ClassInstallHeader, Marshal.SizeOf(PropChangeParams))) + throw new Win32Exception(Marshal.GetLastWin32Error()); + if (!SetupApi.SetupDiCallClassInstaller(UsbApi.DIF_PROPERTYCHANGE, dis, ref dd)) + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Windows/USB/UsbBus.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using UCIS.HWLib.Windows.Devices; +using UCIS.USBLib.Internal.Windows; + +namespace UCIS.HWLib.Windows.USB { + public class UsbBus { + private List<UsbController> devices = null; + public IList<UsbController> Controllers { + get { + if (devices == null) Refresh(); + return devices.AsReadOnly(); + } + } + public void Refresh() { + devices = new List<UsbController>(); + Guid m_Guid = new Guid(UsbApi.GUID_DEVINTERFACE_HUBCONTROLLER); + foreach (DeviceNode dev in DeviceNode.GetDevices(m_Guid)) { + String[] interfaces = dev.GetInterfaces(m_Guid); + if (interfaces == null || interfaces.Length == 0) continue; + devices.Add(new UsbController(this, dev, interfaces[0])); + } + } + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Windows/USB/UsbController.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,31 @@ +using System; +using System.Runtime.InteropServices; +using Microsoft.Win32.SafeHandles; +using UCIS.HWLib.Windows.Devices; +using UCIS.USBLib.Internal.Windows; + +namespace UCIS.HWLib.Windows.USB { + public class UsbController { + public String DevicePath { get; private set; } + public DeviceNode DeviceNode { get; private set; } + public String DeviceDescription { get; private set; } + public String DriverKey { get; private set; } + public UsbHub RootHub { get; private set; } + internal UsbController(UsbBus parent, DeviceNode di, String devicePath) { + this.DeviceNode = di; + this.DevicePath = devicePath; + this.DeviceDescription = di.GetPropertyString(SPDRP.DeviceDesc); + this.DriverKey = di.GetPropertyString(SPDRP.Driver); + + USB_ROOT_HUB_NAME rootHubName; + using (SafeFileHandle handel1 = Kernel32.CreateFile(DevicePath, Kernel32.GENERIC_WRITE, Kernel32.FILE_SHARE_WRITE, IntPtr.Zero, Kernel32.OPEN_EXISTING, 0, IntPtr.Zero)) { + if (handel1.IsInvalid) throw new Exception("No port found!"); + int nBytesReturned; + if (!Kernel32.DeviceIoControl(handel1, UsbApi.IOCTL_USB_GET_ROOT_HUB_NAME, IntPtr.Zero, 0, out rootHubName, Marshal.SizeOf(typeof(USB_ROOT_HUB_NAME)), out nBytesReturned, IntPtr.Zero)) + throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); + } + if (rootHubName.ActualLength <= 0) throw new Exception("rootHubName.ActualLength <= 0"); + RootHub = new UsbHub(this, null, @"\\?\" + rootHubName.RootHubName); + } + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Windows/USB/UsbDevice.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,180 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Runtime.InteropServices; +using System.Text; +using Microsoft.Win32.SafeHandles; +using UCIS.USBLib.Internal.Windows; +using UCIS.HWLib.Windows.Devices; + +namespace UCIS.HWLib.Windows.USB { + public class UsbDevice { + public UsbDevice Parent { get; protected set; } + internal USB_NODE_CONNECTION_INFORMATION_EX NodeConnectionInfo { get; set; } + internal USB_DEVICE_DESCRIPTOR DeviceDescriptor { get; private set; } + internal IList<USB_CONFIGURATION_DESCRIPTOR> ConfigurationDescriptor { get; private set; } + internal IList<USB_INTERFACE_DESCRIPTOR> InterfaceDescriptor { get; private set; } + internal IList<USB_ENDPOINT_DESCRIPTOR> EndpointDescriptor { get; private set; } + internal IList<HID_DESCRIPTOR> HdiDescriptor { get; private set; } + public string DevicePath { get; private set; } + public uint AdapterNumber { get; internal set; } + public string DriverKey { get; private set; } + + public virtual string DeviceDescription { get { return DeviceNode.GetPropertyString(CMRDP.DEVICEDESC); } } + public string DeviceID { get { return DeviceNode.DeviceID; } } + + public bool IsConnected { get; internal set; } + public bool IsHub { get; internal set; } + public string Status { get; internal set; } + public string Speed { get; internal set; } + + public string Manufacturer { get; private set; } + public string SerialNumber { get; private set; } + public string Product { get; private set; } + + public int VendorID { get { return DeviceDescriptor.idVendor; } } + public int ProductID { get { return DeviceDescriptor.idProduct; } } + + private DeviceNode mDeviceNode; + public DeviceNode DeviceNode { + get { + if (mDeviceNode == null && DriverKey != null) { + foreach (DeviceNode node in DeviceNode.GetDevices("USB")) { + if (DriverKey.Equals(node.DriverKey, StringComparison.InvariantCultureIgnoreCase)) { + mDeviceNode = node; + break; + } + } + } + return mDeviceNode; + } + } + + internal UsbDevice(UsbDevice parent, USB_DEVICE_DESCRIPTOR deviceDescriptor, uint adapterNumber) + : this(parent, deviceDescriptor, adapterNumber, null) { } + unsafe internal UsbDevice(UsbDevice parent, USB_DEVICE_DESCRIPTOR deviceDescriptor, uint adapterNumber, string devicePath) { + this.Parent = parent; + this.AdapterNumber = adapterNumber; + this.DeviceDescriptor = deviceDescriptor; + this.DevicePath = devicePath; + ConfigurationDescriptor = new List<USB_CONFIGURATION_DESCRIPTOR>(); + InterfaceDescriptor = new List<USB_INTERFACE_DESCRIPTOR>(); + HdiDescriptor = new List<HID_DESCRIPTOR>(); + EndpointDescriptor = new List<USB_ENDPOINT_DESCRIPTOR>(); + if (devicePath == null) return; + + using (SafeFileHandle handel = Kernel32.CreateFile(devicePath, Kernel32.GENERIC_WRITE, Kernel32.FILE_SHARE_WRITE, IntPtr.Zero, Kernel32.OPEN_EXISTING, 0, IntPtr.Zero)) { + if (handel.IsInvalid) throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); + int nBytesReturned; + int nBytes = UsbApi.MAX_BUFFER_SIZE; + + USB_DESCRIPTOR_REQUEST Request1 = new USB_DESCRIPTOR_REQUEST(); + Request1.ConnectionIndex = adapterNumber;// portCount; + Request1.SetupPacket.wValue = (ushort)((UsbApi.USB_CONFIGURATION_DESCRIPTOR_TYPE << 8)); + Request1.SetupPacket.wLength = (ushort)(nBytes - Marshal.SizeOf(Request1)); + Request1.SetupPacket.wIndex = 0; // 0x409; // Language Code + + // Use an IOCTL call to request the String Descriptor + Byte[] buffer = new Byte[nBytes]; + fixed (Byte* bufferptr = buffer) { + if (!Kernel32.DeviceIoControl(handel, UsbApi.IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, ref Request1, Marshal.SizeOf(typeof(USB_DESCRIPTOR_REQUEST)), (IntPtr)bufferptr, nBytes, out nBytesReturned, IntPtr.Zero)) { + int err = Marshal.GetLastWin32Error(); + Console.WriteLine("IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION returned {0} {1}", err, (new System.ComponentModel.Win32Exception(err)).Message); + //SerialNumber = (new System.ComponentModel.Win32Exception(err)).Message; + if (err != 2 && err != 31 && err != 87) throw new System.ComponentModel.Win32Exception(err); + } else { + if (nBytesReturned > nBytes) throw new IndexOutOfRangeException("IOCtl returned too much data"); + if (nBytesReturned < 0) throw new IndexOutOfRangeException("IOCtl returned insufficient data"); + Byte* ptr = bufferptr + Marshal.SizeOf(Request1); + nBytesReturned -= Marshal.SizeOf(Request1); + if (nBytesReturned < 0) throw new IndexOutOfRangeException("IOCtl returned insufficient data"); + + int offset = 0; + while (offset < nBytesReturned) { + if (offset + Marshal.SizeOf(typeof(USB_DESCRIPTOR)) >= nBytesReturned) throw new IndexOutOfRangeException("Error in configuration descriptor"); + USB_DESCRIPTOR* desc = (USB_DESCRIPTOR*)(ptr + offset); + offset += desc->bLength; + if (offset > nBytesReturned) throw new IndexOutOfRangeException("Error in configuration descriptor"); + Console.WriteLine("Descriptor type {0} length {1}", desc->bDescriptorType, desc->bLength); + if (desc->bDescriptorType == USB_DESCRIPTOR_TYPE.ConfigurationDescriptorType) { + if (desc->bLength < 9) throw new IndexOutOfRangeException("Error in configuration descriptor"); + USB_CONFIGURATION_DESCRIPTOR configurationDescriptor = *(USB_CONFIGURATION_DESCRIPTOR*)desc; + ConfigurationDescriptor.Add(configurationDescriptor); + } else if (desc->bDescriptorType == USB_DESCRIPTOR_TYPE.InterfaceDescriptorType) { + if (desc->bLength < 9) throw new IndexOutOfRangeException("Error in configuration descriptor"); + USB_INTERFACE_DESCRIPTOR interfaceDescriptor = *(USB_INTERFACE_DESCRIPTOR*)desc; + InterfaceDescriptor.Add(interfaceDescriptor); + } else if (desc->bDescriptorType == USB_DESCRIPTOR_TYPE.EndpointDescriptorType) { + if (desc->bLength < 7) throw new IndexOutOfRangeException("Error in configuration descriptor"); + USB_ENDPOINT_DESCRIPTOR endpointDescriptor1 = *(USB_ENDPOINT_DESCRIPTOR*)desc; + EndpointDescriptor.Add(endpointDescriptor1); + } + } + } + // The iManufacturer, iProduct and iSerialNumber entries in the + // device descriptor are really just indexes. So, we have to + // request a string descriptor to get the values for those strings. + if (DeviceDescriptor != null) { + if (DeviceDescriptor.iManufacturer > 0) Manufacturer = GetStringDescriptor(handel, DeviceDescriptor.iManufacturer); + if (DeviceDescriptor.iProduct > 0) Product = GetStringDescriptor(handel, DeviceDescriptor.iProduct); + if (DeviceDescriptor.iSerialNumber > 0) SerialNumber = GetStringDescriptor(handel, DeviceDescriptor.iSerialNumber); + } + } + // Get the Driver Key Name (usefull in locating a device) + USB_NODE_CONNECTION_DRIVERKEY_NAME DriverKeyStruct = new USB_NODE_CONNECTION_DRIVERKEY_NAME(); + DriverKeyStruct.ConnectionIndex = adapterNumber; + // Use an IOCTL call to request the Driver Key Name + if (Kernel32.DeviceIoControl(handel, UsbApi.IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, ref DriverKeyStruct, Marshal.SizeOf(DriverKeyStruct), out DriverKeyStruct, Marshal.SizeOf(DriverKeyStruct), out nBytesReturned, IntPtr.Zero)) { + DriverKey = DriverKeyStruct.DriverKeyName; + } + } + } + + private unsafe String GetStringDescriptor(SafeFileHandle handel, Byte id) { + int nBytes = UsbApi.MAX_BUFFER_SIZE; + int nBytesReturned = 0; + Byte[] buffer = new Byte[nBytes]; + fixed (Byte* bufferptr = buffer) { + // Build a request for string descriptor. + USB_DESCRIPTOR_REQUEST Request = new USB_DESCRIPTOR_REQUEST(); + Request.ConnectionIndex = AdapterNumber; + Request.SetupPacket.wValue = (ushort)((UsbApi.USB_STRING_DESCRIPTOR_TYPE << 8) + id); + Request.SetupPacket.wLength = (ushort)(nBytes - Marshal.SizeOf(Request)); + Request.SetupPacket.wIndex = 0x409; // The language code. + // Use an IOCTL call to request the string descriptor. + if (Kernel32.DeviceIoControl(handel, UsbApi.IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, ref Request, Marshal.SizeOf(Request), (IntPtr)bufferptr, nBytes, out nBytesReturned, IntPtr.Zero)) { + if (nBytesReturned < nBytes) buffer[nBytesReturned] = 0; + if (nBytesReturned + 1 < nBytes) buffer[nBytesReturned + 1] = 0; + // The location of the string descriptor is immediately after + // the Request structure. Because this location is not "covered" + // by the structure allocation, we're forced to zero out this + // chunk of memory by using the StringToHGlobalAuto() hack above + //*(UsbApi.USB_STRING_DESCRIPTOR*)(bufferptr + Marshal.SizeOf(Request)); + USB_STRING_DESCRIPTOR StringDesc = (USB_STRING_DESCRIPTOR)Marshal.PtrToStructure((IntPtr)(bufferptr + Marshal.SizeOf(Request)), typeof(USB_STRING_DESCRIPTOR)); + //return StringDesc.bString; + int len = Math.Min(nBytesReturned - Marshal.SizeOf(Request) - 2, StringDesc.bLength); + return Encoding.Unicode.GetString(buffer, 2 + Marshal.SizeOf(Request), len); + } else { + return null; + } + } + } + + /*public static UsbDevice GetUsbDevice(DeviceNode node) { + String[] hubinterface = node.GetInterfaces(UsbApi.GUID_DEVINTERFACE_USB_HUB); + if (hubinterface != null && hubinterface.Length > 0) return new UsbHub(null, hubinterface[0], false); + String[] devinterface = node.GetInterfaces(UsbApi.GUID_DEVINTERFACE_USB_DEVICE); + if (devinterface == null || devinterface.Length == 0) throw new InvalidOperationException("Device is not an USB device"); + DeviceNode parent = node.GetParent(); + if (parent == null) throw new InvalidOperationException("Could not find parent hub device"); + UsbHub usbhub = GetUsbDevice(parent) as UsbHub; + if (usbhub == null) throw new InvalidOperationException("Could not find parent hub device"); + String driverkey = node.DriverKey; + foreach (UsbDevice usbdev in usbhub.Devices) { + if (driverkey.Equals(usbdev.DriverKey, StringComparison.InvariantCultureIgnoreCase)) return usbdev; + } + throw new InvalidOperationException("Could not find device on parent hub"); + //return null; + }*/ + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Windows/USB/UsbHub.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,77 @@ +using System; +using System.Runtime.InteropServices; +using Microsoft.Win32.SafeHandles; +using UCIS.USBLib.Internal.Windows; +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace UCIS.HWLib.Windows.USB { + public class UsbHub : UsbDevice { + public int PortCount { get; private set; } + public bool IsBusPowered { get; private set; } + public bool IsRootHub { get; private set; } + internal USB_NODE_INFORMATION NodeInformation { get; private set; } + private List<UsbDevice> devices = new List<UsbDevice>(); + public IList<UsbDevice> Devices { get { return devices.AsReadOnly(); } } + public override string DeviceDescription { get { return IsRootHub ? "RootHub" : "Standard-USB-Hub"; } } + internal UsbHub(UsbController parent, USB_DEVICE_DESCRIPTOR deviceDescriptor, string devicePath) + : this(null, deviceDescriptor, devicePath, true) { } + internal UsbHub(UsbDevice parent, USB_DEVICE_DESCRIPTOR deviceDescriptor, string devicePath, Boolean roothub) + : base(parent, deviceDescriptor, 0, devicePath) { + this.IsRootHub = roothub; + + // TODO: Get the driver key name for the root hub. + // Now let's open the hub (based upon the hub name we got above). + using (SafeFileHandle handel2 = Kernel32.CreateFile(this.DevicePath, Kernel32.GENERIC_WRITE, Kernel32.FILE_SHARE_WRITE, IntPtr.Zero, Kernel32.OPEN_EXISTING, 0, IntPtr.Zero)) { + if (handel2.IsInvalid) throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); + USB_NODE_INFORMATION NodeInfo = new USB_NODE_INFORMATION(); + int nBytes = Marshal.SizeOf(typeof(USB_NODE_INFORMATION)); // Marshal.SizeOf(NodeInfo); + // Get the hub information. + int nBytesReturned = -1; + if (Kernel32.DeviceIoControl(handel2, UsbApi.IOCTL_USB_GET_NODE_INFORMATION, ref NodeInfo, nBytes, out NodeInfo, nBytes, out nBytesReturned, IntPtr.Zero)) { + this.NodeInformation = NodeInfo; + this.IsBusPowered = Convert.ToBoolean(NodeInfo.HubInformation.HubIsBusPowered); + this.PortCount = NodeInfo.HubInformation.HubDescriptor.bNumberOfPorts; + } + + for (uint index = 1; index <= PortCount; index++) { + devices.Add(BuildDevice(this, index, this.DevicePath, handel2)); + } + } + } + + private static UsbDevice BuildDevice(UsbDevice parent, uint portCount, string devicePath, SafeFileHandle handel1) { + int nBytesReturned; + int nBytes = Marshal.SizeOf(typeof(USB_NODE_CONNECTION_INFORMATION_EX)); + USB_NODE_CONNECTION_INFORMATION_EX nodeConnection = new USB_NODE_CONNECTION_INFORMATION_EX(); + nodeConnection.ConnectionIndex = portCount; + + //DateTime t = DateTime.Now; + if (!Kernel32.DeviceIoControl(handel1, UsbApi.IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, ref nodeConnection, nBytes, out nodeConnection, nBytes, out nBytesReturned, IntPtr.Zero)) + throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); + //Console.WriteLine("IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX took {0} ms (class={1})", DateTime.Now.Subtract(t).TotalMilliseconds, nodeConnection.DeviceDescriptor.bDeviceClass); + bool isConnected = (nodeConnection.ConnectionStatus == USB_CONNECTION_STATUS.DeviceConnected); + + UsbDevice _Device = null; + if (!isConnected) { + _Device = new UsbDevice(parent, null, portCount); + } else if (nodeConnection.DeviceDescriptor.bDeviceClass == UsbDeviceClass.HubDevice) { + nBytes = Marshal.SizeOf(typeof(USB_NODE_CONNECTION_NAME)); + USB_NODE_CONNECTION_NAME nameConnection = new USB_NODE_CONNECTION_NAME(); + nameConnection.ConnectionIndex = portCount; + if (!Kernel32.DeviceIoControl(handel1, UsbApi.IOCTL_USB_GET_NODE_CONNECTION_NAME, ref nameConnection, nBytes, out nameConnection, nBytes, out nBytesReturned, IntPtr.Zero)) + throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); + _Device = new UsbHub(parent, nodeConnection.DeviceDescriptor, @"\\?\" + nameConnection.NodeName, false); + } else { + _Device = new UsbDevice(parent, nodeConnection.DeviceDescriptor, portCount, devicePath); + } + _Device.NodeConnectionInfo = nodeConnection; + _Device.AdapterNumber = _Device.NodeConnectionInfo.ConnectionIndex; + _Device.Status = ((USB_CONNECTION_STATUS)_Device.NodeConnectionInfo.ConnectionStatus).ToString(); + _Device.Speed = ((USB_DEVICE_SPEED)_Device.NodeConnectionInfo.Speed).ToString(); + _Device.IsConnected = isConnected; + _Device.IsHub = Convert.ToBoolean(_Device.NodeConnectionInfo.DeviceIsHub); + return _Device; + } + } +} \ No newline at end of file