Mercurial > hg > ucis.core
diff USBLib/Windows/USB/UsbDevice.cs @ 21:dcfec2be27c9
Added USBLib
author | Ivo Smits <Ivo@UCIS.nl> |
---|---|
date | Mon, 15 Apr 2013 01:04:59 +0200 |
parents | |
children | 5b14fed54a89 |
line wrap: on
line diff
--- /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