21
|
1 using System; |
|
2 using System.Collections.Generic; |
|
3 using System.Runtime.InteropServices; |
|
4 using System.Text; |
|
5 using Microsoft.Win32.SafeHandles; |
22
|
6 using UCIS.HWLib.Windows.Devices; |
21
|
7 using UCIS.USBLib.Internal.Windows; |
|
8 |
|
9 namespace UCIS.HWLib.Windows.USB { |
|
10 public class UsbDevice { |
|
11 public UsbDevice Parent { get; protected set; } |
|
12 internal USB_NODE_CONNECTION_INFORMATION_EX NodeConnectionInfo { get; set; } |
|
13 internal USB_DEVICE_DESCRIPTOR DeviceDescriptor { get; private set; } |
|
14 internal IList<USB_CONFIGURATION_DESCRIPTOR> ConfigurationDescriptor { get; private set; } |
|
15 internal IList<USB_INTERFACE_DESCRIPTOR> InterfaceDescriptor { get; private set; } |
|
16 internal IList<USB_ENDPOINT_DESCRIPTOR> EndpointDescriptor { get; private set; } |
|
17 internal IList<HID_DESCRIPTOR> HdiDescriptor { get; private set; } |
|
18 public string DevicePath { get; private set; } |
|
19 public uint AdapterNumber { get; internal set; } |
|
20 public string DriverKey { get; private set; } |
|
21 |
|
22 public virtual string DeviceDescription { get { return DeviceNode.GetPropertyString(CMRDP.DEVICEDESC); } } |
|
23 public string DeviceID { get { return DeviceNode.DeviceID; } } |
|
24 |
|
25 public bool IsConnected { get; internal set; } |
|
26 public bool IsHub { get; internal set; } |
|
27 public string Status { get; internal set; } |
|
28 public string Speed { get; internal set; } |
|
29 |
|
30 public string Manufacturer { get; private set; } |
|
31 public string SerialNumber { get; private set; } |
|
32 public string Product { get; private set; } |
|
33 |
|
34 public int VendorID { get { return DeviceDescriptor.idVendor; } } |
|
35 public int ProductID { get { return DeviceDescriptor.idProduct; } } |
|
36 |
|
37 private DeviceNode mDeviceNode; |
|
38 public DeviceNode DeviceNode { |
|
39 get { |
|
40 if (mDeviceNode == null && DriverKey != null) { |
|
41 foreach (DeviceNode node in DeviceNode.GetDevices("USB")) { |
|
42 if (DriverKey.Equals(node.DriverKey, StringComparison.InvariantCultureIgnoreCase)) { |
|
43 mDeviceNode = node; |
|
44 break; |
|
45 } |
|
46 } |
|
47 } |
|
48 return mDeviceNode; |
|
49 } |
|
50 } |
|
51 |
|
52 internal UsbDevice(UsbDevice parent, USB_DEVICE_DESCRIPTOR deviceDescriptor, uint adapterNumber) |
|
53 : this(parent, deviceDescriptor, adapterNumber, null) { } |
|
54 unsafe internal UsbDevice(UsbDevice parent, USB_DEVICE_DESCRIPTOR deviceDescriptor, uint adapterNumber, string devicePath) { |
|
55 this.Parent = parent; |
|
56 this.AdapterNumber = adapterNumber; |
|
57 this.DeviceDescriptor = deviceDescriptor; |
|
58 this.DevicePath = devicePath; |
|
59 ConfigurationDescriptor = new List<USB_CONFIGURATION_DESCRIPTOR>(); |
|
60 InterfaceDescriptor = new List<USB_INTERFACE_DESCRIPTOR>(); |
|
61 HdiDescriptor = new List<HID_DESCRIPTOR>(); |
|
62 EndpointDescriptor = new List<USB_ENDPOINT_DESCRIPTOR>(); |
|
63 if (devicePath == null) return; |
|
64 |
|
65 using (SafeFileHandle handel = Kernel32.CreateFile(devicePath, Kernel32.GENERIC_WRITE, Kernel32.FILE_SHARE_WRITE, IntPtr.Zero, Kernel32.OPEN_EXISTING, 0, IntPtr.Zero)) { |
|
66 if (handel.IsInvalid) throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); |
|
67 int nBytesReturned; |
|
68 int nBytes = UsbApi.MAX_BUFFER_SIZE; |
|
69 |
|
70 USB_DESCRIPTOR_REQUEST Request1 = new USB_DESCRIPTOR_REQUEST(); |
|
71 Request1.ConnectionIndex = adapterNumber;// portCount; |
|
72 Request1.SetupPacket.wValue = (ushort)((UsbApi.USB_CONFIGURATION_DESCRIPTOR_TYPE << 8)); |
|
73 Request1.SetupPacket.wLength = (ushort)(nBytes - Marshal.SizeOf(Request1)); |
|
74 Request1.SetupPacket.wIndex = 0; // 0x409; // Language Code |
|
75 |
|
76 // Use an IOCTL call to request the String Descriptor |
|
77 Byte[] buffer = new Byte[nBytes]; |
|
78 fixed (Byte* bufferptr = buffer) { |
|
79 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)) { |
|
80 int err = Marshal.GetLastWin32Error(); |
|
81 Console.WriteLine("IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION returned {0} {1}", err, (new System.ComponentModel.Win32Exception(err)).Message); |
|
82 //SerialNumber = (new System.ComponentModel.Win32Exception(err)).Message; |
|
83 if (err != 2 && err != 31 && err != 87) throw new System.ComponentModel.Win32Exception(err); |
|
84 } else { |
|
85 if (nBytesReturned > nBytes) throw new IndexOutOfRangeException("IOCtl returned too much data"); |
|
86 if (nBytesReturned < 0) throw new IndexOutOfRangeException("IOCtl returned insufficient data"); |
|
87 Byte* ptr = bufferptr + Marshal.SizeOf(Request1); |
|
88 nBytesReturned -= Marshal.SizeOf(Request1); |
|
89 if (nBytesReturned < 0) throw new IndexOutOfRangeException("IOCtl returned insufficient data"); |
|
90 |
|
91 int offset = 0; |
|
92 while (offset < nBytesReturned) { |
|
93 if (offset + Marshal.SizeOf(typeof(USB_DESCRIPTOR)) >= nBytesReturned) throw new IndexOutOfRangeException("Error in configuration descriptor"); |
|
94 USB_DESCRIPTOR* desc = (USB_DESCRIPTOR*)(ptr + offset); |
|
95 offset += desc->bLength; |
|
96 if (offset > nBytesReturned) throw new IndexOutOfRangeException("Error in configuration descriptor"); |
|
97 Console.WriteLine("Descriptor type {0} length {1}", desc->bDescriptorType, desc->bLength); |
|
98 if (desc->bDescriptorType == USB_DESCRIPTOR_TYPE.ConfigurationDescriptorType) { |
|
99 if (desc->bLength < 9) throw new IndexOutOfRangeException("Error in configuration descriptor"); |
|
100 USB_CONFIGURATION_DESCRIPTOR configurationDescriptor = *(USB_CONFIGURATION_DESCRIPTOR*)desc; |
|
101 ConfigurationDescriptor.Add(configurationDescriptor); |
|
102 } else if (desc->bDescriptorType == USB_DESCRIPTOR_TYPE.InterfaceDescriptorType) { |
|
103 if (desc->bLength < 9) throw new IndexOutOfRangeException("Error in configuration descriptor"); |
|
104 USB_INTERFACE_DESCRIPTOR interfaceDescriptor = *(USB_INTERFACE_DESCRIPTOR*)desc; |
|
105 InterfaceDescriptor.Add(interfaceDescriptor); |
|
106 } else if (desc->bDescriptorType == USB_DESCRIPTOR_TYPE.EndpointDescriptorType) { |
|
107 if (desc->bLength < 7) throw new IndexOutOfRangeException("Error in configuration descriptor"); |
|
108 USB_ENDPOINT_DESCRIPTOR endpointDescriptor1 = *(USB_ENDPOINT_DESCRIPTOR*)desc; |
|
109 EndpointDescriptor.Add(endpointDescriptor1); |
|
110 } |
|
111 } |
|
112 } |
|
113 // The iManufacturer, iProduct and iSerialNumber entries in the |
|
114 // device descriptor are really just indexes. So, we have to |
|
115 // request a string descriptor to get the values for those strings. |
|
116 if (DeviceDescriptor != null) { |
|
117 if (DeviceDescriptor.iManufacturer > 0) Manufacturer = GetStringDescriptor(handel, DeviceDescriptor.iManufacturer); |
|
118 if (DeviceDescriptor.iProduct > 0) Product = GetStringDescriptor(handel, DeviceDescriptor.iProduct); |
|
119 if (DeviceDescriptor.iSerialNumber > 0) SerialNumber = GetStringDescriptor(handel, DeviceDescriptor.iSerialNumber); |
|
120 } |
|
121 } |
|
122 // Get the Driver Key Name (usefull in locating a device) |
|
123 USB_NODE_CONNECTION_DRIVERKEY_NAME DriverKeyStruct = new USB_NODE_CONNECTION_DRIVERKEY_NAME(); |
|
124 DriverKeyStruct.ConnectionIndex = adapterNumber; |
|
125 // Use an IOCTL call to request the Driver Key Name |
|
126 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)) { |
|
127 DriverKey = DriverKeyStruct.DriverKeyName; |
|
128 } |
|
129 } |
|
130 } |
|
131 |
|
132 private unsafe String GetStringDescriptor(SafeFileHandle handel, Byte id) { |
|
133 int nBytes = UsbApi.MAX_BUFFER_SIZE; |
|
134 int nBytesReturned = 0; |
|
135 Byte[] buffer = new Byte[nBytes]; |
|
136 fixed (Byte* bufferptr = buffer) { |
|
137 // Build a request for string descriptor. |
|
138 USB_DESCRIPTOR_REQUEST Request = new USB_DESCRIPTOR_REQUEST(); |
|
139 Request.ConnectionIndex = AdapterNumber; |
|
140 Request.SetupPacket.wValue = (ushort)((UsbApi.USB_STRING_DESCRIPTOR_TYPE << 8) + id); |
|
141 Request.SetupPacket.wLength = (ushort)(nBytes - Marshal.SizeOf(Request)); |
|
142 Request.SetupPacket.wIndex = 0x409; // The language code. |
|
143 // Use an IOCTL call to request the string descriptor. |
|
144 if (Kernel32.DeviceIoControl(handel, UsbApi.IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, ref Request, Marshal.SizeOf(Request), (IntPtr)bufferptr, nBytes, out nBytesReturned, IntPtr.Zero)) { |
|
145 if (nBytesReturned < nBytes) buffer[nBytesReturned] = 0; |
|
146 if (nBytesReturned + 1 < nBytes) buffer[nBytesReturned + 1] = 0; |
|
147 // The location of the string descriptor is immediately after |
|
148 // the Request structure. Because this location is not "covered" |
|
149 // by the structure allocation, we're forced to zero out this |
|
150 // chunk of memory by using the StringToHGlobalAuto() hack above |
|
151 //*(UsbApi.USB_STRING_DESCRIPTOR*)(bufferptr + Marshal.SizeOf(Request)); |
|
152 USB_STRING_DESCRIPTOR StringDesc = (USB_STRING_DESCRIPTOR)Marshal.PtrToStructure((IntPtr)(bufferptr + Marshal.SizeOf(Request)), typeof(USB_STRING_DESCRIPTOR)); |
|
153 //return StringDesc.bString; |
|
154 int len = Math.Min(nBytesReturned - Marshal.SizeOf(Request) - 2, StringDesc.bLength); |
|
155 return Encoding.Unicode.GetString(buffer, 2 + Marshal.SizeOf(Request), len); |
|
156 } else { |
|
157 return null; |
|
158 } |
|
159 } |
|
160 } |
|
161 |
|
162 /*public static UsbDevice GetUsbDevice(DeviceNode node) { |
|
163 String[] hubinterface = node.GetInterfaces(UsbApi.GUID_DEVINTERFACE_USB_HUB); |
|
164 if (hubinterface != null && hubinterface.Length > 0) return new UsbHub(null, hubinterface[0], false); |
|
165 String[] devinterface = node.GetInterfaces(UsbApi.GUID_DEVINTERFACE_USB_DEVICE); |
|
166 if (devinterface == null || devinterface.Length == 0) throw new InvalidOperationException("Device is not an USB device"); |
|
167 DeviceNode parent = node.GetParent(); |
|
168 if (parent == null) throw new InvalidOperationException("Could not find parent hub device"); |
|
169 UsbHub usbhub = GetUsbDevice(parent) as UsbHub; |
|
170 if (usbhub == null) throw new InvalidOperationException("Could not find parent hub device"); |
|
171 String driverkey = node.DriverKey; |
|
172 foreach (UsbDevice usbdev in usbhub.Devices) { |
|
173 if (driverkey.Equals(usbdev.DriverKey, StringComparison.InvariantCultureIgnoreCase)) return usbdev; |
|
174 } |
|
175 throw new InvalidOperationException("Could not find device on parent hub"); |
|
176 //return null; |
|
177 }*/ |
|
178 } |
|
179 } |