From a43d81543ad7a90abae90960fab2d0b83cc85a4f Mon Sep 17 00:00:00 2001 From: Alexey 'Cluster' Avdyukhin Date: Sat, 4 Mar 2017 17:44:11 +0300 Subject: First commit --- CloverShell.csproj | 213 +++ ClovershellConnection.cs | 627 +++++++++ LibWinUsb/Descriptors/ClassCodeType.cs | 60 + LibWinUsb/Descriptors/DescriptorType.cs | 89 ++ LibWinUsb/Descriptors/LangStringDescriptor.cs | 131 ++ LibWinUsb/Descriptors/StringDescriptor.cs | 24 + LibWinUsb/Descriptors/UsbConfigDescriptor.cs | 113 ++ LibWinUsb/Descriptors/UsbDescriptor.cs | 73 + LibWinUsb/Descriptors/UsbDeviceDescriptor.cs | 232 +++ LibWinUsb/Descriptors/UsbEndpointDescriptor.cs | 134 ++ LibWinUsb/Descriptors/UsbInterfaceDescriptor.cs | 126 ++ LibWinUsb/DeviceNotify/DeviceNotifier.cs | 48 + LibWinUsb/DeviceNotify/DeviceNotifyEventArgs.cs | 112 ++ LibWinUsb/DeviceNotify/DeviceType.cs | 58 + LibWinUsb/DeviceNotify/EventType.cs | 58 + LibWinUsb/DeviceNotify/IDeviceNotifier.cs | 52 + LibWinUsb/DeviceNotify/Info/IPortNotifyInfo.cs | 43 + .../DeviceNotify/Info/IUsbDeviceNotifyInfo.cs | 70 + LibWinUsb/DeviceNotify/Info/IVolumeNotifyInfo.cs | 63 + LibWinUsb/DeviceNotify/Info/PortNotifyInfo.cs | 63 + LibWinUsb/DeviceNotify/Info/UsbDeviceNotifyInfo.cs | 112 ++ LibWinUsb/DeviceNotify/Info/VolumeNotifyInfo.cs | 114 ++ .../Internal/DevBroadcastDeviceinterface.cs | 44 + LibWinUsb/DeviceNotify/Internal/DevBroadcastHdr.cs | 35 + .../DeviceNotify/Internal/DevBroadcastPort.cs | 39 + .../DeviceNotify/Internal/DevBroadcastVolume.cs | 38 + .../DeviceNotify/Internal/DevNotifyNativeWindow.cs | 79 ++ .../DeviceNotify/Internal/SafeNotifyHandle.cs | 45 + LibWinUsb/DeviceNotify/Linux/LinuxDevItem.cs | 90 ++ LibWinUsb/DeviceNotify/Linux/LinuxDevItemList.cs | 36 + .../Linux/LinuxDeviceNotifier.DevMonitor.cs | 187 +++ .../Linux/LinuxDeviceNotifier.DeviceListPolling.cs | 99 ++ .../DeviceNotify/Linux/LinuxDeviceNotifier.cs | 139 ++ .../DeviceNotify/Linux/LinuxDeviceNotifierMode.cs | 44 + .../Linux/LinuxDeviceNotifyEventArgs.cs | 70 + .../DeviceNotify/Linux/LinuxUsbDeviceNotifyInfo.cs | 127 ++ LibWinUsb/DeviceNotify/WindowsDeviceNotifier.cs | 146 ++ .../DeviceNotify/WindowsDeviceNotifyEventArgs.cs | 57 + LibWinUsb/IUsbDevice.cs | 100 ++ LibWinUsb/IUsbInterface.cs | 187 +++ LibWinUsb/Info/UsbBaseInfo.cs | 44 + LibWinUsb/Info/UsbConfigInfo.cs | 158 +++ LibWinUsb/Info/UsbDeviceInfo.cs | 215 +++ LibWinUsb/Info/UsbEndpointInfo.cs | 70 + LibWinUsb/Info/UsbInterfaceInfo.cs | 120 ++ LibWinUsb/Internal/Kernel32.cs | 197 +++ LibWinUsb/Internal/OverlappedTransferContext.cs | 113 ++ LibWinUsb/Internal/SafeOverlapped.cs | 115 ++ LibWinUsb/Internal/SetupApi.cs | 670 +++++++++ LibWinUsb/Internal/TransferContextBase.cs | 195 +++ LibWinUsb/Internal/UsbApiBase.cs | 81 ++ LibWinUsb/Internal/UsbRegex/BaseRegSymbolicName.cs | 37 + LibWinUsb/Internal/UsbRegex/NamedGroup.cs | 35 + LibWinUsb/Internal/UsbRegex/RegHardwareID.cs | 105 ++ LibWinUsb/Internal/UsbRegex/RegSymbolicName.cs | 95 ++ LibWinUsb/LibUsb/Internal/LibUsbAPI.cs | 151 ++ LibWinUsb/LibUsb/Internal/LibUsbDriverIO.cs | 100 ++ .../Internal/LibUsbDriverIO_IOControlMessage.cs | 199 +++ LibWinUsb/LibUsb/Internal/LibUsbIoCtl.cs | 65 + LibWinUsb/LibUsb/Internal/LibUsbRequest.cs | 195 +++ LibWinUsb/LibUsb/LibUsbDevice.cs | 320 +++++ LibWinUsb/LibUsb/LibUsbDeviceRegistryKeyRequest.cs | 116 ++ LibWinUsb/LibUsb/LibUsbKernelType.cs | 46 + LibWinUsb/LibUsb/LibUsbRegistry.cs | 321 +++++ LibWinUsb/LibUsbDotNet.csproj | 236 ++++ LibWinUsb/LibUsbDotNet.snk | Bin 0 -> 596 bytes LibWinUsb/Main/ControlEpLockType.cs | 54 + LibWinUsb/Main/DataEpLockType.cs | 44 + .../Main/DataReceivedEnabledChangedEventArgs.cs | 59 + LibWinUsb/Main/DeviceLockType.cs | 48 + LibWinUsb/Main/DevicePropertyType.cs | 101 ++ LibWinUsb/Main/EndpointDataEventArgs.cs | 58 + LibWinUsb/Main/EndpointType.cs | 48 + LibWinUsb/Main/ErrorCode.cs | 184 +++ LibWinUsb/Main/Helper.cs | 283 ++++ LibWinUsb/Main/LegacyUsbRegistry.cs | 245 ++++ LibWinUsb/Main/ReadEndpointID.cs | 90 ++ LibWinUsb/Main/SPDRP.cs | 110 ++ LibWinUsb/Main/SafeContextHandle.cs | 65 + LibWinUsb/Main/SetupApiRegistry.cs | 210 +++ LibWinUsb/Main/UsbConstants.cs | 66 + LibWinUsb/Main/UsbCtrlFlags.cs | 73 + LibWinUsb/Main/UsbDeviceFinder.cs | 319 +++++ LibWinUsb/Main/UsbEndpointBase.cs | 391 ++++++ LibWinUsb/Main/UsbEndpointDirection.cs | 40 + LibWinUsb/Main/UsbEndpointList.cs | 147 ++ LibWinUsb/Main/UsbException.cs | 46 + LibWinUsb/Main/UsbKernelVersion.cs | 91 ++ LibWinUsb/Main/UsbLockStyle.cs | 146 ++ LibWinUsb/Main/UsbRegDeviceList.cs | 179 +++ LibWinUsb/Main/UsbRegistry.cs | 332 +++++ LibWinUsb/Main/UsbRequestRecipient.cs | 48 + LibWinUsb/Main/UsbRequestType.cs | 50 + LibWinUsb/Main/UsbSetupPacket.cs | 95 ++ LibWinUsb/Main/UsbStandardRequest.cs | 78 ++ LibWinUsb/Main/UsbStatusClodes.cs | 31 + LibWinUsb/Main/UsbStream.cs | 286 ++++ LibWinUsb/Main/UsbSymbolicName.cs | 227 +++ LibWinUsb/Main/UsbTransfer.cs | 629 +++++++++ LibWinUsb/Main/WriteEndpointID.cs | 89 ++ LibWinUsb/MonoLibUsb/CallbackDelegates.cs | 31 + .../Descriptors/MonoUsbAltInterfaceDescriptor.cs | 103 ++ .../Descriptors/MonoUsbConfigDescriptor.cs | 115 ++ .../Descriptors/MonoUsbDeviceDescriptor.cs | 134 ++ .../Descriptors/MonoUsbEndpointDescriptor.cs | 77 + .../MonoLibUsb/Descriptors/MonoUsbInterface.cs | 59 + LibWinUsb/MonoLibUsb/MonoLibUsbApi.cs | 1470 ++++++++++++++++++++ LibWinUsb/MonoLibUsb/MonoUsbDevice.cs | 522 +++++++ LibWinUsb/MonoLibUsb/MonoUsbDeviceHandle.cs | 136 ++ LibWinUsb/MonoLibUsb/MonoUsbEndpointReader.cs | 81 ++ LibWinUsb/MonoLibUsb/MonoUsbEndpointWriter.cs | 76 + LibWinUsb/MonoLibUsb/MonoUsbError.cs | 106 ++ LibWinUsb/MonoLibUsb/MonoUsbEventHandler.cs | 192 +++ LibWinUsb/MonoLibUsb/MonoUsbSessionHandle.cs | 116 ++ LibWinUsb/MonoLibUsb/Profile/AddRemoveEventArgs.cs | 34 + LibWinUsb/MonoLibUsb/Profile/AddRemoveType.cs | 38 + .../MonoLibUsb/Profile/MonoUsbConfigHandle.cs | 41 + LibWinUsb/MonoLibUsb/Profile/MonoUsbProfile.cs | 186 +++ .../MonoLibUsb/Profile/MonoUsbProfileHandle.cs | 110 ++ .../Profile/MonoUsbProfileHandleEnumerator.cs | 111 ++ LibWinUsb/MonoLibUsb/Profile/MonoUsbProfileList.cs | 259 ++++ .../MonoLibUsb/Profile/MonoUsbProfileListHandle.cs | 74 + LibWinUsb/MonoLibUsb/Profile/PollfdItem.cs | 28 + .../Transfer/Internal/libusb_control_setup.cs | 35 + .../Internal/libusb_iso_packet_descriptor.cs | 29 + .../Transfer/Internal/libusb_transfer.cs | 52 + .../MonoLibUsb/Transfer/MonoUsbControlSetup.cs | 145 ++ .../Transfer/MonoUsbControlSetupHandle.cs | 113 ++ LibWinUsb/MonoLibUsb/Transfer/MonoUsbIsoPacket.cs | 58 + .../MonoLibUsb/Transfer/MonoUsbTansferStatus.cs | 65 + LibWinUsb/MonoLibUsb/Transfer/MonoUsbTransfer.cs | 519 +++++++ .../MonoLibUsb/Transfer/MonoUsbTransferContext.cs | 232 +++ .../MonoLibUsb/Transfer/MonoUsbTransferFlags.cs | 51 + LibWinUsb/MonoLibUsb/UnixNativeTimeval.cs | 69 + LibWinUsb/UsbDevice.Common.cs | 249 ++++ LibWinUsb/UsbDevice.Error.cs | 166 +++ LibWinUsb/UsbDevice.OS.Specific.cs | 291 ++++ LibWinUsb/UsbDevice.cs | 495 +++++++ LibWinUsb/UsbEndpointReader.cs | 290 ++++ LibWinUsb/UsbEndpointWriter.cs | 100 ++ LibWinUsb/UsbGlobals.cs | 34 + LibWinUsb/WinUsb/DeviceInformationTypes.cs | 33 + LibWinUsb/WinUsb/DeviceSpeedTypes.cs | 45 + .../WinUsb/Internal/SafeWinUsbInterfaceHandle.cs | 67 + LibWinUsb/WinUsb/Internal/WinUsbAPI.cs | 226 +++ LibWinUsb/WinUsb/PipeInformation.cs | 57 + LibWinUsb/WinUsb/PipePolicies.cs | 288 ++++ LibWinUsb/WinUsb/PipePolicyType.cs | 35 + LibWinUsb/WinUsb/PowerPolicies.cs | 98 ++ LibWinUsb/WinUsb/PowerPolicyType.cs | 30 + LibWinUsb/WinUsb/WinUsbDevice.cs | 317 +++++ LibWinUsb/WinUsb/WinUsbRegistry.cs | 518 +++++++ Program.cs | 120 ++ Properties/AssemblyInfo.cs | 36 + 154 files changed, 22100 insertions(+) create mode 100644 CloverShell.csproj create mode 100644 ClovershellConnection.cs create mode 100644 LibWinUsb/Descriptors/ClassCodeType.cs create mode 100644 LibWinUsb/Descriptors/DescriptorType.cs create mode 100644 LibWinUsb/Descriptors/LangStringDescriptor.cs create mode 100644 LibWinUsb/Descriptors/StringDescriptor.cs create mode 100644 LibWinUsb/Descriptors/UsbConfigDescriptor.cs create mode 100644 LibWinUsb/Descriptors/UsbDescriptor.cs create mode 100644 LibWinUsb/Descriptors/UsbDeviceDescriptor.cs create mode 100644 LibWinUsb/Descriptors/UsbEndpointDescriptor.cs create mode 100644 LibWinUsb/Descriptors/UsbInterfaceDescriptor.cs create mode 100644 LibWinUsb/DeviceNotify/DeviceNotifier.cs create mode 100644 LibWinUsb/DeviceNotify/DeviceNotifyEventArgs.cs create mode 100644 LibWinUsb/DeviceNotify/DeviceType.cs create mode 100644 LibWinUsb/DeviceNotify/EventType.cs create mode 100644 LibWinUsb/DeviceNotify/IDeviceNotifier.cs create mode 100644 LibWinUsb/DeviceNotify/Info/IPortNotifyInfo.cs create mode 100644 LibWinUsb/DeviceNotify/Info/IUsbDeviceNotifyInfo.cs create mode 100644 LibWinUsb/DeviceNotify/Info/IVolumeNotifyInfo.cs create mode 100644 LibWinUsb/DeviceNotify/Info/PortNotifyInfo.cs create mode 100644 LibWinUsb/DeviceNotify/Info/UsbDeviceNotifyInfo.cs create mode 100644 LibWinUsb/DeviceNotify/Info/VolumeNotifyInfo.cs create mode 100644 LibWinUsb/DeviceNotify/Internal/DevBroadcastDeviceinterface.cs create mode 100644 LibWinUsb/DeviceNotify/Internal/DevBroadcastHdr.cs create mode 100644 LibWinUsb/DeviceNotify/Internal/DevBroadcastPort.cs create mode 100644 LibWinUsb/DeviceNotify/Internal/DevBroadcastVolume.cs create mode 100644 LibWinUsb/DeviceNotify/Internal/DevNotifyNativeWindow.cs create mode 100644 LibWinUsb/DeviceNotify/Internal/SafeNotifyHandle.cs create mode 100644 LibWinUsb/DeviceNotify/Linux/LinuxDevItem.cs create mode 100644 LibWinUsb/DeviceNotify/Linux/LinuxDevItemList.cs create mode 100644 LibWinUsb/DeviceNotify/Linux/LinuxDeviceNotifier.DevMonitor.cs create mode 100644 LibWinUsb/DeviceNotify/Linux/LinuxDeviceNotifier.DeviceListPolling.cs create mode 100644 LibWinUsb/DeviceNotify/Linux/LinuxDeviceNotifier.cs create mode 100644 LibWinUsb/DeviceNotify/Linux/LinuxDeviceNotifierMode.cs create mode 100644 LibWinUsb/DeviceNotify/Linux/LinuxDeviceNotifyEventArgs.cs create mode 100644 LibWinUsb/DeviceNotify/Linux/LinuxUsbDeviceNotifyInfo.cs create mode 100644 LibWinUsb/DeviceNotify/WindowsDeviceNotifier.cs create mode 100644 LibWinUsb/DeviceNotify/WindowsDeviceNotifyEventArgs.cs create mode 100644 LibWinUsb/IUsbDevice.cs create mode 100644 LibWinUsb/IUsbInterface.cs create mode 100644 LibWinUsb/Info/UsbBaseInfo.cs create mode 100644 LibWinUsb/Info/UsbConfigInfo.cs create mode 100644 LibWinUsb/Info/UsbDeviceInfo.cs create mode 100644 LibWinUsb/Info/UsbEndpointInfo.cs create mode 100644 LibWinUsb/Info/UsbInterfaceInfo.cs create mode 100644 LibWinUsb/Internal/Kernel32.cs create mode 100644 LibWinUsb/Internal/OverlappedTransferContext.cs create mode 100644 LibWinUsb/Internal/SafeOverlapped.cs create mode 100644 LibWinUsb/Internal/SetupApi.cs create mode 100644 LibWinUsb/Internal/TransferContextBase.cs create mode 100644 LibWinUsb/Internal/UsbApiBase.cs create mode 100644 LibWinUsb/Internal/UsbRegex/BaseRegSymbolicName.cs create mode 100644 LibWinUsb/Internal/UsbRegex/NamedGroup.cs create mode 100644 LibWinUsb/Internal/UsbRegex/RegHardwareID.cs create mode 100644 LibWinUsb/Internal/UsbRegex/RegSymbolicName.cs create mode 100644 LibWinUsb/LibUsb/Internal/LibUsbAPI.cs create mode 100644 LibWinUsb/LibUsb/Internal/LibUsbDriverIO.cs create mode 100644 LibWinUsb/LibUsb/Internal/LibUsbDriverIO_IOControlMessage.cs create mode 100644 LibWinUsb/LibUsb/Internal/LibUsbIoCtl.cs create mode 100644 LibWinUsb/LibUsb/Internal/LibUsbRequest.cs create mode 100644 LibWinUsb/LibUsb/LibUsbDevice.cs create mode 100644 LibWinUsb/LibUsb/LibUsbDeviceRegistryKeyRequest.cs create mode 100644 LibWinUsb/LibUsb/LibUsbKernelType.cs create mode 100644 LibWinUsb/LibUsb/LibUsbRegistry.cs create mode 100644 LibWinUsb/LibUsbDotNet.csproj create mode 100644 LibWinUsb/LibUsbDotNet.snk create mode 100644 LibWinUsb/Main/ControlEpLockType.cs create mode 100644 LibWinUsb/Main/DataEpLockType.cs create mode 100644 LibWinUsb/Main/DataReceivedEnabledChangedEventArgs.cs create mode 100644 LibWinUsb/Main/DeviceLockType.cs create mode 100644 LibWinUsb/Main/DevicePropertyType.cs create mode 100644 LibWinUsb/Main/EndpointDataEventArgs.cs create mode 100644 LibWinUsb/Main/EndpointType.cs create mode 100644 LibWinUsb/Main/ErrorCode.cs create mode 100644 LibWinUsb/Main/Helper.cs create mode 100644 LibWinUsb/Main/LegacyUsbRegistry.cs create mode 100644 LibWinUsb/Main/ReadEndpointID.cs create mode 100644 LibWinUsb/Main/SPDRP.cs create mode 100644 LibWinUsb/Main/SafeContextHandle.cs create mode 100644 LibWinUsb/Main/SetupApiRegistry.cs create mode 100644 LibWinUsb/Main/UsbConstants.cs create mode 100644 LibWinUsb/Main/UsbCtrlFlags.cs create mode 100644 LibWinUsb/Main/UsbDeviceFinder.cs create mode 100644 LibWinUsb/Main/UsbEndpointBase.cs create mode 100644 LibWinUsb/Main/UsbEndpointDirection.cs create mode 100644 LibWinUsb/Main/UsbEndpointList.cs create mode 100644 LibWinUsb/Main/UsbException.cs create mode 100644 LibWinUsb/Main/UsbKernelVersion.cs create mode 100644 LibWinUsb/Main/UsbLockStyle.cs create mode 100644 LibWinUsb/Main/UsbRegDeviceList.cs create mode 100644 LibWinUsb/Main/UsbRegistry.cs create mode 100644 LibWinUsb/Main/UsbRequestRecipient.cs create mode 100644 LibWinUsb/Main/UsbRequestType.cs create mode 100644 LibWinUsb/Main/UsbSetupPacket.cs create mode 100644 LibWinUsb/Main/UsbStandardRequest.cs create mode 100644 LibWinUsb/Main/UsbStatusClodes.cs create mode 100644 LibWinUsb/Main/UsbStream.cs create mode 100644 LibWinUsb/Main/UsbSymbolicName.cs create mode 100644 LibWinUsb/Main/UsbTransfer.cs create mode 100644 LibWinUsb/Main/WriteEndpointID.cs create mode 100644 LibWinUsb/MonoLibUsb/CallbackDelegates.cs create mode 100644 LibWinUsb/MonoLibUsb/Descriptors/MonoUsbAltInterfaceDescriptor.cs create mode 100644 LibWinUsb/MonoLibUsb/Descriptors/MonoUsbConfigDescriptor.cs create mode 100644 LibWinUsb/MonoLibUsb/Descriptors/MonoUsbDeviceDescriptor.cs create mode 100644 LibWinUsb/MonoLibUsb/Descriptors/MonoUsbEndpointDescriptor.cs create mode 100644 LibWinUsb/MonoLibUsb/Descriptors/MonoUsbInterface.cs create mode 100644 LibWinUsb/MonoLibUsb/MonoLibUsbApi.cs create mode 100644 LibWinUsb/MonoLibUsb/MonoUsbDevice.cs create mode 100644 LibWinUsb/MonoLibUsb/MonoUsbDeviceHandle.cs create mode 100644 LibWinUsb/MonoLibUsb/MonoUsbEndpointReader.cs create mode 100644 LibWinUsb/MonoLibUsb/MonoUsbEndpointWriter.cs create mode 100644 LibWinUsb/MonoLibUsb/MonoUsbError.cs create mode 100644 LibWinUsb/MonoLibUsb/MonoUsbEventHandler.cs create mode 100644 LibWinUsb/MonoLibUsb/MonoUsbSessionHandle.cs create mode 100644 LibWinUsb/MonoLibUsb/Profile/AddRemoveEventArgs.cs create mode 100644 LibWinUsb/MonoLibUsb/Profile/AddRemoveType.cs create mode 100644 LibWinUsb/MonoLibUsb/Profile/MonoUsbConfigHandle.cs create mode 100644 LibWinUsb/MonoLibUsb/Profile/MonoUsbProfile.cs create mode 100644 LibWinUsb/MonoLibUsb/Profile/MonoUsbProfileHandle.cs create mode 100644 LibWinUsb/MonoLibUsb/Profile/MonoUsbProfileHandleEnumerator.cs create mode 100644 LibWinUsb/MonoLibUsb/Profile/MonoUsbProfileList.cs create mode 100644 LibWinUsb/MonoLibUsb/Profile/MonoUsbProfileListHandle.cs create mode 100644 LibWinUsb/MonoLibUsb/Profile/PollfdItem.cs create mode 100644 LibWinUsb/MonoLibUsb/Transfer/Internal/libusb_control_setup.cs create mode 100644 LibWinUsb/MonoLibUsb/Transfer/Internal/libusb_iso_packet_descriptor.cs create mode 100644 LibWinUsb/MonoLibUsb/Transfer/Internal/libusb_transfer.cs create mode 100644 LibWinUsb/MonoLibUsb/Transfer/MonoUsbControlSetup.cs create mode 100644 LibWinUsb/MonoLibUsb/Transfer/MonoUsbControlSetupHandle.cs create mode 100644 LibWinUsb/MonoLibUsb/Transfer/MonoUsbIsoPacket.cs create mode 100644 LibWinUsb/MonoLibUsb/Transfer/MonoUsbTansferStatus.cs create mode 100644 LibWinUsb/MonoLibUsb/Transfer/MonoUsbTransfer.cs create mode 100644 LibWinUsb/MonoLibUsb/Transfer/MonoUsbTransferContext.cs create mode 100644 LibWinUsb/MonoLibUsb/Transfer/MonoUsbTransferFlags.cs create mode 100644 LibWinUsb/MonoLibUsb/UnixNativeTimeval.cs create mode 100644 LibWinUsb/UsbDevice.Common.cs create mode 100644 LibWinUsb/UsbDevice.Error.cs create mode 100644 LibWinUsb/UsbDevice.OS.Specific.cs create mode 100644 LibWinUsb/UsbDevice.cs create mode 100644 LibWinUsb/UsbEndpointReader.cs create mode 100644 LibWinUsb/UsbEndpointWriter.cs create mode 100644 LibWinUsb/UsbGlobals.cs create mode 100644 LibWinUsb/WinUsb/DeviceInformationTypes.cs create mode 100644 LibWinUsb/WinUsb/DeviceSpeedTypes.cs create mode 100644 LibWinUsb/WinUsb/Internal/SafeWinUsbInterfaceHandle.cs create mode 100644 LibWinUsb/WinUsb/Internal/WinUsbAPI.cs create mode 100644 LibWinUsb/WinUsb/PipeInformation.cs create mode 100644 LibWinUsb/WinUsb/PipePolicies.cs create mode 100644 LibWinUsb/WinUsb/PipePolicyType.cs create mode 100644 LibWinUsb/WinUsb/PowerPolicies.cs create mode 100644 LibWinUsb/WinUsb/PowerPolicyType.cs create mode 100644 LibWinUsb/WinUsb/WinUsbDevice.cs create mode 100644 LibWinUsb/WinUsb/WinUsbRegistry.cs create mode 100644 Program.cs create mode 100644 Properties/AssemblyInfo.cs diff --git a/CloverShell.csproj b/CloverShell.csproj new file mode 100644 index 0000000..572119a --- /dev/null +++ b/CloverShell.csproj @@ -0,0 +1,213 @@ + + + + + Debug + AnyCPU + {15464C82-5343-4B2A-AEC8-BE3CB5BB4AD2} + Exe + Properties + com.clusterrr.clovershell + clovershell + v3.5 + 512 + + + AnyCPU + true + full + false + bin\Debug\ + TRACE;DEBUG;LIBUSBDOTNET WINDOWS_TESTING + prompt + 4 + true + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE;LIBUSBDOTNET WINDOWS_TESTING + prompt + 4 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ClovershellConnection.cs b/ClovershellConnection.cs new file mode 100644 index 0000000..8f0b91b --- /dev/null +++ b/ClovershellConnection.cs @@ -0,0 +1,627 @@ +using LibUsbDotNet; +using LibUsbDotNet.Main; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading; + +namespace com.clusterrr.cloverhack +{ + public class ClovershellConnection : IDisposable + { + class ShellConnection + { + public Socket socket; + public int id; + public ShellConnection() + { + id = -1; + } + } + class ExecConnection + { + public readonly string command; + public Stream stdin; + public Stream stdout; + public Stream stderr; + public int id; + public bool finished; + public bool stdoutFinished; + public bool stderrFinished; + public int result; + public ExecConnection(string command, Stream stdin, Stream stdout, Stream stderr) + { + this.command = command; + id = -1; + this.stdin = stdin; + this.stdout = stdout; + this.stderr = stderr; + finished = false; + stdoutFinished = false; + stderrFinished = false; + } + } + + const UInt16 vid = 0x1F3A; + const UInt16 pid = 0xEFE8; + UsbDevice device = null; + UsbEndpointReader epReader = null; + UsbEndpointWriter epWriter = null; + Thread mainThread = null; + Thread shellThread = null; + bool online = false; + ushort shellPort = 1023; + Queue pendingShellConnections = new Queue(); + List pendingExecConnections = new List(); + ShellConnection[] shellConnections = new ShellConnection[256]; + ExecConnection[] execConnections = new ExecConnection[256]; + List shellConnecionThreads = new List(); + bool enabled = false; + bool autoreconnect = false; + byte[] lastPingResponse = null; + + public bool Enabled + { + get { return enabled; } + set + { + if (enabled == value) return; + enabled = value; + if (value) + { + mainThread = new Thread(mainThreadLoop); + mainThread.Start(); + } + else + { + if (mainThread != null) + mainThread.Abort(); + mainThread = null; + online = false; + if (device != null) + device.Close(); + device = null; + if (epReader != null) + epReader.Dispose(); + epReader = null; + if (epWriter != null) + epWriter.Dispose(); + epWriter = null; + } + } + } + + public bool Autoreconnect + { + get { return autoreconnect; } + set { autoreconnect = value; } + } + + public ushort ShellPort + { + get { return shellPort; } + set + { + shellPort = value; + if (ShellEnabled) + { + ShellEnabled = false; + ShellEnabled = true; + } + } + } + bool shellEnabled = false; + public bool ShellEnabled + { + get { return shellEnabled; } + set + { + if (shellEnabled == value) return; + if (value) + { + shellThread = new Thread(shellThreadLoop); + shellThread.Start(); + } + else + { + shellThread.Abort(); + shellThread = null; + } + foreach (var pending in pendingShellConnections) + pending.socket.Close(); + pendingShellConnections.Clear(); + shellEnabled = value; + } + } + public bool Online + { + get { return online; } + } + + enum ClovershellCommand + { + CMD_PING = 0, + CMD_PONG = 1, + CMD_SHELL_NEW_REQ = 2, + CMD_SHELL_NEW_RESP = 3, + CMD_SHELL_IN = 4, + CMD_SHELL_OUT = 5, + CMD_SHELL_CLOSED = 6, + CMD_SHELL_KILL = 7, + CMD_SHELL_KILL_ALL = 8, + CMD_EXEC_NEW_REQ = 9, + CMD_EXEC_NEW_RESP = 10, + CMD_EXEC_PID = 11, + CMD_EXEC_STDIN = 12, + CMD_EXEC_STDOUT = 13, + CMD_EXEC_STDERR = 14, + CMD_EXEC_RESULT = 15, + CMD_EXEC_KILL = 16, + CMD_EXEC_KILL_ALL = 17 + } + + void dropAll() + { + writeUsb(ClovershellCommand.CMD_SHELL_KILL_ALL, 0); + writeUsb(ClovershellCommand.CMD_EXEC_KILL_ALL, 0); + foreach (var pending in pendingShellConnections) + pending.socket.Close(); + pendingShellConnections.Clear(); + for (int i = 0; i < shellConnections.Length; i++) + { + var connection = shellConnections[i]; + if (connection == null) + continue; + connection.socket.Close(); + shellConnections[i] = null; + } + for (int i = 0; i < execConnections.Length; i++) + execConnections[i] = null; + foreach (var connection in shellConnecionThreads) + connection.Abort(); + shellConnecionThreads.Clear(); + pendingExecConnections.Clear(); + } + + void mainThreadLoop() + { + try + { + while (enabled) + { + online = false; +#if DEBUG + Debug.WriteLine("Waiting for clovershell"); +#endif + while (enabled) + { + try + { + var devices = UsbDevice.AllDevices; + device = null; + foreach (UsbRegistry regDevice in devices) + { + if (regDevice.Vid == vid && regDevice.Pid == pid) + { + regDevice.Open(out device); + break; + } + } + //device = USBDevice.GetSingleDevice(vid, pid); + if (device == null) continue; + IUsbDevice wholeUsbDevice = device as IUsbDevice; + if (!ReferenceEquals(wholeUsbDevice, null)) + { + // This is a "whole" USB device. Before it can be used, + // the desired configuration and interface must be selected. + + // Select config #1 + wholeUsbDevice.SetConfiguration(1); + + // Claim interface #0. + wholeUsbDevice.ClaimInterface(0); + } + + int inEndp = -1; + int outEndp = -1; + int inMax = 0; + int outMax = 0; + foreach (var config in device.Configs) + foreach (var @interface in config.InterfaceInfoList) + foreach (var endp in @interface.EndpointInfoList) + { + + if ((endp.Descriptor.EndpointID & 0x80) != 0) + { + inEndp = endp.Descriptor.EndpointID; + inMax = endp.Descriptor.MaxPacketSize; +#if DEBUG + Debug.WriteLine("IN endpoint found: " + inEndp); + Debug.WriteLine("IN endpoint maxsize: " + inMax); +#endif + } + else + { + outEndp = endp.Descriptor.EndpointID; + outMax = endp.Descriptor.MaxPacketSize; +#if DEBUG + Debug.WriteLine("OUT endpoint found: " + outEndp); + Debug.WriteLine("OUT endpoint maxsize: " + outMax); +#endif + } + } + if (inEndp != 0x81 || inMax != 512 || outEndp != 0x01 || outMax != 512) + { + device.Close(); + device = null; + continue; + } + epReader = device.OpenEndpointReader((ReadEndpointID)inEndp, 65536); + epWriter = device.OpenEndpointWriter((WriteEndpointID)outEndp); + killAll(); + +#if DEBUG + Debug.WriteLine("clovershell connected"); +#endif + var header = new byte[4]; + var body = new byte[65536]; + int len; + while (epReader.Read(body, 50, out len) == ErrorCode.Ok) ; + online = true; + while (device.mUsbRegistry.IsAlive) + { + int recv = 0; + while (recv < header.Length) + { + var res = epReader.Read(header, recv, header.Length - recv, 1000, out len); + if (res == ErrorCode.Ok) + recv += len; + else + { + if (recv > 0 || res != ErrorCode.IoTimedOut) + throw new Exception("USB read error: " + res.ToString()); + break; + } + } + if (recv < header.Length) continue; + var cmd = (ClovershellCommand)header[0]; + var arg = header[1]; + var bodyLen = header[2] + header[3] * 0x100; + recv = 0; + while (recv < bodyLen) + { + var res = epReader.Read(body, recv, bodyLen - recv, 1000, out len); + if (res == ErrorCode.Ok) + recv += len; + else + throw new Exception(string.Format("USB read error ({0}/{1}, cmd: {2}, arg: {3}): {4}", recv, bodyLen, cmd, arg, res.ToString())); + } + if (recv < bodyLen) continue; + proceedPacket(cmd, arg, body, bodyLen); + } + break; + } + catch (ThreadAbortException) + { + return; + } + catch (Exception ex) + { + Debug.WriteLine(ex.Message); + break; + } + } + if (online) Debug.WriteLine("clovershell disconnected"); + online = false; + if (device != null) + device.Close(); + device = null; + if (epReader != null) + epReader.Dispose(); + epReader = null; + if (epWriter != null) + epWriter.Dispose(); + epWriter = null; + if (!autoreconnect) Enabled = false; + Thread.Sleep(1000); + } + } + catch (ThreadAbortException) + { + return; + } + catch (Exception ex) + { + Debug.WriteLine("Critical error: " + ex.Message); + } + } + + void proceedPacket(ClovershellCommand cmd, byte arg, byte[] data, int len = -1) + { + if (len < 0) + len = data.Length; +#if DEBUG + Debug.WriteLine(string.Format("cmd={0}, arg={1:X2}, len={2}", cmd, arg, len)); +#endif + switch (cmd) + { + case ClovershellCommand.CMD_PONG: + lastPingResponse = new byte[len]; + Array.Copy(data, 0, lastPingResponse, 0, len); + break; + case ClovershellCommand.CMD_SHELL_NEW_RESP: + acceptShellConnection(arg); + break; + case ClovershellCommand.CMD_SHELL_OUT: + shellOut(arg, data, len); + break; + case ClovershellCommand.CMD_SHELL_CLOSED: + shellClosed(arg); + break; + case ClovershellCommand.CMD_EXEC_NEW_RESP: + newExecConnection(arg, Encoding.UTF8.GetString(data, 0, len)); + break; + case ClovershellCommand.CMD_EXEC_STDOUT: + execOut(arg, data, len); + break; + case ClovershellCommand.CMD_EXEC_STDERR: + execErr(arg, data, len); + break; + case ClovershellCommand.CMD_EXEC_RESULT: + execResult(arg, data); + break; + } + } + + void killAll() + { + int tLen; + var buff = new byte[4]; + buff[0] = (byte)ClovershellCommand.CMD_SHELL_KILL_ALL; + buff[1] = 0; + buff[2] = 0; + buff[3] = 0; + epWriter.Write(buff, 0, buff.Length, 1000, out tLen); + if (tLen != buff.Length) + throw new Exception("kill all shell: write error"); + buff[0] = (byte)ClovershellCommand.CMD_EXEC_KILL_ALL; + buff[1] = 0; + buff[2] = 0; + buff[3] = 0; + epWriter.Write(buff, 0, buff.Length, 1000, out tLen); + if (tLen != buff.Length) + throw new Exception("kill all exec: write error"); + } + + void writeUsb(ClovershellCommand cmd, byte arg, byte[] data = null, int l = -1) + { + if (!online) throw new Exception("NES Mini is offline"); + var len = (l >= 0) ? l : ((data != null) ? data.Length : 0); + var buff = new byte[len + 4]; + buff[0] = (byte)cmd; + buff[1] = arg; + buff[2] = (byte)(len & 0xFF); + buff[3] = (byte)((len >> 8) & 0xFF); + if (data != null) + Array.Copy(data, 0, buff, 4, len); + int tLen = 0; + epWriter.Write(buff, 0, 4 + len, 1000, out tLen); + if (tLen != 4 + len) + throw new Exception("write error"); + } + + void shellThreadLoop() + { + try + { + var server = new TcpListener(IPAddress.Any, shellPort); + Debug.WriteLine(string.Format("Listening port {0}", shellPort)); + server.Start(); + while (true) + { + var connection = new ShellConnection(); + while (!server.Pending()) Thread.Sleep(100); + connection.socket = server.AcceptSocket(); + Debug.WriteLine("Shell client connected"); + try + { + if (!online) throw new Exception("NES Mini is offline"); + pendingShellConnections.Enqueue(connection); + writeUsb(ClovershellCommand.CMD_SHELL_NEW_REQ, 0); + int t = 0; + while (connection.id < 0) + { + Thread.Sleep(50); + t++; + if (t >= 20) throw new Exception("shell request timeout"); + } + } + catch (ThreadAbortException) + { + return; + } + catch (Exception ex) + { + connection.socket.Send(Encoding.ASCII.GetBytes("Error: " + ex.Message)); + Thread.Sleep(3000); + connection.socket.Close(); + } + } + } + catch (ThreadAbortException) + { + return; + } + catch (Exception ex) + { + Debug.WriteLine(ex.Message); + } + } + + void acceptShellConnection(byte arg) + { + try + { + var connection = pendingShellConnections.Dequeue(); + if (connection == null) return; + connection.id = arg; + shellConnections[connection.id] = connection; + Debug.WriteLine(string.Format("Shell started, id={0}", connection.id)); + var thread = new Thread(listenShellConnection); + shellConnecionThreads.Add(thread); + thread.Start(connection); + } + catch (Exception ex) + { + Debug.WriteLine("shell error: " + ex.Message); + } + } + + void newExecConnection(byte arg, string command) + { + try + { + var connection = (from c in pendingExecConnections where c.command == command select c).First(); + pendingExecConnections.Remove(connection); + connection.id = arg; + execConnections[arg] = connection; + if (connection.stdin != null) + { + if (connection.stdin.CanSeek) + connection.stdin.Seek(0, SeekOrigin.Begin); + var buffer = new byte[8*1024]; + int l; + do + { + l = connection.stdin.Read(buffer, 0, buffer.Length); + if (l > 0) + writeUsb(ClovershellCommand.CMD_EXEC_STDIN, (byte)connection.id, buffer, l); + } while (l > 0); + writeUsb(ClovershellCommand.CMD_EXEC_STDIN, (byte)connection.id); // eof + } + } + catch (Exception ex) + { + Debug.WriteLine("exec error: " + ex.Message); + } + } + + void execOut(byte arg, byte[] data, int len) + { + var c = execConnections[arg]; + if (c == null) return; + if (c.stdout != null) + c.stdout.Write(data, 0, len); + if (len == 0) + c.stdoutFinished = true; + } + + void execErr(byte arg, byte[] data, int len) + { + var c = execConnections[arg]; + if (c == null) return; + if (c.stderr != null) + c.stderr.Write(data, 0, len); + if (len == 0) + c.stderrFinished = true; + } + + void execResult(byte arg, byte[] data) + { + var c = execConnections[arg]; + if (c == null) return; + c.result = data[0]; + c.finished = true; + } + + void listenShellConnection(object o) + { + var connection = o as ShellConnection; + var socket = connection.socket; + var id = connection.id; + try + { + var buff = new byte[1024]; + while (socket.Connected) + { + var l = socket.Receive(buff); + if (l > 0) + writeUsb(ClovershellCommand.CMD_SHELL_IN, (byte)id, buff, l); + else + break; + } + } + catch (Exception) + { + } + Debug.WriteLine(string.Format("Client {0} disconnected", id)); + socket.Close(); + shellConnections[id] = null; + shellConnecionThreads.Remove(Thread.CurrentThread); + } + + void shellOut(byte id, byte[] data, int len) + { + try + { + if (shellConnections[id] == null) return; + shellConnections[id].socket.Send(data, 0, len, SocketFlags.None); + } + catch (Exception ex) + { + Debug.WriteLine("socket write error: " + ex.Message); + } + } + + void shellClosed(byte id) + { + if (shellConnections[id] == null) return; + shellConnections[id].socket.Close(); + shellConnections[id] = null; + } + + public void Dispose() + { + Enabled = false; + ShellEnabled = false; + } + + public int Ping() + { + var rnd = new Random(); + var data = new byte[4]; + rnd.NextBytes(data); + lastPingResponse = null; + var start = DateTime.Now; + writeUsb(ClovershellCommand.CMD_PING, 0, data); + int t = 100; + while ((lastPingResponse == null || !lastPingResponse.SequenceEqual(data)) && (t > 0)) + { + Thread.Sleep(10); + t--; + } + if (t <= 0) return -1; + return (int)(DateTime.Now - start).TotalMilliseconds; + } + + public int Execute(string command, Stream stdin, Stream stdout, Stream stderr) + { + var c = new ExecConnection(command, stdin, stdout, stderr); + pendingExecConnections.Add(c); + writeUsb(ClovershellCommand.CMD_EXEC_NEW_REQ, 0, Encoding.UTF8.GetBytes(command)); + while (!c.finished || !c.stdoutFinished || !c.stderrFinished) + { + Thread.Sleep(50); + if (!Online) throw new Exception("device goes offline"); + } + execConnections[c.id] = null; + return c.result; + } + } +} + diff --git a/LibWinUsb/Descriptors/ClassCodeType.cs b/LibWinUsb/Descriptors/ClassCodeType.cs new file mode 100644 index 0000000..87a5129 --- /dev/null +++ b/LibWinUsb/Descriptors/ClassCodeType.cs @@ -0,0 +1,60 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; + +namespace LibUsbDotNet.Descriptors +{ + /// Device and/or Interface Class codes + [Flags] + public enum ClassCodeType : byte + { + ///In the context of a "device descriptor", this bDeviceClass value indicates that each interface specifies its own class information and all interfaces operate independently. + PerInterface = 0, + + ///Audio class + Audio = 1, + + /// Communications class + Comm = 2, + + /// Human Interface Device class + Hid = 3, + + /// Printer dclass + Printer = 7, + + /// Picture transfer protocol class + Ptp = 6, + + /// Mass storage class + MassStorage = 8, + + /// Hub class + Hub = 9, + + /// Data class + Data = 10, + + /// Class is vendor-specific + VendorSpec = 0xff + } +} \ No newline at end of file diff --git a/LibWinUsb/Descriptors/DescriptorType.cs b/LibWinUsb/Descriptors/DescriptorType.cs new file mode 100644 index 0000000..f91bda5 --- /dev/null +++ b/LibWinUsb/Descriptors/DescriptorType.cs @@ -0,0 +1,89 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// + +using System; + +namespace LibUsbDotNet.Descriptors +{ + /// Standard USB descriptor types. + /// + [Flags] + public enum DescriptorType : byte + { + /// + /// Device descriptor type. + /// + Device = 1, + /// + /// Configuration descriptor type. + /// + Configuration = 2, + /// + /// String descriptor type. + /// + String = 3, + /// + /// Interface descriptor type. + /// + Interface = 4, + /// + /// Endpoint descriptor type. + /// + Endpoint = 5, + /// + /// Device Qualifier descriptor type. + /// + DeviceQualifier = 6, + /// + /// Other Speed Configuration descriptor type. + /// + OtherSpeedConfiguration = 7, + /// + /// Interface Power descriptor type. + /// + InterfacePower = 8, + /// + /// OTG descriptor type. + /// + OTG = 9, + /// + /// Debug descriptor type. + /// + Debug = 10, + /// + /// Interface Association descriptor type. + /// + InterfaceAssociation = 11, + + /// HID descriptor + Hid = 0x21, + + /// HID report descriptor + HidReport = 0x22, + + /// Physical descriptor + Physical = 0x23, + + /// Hub descriptor + Hub = 0x29 + } +} \ No newline at end of file diff --git a/LibWinUsb/Descriptors/LangStringDescriptor.cs b/LibWinUsb/Descriptors/LangStringDescriptor.cs new file mode 100644 index 0000000..3f3d384 --- /dev/null +++ b/LibWinUsb/Descriptors/LangStringDescriptor.cs @@ -0,0 +1,131 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace LibUsbDotNet.Descriptors +{ + internal abstract class UsbMemChunk + { + private readonly int mMaxSize; + + private IntPtr mMemPointer = IntPtr.Zero; + + protected UsbMemChunk(int maxSize) + { + mMaxSize = maxSize; + mMemPointer = Marshal.AllocHGlobal(maxSize); + } + + public int MaxSize + { + get { return mMaxSize; } + } + + public IntPtr Ptr + { + get { return mMemPointer; } + } + + public void Free() + { + if (mMemPointer != IntPtr.Zero) + { + Marshal.FreeHGlobal(mMemPointer); + mMemPointer = IntPtr.Zero; + } + } + + ~UsbMemChunk() { Free(); } + } + + internal class LangStringDescriptor : UsbMemChunk + { + #region FIELD_OFFSETS + + private static readonly int OfsDescriptorType = Marshal.OffsetOf(typeof (UsbDescriptor), "DescriptorType").ToInt32(); + private static readonly int OfsLength = Marshal.OffsetOf(typeof (UsbDescriptor), "Length").ToInt32(); + + #endregion + + public LangStringDescriptor(int maxSize) + : base(maxSize) { } + + public DescriptorType DescriptorType + { + get { return (DescriptorType) Marshal.ReadByte(Ptr, OfsDescriptorType); } + set { Marshal.WriteByte(Ptr, OfsDescriptorType, (byte) value); } + } + + public byte Length + { + get { return Marshal.ReadByte(Ptr, OfsLength); } + set { Marshal.WriteByte(Ptr, OfsLength, value); } + } + + public bool Get(out short[] langIds) + { + langIds = new short[0]; + int totalLength = Length; + if (totalLength <= 2) return false; + + int elementCount = (totalLength - 2)/2; + langIds = new short[elementCount]; + + int startOffset = UsbDescriptor.Size; + for (int iElement = 0; iElement < langIds.Length; iElement++) + { + langIds[iElement] = Marshal.ReadInt16(Ptr, startOffset + (sizeof (ushort)*iElement)); + } + return true; + } + + public bool Get(out byte[] bytes) + { + bytes = new byte[Length]; + Marshal.Copy(Ptr, bytes, 0, bytes.Length); + return true; + } + + public bool Get(out string str) + { + str = string.Empty; + + byte[] bytes; + if (Get(out bytes)) + { + if (bytes.Length <= UsbDescriptor.Size) + { + str = string.Empty; + } + else + { + str = Encoding.Unicode.GetString(bytes, UsbDescriptor.Size, bytes.Length - UsbDescriptor.Size); + } + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/LibWinUsb/Descriptors/StringDescriptor.cs b/LibWinUsb/Descriptors/StringDescriptor.cs new file mode 100644 index 0000000..282f1f9 --- /dev/null +++ b/LibWinUsb/Descriptors/StringDescriptor.cs @@ -0,0 +1,24 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +namespace LibUsbDotNet.Descriptors +{ +} \ No newline at end of file diff --git a/LibWinUsb/Descriptors/UsbConfigDescriptor.cs b/LibWinUsb/Descriptors/UsbConfigDescriptor.cs new file mode 100644 index 0000000..423b945 --- /dev/null +++ b/LibWinUsb/Descriptors/UsbConfigDescriptor.cs @@ -0,0 +1,113 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; +using LibUsbDotNet.Main; +using MonoLibUsb.Descriptors; + +#pragma warning disable 649 + +namespace LibUsbDotNet.Descriptors +{ + /// Usb Configuration Descriptor. + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public class UsbConfigDescriptor : UsbDescriptor + { + /// + /// Total size of this structure in bytes. + /// + public new static readonly int Size = Marshal.SizeOf(typeof (UsbConfigDescriptor)); + + /// + /// Total length in bytes of data returned + /// + public readonly short TotalLength; + + /// + /// Number of Interfaces + /// + public readonly byte InterfaceCount; + + /// + /// Value to use as an argument to select this Configuration + /// + public readonly byte ConfigID; + + /// + /// Index of String Descriptor describing this Configuration + /// + public readonly byte StringIndex; + + /// + /// D7 Reserved, set to 1. (USB 1.0 Bus Powered) + /// D6 Self Powered + /// D5 Remote Wakeup + /// D4..0 Reserved, set to 0. + /// + public readonly byte Attributes; + + /// + /// Maximum Power Consumption in 2mA units + /// + public readonly byte MaxPower; + + internal UsbConfigDescriptor(MonoUsbConfigDescriptor descriptor) + { + Attributes = descriptor.bmAttributes; + ConfigID = descriptor.bConfigurationValue; + DescriptorType = descriptor.bDescriptorType; + InterfaceCount = descriptor.bNumInterfaces; + Length = descriptor.bLength; + MaxPower = descriptor.MaxPower; + StringIndex = descriptor.iConfiguration; + TotalLength = (short) descriptor.wTotalLength; + } + + internal UsbConfigDescriptor() { } + + /// + ///Returns a that represents the current . + /// + /// + /// + ///A that represents the current . + /// + public override string ToString() { return ToString("", ToStringParamValueSeperator, ToStringFieldSeperator); } + + /// + ///Returns a that represents the current . + /// + /// + ///The field prefix string. + ///The field/value seperator string. + ///The value suffix string. + ///A formatted representation of the . + public string ToString(string prefixSeperator, string entitySperator, string suffixSeperator) + { + Object[] values = {Length, DescriptorType, TotalLength, InterfaceCount, ConfigID, StringIndex, "0x" + Attributes.ToString("X2"), MaxPower}; + string[] names = {"Length", "DescriptorType", "TotalLength", "InterfaceCount", "ConfigID", "StringIndex", "Attributes", "MaxPower"}; + + return Helper.ToString(prefixSeperator, names, entitySperator, values, suffixSeperator); + } + } +} \ No newline at end of file diff --git a/LibWinUsb/Descriptors/UsbDescriptor.cs b/LibWinUsb/Descriptors/UsbDescriptor.cs new file mode 100644 index 0000000..7135ad6 --- /dev/null +++ b/LibWinUsb/Descriptors/UsbDescriptor.cs @@ -0,0 +1,73 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; +using LibUsbDotNet.Main; + +#pragma warning disable 649 + +namespace LibUsbDotNet.Descriptors +{ + /// Base class for all usb descriptors structures. + /// + /// This is the actual descriptor as described in the USB 2.0 Specifications. + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public abstract class UsbDescriptor + { + /// + /// String value used to seperate the name/value pairs for all ToString overloads of the descriptor classes. + /// + public static string ToStringParamValueSeperator = ":"; + + /// + /// String value used to seperate the name/value groups for all ToString overloads of the descriptor classes. + /// + public static string ToStringFieldSeperator = "\r\n"; + + /// + /// Total size of this structure in bytes. + /// + public static readonly int Size = Marshal.SizeOf(typeof (UsbDescriptor)); + + /// + /// Length of structure reported by the associated usb device. + /// + public byte Length; + + /// + /// Type of structure reported by the associated usb device. + /// + public DescriptorType DescriptorType; + + /// + /// String representation of the UsbDescriptor class. + /// + public override string ToString() + { + Object[] values = {Length, DescriptorType}; + string[] names = {"Length", "DescriptorType"}; + + return Helper.ToString("", names, ToStringParamValueSeperator, values, ToStringFieldSeperator); + } + } +} \ No newline at end of file diff --git a/LibWinUsb/Descriptors/UsbDeviceDescriptor.cs b/LibWinUsb/Descriptors/UsbDeviceDescriptor.cs new file mode 100644 index 0000000..f545ce1 --- /dev/null +++ b/LibWinUsb/Descriptors/UsbDeviceDescriptor.cs @@ -0,0 +1,232 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; +using LibUsbDotNet.Main; +using MonoLibUsb.Descriptors; + +#pragma warning disable 649 + +namespace LibUsbDotNet.Descriptors +{ + /// Usb Device Descriptor + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public class UsbDeviceDescriptor : UsbDescriptor + { + /// + /// Total size of this structure in bytes. + /// + public new static readonly int Size = Marshal.SizeOf(typeof (UsbDeviceDescriptor)); + + /// + /// USB Specification Number which device complies too. + /// + public short BcdUsb; + + /// + /// Class Code (Assigned by USB Org) + /// If equal to Zero, each interface specifies it’s own class code; If equal to 0xFF, the class code is vendor specified; Otherwise field is valid Class Code. + /// + public ClassCodeType Class; + + /// + /// Subclass Code (Assigned by USB Org) + /// + public byte SubClass; + + /// + /// Protocol Code (Assigned by USB Org) + /// + public byte Protocol; + + /// + /// Maximum Packet Size for Zero Endpoint. Valid Sizes are 8, 16, 32, 64 + /// + public byte MaxPacketSize0; + + /// + /// Vendor ID (Assigned by USB Org) + /// + public short VendorID; + + /// + /// Product ID (Assigned by Manufacturer) + /// + public short ProductID; + + /// + /// Device Release Number + /// + public short BcdDevice; + + /// + /// Index of Manufacturer String Descriptor + /// + public byte ManufacturerStringIndex; + + /// + /// Index of Product String Descriptor + /// + public byte ProductStringIndex; + + /// + /// Index of Serial Number String Descriptor + /// + public byte SerialStringIndex; + + /// + /// Number of Possible Configurations + /// + public byte ConfigurationCount; + + internal UsbDeviceDescriptor() { } + + internal UsbDeviceDescriptor(MonoUsbDeviceDescriptor usbDeviceDescriptor) + { + BcdDevice = usbDeviceDescriptor.BcdDevice; + BcdUsb = usbDeviceDescriptor.BcdUsb; + Class = usbDeviceDescriptor.Class; + ConfigurationCount = usbDeviceDescriptor.ConfigurationCount; + DescriptorType = usbDeviceDescriptor.DescriptorType; + Length = usbDeviceDescriptor.Length; + ManufacturerStringIndex = usbDeviceDescriptor.ManufacturerStringIndex; + MaxPacketSize0 = usbDeviceDescriptor.MaxPacketSize0; + ProductID = usbDeviceDescriptor.ProductID; + ProductStringIndex = usbDeviceDescriptor.ProductStringIndex; + Protocol = usbDeviceDescriptor.Protocol; + SerialStringIndex = usbDeviceDescriptor.SerialStringIndex; + SubClass = usbDeviceDescriptor.SubClass; + VendorID = usbDeviceDescriptor.VendorID; + } + + /// + ///Returns a that represents the current . + /// + /// + /// + ///A that represents the current . + /// + public override string ToString() { return ToString("", ToStringParamValueSeperator, ToStringFieldSeperator); } + + /// + ///Returns a that represents the current . + /// + /// + ///The field prefix string. + ///The field/value seperator string. + ///The value suffix string. + ///A formatted representation of the . + public string ToString(string prefixSeperator, string entitySperator, string suffixSeperator) + { + Object[] values = { + Length, DescriptorType, "0x" + BcdUsb.ToString("X4"), Class, "0x" + SubClass.ToString("X2"), + "0x" + Protocol.ToString("X2"), MaxPacketSize0, + "0x" + VendorID.ToString("X4"), "0x" + ProductID.ToString("X4"), "0x" + BcdDevice.ToString("X4"), + ManufacturerStringIndex, ProductStringIndex, SerialStringIndex, ConfigurationCount + }; + string[] names = { + "Length", "DescriptorType", "BcdUsb", "Class", "SubClass", "Protocol", "MaxPacketSize0", "VendorID", "ProductID", + "BcdDevice", + "ManufacturerStringIndex", "ProductStringIndex", "SerialStringIndex", "ConfigurationCount" + }; + + return Helper.ToString(prefixSeperator, names, entitySperator, values, suffixSeperator); + } + + /// + /// Determines whether the specified is equal to the current . + /// + /// + /// true if the specified is equal to the current ; otherwise, false. + /// + /// The to compare with the current . The parameter is null.2 + public bool Equals(UsbDeviceDescriptor other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return other.BcdUsb == BcdUsb && other.Class == Class && other.SubClass == SubClass && other.Protocol == Protocol && + other.MaxPacketSize0 == MaxPacketSize0 && other.VendorID == VendorID && other.ProductID == ProductID && + other.BcdDevice == BcdDevice && other.ManufacturerStringIndex == ManufacturerStringIndex && + other.ProductStringIndex == ProductStringIndex && other.SerialStringIndex == SerialStringIndex && + other.ConfigurationCount == ConfigurationCount; + } + + /// + /// Determines whether the specified is equal to the current . + /// + /// + /// true if the specified is equal to the current ; otherwise, false. + /// + /// The to compare with the current . The parameter is null.2 + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != typeof (UsbDeviceDescriptor)) return false; + return Equals((UsbDeviceDescriptor) obj); + } + + /// + /// Serves as a hash function for a particular type. + /// + /// + /// A hash code for the current . + /// + /// 2 + public override int GetHashCode() + { + unchecked + { + int result = BcdUsb.GetHashCode(); + result = (result*397) ^ Class.GetHashCode(); + result = (result*397) ^ SubClass.GetHashCode(); + result = (result*397) ^ Protocol.GetHashCode(); + result = (result*397) ^ MaxPacketSize0.GetHashCode(); + result = (result*397) ^ VendorID.GetHashCode(); + result = (result*397) ^ ProductID.GetHashCode(); + result = (result*397) ^ BcdDevice.GetHashCode(); + result = (result*397) ^ ManufacturerStringIndex.GetHashCode(); + result = (result*397) ^ ProductStringIndex.GetHashCode(); + result = (result*397) ^ SerialStringIndex.GetHashCode(); + result = (result*397) ^ ConfigurationCount.GetHashCode(); + return result; + } + } + + /// + /// + /// + /// + /// + /// + public static bool operator ==(UsbDeviceDescriptor left, UsbDeviceDescriptor right) { return Equals(left, right); } + + /// + /// + /// + /// + /// + /// + public static bool operator !=(UsbDeviceDescriptor left, UsbDeviceDescriptor right) { return !Equals(left, right); } + } +} \ No newline at end of file diff --git a/LibWinUsb/Descriptors/UsbEndpointDescriptor.cs b/LibWinUsb/Descriptors/UsbEndpointDescriptor.cs new file mode 100644 index 0000000..cc7f41a --- /dev/null +++ b/LibWinUsb/Descriptors/UsbEndpointDescriptor.cs @@ -0,0 +1,134 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; +using LibUsbDotNet.Main; +using MonoLibUsb.Descriptors; + +#pragma warning disable 649 + +namespace LibUsbDotNet.Descriptors +{ + /// Usb Endpoint Descriptor + /// + /// This is the actual descriptor as described in the USB 2.0 Specifications. + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public class UsbEndpointDescriptor : UsbDescriptor + { + /// + /// Total size of this structure in bytes. + /// + public new static readonly int Size = Marshal.SizeOf(typeof (UsbEndpointDescriptor)); + + /// + /// Endpoint Address + /// Bits 0..3b Endpoint Number. + /// Bits 4..6b Reserved. Set to Zero + /// Bits 7 Direction 0 = Out, 1 = In (Ignored for Control Endpoints) + /// + public readonly byte EndpointID; + + /// + /// Bits 0..1 Transfer Type + /// 00 = Control + /// 01 = Isochronous + /// 10 = Bulk + /// 11 = Interrupt + /// + /// Bits 2..7 are reserved. If Isochronous endpoint, + /// Bits 3..2 = Synchronisation Type (Iso Mode) + /// 00 = No Synchonisation + /// 01 = Asynchronous + /// 10 = Adaptive + /// 11 = Synchronous + /// + /// Bits 5..4 = Usage Type (Iso Mode) + /// 00 = Data Endpoint + /// 01 = Feedback Endpoint + /// 10 = Explicit Feedback Data Endpoint + /// 11 = Reserved + /// + public readonly byte Attributes; + + /// + /// Maximum Packet Size this endpoint is capable of sending or receiving + /// + public readonly short MaxPacketSize; + + /// + /// Interval for polling endpoint data transfers. Value in frame counts. Ignored for Bulk and Control Endpoints. Isochronous must equal 1 and field may range from 1 to 255 for interrupt endpoints. + /// + public readonly byte Interval; + + /// + /// Audio endpoint specific. + /// + public readonly byte Refresh; + + /// + /// Audio endpoint specific. + /// + public readonly byte SynchAddress; + + internal UsbEndpointDescriptor() { } + + internal UsbEndpointDescriptor(MonoUsbEndpointDescriptor descriptor) + { + Attributes = descriptor.bmAttributes; + DescriptorType = descriptor.bDescriptorType; + EndpointID = descriptor.bEndpointAddress; + Interval = descriptor.bInterval; + Length = descriptor.bLength; + MaxPacketSize = (short) descriptor.wMaxPacketSize; + SynchAddress = descriptor.bSynchAddress; + } + + /// + ///Returns a that represents the current . + /// + /// + /// + ///A that represents the current . + /// + public override string ToString() { return ToString("", ToStringParamValueSeperator, ToStringFieldSeperator); } + + /// + ///Returns a that represents the current . + /// + /// + ///The field prefix string. + ///The field/value seperator string. + ///The value suffix string. + ///A formatted representation of the . + public string ToString(string prefixSeperator, string entitySperator, string suffixSeperator) + { + Object[] values = { + Length, DescriptorType, "0x" + EndpointID.ToString("X2"), "0x" + Attributes.ToString("X2"), MaxPacketSize, Interval, + Refresh, "0x" + SynchAddress.ToString("X2") + }; + string[] names = {"Length", "DescriptorType", "EndpointID", "Attributes", "MaxPacketSize", "Interval", "Refresh", "SynchAddress"}; + + return Helper.ToString(prefixSeperator, names, entitySperator, values, suffixSeperator); + } + } +} \ No newline at end of file diff --git a/LibWinUsb/Descriptors/UsbInterfaceDescriptor.cs b/LibWinUsb/Descriptors/UsbInterfaceDescriptor.cs new file mode 100644 index 0000000..6624602 --- /dev/null +++ b/LibWinUsb/Descriptors/UsbInterfaceDescriptor.cs @@ -0,0 +1,126 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; +using LibUsbDotNet.Main; +using MonoLibUsb.Descriptors; + +#pragma warning disable 649 + +namespace LibUsbDotNet.Descriptors +{ + /// Usb Interface Descriptor. + /// + /// This is the actual descriptor as described in the USB 2.0 Specifications. + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public class UsbInterfaceDescriptor : UsbDescriptor + { + /// + /// Total size of this structure in bytes. + /// + public new static readonly int Size = Marshal.SizeOf(typeof (UsbInterfaceDescriptor)); + + /// + /// Number of Interface + /// + public readonly byte InterfaceID; + + /// + /// Value used to select alternative setting + /// + public readonly byte AlternateID; + + /// + /// Number of Endpoints used for this interface + /// + public readonly byte EndpointCount; + + /// + /// Class Code (Assigned by USB Org) + /// + public readonly ClassCodeType Class; + + /// + /// Subclass Code (Assigned by USB Org) + /// + public readonly byte SubClass; + + /// + /// Protocol Code (Assigned by USB Org) + /// + public readonly byte Protocol; + + /// + /// Index of String Descriptor Describing this interface + /// + public readonly byte StringIndex; + + /// + ///Returns a that represents the current . + /// + /// + /// + ///A that represents the current . + /// + public override string ToString() { return ToString("", ToStringParamValueSeperator, ToStringFieldSeperator); } + + + /// + ///Returns a that represents the current . + /// + /// + ///The field prefix string. + ///The field/value seperator string. + ///The value suffix string. + ///A formatted representation of the . + public string ToString(string prefixSeperator, string entitySperator, string suffixSeperator) + { + Object[] values = { + Length, DescriptorType, InterfaceID, AlternateID, EndpointCount, Class, "0x" + SubClass.ToString("X2"), + "0x" + Protocol.ToString("X2"), StringIndex + }; + string[] names = { + "Length", "DescriptorType", "InterfaceID", "AlternateID", "EndpointCount", "Class", "SubClass", "Protocol", + "StringIndex" + }; + + return Helper.ToString(prefixSeperator, names, entitySperator, values, suffixSeperator); + } + + + internal UsbInterfaceDescriptor() { } + + internal UsbInterfaceDescriptor(MonoUsbAltInterfaceDescriptor altInterfaceDescriptor) + { + AlternateID = altInterfaceDescriptor.bAlternateSetting; + Class = altInterfaceDescriptor.bInterfaceClass; + DescriptorType = altInterfaceDescriptor.bDescriptorType; + EndpointCount = altInterfaceDescriptor.bNumEndpoints; + InterfaceID = altInterfaceDescriptor.bInterfaceNumber; + Length = altInterfaceDescriptor.bLength; + Protocol = altInterfaceDescriptor.bInterfaceProtocol; + StringIndex = altInterfaceDescriptor.iInterface; + SubClass = altInterfaceDescriptor.bInterfaceSubClass; + } + } +} \ No newline at end of file diff --git a/LibWinUsb/DeviceNotify/DeviceNotifier.cs b/LibWinUsb/DeviceNotify/DeviceNotifier.cs new file mode 100644 index 0000000..37991c9 --- /dev/null +++ b/LibWinUsb/DeviceNotify/DeviceNotifier.cs @@ -0,0 +1,48 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using LibUsbDotNet.DeviceNotify.Linux; + +namespace LibUsbDotNet.DeviceNotify +{ + /// + /// Platform independent class for linux/windows device notification. + /// + /// + public static class DeviceNotifier + { + /// + /// Creates a new instance of a device notifier class. + /// + /// A under windows and a under linux. + public static IDeviceNotifier OpenDeviceNotifier() + { + if (UsbDevice.IsLinux) + { + return new LinuxDeviceNotifier(); + } + else + { + return new WindowsDeviceNotifier(); + } + } + } +} \ No newline at end of file diff --git a/LibWinUsb/DeviceNotify/DeviceNotifyEventArgs.cs b/LibWinUsb/DeviceNotify/DeviceNotifyEventArgs.cs new file mode 100644 index 0000000..18b4061 --- /dev/null +++ b/LibWinUsb/DeviceNotify/DeviceNotifyEventArgs.cs @@ -0,0 +1,112 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using LibUsbDotNet.DeviceNotify.Info; + +namespace LibUsbDotNet.DeviceNotify +{ + /// + /// Describes the device notify event + /// + public abstract class DeviceNotifyEventArgs : EventArgs + { + internal IUsbDeviceNotifyInfo mDevice; + internal DeviceType mDeviceType; + internal EventType mEventType; + internal object mObject; + internal IPortNotifyInfo mPort; + internal IVolumeNotifyInfo mVolume; + + /// + /// Gets the class. + /// + /// + /// This value is null if the is not set to + /// + public IVolumeNotifyInfo Volume + { + get { return mVolume; } + } + + /// + /// Gets the class. + /// + /// + /// This value is null if the is not set to + /// + public IPortNotifyInfo Port + { + get { return mPort; } + } + + /// + /// Gets the class. + /// + /// + /// This value is null if the is not set to + /// + public IUsbDeviceNotifyInfo Device + { + get { return mDevice; } + } + + /// + /// Gets the for this notification. + /// + public EventType EventType + { + get { return mEventType; } + } + + /// + /// Gets the for this notification. + /// + public DeviceType DeviceType + { + get { return mDeviceType; } + } + + /// + /// Gets the notification class as an object. + /// + /// + /// This value is never null. + /// + public object Object + { + get { return mObject; } + } + + /// + ///Returns a that represents the current . + /// + /// + /// + ///A that represents the current . + /// + public override string ToString() + { + object[] o = {DeviceType, EventType, mObject.ToString()}; + return string.Format("[DeviceType:{0}] [EventType:{1}] {2}", o); + } + } +} \ No newline at end of file diff --git a/LibWinUsb/DeviceNotify/DeviceType.cs b/LibWinUsb/DeviceNotify/DeviceType.cs new file mode 100644 index 0000000..e671bfb --- /dev/null +++ b/LibWinUsb/DeviceNotify/DeviceType.cs @@ -0,0 +1,58 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +namespace LibUsbDotNet.DeviceNotify +{ + /// + /// Type of notification device. + /// + public enum DeviceType + { + /// + /// oem-defined device type. + /// + Oem = 0x00000000, + /// + /// devnode number. + /// + DevNode = 0x00000001, + /// + /// logical volume. + /// + Volume = 0x00000002, + /// + /// serial, parallel. + /// + Port = 0x00000003, + /// + /// network resource. + /// + Net = 0x00000004, + /// + /// device interface class + /// + DeviceInterface = 0x00000005, + /// + /// file system handle. + /// + Handle = 0x00000006 + } +} \ No newline at end of file diff --git a/LibWinUsb/DeviceNotify/EventType.cs b/LibWinUsb/DeviceNotify/EventType.cs new file mode 100644 index 0000000..88ed700 --- /dev/null +++ b/LibWinUsb/DeviceNotify/EventType.cs @@ -0,0 +1,58 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +namespace LibUsbDotNet.DeviceNotify +{ + /// + /// Type of notification event. + /// + public enum EventType + { + /// + /// A custom event has occurred. + /// + CustomEvent = 0x8006, + /// + /// A device or piece of media has been inserted and is now available. + /// + DeviceArrival = 0x8000, + /// + /// Permission is requested to remove a device or piece of media. Any application can deny this request and cancel the removal. + /// + DeviceQueryRemove = 0x8001, + /// + /// A request to remove a device or piece of media has been canceled. + /// + DeviceQueryRemoveFailed = 0x8002, + /// + /// A device or piece of media has been removed. + /// + DeviceRemoveComplete = 0x8004, + /// + /// A device or piece of media is about to be removed. Cannot be denied. + /// + DeviceRemovePending = 0x8003, + /// + /// A device-specific event has occurred. + /// + DeviceTypeSpecific = 0x8005 + } +} \ No newline at end of file diff --git a/LibWinUsb/DeviceNotify/IDeviceNotifier.cs b/LibWinUsb/DeviceNotify/IDeviceNotifier.cs new file mode 100644 index 0000000..02b59e3 --- /dev/null +++ b/LibWinUsb/DeviceNotify/IDeviceNotifier.cs @@ -0,0 +1,52 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; + +namespace LibUsbDotNet.DeviceNotify +{ + /// + /// Notifies an application of a change to the hardware Configuration of a device or + /// the computer. + /// + /// + /// For devices that offer software-controllable features, such as ejection and locking, + /// the system typically sends a message to + /// let applications and device drivers end their use of the device gracefully. If the + /// system forcibly removes a device, it may not send a + /// message before doing so. + /// + /// + /// + /// + public interface IDeviceNotifier + { + /// + /// Enables/Disables notification events. + /// + bool Enabled { get; set; } + + /// + /// Main Notify event for all device notifications. + /// + event EventHandler OnDeviceNotify; + } +} \ No newline at end of file diff --git a/LibWinUsb/DeviceNotify/Info/IPortNotifyInfo.cs b/LibWinUsb/DeviceNotify/Info/IPortNotifyInfo.cs new file mode 100644 index 0000000..fdb1728 --- /dev/null +++ b/LibWinUsb/DeviceNotify/Info/IPortNotifyInfo.cs @@ -0,0 +1,43 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +namespace LibUsbDotNet.DeviceNotify.Info +{ + /// Common interface describing a communication port arrival or removal notification. + /// + public interface IPortNotifyInfo + { + /// + /// Under windows, Gets the name of the port that caused the event. + /// Under windows, Gets the full path of the device caused the event. + /// + string Name { get; } + + /// + ///Returns a that represents the current . + /// + /// + /// + ///A that represents the current . + /// + string ToString(); + } +} \ No newline at end of file diff --git a/LibWinUsb/DeviceNotify/Info/IUsbDeviceNotifyInfo.cs b/LibWinUsb/DeviceNotify/Info/IUsbDeviceNotifyInfo.cs new file mode 100644 index 0000000..2228e3f --- /dev/null +++ b/LibWinUsb/DeviceNotify/Info/IUsbDeviceNotifyInfo.cs @@ -0,0 +1,70 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using LibUsbDotNet.Main; + +namespace LibUsbDotNet.DeviceNotify.Info +{ + /// Common inteface describing USB DEVICE INTERFACE arrival and removal events. + /// + public interface IUsbDeviceNotifyInfo + { + /// + /// The symbolc name class for this device. For more information, see . + /// + UsbSymbolicName SymbolicName { get; } + + /// + /// Gets the full name of the USB device that caused the notification. + /// + string Name { get; } + + /// + /// Gets the Class Guid of the USB device that caused the notification. + /// + Guid ClassGuid { get; } + + /// + /// Parses and returns the VID from the property. + /// + int IdVendor { get; } + + /// + /// Parses and returns the PID from the property. + /// + int IdProduct { get; } + + /// + /// Parses and returns the serial number from the property. + /// + string SerialNumber { get; } + + /// + ///Returns a that represents the current . + /// + /// + /// + ///A that represents the current . + /// + string ToString(); + } +} \ No newline at end of file diff --git a/LibWinUsb/DeviceNotify/Info/IVolumeNotifyInfo.cs b/LibWinUsb/DeviceNotify/Info/IVolumeNotifyInfo.cs new file mode 100644 index 0000000..26a2c42 --- /dev/null +++ b/LibWinUsb/DeviceNotify/Info/IVolumeNotifyInfo.cs @@ -0,0 +1,63 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +namespace LibUsbDotNet.DeviceNotify.Info +{ + /// Common interface describing a storage volume arrival or removal notification. + /// + public interface IVolumeNotifyInfo + { + /// + /// Under windows, gets the letter representation of the unitmask. + /// Under linux, gets the full path of the device name. + /// + string Letter { get; } + + /// + /// If true, change affects media in drive. If false, change affects physical device or drive. + /// + bool ChangeAffectsMediaInDrive { get; } + + /// + /// If True, the indicated logical volume is a network volume + /// + bool IsNetworkVolume { get; } + + /// + /// Raw DevBroadcastVolume flags. + /// + short Flags { get; } + + /// + /// Gets the bit unit mask of the device. IE (bit 0 = A:, bit 1 = B:, etc..) + /// + int Unitmask { get; } + + /// + ///Returns a that represents the current . + /// + /// + /// + ///A that represents the current . + /// + string ToString(); + } +} \ No newline at end of file diff --git a/LibWinUsb/DeviceNotify/Info/PortNotifyInfo.cs b/LibWinUsb/DeviceNotify/Info/PortNotifyInfo.cs new file mode 100644 index 0000000..d7662fb --- /dev/null +++ b/LibWinUsb/DeviceNotify/Info/PortNotifyInfo.cs @@ -0,0 +1,63 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; +using LibUsbDotNet.DeviceNotify.Internal; + +namespace LibUsbDotNet.DeviceNotify.Info +{ + /// Notify information for a communication port + /// + public class PortNotifyInfo : IPortNotifyInfo + { + private readonly DevBroadcastPort mBaseHdr = new DevBroadcastPort(); + private readonly string mName; + + internal PortNotifyInfo(IntPtr lParam) + { + Marshal.PtrToStructure(lParam, mBaseHdr); + IntPtr pName = new IntPtr(lParam.ToInt64() + Marshal.OffsetOf(typeof (DevBroadcastPort), "mNameHolder").ToInt64()); + mName = Marshal.PtrToStringAuto(pName); + } + + #region IPortNotifyInfo Members + + /// + /// Gets the name of the port that caused the event. + /// + public string Name + { + get { return mName; } + } + + /// + ///Returns a that represents the current . + /// + /// + /// + ///A that represents the current . + /// + public override string ToString() { return string.Format("[Port Name:{0}] ", Name); } + + #endregion + } +} \ No newline at end of file diff --git a/LibWinUsb/DeviceNotify/Info/UsbDeviceNotifyInfo.cs b/LibWinUsb/DeviceNotify/Info/UsbDeviceNotifyInfo.cs new file mode 100644 index 0000000..085e1da --- /dev/null +++ b/LibWinUsb/DeviceNotify/Info/UsbDeviceNotifyInfo.cs @@ -0,0 +1,112 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; +using LibUsbDotNet.DeviceNotify.Internal; +using LibUsbDotNet.Main; + +namespace LibUsbDotNet.DeviceNotify.Info +{ + /// Describes the USB device that caused the notification. + /// See the inteface for more information. + /// + public class UsbDeviceNotifyInfo : IUsbDeviceNotifyInfo + { + private readonly DevBroadcastDeviceinterface mBaseHdr = new DevBroadcastDeviceinterface(); + private readonly string mName; + private UsbSymbolicName mSymbolicName; + + internal UsbDeviceNotifyInfo(IntPtr lParam) + { + Marshal.PtrToStructure(lParam, mBaseHdr); + IntPtr pName = new IntPtr(lParam.ToInt64() + Marshal.OffsetOf(typeof (DevBroadcastDeviceinterface), "mNameHolder").ToInt64()); + mName = Marshal.PtrToStringAuto(pName); + } + + #region IUsbDeviceNotifyInfo Members + + /// + /// The symbolc name class for this device. For more information, see . + /// + public UsbSymbolicName SymbolicName + { + get + { + if (ReferenceEquals(mSymbolicName, null)) + mSymbolicName = new UsbSymbolicName(mName); + + return mSymbolicName; + } + } + + /// + /// Gets the full name of the USB device that caused the notification. + /// + public string Name + { + get { return mName; } + } + + /// + /// Gets the Class Guid of the USB device that caused the notification. + /// + public Guid ClassGuid + { + get { return SymbolicName.ClassGuid; } + } + + /// + /// Parses and returns the VID from the property. + /// + public int IdVendor + { + get { return SymbolicName.Vid; } + } + + /// + /// Parses and returns the PID from the property. + /// + public int IdProduct + { + get { return SymbolicName.Pid; } + } + + /// + /// Parses and returns the serial number from the property. + /// + public string SerialNumber + { + get { return SymbolicName.SerialNumber; } + } + + /// + ///Returns a that represents the current . + /// + /// + /// + ///A that represents the current . + /// + public override string ToString() { return SymbolicName.ToString(); } + + #endregion + } +} \ No newline at end of file diff --git a/LibWinUsb/DeviceNotify/Info/VolumeNotifyInfo.cs b/LibWinUsb/DeviceNotify/Info/VolumeNotifyInfo.cs new file mode 100644 index 0000000..d13268e --- /dev/null +++ b/LibWinUsb/DeviceNotify/Info/VolumeNotifyInfo.cs @@ -0,0 +1,114 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; +using LibUsbDotNet.DeviceNotify.Internal; + +namespace LibUsbDotNet.DeviceNotify.Info +{ + /// Describes the storage volume that caused the notification. + /// See for more information. + /// + public class VolumeNotifyInfo : IVolumeNotifyInfo + { + private const int DBTF_MEDIA = 0x0001; + private const int DBTF_NET = 0x0002; + + private readonly DevBroadcastVolume mBaseHdr = new DevBroadcastVolume(); + + internal VolumeNotifyInfo(IntPtr lParam) { Marshal.PtrToStructure(lParam, mBaseHdr); } + + #region IVolumeNotifyInfo Members + + /// + /// Gets the letter representation of the unitmask. + /// + public string Letter + { + get + { + Int32 tempMask = Unitmask; + for (byte b = 65; b < (65 + 32); b++) + { + Byte bValue = b; + if (bValue > 90) + bValue -= 43; + if ((tempMask & 0x1) == 1) + return ((char) bValue).ToString(); + + tempMask >>= 1; + } + + return ((char) 63).ToString(); + } + } + + /// + /// If true, change affects media in drive. If false, change affects physical device or drive. + /// + public bool ChangeAffectsMediaInDrive + { + get { return ((Flags & DBTF_MEDIA) == DBTF_MEDIA); } + } + + /// + /// If True, the indicated logical volume is a network volume + /// + public bool IsNetworkVolume + { + get { return ((Flags & DBTF_NET) == DBTF_NET); } + } + + /// + /// Raw DevBroadcastVolume flags. + /// + public short Flags + { + get { return mBaseHdr.Flags; } + } + + /// + /// Gets the bit unit mask of the device. IE (bit 0 = A:, bit 1 = B:, etc..) + /// + public int Unitmask + { + get { return mBaseHdr.UnitMask; } + } + + /// + ///Returns a that represents the current . + /// + /// + /// + ///A that represents the current . + /// + public override string ToString() + { + return string.Format("[Letter:{0}] [IsNetworkVolume:{1}] [ChangeAffectsMediaInDrive:{2}] ", + Letter, + IsNetworkVolume, + ChangeAffectsMediaInDrive); + } + + #endregion + } +} \ No newline at end of file diff --git a/LibWinUsb/DeviceNotify/Internal/DevBroadcastDeviceinterface.cs b/LibWinUsb/DeviceNotify/Internal/DevBroadcastDeviceinterface.cs new file mode 100644 index 0000000..148e063 --- /dev/null +++ b/LibWinUsb/DeviceNotify/Internal/DevBroadcastDeviceinterface.cs @@ -0,0 +1,44 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; + +#pragma warning disable 169 + +namespace LibUsbDotNet.DeviceNotify.Internal +{ + [StructLayout(LayoutKind.Sequential)] + internal class DevBroadcastDeviceinterface : DevBroadcastHdr + { + public Guid ClassGuid = Guid.Empty; + private char mNameHolder; + + public DevBroadcastDeviceinterface() + { + Size = Marshal.SizeOf(this); + DeviceType = DeviceType.DeviceInterface; + } + + public DevBroadcastDeviceinterface(Guid guid) + : this() { ClassGuid = guid; } + } +} \ No newline at end of file diff --git a/LibWinUsb/DeviceNotify/Internal/DevBroadcastHdr.cs b/LibWinUsb/DeviceNotify/Internal/DevBroadcastHdr.cs new file mode 100644 index 0000000..5bc907c --- /dev/null +++ b/LibWinUsb/DeviceNotify/Internal/DevBroadcastHdr.cs @@ -0,0 +1,35 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System.Runtime.InteropServices; + +namespace LibUsbDotNet.DeviceNotify.Internal +{ + [StructLayout(LayoutKind.Sequential)] + internal class DevBroadcastHdr + { + public int Size; + public DeviceType DeviceType; + public int Rsrvd1; + + internal DevBroadcastHdr() { Size = Marshal.SizeOf(this); } + } +} \ No newline at end of file diff --git a/LibWinUsb/DeviceNotify/Internal/DevBroadcastPort.cs b/LibWinUsb/DeviceNotify/Internal/DevBroadcastPort.cs new file mode 100644 index 0000000..8d9b28f --- /dev/null +++ b/LibWinUsb/DeviceNotify/Internal/DevBroadcastPort.cs @@ -0,0 +1,39 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System.Runtime.InteropServices; + +#pragma warning disable 169 + +namespace LibUsbDotNet.DeviceNotify.Internal +{ + [StructLayout(LayoutKind.Sequential)] + internal class DevBroadcastPort : DevBroadcastHdr + { + private char mNameHolder; + + public DevBroadcastPort() + { + Size = Marshal.SizeOf(this); + DeviceType = DeviceType.Port; + } + } +} \ No newline at end of file diff --git a/LibWinUsb/DeviceNotify/Internal/DevBroadcastVolume.cs b/LibWinUsb/DeviceNotify/Internal/DevBroadcastVolume.cs new file mode 100644 index 0000000..6f69572 --- /dev/null +++ b/LibWinUsb/DeviceNotify/Internal/DevBroadcastVolume.cs @@ -0,0 +1,38 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System.Runtime.InteropServices; + +namespace LibUsbDotNet.DeviceNotify.Internal +{ + [StructLayout(LayoutKind.Sequential)] + internal class DevBroadcastVolume : DevBroadcastHdr + { + public int UnitMask; + public short Flags; + + public DevBroadcastVolume() + { + Size = Marshal.SizeOf(this); + DeviceType = DeviceType.Volume; + } + } +} \ No newline at end of file diff --git a/LibWinUsb/DeviceNotify/Internal/DevNotifyNativeWindow.cs b/LibWinUsb/DeviceNotify/Internal/DevNotifyNativeWindow.cs new file mode 100644 index 0000000..03a6d99 --- /dev/null +++ b/LibWinUsb/DeviceNotify/Internal/DevNotifyNativeWindow.cs @@ -0,0 +1,79 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Windows.Forms; + +namespace LibUsbDotNet.DeviceNotify.Internal +{ + internal sealed class DevNotifyNativeWindow : NativeWindow + { + private const string WINDOW_CAPTION = "{18662f14-0871-455c-bf99-eff135425e3a}"; + private const int WM_DEVICECHANGE = 0x219; + private readonly OnDeviceChangeDelegate mDelDeviceChange; + private readonly OnHandleChangeDelegate mDelHandleChanged; + + internal DevNotifyNativeWindow(OnHandleChangeDelegate delHandleChanged, OnDeviceChangeDelegate delDeviceChange) + { + mDelHandleChanged = delHandleChanged; + mDelDeviceChange = delDeviceChange; + + CreateParams cp = new CreateParams(); + cp.Caption = WINDOW_CAPTION; + cp.X = -100; + cp.Y = -100; + cp.Width = 50; + cp.Height = 50; + CreateHandle(cp); + } + + protected override void OnHandleChange() + { + mDelHandleChanged(Handle); + base.OnHandleChange(); + } + + protected override void WndProc(ref Message m) + { + if (m.Msg == WM_DEVICECHANGE) + { + mDelDeviceChange(ref m); + } + base.WndProc(ref m); + } + + #region Nested Types + + #region Nested type: OnDeviceChangeDelegate + + internal delegate void OnDeviceChangeDelegate(ref Message m); + + #endregion + + #region Nested type: OnHandleChangeDelegate + + internal delegate void OnHandleChangeDelegate(IntPtr windowHandle); + + #endregion + + #endregion + } +} \ No newline at end of file diff --git a/LibWinUsb/DeviceNotify/Internal/SafeNotifyHandle.cs b/LibWinUsb/DeviceNotify/Internal/SafeNotifyHandle.cs new file mode 100644 index 0000000..5960eaa --- /dev/null +++ b/LibWinUsb/DeviceNotify/Internal/SafeNotifyHandle.cs @@ -0,0 +1,45 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using Microsoft.Win32.SafeHandles; + +namespace LibUsbDotNet.DeviceNotify.Internal +{ + internal class SafeNotifyHandle : SafeHandleZeroOrMinusOneIsInvalid + { + public SafeNotifyHandle() + : base(true) { } + + public SafeNotifyHandle(IntPtr pHandle) + : base(true) { SetHandle(pHandle); } + + protected override bool ReleaseHandle() + { + if (handle != IntPtr.Zero) + { + bool bSuccess = WindowsDeviceNotifier.UnregisterDeviceNotification(handle); + handle = IntPtr.Zero; + } + return true; + } + } +} \ No newline at end of file diff --git a/LibWinUsb/DeviceNotify/Linux/LinuxDevItem.cs b/LibWinUsb/DeviceNotify/Linux/LinuxDevItem.cs new file mode 100644 index 0000000..13e892b --- /dev/null +++ b/LibWinUsb/DeviceNotify/Linux/LinuxDevItem.cs @@ -0,0 +1,90 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System.Runtime.InteropServices; +using LibUsbDotNet.Descriptors; +using MonoLibUsb.Descriptors; + +namespace LibUsbDotNet.DeviceNotify.Linux +{ + internal class LinuxDevItem + { + public readonly byte BusNumber; + public readonly byte DeviceAddress; + public readonly UsbDeviceDescriptor DeviceDescriptor; + public readonly string DeviceFileName; + + public LinuxDevItem(string deviceFileName, byte busNumber, byte deviceAddress, byte[] fileDescriptor) + { + DeviceFileName = deviceFileName; + BusNumber = busNumber; + DeviceAddress = deviceAddress; + + + DeviceDescriptor = new UsbDeviceDescriptor(); + GCHandle gcFileDescriptor = GCHandle.Alloc(DeviceDescriptor, GCHandleType.Pinned); + Marshal.Copy(fileDescriptor, 0, gcFileDescriptor.AddrOfPinnedObject(), Marshal.SizeOf(DeviceDescriptor)); + + gcFileDescriptor.Free(); + } + + public LinuxDevItem(string deviceFileName, byte busNumber, byte deviceAddress, MonoUsbDeviceDescriptor monoUsbDeviceDescriptor) + { + DeviceFileName = deviceFileName; + BusNumber = busNumber; + DeviceAddress = deviceAddress; + + + DeviceDescriptor = new UsbDeviceDescriptor(monoUsbDeviceDescriptor); + } + + public bool Equals(LinuxDevItem other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return Equals(other.DeviceFileName, DeviceFileName) && other.BusNumber == BusNumber && other.DeviceAddress == DeviceAddress && + Equals(other.DeviceDescriptor, DeviceDescriptor); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != typeof (LinuxDevItem)) return false; + return Equals((LinuxDevItem) obj); + } + + public override int GetHashCode() + { + unchecked + { + int result = (DeviceFileName != null ? DeviceFileName.GetHashCode() : 0); + result = (result*397) ^ BusNumber.GetHashCode(); + result = (result*397) ^ DeviceAddress.GetHashCode(); + result = (result*397) ^ (DeviceDescriptor != null ? DeviceDescriptor.GetHashCode() : 0); + return result; + } + } + + public static bool operator ==(LinuxDevItem left, LinuxDevItem right) { return Equals(left, right); } + public static bool operator !=(LinuxDevItem left, LinuxDevItem right) { return !Equals(left, right); } + } +} \ No newline at end of file diff --git a/LibWinUsb/DeviceNotify/Linux/LinuxDevItemList.cs b/LibWinUsb/DeviceNotify/Linux/LinuxDevItemList.cs new file mode 100644 index 0000000..e319aac --- /dev/null +++ b/LibWinUsb/DeviceNotify/Linux/LinuxDevItemList.cs @@ -0,0 +1,36 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System.Collections.Generic; + +namespace LibUsbDotNet.DeviceNotify.Linux +{ + internal class LinuxDevItemList : List + { + public LinuxDevItem FindByName(string deviceFileName) + { + foreach (LinuxDevItem item in this) + if (item.DeviceFileName == deviceFileName) return item; + + return null; + } + } +} \ No newline at end of file diff --git a/LibWinUsb/DeviceNotify/Linux/LinuxDeviceNotifier.DevMonitor.cs b/LibWinUsb/DeviceNotify/Linux/LinuxDeviceNotifier.DevMonitor.cs new file mode 100644 index 0000000..bbdab1f --- /dev/null +++ b/LibWinUsb/DeviceNotify/Linux/LinuxDeviceNotifier.DevMonitor.cs @@ -0,0 +1,187 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.IO; +using System.Text.RegularExpressions; +using LibUsbDotNet.Descriptors; + +namespace LibUsbDotNet.DeviceNotify.Linux +{ + public partial class LinuxDeviceNotifier + { + private static Regex _RegParseDeviceInterface; + private static string DeviceIntefaceMatchExpression = "usbdev(?[0-9]+)\\.(?[0-9]+)$"; + private readonly string mDevDir; + private FileSystemWatcher mUsbFS; + + private static Regex RegParseDeviceInterface + { + get + { + if (ReferenceEquals(_RegParseDeviceInterface, null)) + { + _RegParseDeviceInterface = new Regex(DeviceIntefaceMatchExpression, + RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.CultureInvariant | + RegexOptions.Singleline); + } + return _RegParseDeviceInterface; + } + } + + + private static bool IsDeviceEnterface(string name, out byte busNumber, out byte deviceAddress) + { + busNumber = 0; + deviceAddress = 0; + + Match match = RegParseDeviceInterface.Match(name); + if (match.Success) + { + try + { + busNumber = byte.Parse(match.Groups["BusNumber"].Value); + deviceAddress = byte.Parse(match.Groups["DeviceAddress"].Value); + return true; + } + catch + { + return false; + } + } + return false; + } + + private static bool ReadFileDescriptor(string fullPath, out byte[] deviceDescriptorBytes) + { + try + { + FileStream f = File.Open(fullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + deviceDescriptorBytes = new byte[UsbDeviceDescriptor.Size]; + int iRead = f.Read(deviceDescriptorBytes, 0, UsbDeviceDescriptor.Size); + f.Close(); + + return iRead == UsbDeviceDescriptor.Size; + } + catch + { + deviceDescriptorBytes = null; + return false; + } + } + + private void StartDevDirectoryMonitor() + { + if (!ReferenceEquals(mUsbFS, null)) return; + + BuildDevList(); + mUsbFS = new FileSystemWatcher(mDevDir); + mUsbFS.IncludeSubdirectories = false; + mUsbFS.Created += FileAdded; + mUsbFS.Deleted += FileRemoved; + mUsbFS.EnableRaisingEvents = true; + } + + private void BuildDevList() + { + mLinuxDevItemList.Clear(); + string[] deviceInterfaceFiles = Directory.GetFiles(mDevDir, "usbdev*", SearchOption.TopDirectoryOnly); + foreach (string deviceInterfaceFile in deviceInterfaceFiles) + { + byte busNumber; + byte deviceAddress; + string deviceFileName = Path.GetFileName(deviceInterfaceFile); + if (IsDeviceEnterface(deviceFileName, out busNumber, out deviceAddress)) + { + byte[] descriptorBytes; + if (ReadFileDescriptor(deviceInterfaceFile, out descriptorBytes)) + { + LinuxDevItem addedItem = new LinuxDevItem(deviceFileName, busNumber, deviceAddress, descriptorBytes); + mLinuxDevItemList.Add(addedItem); + } + } + } + //Console.WriteLine("LinuxDeviceNotifier:BuildDevList Count:{0}",mLinuxDevItemList.Count); + } + + private void FileRemoved(object sender, FileSystemEventArgs e) + { + byte busNumber; + byte deviceAddress; + if (IsDeviceEnterface(e.Name, out busNumber, out deviceAddress)) + { + LinuxDevItem foundLinuxDevItem; + if ((foundLinuxDevItem = mLinuxDevItemList.FindByName(e.Name)) == null) throw new Exception("FileRemoved:Invalid LinuxDevItem"); + + //Console.WriteLine("Removed Vid:{0:X4} Pid:{1:X4}", foundLinuxDevItem.DeviceDescriptor.VendorID, foundLinuxDevItem.DeviceDescriptor.ProductID); + ////////////////////// + // TODO:DEVICE REMOVAL + ////////////////////// + + mLinuxDevItemList.Remove(foundLinuxDevItem); + EventHandler deviceNotify = OnDeviceNotify; + if (!ReferenceEquals(deviceNotify, null)) + { + deviceNotify(this, new LinuxDeviceNotifyEventArgs(foundLinuxDevItem, DeviceType.DeviceInterface, EventType.DeviceRemoveComplete)); + } + } + } + + private void FileAdded(object sender, FileSystemEventArgs e) + { + byte busNumber; + byte deviceAddress; + if (IsDeviceEnterface(e.Name, out busNumber, out deviceAddress)) + { + byte[] descriptorBytes; + if (ReadFileDescriptor(e.FullPath, out descriptorBytes)) + { + LinuxDevItem addedItem = new LinuxDevItem(e.Name, busNumber, deviceAddress, descriptorBytes); + if (mLinuxDevItemList.FindByName(e.Name) != null) throw new Exception("FileAdded:Invalid LinuxDevItem"); + mLinuxDevItemList.Add(addedItem); + + //Console.WriteLine("Added Vid:{0:X4} Pid:{1:X4}", addedItem.DeviceDescriptor.VendorID, addedItem.DeviceDescriptor.ProductID); + ////////////////////// + // TODO:DEVICE ARRIVAL + ////////////////////// + + EventHandler deviceNotify = OnDeviceNotify; + if (!ReferenceEquals(deviceNotify, null)) + { + deviceNotify(this, new LinuxDeviceNotifyEventArgs(addedItem, DeviceType.DeviceInterface, EventType.DeviceArrival)); + } + } + } + } + + private void StopDevDirectoryMonitor() + { + if (!ReferenceEquals(mUsbFS, null)) + { + mUsbFS.EnableRaisingEvents = false; + mUsbFS.Created -= FileAdded; + mUsbFS.Deleted -= FileRemoved; + mUsbFS.Dispose(); + mUsbFS = null; + } + } + } +} \ No newline at end of file diff --git a/LibWinUsb/DeviceNotify/Linux/LinuxDeviceNotifier.DeviceListPolling.cs b/LibWinUsb/DeviceNotify/Linux/LinuxDeviceNotifier.DeviceListPolling.cs new file mode 100644 index 0000000..78173e0 --- /dev/null +++ b/LibWinUsb/DeviceNotify/Linux/LinuxDeviceNotifier.DeviceListPolling.cs @@ -0,0 +1,99 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Timers; +using LibUsbDotNet.LudnMonoLibUsb; +using MonoLibUsb.Profile; + +namespace LibUsbDotNet.DeviceNotify.Linux +{ + public partial class LinuxDeviceNotifier + { + /// + /// The interval (milliseconds) in which the device list is queried for changes when using the mode. + /// + public static int PollingInterval = 750; + + private Timer mDeviceListPollTimer; + private object PollTimerLock = new object(); + + private void StartDeviceListPolling() + { + lock (PollTimerLock) + { + if (mDeviceListPollTimer != null) return; + + MonoUsbDevice.RefreshProfileList(); + + MonoUsbDevice.ProfileList.AddRemoveEvent += OnAddRemoveEvent; + mDeviceListPollTimer = new Timer(PollingInterval); + mDeviceListPollTimer.Elapsed += PollTimer_Elapsed; + mDeviceListPollTimer.Start(); + } + } + + private void PollTimer_Elapsed(object sender, ElapsedEventArgs e) + { + lock (PollTimerLock) + { + mDeviceListPollTimer.Stop(); + MonoUsbDevice.RefreshProfileList(); + mDeviceListPollTimer.Start(); + } + } + + private void StopDeviceListPolling() + { + lock (PollTimerLock) + { + if (mDeviceListPollTimer == null) return; + mDeviceListPollTimer.Stop(); + mDeviceListPollTimer.Elapsed -= PollTimer_Elapsed; + mDeviceListPollTimer.Dispose(); + MonoUsbDevice.ProfileList.AddRemoveEvent -= OnAddRemoveEvent; + mDeviceListPollTimer = null; + } + } + + + private void OnAddRemoveEvent(object sender, AddRemoveEventArgs e) + { + EventHandler deviceNotify = OnDeviceNotify; + if (!ReferenceEquals(deviceNotify, null)) + { + string deviceFileName = String.Format("usbdev{0}.{1}", e.MonoUSBProfile.BusNumber, e.MonoUSBProfile.DeviceAddress); + + LinuxDevItem linuxDevItem = new LinuxDevItem(deviceFileName, + e.MonoUSBProfile.BusNumber, + e.MonoUSBProfile.DeviceAddress, + e.MonoUSBProfile.DeviceDescriptor); + + deviceNotify(this, + new LinuxDeviceNotifyEventArgs(linuxDevItem, + DeviceType.DeviceInterface, + e.EventType == AddRemoveType.Added + ? EventType.DeviceArrival + : EventType.DeviceRemoveComplete)); + } + } + } +} \ No newline at end of file diff --git a/LibWinUsb/DeviceNotify/Linux/LinuxDeviceNotifier.cs b/LibWinUsb/DeviceNotify/Linux/LinuxDeviceNotifier.cs new file mode 100644 index 0000000..9c9b1c1 --- /dev/null +++ b/LibWinUsb/DeviceNotify/Linux/LinuxDeviceNotifier.cs @@ -0,0 +1,139 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; + +namespace LibUsbDotNet.DeviceNotify.Linux +{ + /// + /// Creates an instance of the class. + /// See the interface or method for more information + /// + /// + ///To make your code platform-independent use the method for creating instances. + /// + public partial class LinuxDeviceNotifier : IDeviceNotifier + { + private readonly LinuxDevItemList mLinuxDevItemList = new LinuxDevItemList(); + private readonly LinuxDeviceNotifierMode mMode = LinuxDeviceNotifierMode.None; + + /// + /// Creates a new instance of the LinuxDeviceNotifier using 'devDir' as the root device path. (IE. '/dev'). + /// + /// The directory to monitor; usually '/dev'. + public LinuxDeviceNotifier(string devDir) + { + mDevDir = devDir; + try + { + StartDevDirectoryMonitor(); + if (mLinuxDevItemList.Count == 0) throw new NotSupportedException("LinuxDeviceNotifier:Dev directory monitor not supported."); + mMode = LinuxDeviceNotifierMode.MonitorDevDirectory; + return; + } + catch + { + StopDevDirectoryMonitor(); + } + mMode = LinuxDeviceNotifierMode.PollDeviceList; + StartDeviceListPolling(); + } + + /// + /// Creates a new instance of the LinuxDeviceNotifier using '/dev' as the root device path. + /// + public LinuxDeviceNotifier() + : this("/dev") { } + + /// + /// Gets the mode being used to detect notification events. + /// + public LinuxDeviceNotifierMode Mode + { + get { return mMode; } + } + + #region IDeviceNotifier Members + + /// + /// Enables/Disables notification events. + /// + public bool Enabled + { + get + { + switch (mMode) + { + case LinuxDeviceNotifierMode.PollDeviceList: + return mDeviceListPollTimer != null; + case LinuxDeviceNotifierMode.MonitorDevDirectory: + return mUsbFS != null; + default: + throw new ArgumentOutOfRangeException(); + } + } + set + { + if (value) + Start(); + else + Stop(); + } + } + + /// + /// Main Notify event for all device notifications. + /// + public event EventHandler OnDeviceNotify; + + #endregion + + private void Stop() + { + switch (mMode) + { + case LinuxDeviceNotifierMode.PollDeviceList: + StopDeviceListPolling(); + break; + case LinuxDeviceNotifierMode.MonitorDevDirectory: + StopDevDirectoryMonitor(); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + private void Start() + { + switch (mMode) + { + case LinuxDeviceNotifierMode.PollDeviceList: + StartDeviceListPolling(); + break; + case LinuxDeviceNotifierMode.MonitorDevDirectory: + StartDevDirectoryMonitor(); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + } +} \ No newline at end of file diff --git a/LibWinUsb/DeviceNotify/Linux/LinuxDeviceNotifierMode.cs b/LibWinUsb/DeviceNotify/Linux/LinuxDeviceNotifierMode.cs new file mode 100644 index 0000000..a7b9ec5 --- /dev/null +++ b/LibWinUsb/DeviceNotify/Linux/LinuxDeviceNotifierMode.cs @@ -0,0 +1,44 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System.IO; + +namespace LibUsbDotNet.DeviceNotify.Linux +{ + /// + /// Modes the linux device notifier can use to detect notification events. + /// + public enum LinuxDeviceNotifierMode + { + /// + /// The device notifier is unavailable on this platform. + /// + None, + /// + /// The device notifier is polling the device list every 750ms to detect usb add and removal events. + /// + PollDeviceList, + /// + /// The device notifier is using a to monitor the "/dev" directory for file add and delete. + /// + MonitorDevDirectory + } +} \ No newline at end of file diff --git a/LibWinUsb/DeviceNotify/Linux/LinuxDeviceNotifyEventArgs.cs b/LibWinUsb/DeviceNotify/Linux/LinuxDeviceNotifyEventArgs.cs new file mode 100644 index 0000000..0a3c667 --- /dev/null +++ b/LibWinUsb/DeviceNotify/Linux/LinuxDeviceNotifyEventArgs.cs @@ -0,0 +1,70 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; + +namespace LibUsbDotNet.DeviceNotify.Linux +{ + /// + /// Describes the device notify event + /// + public class LinuxDeviceNotifyEventArgs : DeviceNotifyEventArgs + { + internal LinuxDeviceNotifyEventArgs(LinuxDevItem linuxDevItem, DeviceType deviceType, EventType eventType) + { + mEventType = eventType; + mDeviceType = deviceType; + switch (mDeviceType) + { + case DeviceType.Volume: + throw new NotImplementedException(mDeviceType.ToString()); + case DeviceType.Port: + throw new NotImplementedException(mDeviceType.ToString()); + case DeviceType.DeviceInterface: + mDevice = new LinuxUsbDeviceNotifyInfo(linuxDevItem); + mObject = mDevice; + break; + } + } + + //internal LinuxDeviceNotifyEventArgs(DevBroadcastHdr hdr, IntPtr ptrHdr, EventType eventType) + //{ + // mBaseHdr = hdr; + // mEventType = eventType; + // mDeviceType = mBaseHdr.DeviceType; + // switch (mDeviceType) + // { + // case DeviceType.Volume: + // mVolume = new VolumeNotifyInfo(ptrHdr); + // mObject = mVolume; + // break; + // case DeviceType.Port: + // mPort = new PortNotifyInfo(ptrHdr); + // mObject = mPort; + // break; + // case DeviceType.DeviceInterface: + // mDevice = new UsbDeviceNotifyInfo(ptrHdr); + // mObject = mDevice; + // break; + // } + //} + } +} \ No newline at end of file diff --git a/LibWinUsb/DeviceNotify/Linux/LinuxUsbDeviceNotifyInfo.cs b/LibWinUsb/DeviceNotify/Linux/LinuxUsbDeviceNotifyInfo.cs new file mode 100644 index 0000000..cbdc17f --- /dev/null +++ b/LibWinUsb/DeviceNotify/Linux/LinuxUsbDeviceNotifyInfo.cs @@ -0,0 +1,127 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using LibUsbDotNet.Descriptors; +using LibUsbDotNet.DeviceNotify.Info; +using LibUsbDotNet.Main; + +namespace LibUsbDotNet.DeviceNotify.Linux +{ + /// Describes the USB device that caused the notification. + /// see the inteface for more information. + /// + public class LinuxUsbDeviceNotifyInfo : IUsbDeviceNotifyInfo + { + private readonly LinuxDevItem mLinuxDevItem; + + internal LinuxUsbDeviceNotifyInfo(LinuxDevItem linuxDevItem) { mLinuxDevItem = linuxDevItem; } + + /// + /// Gets the for the device that caused the event. + /// + public UsbDeviceDescriptor DeviceDescriptor + { + get { return mLinuxDevItem.DeviceDescriptor; } + } + + /// + /// Gets the bus number the device is connected to. + /// + public byte BusNumber + { + get { return mLinuxDevItem.BusNumber; } + } + + /// + /// Get the device instance address. + /// + public byte DeviceAddress + { + get { return mLinuxDevItem.DeviceAddress; } + } + + #region IUsbDeviceNotifyInfo Members + + /// + /// Not supported. Always returns null. + /// + public UsbSymbolicName SymbolicName + { + get { return null; } + } + + /// + /// Gets the name of the USB device file descriptor that caused the notification. + /// + public string Name + { + get { return mLinuxDevItem.DeviceFileName; } + } + + /// + /// Not supported. Always returs Guid.Empty. + /// + public Guid ClassGuid + { + get { return Guid.Empty; } + } + + /// + /// Parses and returns the VID from the property. + /// + public int IdVendor + { + get { return (int)((ushort)mLinuxDevItem.DeviceDescriptor.VendorID); } + } + + /// + /// Parses and returns the PID from the property. + /// + public int IdProduct + { + get { return (int)((ushort)mLinuxDevItem.DeviceDescriptor.ProductID); } + } + + /// + /// Not supported. Always returns String.Empty. + /// + public string SerialNumber + { + get { return string.Empty; } + } + + /// + ///Returns a that represents the current . + /// + /// + /// + ///A that represents the current . + /// + public override string ToString() + { + object[] values = new object[] {Name, BusNumber, DeviceAddress, DeviceDescriptor.ToString()}; + return string.Format("Name:{0} BusNumber:{1} DeviceAddress:{2}\n{3}", values); + } + + #endregion + } +} \ No newline at end of file diff --git a/LibWinUsb/DeviceNotify/WindowsDeviceNotifier.cs b/LibWinUsb/DeviceNotify/WindowsDeviceNotifier.cs new file mode 100644 index 0000000..275f0c2 --- /dev/null +++ b/LibWinUsb/DeviceNotify/WindowsDeviceNotifier.cs @@ -0,0 +1,146 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using LibUsbDotNet.DeviceNotify.Internal; + +namespace LibUsbDotNet.DeviceNotify +{ + /// + /// Notifies an application of a change to the hardware Configuration of a device or + /// the computer. See or interface for more information + /// + /// + /// This is the windows implementation of the device notifier. + /// + public class WindowsDeviceNotifier : IDeviceNotifier + { + private readonly DevBroadcastDeviceinterface mDevInterface = new DevBroadcastDeviceinterface(new Guid("A5DCBF10-6530-11D2-901F-00C04FB951ED")); + + private SafeNotifyHandle mDevInterfaceHandle; + private bool mEnabled = true; + private DevNotifyNativeWindow mNotifyWindow; + + /// + /// Creates an instance of the class. + /// See the interface or method for more information + /// + /// + ///To make your code platform-independent use the method for creating instances. + /// + public WindowsDeviceNotifier() { mNotifyWindow = new DevNotifyNativeWindow(OnHandleChange, OnDeviceChange); } + + #region IDeviceNotifier Members + + /// + /// Enables/Disables notification events. + /// + public bool Enabled + { + get { return mEnabled; } + set { mEnabled = value; } + } + + + /// + /// Main Notify event for all device notifications. + /// + public event EventHandler OnDeviceNotify; + + #endregion + + [DllImport("user32.dll", SetLastError = true, EntryPoint = "RegisterDeviceNotificationA", CharSet = CharSet.Ansi)] + private static extern SafeNotifyHandle RegisterDeviceNotification(IntPtr hRecipient, + [MarshalAs(UnmanagedType.AsAny), In] object notificationFilter, + int flags); + + [DllImport("user32.dll", SetLastError = true)] + internal static extern bool UnregisterDeviceNotification(IntPtr handle); + + /// + ///Releases the resources associated with this window. + /// + /// + ~WindowsDeviceNotifier() + { + if (mNotifyWindow != null) mNotifyWindow.DestroyHandle(); + mNotifyWindow = null; + + if (mDevInterfaceHandle != null) mDevInterfaceHandle.Dispose(); + mDevInterfaceHandle = null; + } + + internal bool RegisterDeviceInterface(IntPtr windowHandle) + { + if (mDevInterfaceHandle != null) + { + mDevInterfaceHandle.Dispose(); + mDevInterfaceHandle = null; + } + if (windowHandle != IntPtr.Zero) + { + mDevInterfaceHandle = RegisterDeviceNotification(windowHandle, mDevInterface, 0); + if (mDevInterfaceHandle != null && !mDevInterfaceHandle.IsInvalid) + return true; + return false; + } + return false; + } + + + private void OnDeviceChange(ref Message m) + { + if (!mEnabled) return; + if (m.LParam.ToInt32() != 0) + { + EventHandler temp = OnDeviceNotify; + if (!ReferenceEquals(temp, null)) + { + DeviceNotifyEventArgs args; + DevBroadcastHdr hdr = new DevBroadcastHdr(); + Marshal.PtrToStructure(m.LParam, hdr); + switch (hdr.DeviceType) + { + case DeviceType.Port: + case DeviceType.Volume: + case DeviceType.DeviceInterface: + args = new WindowsDeviceNotifyEventArgs(hdr, m.LParam, (EventType) m.WParam.ToInt32()); + break; + default: + args = null; + break; + } + + if (!ReferenceEquals(args, null)) temp(this, args); + } + } + } + + private void OnHandleChange(IntPtr newWindowHandle) + { + bool bSuccess = RegisterDeviceInterface(newWindowHandle); + Debug.Print("RegisterDeviceInterface:" + bSuccess); + } + } +} \ No newline at end of file diff --git a/LibWinUsb/DeviceNotify/WindowsDeviceNotifyEventArgs.cs b/LibWinUsb/DeviceNotify/WindowsDeviceNotifyEventArgs.cs new file mode 100644 index 0000000..b68246e --- /dev/null +++ b/LibWinUsb/DeviceNotify/WindowsDeviceNotifyEventArgs.cs @@ -0,0 +1,57 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using LibUsbDotNet.DeviceNotify.Info; +using LibUsbDotNet.DeviceNotify.Internal; + +namespace LibUsbDotNet.DeviceNotify +{ + /// + /// Describes the device notify event + /// + public class WindowsDeviceNotifyEventArgs : DeviceNotifyEventArgs + { + private readonly DevBroadcastHdr mBaseHdr; + + internal WindowsDeviceNotifyEventArgs(DevBroadcastHdr hdr, IntPtr ptrHdr, EventType eventType) + { + mBaseHdr = hdr; + mEventType = eventType; + mDeviceType = mBaseHdr.DeviceType; + switch (mDeviceType) + { + case DeviceType.Volume: + mVolume = new VolumeNotifyInfo(ptrHdr); + mObject = mVolume; + break; + case DeviceType.Port: + mPort = new PortNotifyInfo(ptrHdr); + mObject = mPort; + break; + case DeviceType.DeviceInterface: + mDevice = new UsbDeviceNotifyInfo(ptrHdr); + mObject = mDevice; + break; + } + } + } +} \ No newline at end of file diff --git a/LibWinUsb/IUsbDevice.cs b/LibWinUsb/IUsbDevice.cs new file mode 100644 index 0000000..d333970 --- /dev/null +++ b/LibWinUsb/IUsbDevice.cs @@ -0,0 +1,100 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using LibUsbDotNet.LudnMonoLibUsb; +using LibUsbDotNet.WinUsb; + +namespace LibUsbDotNet +{ + /// + /// The interface contains members needed to configure a USB device for use. + /// + /// + /// Only "whole" usb devices have a interface such as a + /// or a . This indicates + /// the USB device must be properly configured by the user before it can be used. + /// Partial or interfaces of devices such as a do not have an + /// interface. This indicates that the driver is handling device configuration. + /// + /// + /// This example uses the interface to select the desired configuration and interface + /// for usb devices that require it. + /// + /// + public interface IUsbDevice : IUsbInterface + { + /// + /// Sets the USB devices active configuration value. + /// + /// The active configuration value. A zero value means the device is not configured and a non-zero value indicates the device is configured. + /// True on success. + /// + /// A USB device can have several different configurations, but only one active configuration. + /// + bool SetConfiguration(byte config); + + /// + /// Gets the USB devices active configuration value. + /// + /// The active configuration value. A zero value means the device is not configured and a non-zero value indicates the device is configured. + /// True on success. + bool GetConfiguration(out byte config); + + /// + /// Sets an alternate interface for the most recent claimed interface. + /// + /// The alternate interface to select for the most recent claimed interface See . + /// True on success. + bool SetAltInterface(int alternateID); + + /// + /// Gets the selected alternate interface of the specified interface. + /// + /// The interface settings number (index) to retrieve the selected alternate interface setting for. + /// The alternate interface setting selected for use with the specified interface. + /// True on success. + bool GetAltInterfaceSetting(byte interfaceID, out byte selectedAltInterfaceID); + + /// + /// Claims the specified interface of the device. + /// + /// The interface to claim. + /// True on success. + bool ClaimInterface(int interfaceID); + + /// + /// Releases an interface that was previously claimed with . + /// + /// The interface to release. + /// True on success. + bool ReleaseInterface(int interfaceID); + + /// + /// Sends a usb device reset command. + /// + /// + /// After calling , the instance is disposed and + /// no longer usable. A new instance must be obtained from the device list. + /// + /// True on success. + bool ResetDevice(); + } +} \ No newline at end of file diff --git a/LibWinUsb/IUsbInterface.cs b/LibWinUsb/IUsbInterface.cs new file mode 100644 index 0000000..a023f70 --- /dev/null +++ b/LibWinUsb/IUsbInterface.cs @@ -0,0 +1,187 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Collections.ObjectModel; +using LibUsbDotNet.Descriptors; +using LibUsbDotNet.Info; +using LibUsbDotNet.Main; + +namespace LibUsbDotNet +{ + /// + /// The interface contains members needed communicate with an + /// interface of a usb device. + /// + /// + /// All USB device classes implement these members. + /// + public interface IUsbInterface + { + /// + /// A list of endpoints that have beened opened by this class. + /// + UsbEndpointList ActiveEndpoints { get; } + + /// + /// Gets the available configurations for this + /// + /// + /// The first time this property is accessed it will query the for all configurations. Subsequent request will return a cached copy of all configurations. + /// + ReadOnlyCollection Configs { get; } + + /// + /// Returns the DriverMode this USB device is using. + /// + UsbDevice.DriverModeType DriverMode { get; } + + /// + /// Gets the actual device descriptor the the current . + /// + UsbDeviceInfo Info { get; } + + /// + /// Gets a value indication if the device handle is valid. + /// + bool IsOpen { get; } + + /// + /// Gets the class that opened the device, or null if the device was not opened by the class. + /// + UsbRegistry UsbRegistryInfo { get; } + + /// + /// Closes and frees device resources. Once closed the device cannot be reopened. A new class must be obtained using the class. + /// + /// True on success. + bool Close(); + + /// + /// Sends/Receives an IO control message to endpoint 0. + /// + /// Contains parameters for the control request. See section 9.3 USB Device Requests of the Universal Serial Bus Specification Revision 2.0 for more information. + /// Data to be sent/received from the device. + /// Length of the buffer param. + /// Number of bytes sent or received (depends on the direction of the control transfer). + /// True on success. + bool ControlTransfer(ref UsbSetupPacket setupPacket, IntPtr buffer, int bufferLength, out int lengthTransferred); + + /// + /// Transmits io control message to endpoint 0. + /// + /// Contains parameters for the control request. See section 9.3 USB Device Requests of the Universal Serial Bus Specification Revision 2.0 for more information. + /// Data to be sent/received from the device. Th + /// Length of the buffer param. + /// Number of bytes sent or received (depends on the direction of the control transfer). + /// True on success. + bool ControlTransfer(ref UsbSetupPacket setupPacket, object buffer, int bufferLength, out int lengthTransferred); + + /// + /// Gets a specific descriptor from the device. See for more information. + /// + /// The descriptor type ID to retrieve; this is usually one of the enumerations. + /// Descriptor index. + /// Descriptor language id. + /// Memory to store the returned descriptor in. + /// Length of the buffer parameter in bytes. + /// The number of bytes transferred to buffer upon success. + /// True on success. + bool GetDescriptor(byte descriptorType, byte index, short langId, IntPtr buffer, int bufferLength, out int transferLength); + + /// + /// Gets a specific descriptor from the device. See for more information. + /// + /// The descriptor type ID to retrieve; this is usually one of the enumerations. + /// Descriptor index. + /// Descriptor language id. + /// Memory to store the returned descriptor in. + /// Length of the buffer parameter in bytes. + /// The number of bytes transferred to buffer upon success. + /// True on success. + bool GetDescriptor(byte descriptorType, byte index, short langId, object buffer, int bufferLength, out int transferLength); + + /// + /// Asking for the zero'th index is special - it returns a string + /// descriptor that contains all the language IDs supported by the + /// device. Typically there aren't many - often only one. The + /// language IDs are 16 bit numbers, and they start at the third byte + /// in the descriptor. See USB 2.0 specification, section 9.6.7, for + /// more information on this. + /// + /// A collection of LCIDs that the current supports. + bool GetLangIDs(out short[] langIDs); + + /// + /// Gets a string descriptor from the device. + /// + /// Buffer to store the returned string in upon success. + /// The language ID to retrieve the string in. (0x409 for english). + /// The string index to retrieve. + /// True on success. + bool GetString(out string stringData, short langId, byte stringIndex); + + /// + /// Opens/re-opens this USB device instance for communication. + /// + ///True if the device is already opened or was opened successfully. False if the device does not exists or is no longer valid. + bool Open(); + + /// + /// Opens a endpoint for reading + /// + /// Endpoint number for read operations. + /// Size of the read buffer allocated for the event. + /// A class ready for reading. If the specified endpoint is already been opened, the original class is returned. + UsbEndpointReader OpenEndpointReader(ReadEndpointID readEndpointID, int readBufferSize); + + /// + /// Opens an endpoint for reading + /// + /// Endpoint number for read operations. + /// Size of the read buffer allocated for the event. + /// The type of endpoint to open. + /// A class ready for reading. If the specified endpoint is already been opened, the original class is returned. + UsbEndpointReader OpenEndpointReader(ReadEndpointID readEndpointID, int readBufferSize, EndpointType endpointType); + + /// + /// Opens a endpoint for reading + /// + /// Endpoint number for read operations. + /// A class ready for reading. If the specified endpoint is already been opened, the original class is returned. + UsbEndpointReader OpenEndpointReader(ReadEndpointID readEndpointID); + + /// + /// Opens a endpoint for writing + /// + /// Endpoint number for read operations. + /// A class ready for writing. If the specified endpoint is already been opened, the original class is returned. + UsbEndpointWriter OpenEndpointWriter(WriteEndpointID writeEndpointID); + + /// + /// Opens an endpoint for writing + /// + /// Endpoint number for read operations. + /// The type of endpoint to open. + /// A class ready for writing. If the specified endpoint is already been opened, the original class is returned. + UsbEndpointWriter OpenEndpointWriter(WriteEndpointID writeEndpointID, EndpointType endpointType); + } +} \ No newline at end of file diff --git a/LibWinUsb/Info/UsbBaseInfo.cs b/LibWinUsb/Info/UsbBaseInfo.cs new file mode 100644 index 0000000..9cd13fd --- /dev/null +++ b/LibWinUsb/Info/UsbBaseInfo.cs @@ -0,0 +1,44 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace LibUsbDotNet.Info +{ + /// Base class for all Usb descriptors. + /// , , + ///

LibUsbDotNet supports and parses all the basic usb descriptors.

+ /// Unknown descriptors such as driver specific class descriptors are stored as byte arrays and are accessible from the property. + ///

+ public abstract class UsbBaseInfo + { + internal List mRawDescriptors = new List(); + + /// + /// Gets the device-specific custom descriptor lists. + /// + public ReadOnlyCollection CustomDescriptors + { + get { return mRawDescriptors.AsReadOnly(); } + } + } +} \ No newline at end of file diff --git a/LibWinUsb/Info/UsbConfigInfo.cs b/LibWinUsb/Info/UsbConfigInfo.cs new file mode 100644 index 0000000..5e1aff6 --- /dev/null +++ b/LibWinUsb/Info/UsbConfigInfo.cs @@ -0,0 +1,158 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using LibUsbDotNet.Descriptors; +using LibUsbDotNet.Main; +using LibUsbDotNet.LudnMonoLibUsb; +using MonoLibUsb.Descriptors; + +namespace LibUsbDotNet.Info +{ + /// Contains all Configuration information for the current . + /// + public class UsbConfigInfo : UsbBaseInfo + { + private readonly List mInterfaceList = new List(); + internal readonly UsbConfigDescriptor mUsbConfigDescriptor; + private String mConfigString; + internal UsbDevice mUsbDevice; + + internal UsbConfigInfo(UsbDevice usbDevice, UsbConfigDescriptor descriptor, ref List rawDescriptors) + { + mUsbDevice = usbDevice; + mUsbConfigDescriptor = descriptor; + mRawDescriptors = rawDescriptors; + + UsbInterfaceInfo currentInterface = null; + for (int iRawDescriptor = 0; iRawDescriptor < rawDescriptors.Count; iRawDescriptor++) + { + byte[] bytesRawDescriptor = rawDescriptors[iRawDescriptor]; + + switch (bytesRawDescriptor[1]) + { + case (byte) DescriptorType.Interface: + currentInterface = new UsbInterfaceInfo(usbDevice, bytesRawDescriptor); + mRawDescriptors.RemoveAt(iRawDescriptor); + mInterfaceList.Add(currentInterface); + iRawDescriptor--; + break; + case (byte) DescriptorType.Endpoint: + if (currentInterface == null) + throw new UsbException(this, "Recieved and endpoint descriptor before receiving an interface descriptor."); + + currentInterface.mEndpointInfo.Add(new UsbEndpointInfo(bytesRawDescriptor)); + mRawDescriptors.RemoveAt(iRawDescriptor); + iRawDescriptor--; + break; + default: + if (currentInterface != null) + { + currentInterface.mRawDescriptors.Add(bytesRawDescriptor); + mRawDescriptors.RemoveAt(iRawDescriptor); + iRawDescriptor--; + } + break; + } + } + } + + internal UsbConfigInfo(MonoUsbDevice usbDevice, MonoUsbConfigDescriptor configDescriptor) + { + mUsbDevice = usbDevice; + + mUsbConfigDescriptor = new UsbConfigDescriptor(configDescriptor); + + List monoUSBInterfaces = configDescriptor.InterfaceList; + foreach (MonoUsbInterface usbInterface in monoUSBInterfaces) + { + List monoUSBAltInterfaces = usbInterface.AltInterfaceList; + foreach (MonoUsbAltInterfaceDescriptor monoUSBAltInterface in monoUSBAltInterfaces) + { + UsbInterfaceInfo usbInterfaceInfo = new UsbInterfaceInfo(mUsbDevice, monoUSBAltInterface); + mInterfaceList.Add(usbInterfaceInfo); + } + } + } + + /// + /// Gets the actual for the current config. + /// + public UsbConfigDescriptor Descriptor + { + get { return mUsbConfigDescriptor; } + } + + /// + /// Gets the string representation of the string index. + /// + public String ConfigString + { + get + { + if (ReferenceEquals(mConfigString, null)) + { + mConfigString = String.Empty; + if (Descriptor.StringIndex > 0) + { + mUsbDevice.GetString(out mConfigString, mUsbDevice.Info.CurrentCultureLangID, Descriptor.StringIndex); + } + } + return mConfigString; + } + } + + /// + /// Gets the collection of USB device interfaces associated with this instance. + /// + public ReadOnlyCollection InterfaceInfoList + { + get { return mInterfaceList.AsReadOnly(); } + } + + /// + ///Returns a that represents the current . + /// + /// + /// + ///A that represents the current . + /// + public override string ToString() { return ToString("", UsbDescriptor.ToStringParamValueSeperator, UsbDescriptor.ToStringFieldSeperator); } + + /// + ///Returns a that represents the current . + /// + /// + ///The field prefix string. + ///The field/value seperator string. + ///The value suffix string. + ///A formatted representation of the . + public string ToString(string prefixSeperator, string entitySperator, string suffixSeperator) + { + Object[] values = {ConfigString}; + string[] names = {"ConfigString"}; + return Descriptor.ToString(prefixSeperator, entitySperator, suffixSeperator) + + Helper.ToString(prefixSeperator, names, entitySperator, values, suffixSeperator); + } + } +} \ No newline at end of file diff --git a/LibWinUsb/Info/UsbDeviceInfo.cs b/LibWinUsb/Info/UsbDeviceInfo.cs new file mode 100644 index 0000000..173b5ef --- /dev/null +++ b/LibWinUsb/Info/UsbDeviceInfo.cs @@ -0,0 +1,215 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Globalization; +using System.Runtime.InteropServices; +using LibUsbDotNet.Descriptors; +using LibUsbDotNet.Main; +using MonoLibUsb.Descriptors; + +namespace LibUsbDotNet.Info +{ + /// Contains USB device descriptor information. + /// + public class UsbDeviceInfo + { + private const short NO_LANG = short.MaxValue; + private readonly UsbDeviceDescriptor mDeviceDescriptor; + private short mCurrentCultureLangID = NO_LANG; + private String mManufacturerString; + private String mProductString; + private String mSerialString; + internal UsbDevice mUsbDevice; + + internal UsbDeviceInfo(UsbDevice usbDevice) + { + mUsbDevice = usbDevice; + GetDeviceDescriptor(mUsbDevice, out mDeviceDescriptor); + } + + internal UsbDeviceInfo(UsbDevice usbDevice, MonoUsbDeviceDescriptor usbDeviceDescriptor) + { + mUsbDevice = usbDevice; + + mDeviceDescriptor = new UsbDeviceDescriptor(); + mDeviceDescriptor.BcdDevice = usbDeviceDescriptor.BcdDevice; + mDeviceDescriptor.BcdUsb = usbDeviceDescriptor.BcdUsb; + mDeviceDescriptor.Class = usbDeviceDescriptor.Class; + mDeviceDescriptor.ConfigurationCount = usbDeviceDescriptor.ConfigurationCount; + mDeviceDescriptor.DescriptorType = usbDeviceDescriptor.DescriptorType; + mDeviceDescriptor.Length = usbDeviceDescriptor.Length; + mDeviceDescriptor.ManufacturerStringIndex = usbDeviceDescriptor.ManufacturerStringIndex; + mDeviceDescriptor.MaxPacketSize0 = usbDeviceDescriptor.MaxPacketSize0; + mDeviceDescriptor.ProductID = usbDeviceDescriptor.ProductID; + mDeviceDescriptor.ProductStringIndex = usbDeviceDescriptor.ProductStringIndex; + mDeviceDescriptor.Protocol = usbDeviceDescriptor.Protocol; + mDeviceDescriptor.SerialStringIndex = usbDeviceDescriptor.SerialStringIndex; + mDeviceDescriptor.SubClass = usbDeviceDescriptor.SubClass; + mDeviceDescriptor.VendorID = usbDeviceDescriptor.VendorID; + } + + /// + /// The raw for the current . + /// + public UsbDeviceDescriptor Descriptor + { + get { return mDeviceDescriptor; } + } + + /// + /// Request all available languages from the USB device (string index 0) and return the most appropriate LCID given the current operating systems locale settings. See System.Globalization.CultureInfo.CurrentCulture.LCID. + /// + /// + /// Once the USB devices CurrentCultureLangID has been retreived, subsequent request will return a cached copy of the LCID. + /// + public short CurrentCultureLangID + { + get + { + if (mCurrentCultureLangID == NO_LANG) + { + short currentCultureLangID = (short) CultureInfo.CurrentCulture.LCID; + short[] deviceLangIDs; + if (mUsbDevice.GetLangIDs(out deviceLangIDs)) + { + foreach (short deviceLangID in deviceLangIDs) + { + if (deviceLangID == currentCultureLangID) + { + mCurrentCultureLangID = deviceLangID; + return mCurrentCultureLangID; + } + } + } + mCurrentCultureLangID = deviceLangIDs.Length > 0 ? deviceLangIDs[0] : (short) 0; + } + return mCurrentCultureLangID; + } + } + + /// + /// Gets the string representation of the string index. + /// + public String ManufacturerString + { + get + { + if (ReferenceEquals(mManufacturerString, null)) + { + mManufacturerString = String.Empty; + if (Descriptor.ManufacturerStringIndex > 0) + { + mUsbDevice.GetString(out mManufacturerString, CurrentCultureLangID, Descriptor.ManufacturerStringIndex); + } + } + return mManufacturerString; + } + } + + /// + /// Gets the string representation of the string index. + /// + public String ProductString + { + get + { + if (ReferenceEquals(mProductString, null)) + { + mProductString = String.Empty; + if (Descriptor.ProductStringIndex > 0) + { + mUsbDevice.GetString(out mProductString, CurrentCultureLangID, Descriptor.ProductStringIndex); + } + } + return mProductString; + } + } + + /// + /// Gets the string representation of the string index. + /// + public String SerialString + { + get + { + if (ReferenceEquals(mSerialString, null)) + { + mSerialString = String.Empty; + if (Descriptor.SerialStringIndex > 0) + { + mUsbDevice.GetString(out mSerialString, 0x0409, Descriptor.SerialStringIndex); + } + } + return mSerialString; + } + } + + /// + ///Returns a that represents the current . + /// + /// + /// + ///A that represents the current . + /// + public override string ToString() { return ToString("", UsbDescriptor.ToStringParamValueSeperator, UsbDescriptor.ToStringFieldSeperator); } + + /// + ///Returns a that represents the current . + /// + /// + ///The field prefix string. + ///The field/value seperator string. + ///The value suffix string. + ///A formatted representation of the . + public string ToString(string prefixSeperator, string entitySperator, string suffixSeperator) + { + string[] names = {"ManufacturerString", "ProductString", "SerialString"}; + Object[] values = {ManufacturerString, ProductString, SerialString}; + return Descriptor.ToString(prefixSeperator, entitySperator, suffixSeperator) + + Helper.ToString(prefixSeperator, names, entitySperator, values, suffixSeperator); + } + + internal static bool GetDeviceDescriptor(UsbDevice usbDevice, out UsbDeviceDescriptor deviceDescriptor) + { + if (usbDevice.mCachedDeviceDescriptor!=null) + { + deviceDescriptor = usbDevice.mCachedDeviceDescriptor; + return true; + } + deviceDescriptor = new UsbDeviceDescriptor(); + + GCHandle gcDeviceDescriptor = GCHandle.Alloc(deviceDescriptor, GCHandleType.Pinned); + int ret; + bool bSuccess = usbDevice.GetDescriptor((byte) DescriptorType.Device, + 0, + 0, + gcDeviceDescriptor.AddrOfPinnedObject(), + UsbDeviceDescriptor.Size, + out ret); + gcDeviceDescriptor.Free(); + + if (bSuccess) return true; + + return false; + } + } +} \ No newline at end of file diff --git a/LibWinUsb/Info/UsbEndpointInfo.cs b/LibWinUsb/Info/UsbEndpointInfo.cs new file mode 100644 index 0000000..30cc19f --- /dev/null +++ b/LibWinUsb/Info/UsbEndpointInfo.cs @@ -0,0 +1,70 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using LibUsbDotNet.Descriptors; +using LibUsbDotNet.Main; +using MonoLibUsb.Descriptors; + +namespace LibUsbDotNet.Info +{ + /// Contains Endpoint information for the current . + /// + public class UsbEndpointInfo : UsbBaseInfo + { + internal UsbEndpointDescriptor mUsbEndpointDescriptor; + + internal UsbEndpointInfo(byte[] descriptor) + { + mUsbEndpointDescriptor = new UsbEndpointDescriptor(); + Helper.BytesToObject(descriptor, 0, Math.Min(UsbEndpointDescriptor.Size, descriptor[0]), mUsbEndpointDescriptor); + } + + internal UsbEndpointInfo(MonoUsbEndpointDescriptor monoUsbEndpointDescriptor) { mUsbEndpointDescriptor = new UsbEndpointDescriptor(monoUsbEndpointDescriptor); } + + /// + /// Gets the information. + /// + public UsbEndpointDescriptor Descriptor + { + get { return mUsbEndpointDescriptor; } + } + + /// + ///Returns a that represents the current . + /// + /// + /// + ///A that represents the current . + /// + public override string ToString() { return Descriptor.ToString(); } + + /// + ///Returns a that represents the current . + /// + /// + ///The field prefix string. + ///The field/value seperator string. + ///The value suffix string. + ///A formatted representation of the . + public string ToString(string prefixSeperator, string entitySperator, string suffixSeperator) { return Descriptor.ToString(prefixSeperator, entitySperator, suffixSeperator); } + } +} \ No newline at end of file diff --git a/LibWinUsb/Info/UsbInterfaceInfo.cs b/LibWinUsb/Info/UsbInterfaceInfo.cs new file mode 100644 index 0000000..1791efa --- /dev/null +++ b/LibWinUsb/Info/UsbInterfaceInfo.cs @@ -0,0 +1,120 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using LibUsbDotNet.Descriptors; +using LibUsbDotNet.Main; +using MonoLibUsb.Descriptors; + +namespace LibUsbDotNet.Info +{ + /// Describes a USB device interface. + /// + public class UsbInterfaceInfo : UsbBaseInfo + { + internal readonly UsbInterfaceDescriptor mUsbInterfaceDescriptor; + internal List mEndpointInfo = new List(); + private String mInterfaceString; + internal UsbDevice mUsbDevice; + + internal UsbInterfaceInfo(UsbDevice usbDevice, byte[] descriptor) + { + mUsbDevice = usbDevice; + mUsbInterfaceDescriptor = new UsbInterfaceDescriptor(); + Helper.BytesToObject(descriptor, 0, Math.Min(UsbInterfaceDescriptor.Size, descriptor[0]), mUsbInterfaceDescriptor); + } + + internal UsbInterfaceInfo(UsbDevice usbDevice, MonoUsbAltInterfaceDescriptor monoUSBAltInterfaceDescriptor) + { + mUsbDevice = usbDevice; + + mUsbInterfaceDescriptor = new UsbInterfaceDescriptor(monoUSBAltInterfaceDescriptor); + List monoUsbEndpoints = monoUSBAltInterfaceDescriptor.EndpointList; + foreach (MonoUsbEndpointDescriptor monoUSBEndpoint in monoUsbEndpoints) + { + mEndpointInfo.Add(new UsbEndpointInfo(monoUSBEndpoint)); + } + } + + /// + /// Gets the actual interface descriptor. + /// + public UsbInterfaceDescriptor Descriptor + { + get { return mUsbInterfaceDescriptor; } + } + + /// + /// Gets the collection of endpoint descriptors associated with this interface. + /// + public ReadOnlyCollection EndpointInfoList + { + get { return mEndpointInfo.AsReadOnly(); } + } + + /// + /// Gets the string representation of the string index. + /// + public String InterfaceString + { + get + { + if (ReferenceEquals(mInterfaceString, null)) + { + mInterfaceString = String.Empty; + if (Descriptor.StringIndex > 0) + { + mUsbDevice.GetString(out mInterfaceString, mUsbDevice.Info.CurrentCultureLangID, Descriptor.StringIndex); + } + } + return mInterfaceString; + } + } + + + /// + ///Returns a that represents the current . + /// + /// + /// + ///A that represents the current . + /// + public override string ToString() { return ToString("", UsbDescriptor.ToStringParamValueSeperator, UsbDescriptor.ToStringFieldSeperator); } + + /// + ///Returns a that represents the current . + /// + /// + ///The field prefix string. + ///The field/value seperator string. + ///The value suffix string. + ///A formatted representation of the . + public string ToString(string prefixSeperator, string entitySperator, string suffixSeperator) + { + Object[] values = {InterfaceString}; + string[] names = {"InterfaceString"}; + return Descriptor.ToString(prefixSeperator, entitySperator, suffixSeperator) + + Helper.ToString(prefixSeperator, names, entitySperator, values, suffixSeperator); + } + } +} \ No newline at end of file diff --git a/LibWinUsb/Internal/Kernel32.cs b/LibWinUsb/Internal/Kernel32.cs new file mode 100644 index 0000000..10ef296 --- /dev/null +++ b/LibWinUsb/Internal/Kernel32.cs @@ -0,0 +1,197 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Globalization; +using System.Runtime.InteropServices; +using System.Security; +using System.Text; +using Microsoft.Win32.SafeHandles; + +// ReSharper disable InconsistentNaming + +namespace LibUsbDotNet.Internal +{ + [SuppressUnmanagedCodeSecurity] + internal static class Kernel32 + { + private const int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000; + private static readonly StringBuilder m_sbSysMsg = new StringBuilder(1024); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern SafeFileHandle CreateFile(string fileName, + [MarshalAs(UnmanagedType.U4)] NativeFileAccess fileAccess, + [MarshalAs(UnmanagedType.U4)] NativeFileShare fileShare, + IntPtr securityAttributes, + [MarshalAs(UnmanagedType.U4)] NativeFileMode creationDisposition, + NativeFileFlag flags, + IntPtr template); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] + private static extern int FormatMessage(int dwFlags, + IntPtr lpSource, + int dwMessageId, + int dwLanguageId, + [Out] StringBuilder lpBuffer, + int nSize, + IntPtr lpArguments); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)] + public static extern bool GetOverlappedResult(SafeHandle hDevice, IntPtr lpOverlapped, out int lpNumberOfBytesTransferred, bool bWait); + + + public static string FormatSystemMessage(int dwMessageId) + { + lock (m_sbSysMsg) + { + int ret = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + IntPtr.Zero, + dwMessageId, + CultureInfo.CurrentCulture.LCID, + m_sbSysMsg, + m_sbSysMsg.Capacity - 1, + IntPtr.Zero); + + if (ret > 0) return m_sbSysMsg.ToString(0, ret); + return null; + } + } + + #region DeviceIoControl + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)] + public static extern bool DeviceIoControl(SafeHandle hDevice, + int IoControlCode, + [MarshalAs(UnmanagedType.AsAny), In] object InBuffer, + int nInBufferSize, + IntPtr OutBuffer, + int nOutBufferSize, + out int pBytesReturned, + IntPtr pOverlapped); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)] + public static extern bool DeviceIoControl(SafeHandle hDevice, + int IoControlCode, + [MarshalAs(UnmanagedType.AsAny), In] object InBuffer, + int nInBufferSize, + [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 6), Out] byte[] OutBuffer, + int nOutBufferSize, + out int pBytesReturned, + IntPtr Overlapped); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)] + public static extern bool DeviceIoControl(SafeHandle hDevice, + int IoControlCode, + IntPtr InBuffer, + int nInBufferSize, + IntPtr OutBuffer, + int nOutBufferSize, + out int pBytesReturned, + IntPtr Overlapped); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi, EntryPoint = "DeviceIoControl")] + public static extern bool DeviceIoControlAsObject(SafeHandle hDevice, + int IoControlCode, + [MarshalAs(UnmanagedType.AsAny), In] object InBuffer, + int nInBufferSize, + IntPtr OutBuffer, + int nOutBufferSize, + ref int pBytesReturned, + IntPtr Overlapped); + + #endregion + } + + [Flags] + internal 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 + } + + internal enum NativeFileMode : uint + { + CREATE_NEW = 1, + CREATE_ALWAYS = 2, + OPEN_EXISTING = 3, + OPEN_ALWAYS = 4, + TRUNCATE_EXISTING = 5, + } + + [Flags] + internal enum NativeFileShare : uint + { + NONE = 0, + FILE_SHARE_READ = 0x00000001, + FILE_SHARE_WRITE = 0x00000002, + FILE_SHARE_DEELETE = 0x00000004, + } + + [Flags] + internal 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 diff --git a/LibWinUsb/Internal/OverlappedTransferContext.cs b/LibWinUsb/Internal/OverlappedTransferContext.cs new file mode 100644 index 0000000..bd9a073 --- /dev/null +++ b/LibWinUsb/Internal/OverlappedTransferContext.cs @@ -0,0 +1,113 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; +using System.Threading; +using LibUsbDotNet.Main; + +namespace LibUsbDotNet.Internal +{ + internal class OverlappedTransferContext : UsbTransfer + { + private readonly SafeOverlapped mOverlapped = new SafeOverlapped(); + + public OverlappedTransferContext(UsbEndpointBase endpointBase) + : base(endpointBase) { } + + public SafeOverlapped Overlapped + { + get { return mOverlapped; } + } + + public override ErrorCode Submit() + { + int iTransferred; + ErrorCode eReturn = ErrorCode.Success; + + if (mTransferCancelEvent.WaitOne(0, false)) return ErrorCode.IoCancelled; + if (!mTransferCompleteEvent.WaitOne(0, UsbConstants.EXIT_CONTEXT)) return ErrorCode.ResourceBusy; + + mHasWaitBeenCalled = false; + mTransferCompleteEvent.Reset(); + Overlapped.ClearAndSetEvent(mTransferCompleteEvent.SafeWaitHandle.DangerousGetHandle()); + + int ret = EndpointBase.PipeTransferSubmit(NextBufPtr, + RequestCount, + out iTransferred, + mIsoPacketSize, + Overlapped.GlobalOverlapped); + if (ret != 0 && ret != (int) UsbStatusClodes.ErrorIoPending) + { + mTransferCompleteEvent.Set(); + UsbError usbErr = UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "PipeTransferSubmit", EndpointBase); + + eReturn = usbErr.ErrorCode; + } + return eReturn; + } + + public override ErrorCode Wait(out int transferredCount, bool cancel) + { + if (mHasWaitBeenCalled) throw new UsbException(this, "Repeated calls to wait with a submit is not allowed."); + + transferredCount = 0; + bool bSuccess; + // Temporarily release the transfer lock while we wait for something to happen. + int iWait = WaitHandle.WaitAny(new WaitHandle[] { mTransferCompleteEvent, mTransferCancelEvent }, mTimeout, UsbConstants.EXIT_CONTEXT); + if (iWait == WaitHandle.WaitTimeout && !cancel) + { + return ErrorCode.IoTimedOut; + } + mHasWaitBeenCalled = true; + + if (iWait != 0) + { + bSuccess = EndpointBase.mUsbApi.AbortPipe(EndpointBase.Handle, EndpointBase.EpNum); + bool bTransferComplete = mTransferCompleteEvent.WaitOne(100, UsbConstants.EXIT_CONTEXT); + mTransferCompleteEvent.Set(); + if (!bSuccess || !bTransferComplete) + { + ErrorCode ec = bSuccess ? ErrorCode.Win32Error : ErrorCode.CancelIoFailed; + UsbError.Error(ec, Marshal.GetLastWin32Error(), "Wait:AbortPipe Failed", this); + return ec; + } + if (iWait == WaitHandle.WaitTimeout) return ErrorCode.IoTimedOut; + return ErrorCode.IoCancelled; + } + + try + { + bSuccess = EndpointBase.mUsbApi.GetOverlappedResult(EndpointBase.Handle, Overlapped.GlobalOverlapped, out transferredCount, true); + if (!bSuccess) + { + UsbError usbErr = UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "GetOverlappedResult", EndpointBase); + return usbErr.ErrorCode; + } + return ErrorCode.None; + } + catch + { + return ErrorCode.UnknownError; + } + } + } +} \ No newline at end of file diff --git a/LibWinUsb/Internal/SafeOverlapped.cs b/LibWinUsb/Internal/SafeOverlapped.cs new file mode 100644 index 0000000..dae0f4e --- /dev/null +++ b/LibWinUsb/Internal/SafeOverlapped.cs @@ -0,0 +1,115 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; +using System.Threading; + +namespace LibUsbDotNet.Internal +{ + internal class SafeOverlapped : IDisposable + { + // Find the structural starting positions in the NativeOverlapped structure. + private static readonly int FieldOffsetEventHandle = Marshal.OffsetOf(typeof (NativeOverlapped), "EventHandle").ToInt32(); + private static readonly int FieldOffsetInternalHigh = Marshal.OffsetOf(typeof (NativeOverlapped), "InternalHigh").ToInt32(); + private static readonly int FieldOffsetInternalLow = Marshal.OffsetOf(typeof (NativeOverlapped), "InternalLow").ToInt32(); + private static readonly int FieldOffsetOffsetHigh = Marshal.OffsetOf(typeof (NativeOverlapped), "OffsetHigh").ToInt32(); + private static readonly int FieldOffsetOffsetLow = Marshal.OffsetOf(typeof (NativeOverlapped), "OffsetLow").ToInt32(); + private IntPtr mPtrOverlapped = IntPtr.Zero; + + public SafeOverlapped() + { + // Globally allocated the memory for the overlapped structure + mPtrOverlapped = Marshal.AllocHGlobal(Marshal.SizeOf(typeof (NativeOverlapped))); + } + + public IntPtr InternalLow + { + get { return Marshal.ReadIntPtr(mPtrOverlapped, FieldOffsetInternalLow); } + set { Marshal.WriteIntPtr(mPtrOverlapped, FieldOffsetInternalLow, value); } + } + + public IntPtr InternalHigh + { + get { return Marshal.ReadIntPtr(mPtrOverlapped, FieldOffsetInternalHigh); } + set { Marshal.WriteIntPtr(mPtrOverlapped, FieldOffsetInternalHigh, value); } + } + + public int OffsetLow + { + get { return Marshal.ReadInt32(mPtrOverlapped, FieldOffsetOffsetLow); } + set { Marshal.WriteInt32(mPtrOverlapped, FieldOffsetOffsetLow, value); } + } + + public int OffsetHigh + { + get { return Marshal.ReadInt32(mPtrOverlapped, FieldOffsetOffsetHigh); } + set { Marshal.WriteInt32(mPtrOverlapped, FieldOffsetOffsetHigh, value); } + } + + /// + /// The overlapped event wait hande. + /// + public IntPtr EventHandle + { + get { return Marshal.ReadIntPtr(mPtrOverlapped, FieldOffsetEventHandle); } + set { Marshal.WriteIntPtr(mPtrOverlapped, FieldOffsetEventHandle, value); } + } + + /// + /// Pass this into the DeviceIoControl and GetOverlappedResult APIs + /// + public IntPtr GlobalOverlapped + { + get { return mPtrOverlapped; } + } + + #region IDisposable Members + + public void Dispose() + { + if (mPtrOverlapped != IntPtr.Zero) + { + Marshal.FreeHGlobal(mPtrOverlapped); + mPtrOverlapped = IntPtr.Zero; + } + } + + #endregion + + /// + /// Set the overlapped wait handle and clear out the rest of the structure. + /// + /// + public void ClearAndSetEvent(IntPtr hEventOverlapped) + { + EventHandle = hEventOverlapped; + InternalLow = IntPtr.Zero; + InternalHigh = IntPtr.Zero; + OffsetLow = 0; + OffsetHigh = 0; + } + + + // Clean up the globally allocated memory. + ~SafeOverlapped() { Dispose(); } + } +} \ No newline at end of file diff --git a/LibWinUsb/Internal/SetupApi.cs b/LibWinUsb/Internal/SetupApi.cs new file mode 100644 index 0000000..ced66c8 --- /dev/null +++ b/LibWinUsb/Internal/SetupApi.cs @@ -0,0 +1,670 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using LibUsbDotNet.Main; +using LibUsbDotNet.WinUsb; +using Microsoft.Win32; + +// ReSharper disable InconsistentNaming +// ReSharper disable ClassNeverInstantiated.Local +// ReSharper disable UnusedMember.Local +// ReSharper disable ConvertIfStatementToConditionalTernaryExpression +// ReSharper disable UnusedParameter.Local + +namespace LibUsbDotNet.Internal +{ + internal class SetupApi + { + #region Delegates + + public delegate bool ClassEnumeratorDelegate( + IntPtr DeviceInfoSet, int deviceIndex, ref SP_DEVINFO_DATA DeviceInfoData, object classEnumeratorCallbackParam1); + + #endregion + + #region Enumerations + + #region CR enum + + public 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) + } + + #endregion + + #region DeviceInterfaceDataFlags enum + + public enum DeviceInterfaceDataFlags : uint + { + Active = 0x00000001, + Default = 0x00000002, + Removed = 0x00000004 + } + + #endregion + + #region DICFG enum + + [Flags] + public enum DICFG + { + /// + /// 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 . + /// + DEFAULT = 0x00000001, + /// + /// Return only devices that are currently present in a system. + /// + PRESENT = 0x00000002, + /// + /// Return a list of installed devices for all device setup classes or all device interface classes. + /// + ALLCLASSES = 0x00000004, + /// + /// Return only devices that are a part of the current hardware profile. + /// + PROFILE = 0x00000008, + /// + /// Return devices that support device interfaces for the specified device interface classes. + /// + DEVICEINTERFACE = 0x00000010, + } + + #endregion + + #region DICUSTOMDEVPROP enum + + public enum DICUSTOMDEVPROP + { + NONE = 0, + MERGE_MULTISZ = 0x00000001, + } + + #endregion + + [Flags] + public enum DevKeyType + { + DEV = 0x00000001, // Open/Create/Delete device key + DRV = 0x00000002, // Open/Create/Delete driver key + BOTH = 0x00000004, // Delete both driver and Device key + + } + #endregion + + private const string STRUCT_END_MARK = "STRUCT_END_MARK"; + + public static readonly Guid GUID_DEVINTERFACE_USB_DEVICE = new Guid("f18a0e88-c30c-11d0-8815-00a0c906bed8"); + + public static bool Is64Bit + { + get { return (IntPtr.Size == 8); } + } + + + /// + /// + /// + /// Caller-supplied device instance handle that is bound to the local machine. + /// Address of a buffer to receive a device instance ID string. The required buffer size can be obtained by calling CM_Get_Device_ID_Size, then incrementing the received value to allow room for the string's terminating NULL. + /// Caller-supplied length, in characters, of the buffer specified by Buffer. + /// Not used. set to 0. + /// If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h. + [DllImport("setupapi.dll", CharSet = CharSet.Auto)] + public static extern CR CM_Get_Device_ID(IntPtr dnDevInst, IntPtr Buffer, int BufferLen, int ulFlags); + + + /// + /// The CM_Get_Parent function obtains a device instance handle to the parent node of a specified device node, in the local machine's device tree. + /// + /// Caller-supplied pointer to the device instance handle to the parent node that this function retrieves. The retrieved handle is bound to the local machine. + /// Caller-supplied device instance handle that is bound to the local machine. + /// Not used. set to 0. + /// If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in cfgmgr32.h. + [DllImport("setupapi.dll")] + public static extern CR CM_Get_Parent(out IntPtr pdnDevInst, IntPtr dnDevInst, int ulFlags); + + [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(IntPtr DeviceInfoSet, int MemberIndex, ref SP_DEVINFO_DATA DeviceInfoData); + + /// + /// The SetupDiEnumDeviceInterfaces function enumerates the device interfaces that are contained in a device information set. + /// + /// A pointer to a device information set that contains the device interfaces for which to return information. This handle is typically returned by SetupDiGetClassDevs. + /// A pointer to an SP_DEVINFO_DATA structure that specifies a device information element in DeviceInfoSet. This parameter is optional and can be NULL. If this parameter is specified, SetupDiEnumDeviceInterfaces constrains the enumeration to the interfaces that are supported by the specified device. If this parameter is NULL, repeated calls to SetupDiEnumDeviceInterfaces return information about the interfaces that are associated with all the device information elements in DeviceInfoSet. This pointer is typically returned by SetupDiEnumDeviceInfo. + /// A pointer to a GUID that specifies the device interface class for the requested interface. + /// A zero-based index into the list of interfaces in the device information set. The caller should call this function first with MemberIndex set to zero to obtain the first interface. Then, repeatedly increment MemberIndex and retrieve an interface until this function fails and GetLastError returns ERROR_NO_MORE_ITEMS. If DeviceInfoData specifies a particular device, the MemberIndex is relative to only the interfaces exposed by that device. + /// A pointer to a caller-allocated buffer that contains, on successful return, a completed SP_DEVICE_INTERFACE_DATA structure that identifies an interface that meets the search parameters. The caller must set DeviceInterfaceData.cbSize to sizeof(SP_DEVICE_INTERFACE_DATA) before calling this function. + /// + [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern Boolean SetupDiEnumDeviceInterfaces(IntPtr 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(IntPtr hDevInfo, + [MarshalAs(UnmanagedType.AsAny)] object devInfo, + ref Guid interfaceClassGuid, + int memberIndex, + ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData); + + /// + /// The SetupDiGetClassDevs function returns a handle to a device information set that contains requested device information elements for a local machine. + /// + /// A pointer to the GUID for a device setup class or a device interface class. This pointer is optional and can be NULL. For more information about how to set ClassGuid, see the following Comments section. + /// A pointer to a NULL-terminated string that supplies the name of a Plug and Play (PnP) enumerator or a PnP device instance identifier. This pointer is optional and can be NULL. For more information about how to set the Enumerator value, see the following Comments section. + /// A handle of the top-level window to be used for a user interface that is associated with installing a device instance in the device information set. This handle is optional and can be NULL. + /// A variable of type DWORD that specifies control options that filter the device information elements that are added to the device information set. This parameter can be a bitwise OR of zero or more of the following flags. + /// + [DllImport("setupapi.dll", CharSet = CharSet.Ansi, EntryPoint = "SetupDiGetClassDevsA")] + public static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, + [MarshalAs(UnmanagedType.LPTStr)] string Enumerator, + IntPtr hwndParent, + DICFG Flags); + + [DllImport("setupapi.dll", CharSet = CharSet.Ansi, EntryPoint = "SetupDiGetClassDevsA")] + public static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, int Enumerator, IntPtr hwndParent, DICFG Flags); + + [DllImport("setupapi.dll", CharSet = CharSet.Ansi, EntryPoint = "SetupDiGetClassDevsA")] + public static extern IntPtr SetupDiGetClassDevs(int ClassGuid, string Enumerator, IntPtr hwndParent, DICFG Flags); + + [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern bool SetupDiGetCustomDeviceProperty(IntPtr DeviceInfoSet, + ref SP_DEVINFO_DATA DeviceInfoData, + string CustomPropertyName, + DICUSTOMDEVPROP Flags, + out RegistryValueKind PropertyRegDataType, + Byte[] PropertyBuffer, + int PropertyBufferSize, + out int RequiredSize); + + /// + /// The SetupDiGetDeviceInstanceId function retrieves the device instance ID that is associated with a device information element. + /// + /// A handle to the device information set that contains the device information element that represents the device for which to retrieve a device instance ID. + /// A pointer to an SP_DEVINFO_DATA structure that specifies the device information element in DeviceInfoSet. + /// A pointer to the character buffer that will receive the NULL-terminated device instance ID for the specified device information element. For information about device instance IDs, see Device Identification Strings. + /// The size, in characters, of the DeviceInstanceId buffer. + /// A pointer to the variable that receives the number of characters required to store the device instance ID. + /// The function returns TRUE if it is successful. Otherwise, it returns FALSE and the logged error can be retrieved with a call to GetLastError. + [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Ansi, EntryPoint = "SetupDiGetDeviceInstanceIdA")] + public static extern bool SetupDiGetDeviceInstanceId(IntPtr DeviceInfoSet, + ref SP_DEVINFO_DATA DeviceInfoData, + StringBuilder DeviceInstanceId, + int DeviceInstanceIdSize, + out int RequiredSize); + + [DllImport(@"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern Boolean SetupDiGetDeviceInterfaceDetail(IntPtr hDevInfo, + ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData, + DEVICE_INTERFACE_DETAIL_HANDLE deviceInterfaceDetailData, + int deviceInterfaceDetailDataSize, + out int requiredSize, + [MarshalAs(UnmanagedType.AsAny)] object deviceInfoData); + [DllImport(@"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern Boolean SetupDiGetDeviceInterfaceDetail(IntPtr hDevInfo, + ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData, + DEVICE_INTERFACE_DETAIL_HANDLE deviceInterfaceDetailData, + int deviceInterfaceDetailDataSize, + out int requiredSize, + ref SP_DEVINFO_DATA deviceInfoData); + + + [DllImport("setupapi.dll", CharSet = CharSet.Auto)] + public static extern bool SetupDiGetDeviceInterfacePropertyKeys(IntPtr DeviceInfoSet, + ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, + byte[] propKeyBuffer, + int propKeyBufferElements, + out int RequiredPropertyKeyCount, + int Flags); + + /// + /// The SetupDiGetDeviceRegistryProperty function retrieves the specified device property. + /// This handle is typically returned by the SetupDiGetClassDevs or SetupDiGetClassDevsEx function. + /// + /// Handle to the device information set that contains the interface and its underlying device. + /// Pointer to an SP_DEVINFO_DATA structure that defines the device instance. + /// Device property to be retrieved. SEE MSDN + /// Pointer to a variable that receives the registry data Type. This parameter can be NULL. + /// Pointer to a buffer that receives the requested device property. + /// Size of the buffer, in bytes. + /// Pointer to a variable that receives the required buffer size, in bytes. This parameter can be NULL. + /// If the function succeeds, the return value is nonzero. + [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern bool SetupDiGetDeviceRegistryProperty(IntPtr DeviceInfoSet, + ref SP_DEVINFO_DATA DeviceInfoData, + SPDRP Property, + out RegistryValueKind PropertyRegDataType, + byte[] PropertyBuffer, + int PropertyBufferSize, + out int RequiredSize); + + [DllImport("setupapi.dll", CharSet = CharSet.Auto)] + public static extern CR CM_Get_Device_ID(uint dnDevInst, StringBuilder Buffer, int BufferLen, int ulFlags); + + [DllImport("Setupapi", CharSet = CharSet.Auto, SetLastError = true)] + public static extern IntPtr SetupDiOpenDevRegKey(IntPtr hDeviceInfoSet, ref SP_DEVINFO_DATA deviceInfoData, int scope, int hwProfile, DevKeyType keyType, RegistryKeyPermissionCheck samDesired); + + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern int RegEnumValue(IntPtr hKey, int index, StringBuilder lpValueName, ref int lpcValueName, IntPtr lpReserved, out RegistryValueKind lpType, byte[] data, ref int dataLength); + + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern int RegEnumValue(IntPtr hKey, int index, StringBuilder lpValueName, ref int lpcValueName, IntPtr lpReserved, out RegistryValueKind lpType, StringBuilder data, ref int dataLength); + + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern int RegCloseKey(IntPtr hKey); + + public static bool EnumClassDevs(string enumerator, + DICFG flags, + ClassEnumeratorDelegate classEnumeratorCallback, + object classEnumeratorCallbackParam1) + { + SP_DEVINFO_DATA dev_info_data = SP_DEVINFO_DATA.Empty; + + int dev_index = 0; + + IntPtr dev_info = SetupDiGetClassDevs(0, enumerator, IntPtr.Zero, flags); + + if (dev_info == IntPtr.Zero || dev_info.ToInt64() == -1) return false; + bool bSuccess = false; + while (SetupDiEnumDeviceInfo(dev_info, dev_index, ref dev_info_data)) + { + if (classEnumeratorCallback(dev_info, dev_index, ref dev_info_data, classEnumeratorCallbackParam1)) + { + bSuccess = true; + break; + } + + dev_index++; + } + + SetupDiDestroyDeviceInfoList(dev_info); + + return bSuccess; + } + + public static void getSPDRPProperties(IntPtr deviceInfoSet, ref SP_DEVINFO_DATA deviceInfoData, Dictionary deviceProperties) + { + byte[] propBuffer = new byte[1024]; + Dictionary allProps = Helper.GetEnumData(typeof(SPDRP)); + foreach (KeyValuePair prop in allProps) + { + object oValue = String.Empty; + int iReturnBytes; + RegistryValueKind regPropType; + bool bSuccess = SetupDiGetDeviceRegistryProperty(deviceInfoSet, + ref deviceInfoData, + (SPDRP)prop.Value, + out regPropType, + propBuffer, + propBuffer.Length, + out iReturnBytes); + if (bSuccess) + { + switch ((SPDRP)prop.Value) + { + 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: + oValue = UsbRegistry.GetAsString(propBuffer, iReturnBytes); + break; + case SPDRP.HardwareId: + case SPDRP.CompatibleIds: + case SPDRP.LocationPaths: + oValue = UsbRegistry.GetAsStringArray(propBuffer, iReturnBytes); + break; + case SPDRP.BusNumber: + case SPDRP.InstallState: + case SPDRP.LegacyBusType: + case SPDRP.RemovalPolicy: + case SPDRP.UiNumber: + case SPDRP.Address: + oValue = UsbRegistry.GetAsStringInt32(propBuffer, iReturnBytes); + break; + case SPDRP.BusTypeGuid: + oValue = UsbRegistry.GetAsGuid(propBuffer, iReturnBytes); + break; + } + } + else + oValue = String.Empty; + + deviceProperties.Add(prop.Key, oValue); + } + } + + public static bool SetupDiGetDeviceInterfaceDetailLength(IntPtr hDevInfo, + ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData, + out int requiredLength) + { + DEVICE_INTERFACE_DETAIL_HANDLE tmp = new DEVICE_INTERFACE_DETAIL_HANDLE(); + return SetupDiGetDeviceInterfaceDetail(hDevInfo, ref deviceInterfaceData, tmp, 0, out requiredLength, null); + } + + public static bool SetupDiGetDeviceRegistryProperty(out byte[] regBytes, + IntPtr DeviceInfoSet, + ref SP_DEVINFO_DATA DeviceInfoData, + SPDRP Property) + { + regBytes = null; + byte[] tmp = new byte[1024]; + int iReqSize; + RegistryValueKind regValueType; + if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet, ref DeviceInfoData, Property, out regValueType, tmp, tmp.Length, out iReqSize)) + { + UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "SetupDiGetDeviceRegistryProperty", typeof(SetupApi)); + return false; + } + regBytes = new byte[iReqSize]; + Array.Copy(tmp, regBytes, regBytes.Length); + return true; + } + + public static bool SetupDiGetDeviceRegistryProperty(out string regSZ, IntPtr DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, SPDRP Property) + { + regSZ = null; + byte[] tmp; + if (SetupDiGetDeviceRegistryProperty(out tmp, DeviceInfoSet, ref DeviceInfoData, Property)) + { + regSZ = Encoding.Unicode.GetString(tmp).TrimEnd(new char[] {'\0'}); + return true; + } + return false; + } + + public static bool SetupDiGetDeviceRegistryProperty(out string[] regMultiSZ, + IntPtr DeviceInfoSet, + ref SP_DEVINFO_DATA DeviceInfoData, + SPDRP Property) + { + regMultiSZ = null; + string tmp; + if (SetupDiGetDeviceRegistryProperty(out tmp, DeviceInfoSet, ref DeviceInfoData, Property)) + { + regMultiSZ = tmp.Split(new char[] {'\0'}, StringSplitOptions.RemoveEmptyEntries); + return true; + } + return false; + } + + private static bool cbHasDeviceInterfaceGUID(IntPtr DeviceInfoSet, + int deviceIndex, + ref SP_DEVINFO_DATA DeviceInfoData, + object devInterfaceGuid) + { + RegistryValueKind propertyType; + byte[] propBuffer = new byte[256]; + int requiredSize; + bool bSuccess = SetupDiGetCustomDeviceProperty(DeviceInfoSet, + ref DeviceInfoData, + "DeviceInterfaceGuids", + DICUSTOMDEVPROP.NONE, + out propertyType, + propBuffer, + propBuffer.Length, + out requiredSize); + if (bSuccess) + { + Guid devGuid = (Guid) devInterfaceGuid; + string[] stemp = Encoding.Unicode.GetString(propBuffer, 0, requiredSize).Split(new char[] {'\0'}, + StringSplitOptions.RemoveEmptyEntries); + Guid findGuid = new Guid(stemp[0]); + return (devGuid == findGuid); + } + return false; + } + + #region Nested Types + + #region Nested type: DEVICE_INTERFACE_DETAIL_HANDLE + + [StructLayout(LayoutKind.Sequential)] + public struct DEVICE_INTERFACE_DETAIL_HANDLE + { + private IntPtr mPtr; + + internal DEVICE_INTERFACE_DETAIL_HANDLE(IntPtr ptrInit) { mPtr = ptrInit; } + } + + #endregion + + #region Nested type: DeviceInterfaceDetailHelper + + public class DeviceInterfaceDetailHelper + { + public static readonly int SIZE = Is64Bit ? 8 : 6; + private IntPtr mpDevicePath; + private IntPtr mpStructure; + + public DeviceInterfaceDetailHelper(int maximumLength) + { + mpStructure = Marshal.AllocHGlobal(maximumLength); + mpDevicePath = new IntPtr(mpStructure.ToInt64() + Marshal.SizeOf(typeof (int))); + } + + public DEVICE_INTERFACE_DETAIL_HANDLE Handle + { + get + { + Marshal.WriteInt32(mpStructure, SIZE); + return new DEVICE_INTERFACE_DETAIL_HANDLE(mpStructure); + } + } + + public string DevicePath + { + get { return Marshal.PtrToStringAuto(mpDevicePath); } + } + + + public void Free() + { + if (mpStructure != IntPtr.Zero) + Marshal.FreeHGlobal(mpStructure); + + mpDevicePath = IntPtr.Zero; + mpStructure = IntPtr.Zero; + } + + + ~DeviceInterfaceDetailHelper() { Free(); } + } + + #endregion + + #region Nested type: MaxStructSizes + + private class MaxStructSizes + { + public const int SP_DEVINFO_DATA = 40; + } + + #endregion + + #region Nested type: SP_DEVICE_INTERFACE_DATA + + [StructLayout(LayoutKind.Sequential)] + public struct SP_DEVICE_INTERFACE_DATA + { + public static readonly SP_DEVICE_INTERFACE_DATA Empty = new SP_DEVICE_INTERFACE_DATA(Marshal.SizeOf(typeof (SP_DEVICE_INTERFACE_DATA))); + + public UInt32 cbSize; + public Guid interfaceClassGuid; + public UInt32 flags; + private UIntPtr reserved; + + private SP_DEVICE_INTERFACE_DATA(int size) + { + cbSize = (uint) size; + reserved = UIntPtr.Zero; + flags = 0; + interfaceClassGuid = Guid.Empty; + } + } + + #endregion + + //[StructLayout(LayoutKind.Sequential, Pack = 1)] + //public struct SP_DEVICE_INTERFACE_DATA + //{ + // public static readonly SP_DEVICE_INTERFACE_DATA Empty = new SP_DEVICE_INTERFACE_DATA(GetSetupApiSize(typeof (SP_DEVICE_INTERFACE_DATA))); + + // public readonly uint cbSize; + // public Guid interfaceClassGuid; + // public DeviceInterfaceDataFlags flags; + // private IntPtr reserved; + + // private SP_DEVICE_INTERFACE_DATA(int size) + // { + // reserved = new IntPtr(); + // flags = 0; + // interfaceClassGuid = Guid.Empty; + // cbSize = size; + // } + //} + + #region Nested type: SP_DEVINFO_DATA + + [StructLayout(LayoutKind.Sequential)] + public struct SP_DEVINFO_DATA + { + public static readonly SP_DEVINFO_DATA Empty = new SP_DEVINFO_DATA(Marshal.SizeOf(typeof (SP_DEVINFO_DATA))); + + public UInt32 cbSize; + public Guid ClassGuid; + public UInt32 DevInst; + public IntPtr Reserved; + + private SP_DEVINFO_DATA(int size) + { + cbSize = (uint) size; + ClassGuid = Guid.Empty; + DevInst = 0; + Reserved = IntPtr.Zero; + } + } + + #endregion + + //[StructLayout(LayoutKind.Sequential, Pack = IntPtr.Size==8?8:1, Size = MaxStructSizes.SP_DEVINFO_DATA)] + //public struct SP_DEVINFO_DATA + //{ + // public static readonly SP_DEVINFO_DATA Empty = new SP_DEVINFO_DATA(Marshal.SizeOf(typeof(SP_DEVINFO_DATA))); + + // public readonly int cbSize; + // public Guid ClassGuid; + // public IntPtr DevInst; + // public IntPtr Reserved; + // private SP_DEVINFO_DATA(int size) + // { + // cbSize = size; + // ClassGuid = Guid.Empty; + // DevInst = IntPtr.Zero; + // Reserved = IntPtr.Zero; + + // STRUCT_END_MARK = 0; + // } + //} + + #endregion + } +} \ No newline at end of file diff --git a/LibWinUsb/Internal/TransferContextBase.cs b/LibWinUsb/Internal/TransferContextBase.cs new file mode 100644 index 0000000..e5156fc --- /dev/null +++ b/LibWinUsb/Internal/TransferContextBase.cs @@ -0,0 +1,195 @@ +// Copyright © 2006-2009 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Threading; +using LibUsbDotNet.Main; +using Microsoft.Win32.SafeHandles; + +namespace LibUsbDotNet.Internal +{ + public abstract class TransferContextBase : IDisposable + { + private readonly UsbEndpointBase mEndpointBase; + + private IntPtr mBuffer; + private int mCurrentOffset; + private int mCurrentRemaining; + private int mCurrentTransmitted; + + private int mFailRetries; + protected int mOriginalCount; + protected int mOriginalOffset; + private PinnedHandle mPinnedHandle; + + protected int mTimeout; + + protected bool mHasWaitBeenCalled = true; + + protected ManualResetEvent mTransferCancelEvent = new ManualResetEvent(false); + protected internal ManualResetEvent mTransferCompleteEvent = new ManualResetEvent(true); + + protected TransferContextBase(UsbEndpointBase endpointBase) { mEndpointBase = endpointBase; } + + public UsbEndpointBase EndpointBase + { + get { return mEndpointBase; } + } + + protected int RequestCount + { + get { return (mCurrentRemaining > UsbEndpointBase.MaxReadWrite ? UsbEndpointBase.MaxReadWrite : mCurrentRemaining); } + } + + protected int FailRetries + { + get { return mFailRetries; } + } + + protected IntPtr NextBufPtr + { + get { return new IntPtr(mBuffer.ToInt64() + mCurrentOffset); } + } + + public bool IsCancelled + { + get { return mTransferCancelEvent.WaitOne(0, UsbConstants.EXIT_CONTEXT); } + } + + public bool IsComplete + { + get { return mTransferCompleteEvent.WaitOne(0, UsbConstants.EXIT_CONTEXT); } + } + + public SafeWaitHandle CancelWaitHandle + { + get { return mTransferCancelEvent.SafeWaitHandle; } + } + + public SafeWaitHandle CompleteWaitHandle + { + get { return mTransferCompleteEvent.SafeWaitHandle; } + } + + #region IDisposable Members + + public virtual void Dispose() + { + if (!IsCancelled) Cancel(); + + int dummy; + if (!mHasWaitBeenCalled) Wait(out dummy); + } + + #endregion + + public virtual ErrorCode Cancel() + { + mTransferCancelEvent.Set(); + return ErrorCode.Success; + } + + public abstract ErrorCode Submit(); + + public abstract ErrorCode Wait(out int transferredCount); + + + public virtual void Fill(object buffer, int offset, int count, int timeout) + { + if (mPinnedHandle != null) mPinnedHandle.Dispose(); + mPinnedHandle = new PinnedHandle(buffer); + Fill(mPinnedHandle.Handle, offset, count, timeout); + } + + public virtual void Fill(IntPtr buffer, int offset, int count, int timeout) + { + mBuffer = buffer; + + mOriginalOffset = offset; + mOriginalCount = count; + mTimeout = timeout; + Reset(); + } + + internal static ErrorCode SyncTransfer(TransferContextBase transferContext, + IntPtr buffer, + int offset, + int length, + int timeout, + out int transferLength) + { + if (ReferenceEquals(transferContext, null)) throw new NullReferenceException("Invalid transfer context."); + if (offset < 0) throw new ArgumentException("must be >=0", "offset"); + + lock (transferContext) + { + transferLength = 0; + + int transferred; + ErrorCode ec; + + transferContext.Fill(buffer, offset, length, timeout); + + while (true) + { + ec = transferContext.Submit(); + if (ec == ErrorCode.IoEndpointGlobalCancelRedo) continue; + if (ec != ErrorCode.Success) return ec; + + ec = transferContext.Wait(out transferred); + if (ec == ErrorCode.IoEndpointGlobalCancelRedo) continue; + if (ec != ErrorCode.Success) return ec; + + transferLength += transferred; + + if ((ec != ErrorCode.None || transferred != UsbEndpointBase.MaxReadWrite) || + !transferContext.IncrementTransfer(transferred)) + break; + } + + return ec; + } + } + + public bool IncrementTransfer(int amount) + { + mCurrentTransmitted += amount; + mCurrentOffset += amount; + mCurrentRemaining -= amount; + + if (mCurrentRemaining <= 0) return false; + + return true; + } + + protected void IncFailRetries() { mFailRetries++; } + + public void Reset() + { + mCurrentOffset = mOriginalOffset; + mCurrentRemaining = mOriginalCount; + mCurrentTransmitted = 0; + mFailRetries = 0; + + mTransferCancelEvent.Reset(); + } + } +} \ No newline at end of file diff --git a/LibWinUsb/Internal/UsbApiBase.cs b/LibWinUsb/Internal/UsbApiBase.cs new file mode 100644 index 0000000..3d6e37f --- /dev/null +++ b/LibWinUsb/Internal/UsbApiBase.cs @@ -0,0 +1,81 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; +using LibUsbDotNet.Main; + +namespace LibUsbDotNet.Internal +{ + internal abstract class UsbApiBase + { + public abstract bool AbortPipe(SafeHandle interfaceHandle, byte pipeID); + + public abstract bool ControlTransfer(SafeHandle interfaceHandle, + UsbSetupPacket setupPacket, + IntPtr buffer, + int bufferLength, + out int lengthTransferred); + + public abstract bool FlushPipe(SafeHandle interfaceHandle, byte pipeID); + + public abstract bool GetDescriptor(SafeHandle interfaceHandle, + byte descriptorType, + byte index, + ushort languageID, + IntPtr buffer, + int bufferLength, + out int lengthTransferred); + + + public abstract bool GetOverlappedResult(SafeHandle interfaceHandle, IntPtr pOverlapped, out int numberOfBytesTransferred, bool wait); + + //public abstract bool ReadPipe(UsbEndpointBase endPointBase, + // Byte[] buffer, + // int bufferLength, + // out int lengthTransferred, + // int isoPacketSize, + // IntPtr pOverlapped); + + public abstract bool ReadPipe(UsbEndpointBase endPointBase, + IntPtr pBuffer, + int bufferLength, + out int lengthTransferred, + int isoPacketSize, + IntPtr pOverlapped); + + public abstract bool ResetPipe(SafeHandle interfaceHandle, byte pipeID); + + //public abstract bool WritePipe(UsbEndpointBase endPointBase, + // Byte[] buffer, + // int bufferLength, + // out int lengthTransferred, + // int isoPacketSize, + // IntPtr pOverlapped); + + public abstract bool WritePipe(UsbEndpointBase endPointBase, + IntPtr pBuffer, + int bufferLength, + out int lengthTransferred, + int isoPacketSize, + IntPtr pOverlapped); + } +} \ No newline at end of file diff --git a/LibWinUsb/Internal/UsbRegex/BaseRegSymbolicName.cs b/LibWinUsb/Internal/UsbRegex/BaseRegSymbolicName.cs new file mode 100644 index 0000000..af9b1f3 --- /dev/null +++ b/LibWinUsb/Internal/UsbRegex/BaseRegSymbolicName.cs @@ -0,0 +1,37 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System.Text.RegularExpressions; + +namespace LibUsbDotNet.Internal.UsbRegex +{ + internal class BaseRegSymbolicName : Regex + { + private const RegexOptions OPTIONS = + RegexOptions.CultureInvariant | RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline | RegexOptions.Compiled | + RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase; + + private const string PATTERN = + @"((&){0,1}Vid_(?[0-9A-Fa-f]{1,4})(&){0,1}Pid_(?[0-9A-Fa-f]{1,4})((&){0,1}Rev_(?[0-9A-Fa-f]{1,4})){0,1})((\x23{0,1}\{(?([0-9A-Fa-f]+)-([0-9A-Fa-f]+)-([0-9A-Fa-f]+)-([0-9A-Fa-f]+)-([0-9A-Fa-f]+))})|(\x23(?[\x20-\x22\x24-\x2b\x2d-\x7f]+?)(?=\x23|$)))*"; + + public BaseRegSymbolicName() : base(PATTERN, OPTIONS) { } + } +} \ No newline at end of file diff --git a/LibWinUsb/Internal/UsbRegex/NamedGroup.cs b/LibWinUsb/Internal/UsbRegex/NamedGroup.cs new file mode 100644 index 0000000..dbd9c97 --- /dev/null +++ b/LibWinUsb/Internal/UsbRegex/NamedGroup.cs @@ -0,0 +1,35 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +namespace LibUsbDotNet.Internal.UsbRegex +{ + internal struct NamedGroup + { + public readonly string GroupName; + public readonly int GroupNumber; + + public NamedGroup(int GroupNumber, string GroupName) + { + this.GroupNumber = GroupNumber; + this.GroupName = GroupName; + } + } +} \ No newline at end of file diff --git a/LibWinUsb/Internal/UsbRegex/RegHardwareID.cs b/LibWinUsb/Internal/UsbRegex/RegHardwareID.cs new file mode 100644 index 0000000..253e977 --- /dev/null +++ b/LibWinUsb/Internal/UsbRegex/RegHardwareID.cs @@ -0,0 +1,105 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Text.RegularExpressions; + +namespace LibUsbDotNet.Internal.UsbRegex +{ + /// + /// Regular expression class for quick parsing of usb hardware ids. + /// + internal class RegHardwareID : Regex + { + #region Enumerations + + public enum ENamedGroups + { + Vid = 1, + Pid = 2, + Rev = 3, + MI= 4 + } + + #endregion + + private const RegexOptions OPTIONS = + RegexOptions.CultureInvariant | RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline | RegexOptions.Compiled | + RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase; + + private const string PATTERN = "(Vid_(?[0-9A-F]{1,4}))|(Pid_(?[0-9A-F]{1,4}))|(Rev_(?[0-9]{1,4}))|(MI_(?[0-9A-F]{1,2}))"; + + public static readonly NamedGroup[] NAMED_GROUPS = new NamedGroup[] + { + new NamedGroup(1, "Vid"), new NamedGroup(2, "Pid"), new NamedGroup(3, "Rev"), + new NamedGroup(4, "MI") + }; + + public RegHardwareID() : base(PATTERN, OPTIONS) { } + + private static RegHardwareID __globalInstance; + public static RegHardwareID GlobalInstance + { + get + { + if (ReferenceEquals(__globalInstance,null)) + __globalInstance=new RegHardwareID(); + return __globalInstance; + } + } + + public new string[] GetGroupNames() { return new string[] {"Vid", "Pid", "Rev", "MI"}; } + + public new int[] GetGroupNumbers() { return new int[] {1, 2, 3, 4}; } + + public new string GroupNameFromNumber(int GroupNumber) + { + switch (GroupNumber) + { + case 1: + return "Vid"; + case 2: + return "Pid"; + case 3: + return "Rev"; + case 4: + return "MI"; + } + return ""; + } + + public new int GroupNumberFromName(string GroupName) + { + switch (GroupName) + { + case "Vid": + return 1; + case "Pid": + return 2; + case "Rev": + return 3; + case "MI": + return 4; + } + return -1; + } + } +} \ No newline at end of file diff --git a/LibWinUsb/Internal/UsbRegex/RegSymbolicName.cs b/LibWinUsb/Internal/UsbRegex/RegSymbolicName.cs new file mode 100644 index 0000000..44cd56a --- /dev/null +++ b/LibWinUsb/Internal/UsbRegex/RegSymbolicName.cs @@ -0,0 +1,95 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +namespace LibUsbDotNet.Internal.UsbRegex +{ + /// + /// Regular expression class for parsing USB symbolic names and hardware ids. + /// + internal class RegSymbolicName : BaseRegSymbolicName + { + public static readonly NamedGroup[] NamedGroups = new NamedGroup[] + { + new NamedGroup(1, "Vid"), + new NamedGroup(2, "Pid"), + new NamedGroup(3, "Rev"), + new NamedGroup(4, "ClassGuid"), + new NamedGroup(5, "String"), + }; + + public new string[] GetGroupNames() { return new string[] {"Vid", "Pid", "Rev", "ClassGuid", "String"}; } + + public new int[] GetGroupNumbers() { return new int[] {1, 2, 3, 4, 5}; } + + public new string GroupNameFromNumber(int groupNumber) + { + switch (groupNumber) + { + case 1: + return "Vid"; + + case 2: + return "Pid"; + + case 3: + return "Rev"; + + case 4: + return "ClassGuid"; + + case 5: + return "String"; + } + return ""; + } + + public new int GroupNumberFromName(string groupName) + { + switch (groupName.ToLower()) + { + case "vid": + return 1; + + case "pid": + return 2; + + case "rev": + return 3; + + case "classguid": + return 4; + + case "string": + return 5; + } + return -1; + } + } + + internal enum NamedGroupType + { + Vid = 1, + Pid = 2, + Rev = 3, + ClassGuid = 4, + String = 5, + } +} \ No newline at end of file diff --git a/LibWinUsb/LibUsb/Internal/LibUsbAPI.cs b/LibWinUsb/LibUsb/Internal/LibUsbAPI.cs new file mode 100644 index 0000000..ce557af --- /dev/null +++ b/LibWinUsb/LibUsb/Internal/LibUsbAPI.cs @@ -0,0 +1,151 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; +using LibUsbDotNet.Main; + +namespace LibUsbDotNet.Internal.LibUsb +{ + internal class LibUsbAPI : UsbApiBase + { + public override bool AbortPipe(SafeHandle interfaceHandle, byte pipeID) + { + LibUsbRequest req = new LibUsbRequest(); + + int ret; + req.Endpoint.ID = pipeID; + req.Timeout = UsbConstants.DEFAULT_TIMEOUT; + return LibUsbDriverIO.UsbIOSync(interfaceHandle, LibUsbIoCtl.ABORT_ENDPOINT, req, LibUsbRequest.Size, IntPtr.Zero, 0, out ret); + } + + public bool ResetDevice(SafeHandle interfaceHandle) + { + LibUsbRequest req = new LibUsbRequest(); + + int ret; + req.Timeout = UsbConstants.DEFAULT_TIMEOUT; + return LibUsbDriverIO.UsbIOSync(interfaceHandle, LibUsbIoCtl.RESET_DEVICE, req, LibUsbRequest.Size, IntPtr.Zero, 0, out ret); + } + + public override bool ControlTransfer(SafeHandle interfaceHandle, + UsbSetupPacket setupPacket, + IntPtr buffer, + int bufferLength, + out int lengthTransferred) + { + return LibUsbDriverIO.ControlTransfer(interfaceHandle, + setupPacket, + buffer, + bufferLength, + out lengthTransferred, + UsbConstants.DEFAULT_TIMEOUT); + } + + public override bool FlushPipe(SafeHandle interfaceHandle, byte pipeID) { return true; } + + + public override bool GetDescriptor(SafeHandle interfaceHandle, + byte descriptorType, + byte index, + ushort languageID, + IntPtr buffer, + int bufferLength, + out int lengthTransferred) + { + LibUsbRequest req = new LibUsbRequest(); + req.Descriptor.Index = index; + req.Descriptor.LangID = languageID; + req.Descriptor.Recipient = (byte) UsbEndpointDirection.EndpointIn & 0x1F; + req.Descriptor.Type = descriptorType; + return LibUsbDriverIO.UsbIOSync(interfaceHandle, + LibUsbIoCtl.GET_DESCRIPTOR, + req, + LibUsbRequest.Size, + buffer, + bufferLength, + out lengthTransferred); + } + + + public override bool GetOverlappedResult(SafeHandle interfaceHandle, IntPtr pOverlapped, out int numberOfBytesTransferred, bool wait) { return Kernel32.GetOverlappedResult(interfaceHandle, pOverlapped, out numberOfBytesTransferred, wait); } + + + public override bool ReadPipe(UsbEndpointBase endPointBase, + IntPtr buffer, + int bufferLength, + out int lengthTransferred, + int isoPacketSize, + IntPtr pOverlapped) + { + LibUsbRequest req = new LibUsbRequest(); + req.Endpoint.ID = endPointBase.EpNum; + req.Endpoint.PacketSize = isoPacketSize; + req.Timeout = UsbConstants.DEFAULT_TIMEOUT; + + int cltCode = endPointBase.Type == EndpointType.Isochronous ? LibUsbIoCtl.ISOCHRONOUS_READ : LibUsbIoCtl.INTERRUPT_OR_BULK_READ; + + + return Kernel32.DeviceIoControl(endPointBase.Device.Handle, + cltCode, + req, + LibUsbRequest.Size, + buffer, + bufferLength, + out lengthTransferred, + pOverlapped); + } + + public override bool ResetPipe(SafeHandle interfaceHandle, byte pipeID) + { + LibUsbRequest req = new LibUsbRequest(); + + int ret; + req.Endpoint.ID = pipeID; + req.Timeout = UsbConstants.DEFAULT_TIMEOUT; + return LibUsbDriverIO.UsbIOSync(interfaceHandle, LibUsbIoCtl.RESET_ENDPOINT, req, LibUsbRequest.Size, IntPtr.Zero, 0, out ret); + } + + + public override bool WritePipe(UsbEndpointBase endPointBase, + IntPtr buffer, + int bufferLength, + out int lengthTransferred, + int isoPacketSize, + IntPtr pOverlapped) + { + LibUsbRequest req = new LibUsbRequest(); + req.Endpoint.ID = endPointBase.EpNum; + req.Endpoint.PacketSize = isoPacketSize; + req.Timeout = UsbConstants.DEFAULT_TIMEOUT; + int cltCode = endPointBase.Type == EndpointType.Isochronous ? LibUsbIoCtl.ISOCHRONOUS_WRITE : LibUsbIoCtl.INTERRUPT_OR_BULK_WRITE; + + return Kernel32.DeviceIoControl(endPointBase.Handle, + cltCode, + req, + LibUsbRequest.Size, + buffer, + bufferLength, + out lengthTransferred, + pOverlapped); + } + } +} \ No newline at end of file diff --git a/LibWinUsb/LibUsb/Internal/LibUsbDriverIO.cs b/LibWinUsb/LibUsb/Internal/LibUsbDriverIO.cs new file mode 100644 index 0000000..a87fd6a --- /dev/null +++ b/LibWinUsb/LibUsb/Internal/LibUsbDriverIO.cs @@ -0,0 +1,100 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; +using System.Threading; +using LibUsbDotNet.Main; +using Microsoft.Win32.SafeHandles; + +namespace LibUsbDotNet.Internal.LibUsb +{ + internal partial class LibUsbDriverIO + { + public const int ERROR_IO_PENDING = 997; + public const int FALSE = 0; + public const int FILE_FLAG_OVERLAPPED = 0x40000000; + internal const string LIBUSB_DEVICE_NAME = "\\\\.\\libusb0-"; + public const int TRUE = 1; + + private static byte[] _tempCfgBuf; + + internal static byte[] GlobalTempCfgBuffer + { + get + { + if (ReferenceEquals(null, _tempCfgBuf)) + _tempCfgBuf = new byte[4096]; + + return _tempCfgBuf; + } + } + + + internal static string GetDeviceNameString(int index) { return String.Format("{0}{1}", LIBUSB_DEVICE_NAME, index.ToString("0000")); } + + internal static SafeFileHandle OpenDevice(String deviceFileName) + { + return Kernel32.CreateFile(deviceFileName, + NativeFileAccess.SPECIAL, + NativeFileShare.NONE, + IntPtr.Zero, + NativeFileMode.OPEN_EXISTING, + NativeFileFlag.FILE_FLAG_OVERLAPPED, + IntPtr.Zero); + } + + + internal static bool UsbIOSync(SafeHandle dev, int code, Object inBuffer, int inSize, IntPtr outBuffer, int outSize, out int ret) + { + SafeOverlapped deviceIoOverlapped = new SafeOverlapped(); + ManualResetEvent hEvent = new ManualResetEvent(false); + deviceIoOverlapped.ClearAndSetEvent(hEvent.SafeWaitHandle.DangerousGetHandle()); + ret = 0; + + if (!Kernel32.DeviceIoControlAsObject(dev, code, inBuffer, inSize, outBuffer, outSize, ref ret, deviceIoOverlapped.GlobalOverlapped)) + { + int iError = Marshal.GetLastWin32Error(); + if (iError != ERROR_IO_PENDING) + { + // Don't log errors for these control codes. + do + { + if (code == LibUsbIoCtl.GET_REG_PROPERTY) break; + if (code == LibUsbIoCtl.GET_CUSTOM_REG_PROPERTY) break; + UsbError.Error(ErrorCode.Win32Error, iError, String.Format("DeviceIoControl code {0:X8} failed:{1}", code, Kernel32.FormatSystemMessage(iError)), typeof(LibUsbDriverIO)); + } while (false); + + hEvent.Close(); + return false; + } + } + if (Kernel32.GetOverlappedResult(dev, deviceIoOverlapped.GlobalOverlapped, out ret, true)) + { + hEvent.Close(); + return true; + } + UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "GetOverlappedResult failed.\nIoCtlCode:" + code, typeof(LibUsbDriverIO)); + hEvent.Close(); + return false; + } + } +} \ No newline at end of file diff --git a/LibWinUsb/LibUsb/Internal/LibUsbDriverIO_IOControlMessage.cs b/LibWinUsb/LibUsb/Internal/LibUsbDriverIO_IOControlMessage.cs new file mode 100644 index 0000000..8018707 --- /dev/null +++ b/LibWinUsb/LibUsb/Internal/LibUsbDriverIO_IOControlMessage.cs @@ -0,0 +1,199 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; +using LibUsbDotNet.Main; + +namespace LibUsbDotNet.Internal.LibUsb +{ + internal partial class LibUsbDriverIO + { + public const int EINVAL = 22; + + internal static bool ControlTransferEx(SafeHandle interfaceHandle, + UsbSetupPacket setupPacket, + IntPtr buffer, + int bufferLength, + out int lengthTransferred, + int timeout) + { + lengthTransferred = 0; + LibUsbRequest req = new LibUsbRequest(); + + req.Timeout = timeout; + req.Control.RequestType = (byte) setupPacket.RequestType; + req.Control.Request = (byte) setupPacket.Request; + req.Control.Value = (ushort) setupPacket.Value; + req.Control.Index = (ushort) setupPacket.Index; + req.Control.Length = (ushort) setupPacket.Length; + + /* in request? */ + Byte[] reqBytes = req.Bytes; + Byte[] inBytes = reqBytes; + if ((setupPacket.RequestType & (byte) UsbEndpointDirection.EndpointIn) == 0) + { + inBytes = new byte[LibUsbRequest.Size + bufferLength]; + reqBytes.CopyTo(inBytes, 0); + if (buffer != IntPtr.Zero) Marshal.Copy(buffer, inBytes, LibUsbRequest.Size, bufferLength); + + buffer = IntPtr.Zero; + bufferLength = 0; + } + + if (UsbIOSync(interfaceHandle, LibUsbIoCtl.CONTROL_TRANSFER, inBytes, inBytes.Length, buffer, bufferLength, out lengthTransferred)) + { + /* in request? */ + if ((setupPacket.RequestType & (byte)UsbEndpointDirection.EndpointIn) == 0) + lengthTransferred = (inBytes.Length - reqBytes.Length); + + return true; + } + return false; + } + + internal static bool ControlTransfer(SafeHandle interfaceHandle, + UsbSetupPacket setupPacket, + IntPtr buffer, + int bufferLength, + out int lengthTransferred, + int timeout) + { + lengthTransferred = 0; + LibUsbRequest req = new LibUsbRequest(); + int code; + + req.Timeout = timeout; + + switch ((UsbRequestType)(setupPacket.RequestType & (0x03 << 5))) + { + case UsbRequestType.TypeStandard: + switch ((UsbStandardRequest)setupPacket.Request) + { + case UsbStandardRequest.GetStatus: + req.Status.Recipient = (int) setupPacket.RequestType & 0x1F; + req.Status.Index = setupPacket.Index; + code = LibUsbIoCtl.GET_STATUS; + break; + + case UsbStandardRequest.ClearFeature: + req.Feature.Recipient = (int) setupPacket.RequestType & 0x1F; + req.Feature.ID = setupPacket.Value; + req.Feature.Index = setupPacket.Index; + code = LibUsbIoCtl.CLEAR_FEATURE; + break; + + case UsbStandardRequest.SetFeature: + req.Feature.Recipient = (int) setupPacket.RequestType & 0x1F; + req.Feature.ID = setupPacket.Value; + req.Feature.Index = setupPacket.Index; + code = LibUsbIoCtl.SET_FEATURE; + break; + + case UsbStandardRequest.GetDescriptor: + req.Descriptor.Recipient = (int) setupPacket.RequestType & 0x1F; + req.Descriptor.Type = (setupPacket.Value >> 8) & 0xFF; + req.Descriptor.Index = setupPacket.Value & 0xFF; + req.Descriptor.LangID = setupPacket.Index; + code = LibUsbIoCtl.GET_DESCRIPTOR; + break; + + case UsbStandardRequest.SetDescriptor: + req.Descriptor.Recipient = (int) setupPacket.RequestType & 0x1F; + req.Descriptor.Type = (setupPacket.Value >> 8) & 0xFF; + req.Descriptor.Index = setupPacket.Value & 0xFF; + req.Descriptor.LangID = setupPacket.Index; + code = LibUsbIoCtl.SET_DESCRIPTOR; + break; + + case UsbStandardRequest.GetConfiguration: + code = LibUsbIoCtl.GET_CONFIGURATION; + break; + + case UsbStandardRequest.SetConfiguration: + req.Config.ID = setupPacket.Value; + code = LibUsbIoCtl.SET_CONFIGURATION; + break; + + case UsbStandardRequest.GetInterface: + req.Iface.ID = setupPacket.Index; + code = LibUsbIoCtl.GET_INTERFACE; + break; + + case UsbStandardRequest.SetInterface: + req.Iface.ID = setupPacket.Index; + req.Iface.AlternateID = setupPacket.Value; + code = LibUsbIoCtl.SET_INTERFACE; + break; + + default: + UsbError.Error(ErrorCode.IoControlMessage,0, + String.Format("Invalid request: 0x{0:X8}", setupPacket.Request), + typeof(LibUsbDriverIO)); + return false; + } + break; + + case UsbRequestType.TypeVendor: + case UsbRequestType.TypeClass: + + req.Vendor.Type = ((byte) setupPacket.RequestType >> 5) & 0x03; + req.Vendor.Recipient = (int) setupPacket.RequestType & 0x1F; + req.Vendor.Request = (int) setupPacket.Request; + req.Vendor.ID = setupPacket.Value; + req.Vendor.Index = setupPacket.Index; + + code = ((byte) setupPacket.RequestType & 0x80) > 0 ? LibUsbIoCtl.VENDOR_READ : LibUsbIoCtl.VENDOR_WRITE; + break; + + case UsbRequestType.TypeReserved: + default: + UsbError.Error(ErrorCode.IoControlMessage,0, + String.Format("invalid or unsupported request type: 0x{0:X8}", setupPacket.RequestType), + typeof(LibUsbDriverIO)); + return false; + } + + /* in request? */ + Byte[] reqBytes = req.Bytes; + Byte[] inBytes = reqBytes; + if ((setupPacket.RequestType & (byte)UsbEndpointDirection.EndpointIn) == 0) + { + inBytes = new byte[LibUsbRequest.Size + bufferLength]; + reqBytes.CopyTo(inBytes, 0); + if (buffer != IntPtr.Zero) Marshal.Copy(buffer, inBytes, LibUsbRequest.Size, bufferLength); + + buffer = IntPtr.Zero; + bufferLength = 0; + } + + if (UsbIOSync(interfaceHandle, code, inBytes, inBytes.Length, buffer, bufferLength, out lengthTransferred)) + { + /* in request? */ + if ((setupPacket.RequestType & (byte)UsbEndpointDirection.EndpointIn) == 0) + lengthTransferred = (inBytes.Length - reqBytes.Length); + + return true; + } + return false; + } + } +} \ No newline at end of file diff --git a/LibWinUsb/LibUsb/Internal/LibUsbIoCtl.cs b/LibWinUsb/LibUsb/Internal/LibUsbIoCtl.cs new file mode 100644 index 0000000..f0707af --- /dev/null +++ b/LibWinUsb/LibUsb/Internal/LibUsbIoCtl.cs @@ -0,0 +1,65 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +namespace LibUsbDotNet.Internal.LibUsb +{ + internal 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_NEITHER = 3; + private const int METHOD_OUT_DIRECT = 2; + + 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); } + } +} \ No newline at end of file diff --git a/LibWinUsb/LibUsb/Internal/LibUsbRequest.cs b/LibWinUsb/LibUsb/Internal/LibUsbRequest.cs new file mode 100644 index 0000000..fe151ef --- /dev/null +++ b/LibWinUsb/LibUsb/Internal/LibUsbRequest.cs @@ -0,0 +1,195 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; +using LibUsbDotNet.Descriptors; +using LibUsbDotNet.Main; + +namespace LibUsbDotNet.Internal.LibUsb +{ + [StructLayout(LayoutKind.Explicit, Pack = 1, Size = sizeof (int)*6)] + internal class 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) DescriptorType.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) DescriptorType.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)] + internal struct Descriptor + { + public int Type; + public int Index; + public int LangID; + public int Recipient; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct Config + { + public int ID; + } ; + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct Control + { + public byte RequestType; + public byte Request; + public ushort Value; + public ushort Index; + public ushort Length; + } ; + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct DeviceProperty + { + public int ID; + } ; + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct Iface + { + public int ID; + public int AlternateID; + } ; + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct Endpoint + { + public int ID; + public int PacketSize; + } ; + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct Vendor + { + public int Type; + public int Recipient; + public int Request; + public int ID; + public int Index; + } ; + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct Feature + { + public int Recipient; + public int ID; + public int Index; + } ; + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct Status + { + public int Recipient; + public int Index; + public int ID; + } ; + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct Debug + { + public int Level; + } ; + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct DeviceRegKey + { + public int KeyType; + public int NameOffset; + public int ValueOffset; + public int ValueLength; + } ; + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct BusQueryID + { + public ushort IDType; + } ; + +} \ No newline at end of file diff --git a/LibWinUsb/LibUsb/LibUsbDevice.cs b/LibWinUsb/LibUsb/LibUsbDevice.cs new file mode 100644 index 0000000..f154ef3 --- /dev/null +++ b/LibWinUsb/LibUsb/LibUsbDevice.cs @@ -0,0 +1,320 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using LibUsbDotNet.Info; +using LibUsbDotNet.Internal; +using LibUsbDotNet.Internal.LibUsb; +using LibUsbDotNet.Main; +using Microsoft.Win32.SafeHandles; + +namespace LibUsbDotNet.LibUsb +{ + /// Contains members that are specific to the LibUsb-Win32 driver. + /// + /// Use the class instead to allow your code to work with either LibUsb or WinUsb. + /// + public class LibUsbDevice : UsbDevice, IUsbDevice + { + private readonly List mClaimedInterfaces = new List(); + private readonly string mDeviceFilename; + + + internal LibUsbDevice(UsbApiBase api, SafeHandle usbHandle, string deviceFilename) + : base(api, usbHandle) { mDeviceFilename = deviceFilename; } + + /// + /// Gets a list of libusb devices directly from the kernel; bypassing the windows registry. + /// This function is intended for users that do not use the native kernel driver. + /// If using the native kernel (sys) driver supplied with LibUsbDotNet see the . + /// + /// + /// + /// + /// + public static List LegacyLibUsbDeviceList + { + get + { + List deviceList = new List(); + for (int i = 1; i < UsbConstants.MAX_DEVICES; i++) + { + LibUsbDevice newLibUsbDevice; + string deviceFileName = LibUsbDriverIO.GetDeviceNameString(i); + if (!Open(deviceFileName, out newLibUsbDevice)) continue; + + newLibUsbDevice.mDeviceInfo = new UsbDeviceInfo(newLibUsbDevice); + newLibUsbDevice.Close(); + deviceList.Add(newLibUsbDevice); + } + + return deviceList; + } + } + + + /// + /// Gets the Device filename for this device. + /// + public string DeviceFilename + { + get { return mDeviceFilename; } + } + + #region IUsbDevice Members + + /// + /// Opens the USB device handle. + /// + /// + ///True if the device is already opened or was opened successfully. + ///False if the device does not exists or is no longer valid. + /// + public override bool Open() + { + if (IsOpen) return true; + + mUsbHandle = LibUsbDriverIO.OpenDevice(mDeviceFilename); + if (!IsOpen) + { + UsbError.Error(ErrorCode.Win32Error,Marshal.GetLastWin32Error(), "LibUsbDevice.Open Failed", this); + return false; + } + return true; + } + + /// + /// Claims the specified interface of the device. + /// + /// The interface to claim. + /// True on success. + public bool ClaimInterface(int interfaceID) + { + if (mClaimedInterfaces.Contains(interfaceID)) return true; + + LibUsbRequest req = new LibUsbRequest(); + req.Iface.ID = interfaceID; + req.Timeout = UsbConstants.DEFAULT_TIMEOUT; + + int ret; + bool bSuccess = UsbIoSync(LibUsbIoCtl.CLAIM_INTERFACE, req, LibUsbRequest.Size, IntPtr.Zero, 0, out ret); + if (bSuccess) + mClaimedInterfaces.Add(interfaceID); + + return bSuccess; + } + + /// + /// Returns the DriverMode this USB device is using. + /// + public override DriverModeType DriverMode + { + get { return DriverModeType.LibUsb; } + } + + /// + /// Closes the and disposes any . + /// + /// True on success. + public override bool Close() + { + if (IsOpen) + { + ReleaseAllInterfaces(); + ActiveEndpoints.Clear(); + mUsbHandle.Close(); + } + return true; + } + + /// + /// Releases an interface that was previously claimed with . + /// + /// The interface to release. + /// True on success. + public bool ReleaseInterface(int interfaceID) + { + LibUsbRequest req = new LibUsbRequest(); + req.Iface.ID = interfaceID; + if (!mClaimedInterfaces.Remove(interfaceID)) return true; + + req.Timeout = UsbConstants.DEFAULT_TIMEOUT; + + int ret; + // NOTE: A claimed interface is ALWAYS removed from the internal list. + bool bSuccess = UsbIoSync(LibUsbIoCtl.RELEASE_INTERFACE, req, LibUsbRequest.Size, IntPtr.Zero, 0, out ret); + + return bSuccess; + } + + + /// + /// Sets an alternate interface for the most recent claimed interface. + /// + /// The alternate interface to select for the most recent claimed interface See . + /// True on success. + public bool SetAltInterface(int alternateID) + { + if (mClaimedInterfaces.Count == 0) throw new UsbException(this, "You must claim an interface before setting an alternate interface."); + return SetAltInterface(mClaimedInterfaces[mClaimedInterfaces.Count - 1], alternateID); + } + + /// + /// Sets the USB devices active configuration value. + /// + /// The active configuration value. A zero value means the device is not configured and a non-zero value indicates the device is configured. + /// True on success. + /// + /// A USB device can have several different configurations, but only one active configuration. + /// + public bool SetConfiguration(byte config) + { + int uTransferLength; + + UsbSetupPacket setupPkt = new UsbSetupPacket(); + setupPkt.RequestType = (byte)UsbEndpointDirection.EndpointOut | (byte)UsbRequestType.TypeStandard | (byte)UsbRequestRecipient.RecipDevice; + setupPkt.Request = (byte)UsbStandardRequest.SetConfiguration; + setupPkt.Value = config; + setupPkt.Index = 0; + setupPkt.Length = 0; + + bool bSuccess = ControlTransfer(ref setupPkt, null, 0, out uTransferLength); + if (bSuccess) + mCurrentConfigValue = config; + else + UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "SetConfiguration", this); + + return bSuccess; + } + + #endregion + + /// + /// Opens the USB device for communucation. + /// + /// The LibUsb device filename to open. + /// The newly created UsbDevice. + /// True on success. + public static bool Open(string deviceFilename, out LibUsbDevice usbDevice) + { + usbDevice = null; + SafeFileHandle sfh = LibUsbDriverIO.OpenDevice(deviceFilename); + if (!sfh.IsClosed && !sfh.IsInvalid) + { + usbDevice = new LibUsbDevice(LibUsbApi, sfh, deviceFilename); + return true; + } + else + { +// UsbDevice.Error(ErrorCode.DeviceNotFound, "The device is no longer attached or failed to open.", typeof(LibUsbDevice)); + } + return false; + } + + /// + /// Releases all interface claimed by . + /// + /// True on success. + public int ReleaseAllInterfaces() + { + int claimedInterfaces = 0; + while (mClaimedInterfaces.Count > 0) + { + claimedInterfaces++; + ReleaseInterface(mClaimedInterfaces[mClaimedInterfaces.Count - claimedInterfaces]); + } + + return claimedInterfaces; + } + + /// + /// Releases the last interface claimed by . + /// + /// True on success. + public bool ReleaseInterface() + { + //throw new UsbException(this, "You must claim an interface before releasing an interface."); + if (mClaimedInterfaces.Count == 0) return true; + return ReleaseInterface(mClaimedInterfaces[mClaimedInterfaces.Count - 1]); + } + + /// + /// Sets an alternate interface for the specified interface. + /// + /// The interface index to specify an alternate setting for. + /// The alternate interface setting. + /// True on success. + public bool SetAltInterface(int interfaceID, int alternateID) + { + if (!mClaimedInterfaces.Contains(interfaceID)) + throw new UsbException(this, String.Format("You must claim interface {0} before setting an alternate interface.", interfaceID)); + LibUsbRequest req = new LibUsbRequest(); + req.Iface.ID = interfaceID; + req.Iface.AlternateID = alternateID; + req.Timeout = UsbConstants.DEFAULT_TIMEOUT; + + int ret; + return UsbIoSync(LibUsbIoCtl.SET_INTERFACE, req, LibUsbRequest.Size, IntPtr.Zero, 0, out ret); + } + + /// + /// Sends a usb device reset command. + /// + /// + /// After calling , the instance is disposed and + /// no longer usable. A new instance must be obtained from the device list. + /// + /// True on success. + public bool ResetDevice() + { + bool bSuccess; + if (!IsOpen) throw new UsbException(this, "Device is not opened."); + ActiveEndpoints.Clear(); + + if ((bSuccess = LibUsbApi.ResetDevice(mUsbHandle))!=true) + { + UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "ResetDevice Failed", this); + } + else + { + Close(); + } + + return bSuccess; + } + + internal bool ControlTransferEx(UsbSetupPacket setupPacket, + IntPtr buffer, + int bufferLength, + out int lengthTransferred, + int timeout) + { + bool bSuccess = LibUsbDriverIO.ControlTransferEx(mUsbHandle, setupPacket, buffer, bufferLength, out lengthTransferred, timeout); + + + return bSuccess; + } + + internal bool UsbIoSync(int controlCode, Object inBuffer, int inSize, IntPtr outBuffer, int outSize, out int ret) { return LibUsbDriverIO.UsbIOSync(mUsbHandle, controlCode, inBuffer, inSize, outBuffer, outSize, out ret); } + } +} \ No newline at end of file diff --git a/LibWinUsb/LibUsb/LibUsbDeviceRegistryKeyRequest.cs b/LibWinUsb/LibUsb/LibUsbDeviceRegistryKeyRequest.cs new file mode 100644 index 0000000..e5ee007 --- /dev/null +++ b/LibWinUsb/LibUsb/LibUsbDeviceRegistryKeyRequest.cs @@ -0,0 +1,116 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Text; +using LibUsbDotNet.Internal.LibUsb; +using LibUsbDotNet.Main; + +namespace LibUsbDotNet.LibUsb +{ + internal static class LibUsbDeviceRegistryKeyRequest + { + public static byte[] RegGetRequest(string name, int valueBufferSize) + { + if (valueBufferSize < 1 || name.Trim().Length == 0) throw new UsbException("Global", "Invalid DeviceRegistry het parameter."); + + LibUsbRequest req = new LibUsbRequest(); + int uOffset = LibUsbRequest.Size; + req.DeviceRegKey.KeyType = (int) KeyType.RegBinary; + + byte[] bytesName = Encoding.Unicode.GetBytes(name + "\0"); + + req.DeviceRegKey.NameOffset = uOffset; + uOffset += bytesName.Length; + req.DeviceRegKey.ValueOffset = uOffset; + req.DeviceRegKey.ValueLength = (valueBufferSize); + + uOffset += Math.Max(uOffset + 1, valueBufferSize - (LibUsbRequest.Size + bytesName.Length)); + byte[] buffer = new byte[uOffset]; + byte[] regBytes = req.Bytes; + + Array.Copy(regBytes, buffer, regBytes.Length); + Array.Copy(bytesName, 0, buffer, req.DeviceRegKey.NameOffset, bytesName.Length); + + return buffer; + } + + public static byte[] RegSetBinaryRequest(string name, byte[] value) + { + LibUsbRequest req = new LibUsbRequest(); + int uOffset = LibUsbRequest.Size; + req.DeviceRegKey.KeyType = (int) KeyType.RegBinary; + + byte[] bytesName = Encoding.Unicode.GetBytes(name + "\0"); + byte[] bytesValue = value; + + req.DeviceRegKey.NameOffset = uOffset; + uOffset += bytesName.Length; + req.DeviceRegKey.ValueOffset = uOffset; + req.DeviceRegKey.ValueLength = bytesValue.Length; + + uOffset += bytesValue.Length; + byte[] buffer = new byte[uOffset]; + byte[] regBytes = req.Bytes; + + Array.Copy(regBytes, buffer, regBytes.Length); + Array.Copy(bytesName, 0, buffer, req.DeviceRegKey.NameOffset, bytesName.Length); + Array.Copy(bytesValue, 0, buffer, req.DeviceRegKey.ValueOffset, bytesValue.Length); + + return buffer; + } + + public static byte[] RegSetStringRequest(string name, string value) + { + LibUsbRequest req = new LibUsbRequest(); + int uOffset = LibUsbRequest.Size; + req.DeviceRegKey.KeyType = (int) KeyType.RegSz; + + byte[] bytesName = Encoding.Unicode.GetBytes(name + "\0"); + byte[] bytesValue = Encoding.Unicode.GetBytes(value + "\0"); + + req.DeviceRegKey.NameOffset = uOffset; + uOffset += bytesName.Length; + req.DeviceRegKey.ValueOffset = uOffset; + req.DeviceRegKey.ValueLength = bytesValue.Length; + + uOffset += bytesValue.Length; + byte[] buffer = new byte[uOffset]; + byte[] regBytes = req.Bytes; + + Array.Copy(regBytes, buffer, regBytes.Length); + Array.Copy(bytesName, 0, buffer, req.DeviceRegKey.NameOffset, bytesName.Length); + Array.Copy(bytesValue, 0, buffer, req.DeviceRegKey.ValueOffset, bytesValue.Length); + + return buffer; + } + + #region Nested Types + + private enum KeyType + { + RegSz = 1, // Unicode nul terminated string + RegBinary = 3, // Free form binary + } + + #endregion + } +} \ No newline at end of file diff --git a/LibWinUsb/LibUsb/LibUsbKernelType.cs b/LibWinUsb/LibUsb/LibUsbKernelType.cs new file mode 100644 index 0000000..5a486b2 --- /dev/null +++ b/LibWinUsb/LibUsb/LibUsbKernelType.cs @@ -0,0 +1,46 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +namespace LibUsbDotNet.LibUsb +{ + /// + /// Kernel types supported by LibUsbDotNet. See for more details. + /// + public enum LibUsbKernelType + { + /// + /// LibUsb support us unavailable. + /// + Unknown, + /// + /// LibUsbDotNet native kernel driver detected. + /// + NativeLibUsb, + /// + /// Original libusb-win32 kernel driver detected. + /// + LegacyLibUsb, + /// + /// mono-linux libusb 1.x driver detected. + /// + MonoLibUsb + } +} \ No newline at end of file diff --git a/LibWinUsb/LibUsb/LibUsbRegistry.cs b/LibWinUsb/LibUsb/LibUsbRegistry.cs new file mode 100644 index 0000000..5204fd1 --- /dev/null +++ b/LibWinUsb/LibUsb/LibUsbRegistry.cs @@ -0,0 +1,321 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using LibUsbDotNet.Internal.LibUsb; +using LibUsbDotNet.Main; +using Microsoft.Win32.SafeHandles; +using Debug=System.Diagnostics.Debug; + +namespace LibUsbDotNet.LibUsb +{ + /// LibUsb specific members for device registry settings. + /// + public class LibUsbRegistry : UsbRegistry + { + private readonly string mDeviceFilename; + private readonly int mDeviceIndex; + + private LibUsbRegistry(SafeFileHandle usbHandle, string deviceFileName, int deviceIndex) + { + mDeviceFilename = deviceFileName; + mDeviceIndex = deviceIndex; + GetPropertiesSPDRP(usbHandle); + string symbolicName; + + if (GetCustomDeviceKeyValue(usbHandle, SYMBOLIC_NAME_KEY, out symbolicName, 512) == ErrorCode.None) + { + mDeviceProperties.Add(SYMBOLIC_NAME_KEY, symbolicName); + } + + // If the SymbolicName key does not exists, use the first HardwareID string. + if (!mDeviceProperties.ContainsKey(SYMBOLIC_NAME_KEY) || String.IsNullOrEmpty(symbolicName)) + { + string[] hwIDs = mDeviceProperties[SPDRP.HardwareId.ToString()] as string[]; + + if ((hwIDs == null) || hwIDs.Length==0) + { + LibUsbDevice usbDevice = new LibUsbDevice(UsbDevice.LibUsbApi, usbHandle, deviceFileName); + LegacyUsbRegistry.GetPropertiesSPDRP(usbDevice, mDeviceProperties); + return; + } + + if (hwIDs.Length > 0) + { + mDeviceProperties.Add(SYMBOLIC_NAME_KEY, hwIDs[0]); + } + } + + string deviceInterfaceGuids; + if (GetCustomDeviceKeyValue(usbHandle, LIBUSB_INTERFACE_GUIDS, out deviceInterfaceGuids, 512) == ErrorCode.None) + { + string[] deviceInterfaceGuidsArray = deviceInterfaceGuids.Split(new char[] {'\0'}, StringSplitOptions.RemoveEmptyEntries); + + mDeviceProperties.Add(LIBUSB_INTERFACE_GUIDS, deviceInterfaceGuidsArray); + } + } + + /// + /// Gets the 0 based index of this libusb device + /// + public int DeviceIndex + { + get { return mDeviceIndex; } + } + + /// + /// Gets a list of available LibUsb devices. + /// + public static List DeviceList + { + get + { + List deviceList = new List(); + for (int i = 1; i < UsbConstants.MAX_DEVICES; i++) + { + string deviceFileName = LibUsbDriverIO.GetDeviceNameString(i); + + SafeFileHandle deviceHandle = LibUsbDriverIO.OpenDevice(deviceFileName); + if (deviceHandle != null && !deviceHandle.IsInvalid && !deviceHandle.IsClosed) + { + try + { + LibUsbRegistry regInfo = new LibUsbRegistry(deviceHandle, deviceFileName, i); + //System.Diagnostics.Debug.Print("Address:{0}, Index:{1}, {2}", regInfo[SPDRP.Address], i, regInfo[SPDRP.DeviceDesc]); + deviceList.Add(regInfo); + } + catch (Exception ex) + { + Debug.Print(ex.Message); + } + } + if (deviceHandle != null && !deviceHandle.IsClosed) deviceHandle.Close(); + } + + return deviceList; + } + } + + /// + /// Check this value to determine if the usb device is still connected to the bus and ready to open. + /// + public override bool IsAlive + { + get + { + if (String.IsNullOrEmpty(SymbolicName)) throw new UsbException(this, "A symbolic name is required for this property."); + List deviceList = DeviceList; + foreach (LibUsbRegistry registry in deviceList) + { + if (String.IsNullOrEmpty(registry.SymbolicName)) continue; + + if (registry.SymbolicName == SymbolicName) + return true; + } + return false; + } + } + + /// + /// Opens the USB device for communucation. + /// + /// Return a new instance of the class. + /// If the device fails to open a null refrence is return. For extended error + /// information use the . + /// + public override UsbDevice Device + { + get + { + LibUsbDevice libUsbDevice; + Open(out libUsbDevice); + return libUsbDevice; + } + } + + /// + /// Gets the DeviceInterfaceGuids for the WinUsb device. + /// + public override Guid[] DeviceInterfaceGuids + { + get + { + if (ReferenceEquals(mDeviceInterfaceGuids, null)) + { + if (!mDeviceProperties.ContainsKey(LIBUSB_INTERFACE_GUIDS)) return new Guid[0]; + + string[] saDeviceInterfaceGuids = mDeviceProperties[LIBUSB_INTERFACE_GUIDS] as string[]; + if (ReferenceEquals(saDeviceInterfaceGuids, null)) return new Guid[0]; + + mDeviceInterfaceGuids = new Guid[saDeviceInterfaceGuids.Length]; + + for (int i = 0; i < saDeviceInterfaceGuids.Length; i++) + { + string sGuid = saDeviceInterfaceGuids[i].Trim(new char[] {' ', '{', '}', '[', ']', '\0'}); + mDeviceInterfaceGuids[i] = new Guid(sGuid); + } + } + return mDeviceInterfaceGuids; + } + } + + /// + /// Opens the USB device for communucation. + /// + /// The newly created UsbDevice. + /// True on success. + public bool Open(out LibUsbDevice usbDevice) + { + bool bSuccess = LibUsbDevice.Open(mDeviceFilename, out usbDevice); + if (bSuccess) + { + usbDevice.mUsbRegistry = this; + } + + return bSuccess; + } + + /// + /// Opens the USB device for communucation. + /// + /// The newly created UsbDevice. + /// True on success. + public override bool Open(out UsbDevice usbDevice) + { + usbDevice = null; + LibUsbDevice libUsbDevice; + bool bSuccess = Open(out libUsbDevice); + if (bSuccess) + usbDevice = libUsbDevice; + return bSuccess; + } + + internal ErrorCode GetCustomDeviceKeyValue(SafeFileHandle usbHandle, string key, out string propData, int maxDataLength) + { + byte[] propDataBytes; + ErrorCode eReturn = GetCustomDeviceKeyValue(usbHandle, key, out propDataBytes, maxDataLength); + if (eReturn == ErrorCode.None) + { + propData = Encoding.Unicode.GetString(propDataBytes); + propData.TrimEnd(new char[] {'\0'}); + } + else + { + propData = null; + } + + return eReturn; + } + + internal ErrorCode GetCustomDeviceKeyValue(SafeFileHandle usbHandle, string key, out byte[] propData, int maxDataLength) + { + ErrorCode eReturn = ErrorCode.None; + int iReturnBytes; + propData = null; + byte[] bytesReq = LibUsbDeviceRegistryKeyRequest.RegGetRequest(key, maxDataLength); + GCHandle gcbytesReq = GCHandle.Alloc(bytesReq, GCHandleType.Pinned); + + bool bSuccess = LibUsbDriverIO.UsbIOSync(usbHandle, + LibUsbIoCtl.GET_CUSTOM_REG_PROPERTY, + bytesReq, + bytesReq.Length, + gcbytesReq.AddrOfPinnedObject(), + bytesReq.Length, + out iReturnBytes); + gcbytesReq.Free(); + if (bSuccess) + { + propData = new byte[iReturnBytes]; + Array.Copy(bytesReq, propData, iReturnBytes); + } + else + { + eReturn = ErrorCode.GetDeviceKeyValueFailed; + // dont log this as an error; + //UsbError.Error(eReturn,0, "Failed getting device registry Key:" + key, this); + } + return eReturn; + } + + private void GetPropertiesSPDRP(SafeHandle usbHandle) + { + byte[] propBuffer = new byte[1024]; + GCHandle gcPropBuffer = GCHandle.Alloc(propBuffer, GCHandleType.Pinned); + + LibUsbRequest req = new LibUsbRequest(); + Dictionary allProps = Helper.GetEnumData(typeof (DevicePropertyType)); + foreach (KeyValuePair prop in allProps) + { + object oValue = String.Empty; + + req.DeviceProperty.ID = prop.Value; + int iReturnBytes; + bool bSuccess = LibUsbDriverIO.UsbIOSync(usbHandle, + LibUsbIoCtl.GET_REG_PROPERTY, + req, + LibUsbRequest.Size, + gcPropBuffer.AddrOfPinnedObject(), + propBuffer.Length, + out iReturnBytes); + if (bSuccess) + { + switch ((DevicePropertyType) prop.Value) + { + case DevicePropertyType.PhysicalDeviceObjectName: + case DevicePropertyType.LocationInformation: + case DevicePropertyType.Class: + case DevicePropertyType.Mfg: + case DevicePropertyType.DeviceDesc: + case DevicePropertyType.Driver: + case DevicePropertyType.EnumeratorName: + case DevicePropertyType.FriendlyName: + case DevicePropertyType.ClassGuid: + oValue = GetAsString(propBuffer, iReturnBytes); + break; + case DevicePropertyType.HardwareId: + case DevicePropertyType.CompatibleIds: + oValue = GetAsStringArray(propBuffer, iReturnBytes); + break; + case DevicePropertyType.BusNumber: + case DevicePropertyType.InstallState: + case DevicePropertyType.LegacyBusType: + case DevicePropertyType.RemovalPolicy: + case DevicePropertyType.UiNumber: + case DevicePropertyType.Address: + oValue = GetAsStringInt32(propBuffer, iReturnBytes); + break; + case DevicePropertyType.BusTypeGuid: + oValue = GetAsGuid(propBuffer, iReturnBytes); + break; + } + } + else + oValue = String.Empty; + + mDeviceProperties.Add(prop.Key, oValue); + } + gcPropBuffer.Free(); + } + } +} \ No newline at end of file diff --git a/LibWinUsb/LibUsbDotNet.csproj b/LibWinUsb/LibUsbDotNet.csproj new file mode 100644 index 0000000..17d34a2 --- /dev/null +++ b/LibWinUsb/LibUsbDotNet.csproj @@ -0,0 +1,236 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {0A78F6FF-5586-4052-8104-E23FF83A7CE1} + Library + Properties + LibUsbDotNet + LibUsbDotNet + + + 2.0 + + + v2.0 + false + LibUsbDotNet.snk + + + true + full + false + bin\Debug\ + TRACE;DEBUG;LIBUSBDOTNET + prompt + 4 + false + false + + + pdbonly + true + ..\bin\Release\ + TRACE;LIBUSBDOTNET + prompt + 4 + ..\bin\Release\LibUsbDotNet.xml + Auto + false + false + + + true + bin\x86\Debug\ + TRACE;DEBUG;LIBUSBDOTNET + full + x86 + false + prompt + + + bin\x86\Release\ + TRACE;LIBUSBDOTNET + ..\bin\Release\LibUsbDotNet.xml + true + pdbonly + x86 + prompt + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Code + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/LibWinUsb/LibUsbDotNet.snk b/LibWinUsb/LibUsbDotNet.snk new file mode 100644 index 0000000..1a5edfa Binary files /dev/null and b/LibWinUsb/LibUsbDotNet.snk differ diff --git a/LibWinUsb/Main/ControlEpLockType.cs b/LibWinUsb/Main/ControlEpLockType.cs new file mode 100644 index 0000000..e108132 --- /dev/null +++ b/LibWinUsb/Main/ControlEpLockType.cs @@ -0,0 +1,54 @@ +// Copyright © 2006-2009 Travis Robinson. All rights reserved. +// +// website: sourceforge.net/projects/libusbdotnet/ +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +namespace LibUsbDotNet.Main +{ + /// The locking strategy for endpoint 0 operations in regards to any pending endpoint data operations. + /// + /// Some USB devices have problems handling endpoint 0 control messages when other endpoints on the device have pending IO operations. + /// Must be combined with . + /// + public enum ControlEpLockType + { + /// + /// Endpoint 0 transfers do not interfere with data endpoint transfers in any way. This is the default. + /// + None, + /// + /// If data endpoints for the device remain busy for longer than , then force an IO cancel operation for the busy endpoints. + /// + /// + /// There is a potential for loss of data when using this option. + /// This will immediately cancel pending I/O transfers on all data endpoints when a enpoint 0 control transfer is initiated. + /// + CancelIoOnLockTimeout, + /// + /// If data endpoints for the device remain busy for longer than , then consider the remaining endpoints with IO pending operation as idle and continue with operation. + /// This option is the same as ErrorOnLockTimeout only instead of returning with an error after the lock timeout period, an attempt is made to transfer data anyways. (Ignoring the lock) + /// + ContinueOnLockTimeout, + /// + /// If data endpoints for the device remain busy for longer than , then return a LockTimeout error code. + /// Setting this value will lock ALL the devices data endpoints (1-15) before transfering data to the control enpoint 0. + /// + ErrorOnLockTimeout + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/DataEpLockType.cs b/LibWinUsb/Main/DataEpLockType.cs new file mode 100644 index 0000000..4b667db --- /dev/null +++ b/LibWinUsb/Main/DataEpLockType.cs @@ -0,0 +1,44 @@ +// Copyright © 2006-2009 Travis Robinson. All rights reserved. +// +// website: sourceforge.net/projects/libusbdotnet/ +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; + +namespace LibUsbDotNet.Main +{ + /// Data endpoint locking strategy. + /// + [Flags] + public enum DataEpLockType + { + /// + /// Don't lock the device IO functions. + /// + /// + /// This option is not thread/proccess safe. + /// + None, + /// + /// Use a semapore to lock data endpoint IO operations. This prevents multiple threads/proccesses from accessing + /// the same at the same time. + /// + Locked, + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/DataReceivedEnabledChangedEventArgs.cs b/LibWinUsb/Main/DataReceivedEnabledChangedEventArgs.cs new file mode 100644 index 0000000..11aa7bc --- /dev/null +++ b/LibWinUsb/Main/DataReceivedEnabledChangedEventArgs.cs @@ -0,0 +1,59 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; + +namespace LibUsbDotNet.Main +{ + /// + /// Event arguments that are passed when is changes state. + /// + public class DataReceivedEnabledChangedEventArgs : EventArgs + { + private readonly bool mEnabled; + private readonly ErrorCode mErrorCode = ErrorCode.Success; + + internal DataReceivedEnabledChangedEventArgs(bool enabled, ErrorCode errorCode) + { + mEnabled = enabled; + mErrorCode = errorCode; + } + + internal DataReceivedEnabledChangedEventArgs(bool enabled) + : this(enabled, ErrorCode.Success) { } + + /// + /// The that caused the event to terminate. + /// + public ErrorCode ErrorCode + { + get { return mErrorCode; } + } + + /// + /// True if changes from True to False. + /// + public bool Enabled + { + get { return mEnabled; } + } + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/DeviceLockType.cs b/LibWinUsb/Main/DeviceLockType.cs new file mode 100644 index 0000000..56fa76c --- /dev/null +++ b/LibWinUsb/Main/DeviceLockType.cs @@ -0,0 +1,48 @@ +// Copyright © 2006-2009 Travis Robinson. All rights reserved. +// +// website: sourceforge.net/projects/libusbdotnet/ +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; + +namespace LibUsbDotNet.Main +{ + /// The locking strategy for endpoint 0 operations per proccess/thread + /// + [Flags] + public enum DeviceLockType + { + /// + /// Don't lock the device IO functions. + /// + /// + /// This option is not thread/proccess safe. + /// + None, + /// + /// Use a global semapore to lock endpoint I/O operations. This prevents multiple threads/proccesses from accessing + /// the IO functions (IE , etc..) at the same time. + /// + /// + /// Using this option will allow your LibUsbDotNet applications to comunicate cooperatively with the same USB device. + /// NOTE: Usb devices using the WinUsb.dll driver can't be shared by multiple processes. + /// + Locked, + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/DevicePropertyType.cs b/LibWinUsb/Main/DevicePropertyType.cs new file mode 100644 index 0000000..026ff32 --- /dev/null +++ b/LibWinUsb/Main/DevicePropertyType.cs @@ -0,0 +1,101 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +namespace LibUsbDotNet.Main +{ + /// Standard Windows registry properties for USB devices and other hardware. + /// + public enum DevicePropertyType + { + /// + /// Requests a string describing the device, such as "Microsoft PS/2 Port Mouse", typically defined by the manufacturer. + /// + DeviceDesc = 0, + /// + /// Requests the hardware IDs provided by the device that identify the device. + /// + HardwareId = 1, + /// + /// Requests the compatible IDs reported by the device. + /// + CompatibleIds = 2, + /// + /// Requests the name of the device's setup class, in text format. + /// + Class = 5, + /// + /// Requests the GUID for the device's setup class. + /// + ClassGuid = 6, + /// + /// Requests the name of the driver-specific registry key. + /// + Driver = 7, + /// + /// Requests a string identifying the manufacturer of the device. + /// + Mfg = 8, + /// + /// Requests a string that can be used to distinguish between two similar devices, typically defined by the class installer. + /// + FriendlyName = 9, + /// + /// Requests information about the device's location on the bus; the interpretation of this information is bus-specific. + /// + LocationInformation = 10, + /// + /// Requests the name of the PDO for this device. + /// + PhysicalDeviceObjectName = 11, + /// + /// Requests the GUID for the bus that the device is connected to. + /// + BusTypeGuid = 12, + /// + /// Requests the bus type, such as PCIBus or PCMCIABus. + /// + LegacyBusType = 13, + /// + /// Requests the legacy bus number of the bus the device is connected to. + /// + BusNumber = 14, + /// + /// Requests the name of the enumerator for the device, such as "USB". + /// + EnumeratorName = 15, + /// + /// Requests the address of the device on the bus. + /// + Address = 16, + /// + /// Requests a number associated with the device that can be displayed in the user interface. + /// + UiNumber = 17, + /// + /// Windows XP and later.) Requests the device's installation state. + /// + InstallState = 18, + /// + /// (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. + /// + RemovalPolicy = 19 + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/EndpointDataEventArgs.cs b/LibWinUsb/Main/EndpointDataEventArgs.cs new file mode 100644 index 0000000..28135a0 --- /dev/null +++ b/LibWinUsb/Main/EndpointDataEventArgs.cs @@ -0,0 +1,58 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; + +namespace LibUsbDotNet.Main +{ + /// Endpoint data received arguments returned by the event. + /// + public class EndpointDataEventArgs : EventArgs + { + private readonly byte[] mBytesReceived; + private readonly int mCount; + + internal EndpointDataEventArgs(byte[] bytes, int size) + { + mBytesReceived = bytes; + mCount = size; + } + + /// + /// Gets the buffer of the received data. + /// + /// + /// Use the property to determine the number of bytes actually received. + /// + public byte[] Buffer + { + get { return mBytesReceived; } + } + + /// + /// Gets the number of bytes received. + /// + public int Count + { + get { return mCount; } + } + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/EndpointType.cs b/LibWinUsb/Main/EndpointType.cs new file mode 100644 index 0000000..8a341fb --- /dev/null +++ b/LibWinUsb/Main/EndpointType.cs @@ -0,0 +1,48 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; + +namespace LibUsbDotNet.Main +{ + /// All possible USB endpoint types. + /// + [Flags] + public enum EndpointType : byte + { + /// + /// Control endpoint type. + /// + Control, + /// + /// Isochronous endpoint type. + /// + Isochronous, + /// + /// Bulk endpoint type. + /// + Bulk, + /// + /// Interrupt endpoint type. + /// + Interrupt + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/ErrorCode.cs b/LibWinUsb/Main/ErrorCode.cs new file mode 100644 index 0000000..651c3b6 --- /dev/null +++ b/LibWinUsb/Main/ErrorCode.cs @@ -0,0 +1,184 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// + +using MonoLibUsb; + +namespace LibUsbDotNet.Main +{ + /// + /// General area in which the failure occurred. See the class. + /// + public enum ErrorCode + { + /// + /// No error. (None, Success, and Ok) + /// + None = 0, + /// + /// No error. + /// + Success = 0, + /// + /// No error. + /// + Ok = 0, + /// + /// The USB device has errors in its Configuration descriptor. + /// + InvalidConfig = -16384, + /// + /// A synchronous device IO operation failed. + /// + IoSyncFailed, + /// + /// A request for a string failed. + /// + GetString, + /// + /// A specified endpoint is invalid for the operation. + /// + InvalidEndpoint, + /// + /// A request to cancel IO operation failed. + /// + AbortEndpoint, + /// + /// A call to the core Win32 API DeviceIOControl failed. + /// + DeviceIoControl, + /// + /// A call to the core Win32 API GetOverlappedResult failed. + /// + GetOverlappedResult, + /// + /// An Endpoints receive thread was dangerously terminated. + /// + ReceiveThreadTerminated, + /// + /// A write operation failed. + /// + WriteFailed, + /// + /// A read operation failed. + /// + ReadFailed, + /// + /// An endpoint 0 IO control message failed. + /// + IoControlMessage, + /// + /// The action of cancelling the IO operation failed. + /// + CancelIoFailed, + /// + /// An IO operation was cancelled by the user before it completed. + /// + /// + /// IoCancelled errors may occur as normal operation; for this reason they are not logged as a . + /// + IoCancelled, + /// + /// An IO operation timed out before it completed. + /// + /// + /// IoTimedOut errors may occur as normal operation; for this reason they are not logged as a . + /// + IoTimedOut, + /// + /// An IO operation was cancelled and will be re-submiited when ready. + /// + /// + /// IoEndpointGlobalCancelRedo errors may occur as normal operation; for this reason they are not logged as a . + /// + IoEndpointGlobalCancelRedo, + /// + /// Failed retrieving a custom USB device key value. + /// + GetDeviceKeyValueFailed, + /// + /// Failed setting a custom USB device key value. + /// + SetDeviceKeyValueFailed, + /// + /// The error is a standard windows error. + /// + Win32Error, + /// + /// An attempt was made to lock a device that is already locked. + /// + DeviceAllreadyLocked, + /// + /// An attempt was made to lock an endpoint that is already locked. + /// + EndpointAllreadyLocked, + /// + /// The USB device request failed because the USB device was not found. + /// + DeviceNotFound, + /// + /// Operation was intentionally cancelled by the user or application. + /// + UserAborted, + /// + /// Invalid parameter. + /// + InvalidParam, + + /// + /// Access denied (insufficient permissions). + /// + AccessDenied, + /// + /// Resource Busy. + /// + ResourceBusy, + /// + /// Overflow. + /// + Overflow, + /// + /// Pipe error or endpoint halted. + /// + PipeError, + /// + /// System call interrupted (perhaps due to signal). + /// + Interrupted, + + /// + /// Insufficient memory. + /// + InsufficientMemory, + /// + /// Operation not supported or unimplemented on this platform. + /// + NotSupported, + /// + /// Unknown or other error. + /// + UnknownError, + /// + /// The error is one of the + /// + MonoApiError + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/Helper.cs b/LibWinUsb/Main/Helper.cs new file mode 100644 index 0000000..9b3ee53 --- /dev/null +++ b/LibWinUsb/Main/Helper.cs @@ -0,0 +1,283 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; + +namespace LibUsbDotNet.Main +{ + /// + /// General utilities class used by LudnLite and exposed publicly for your convience. + /// + public static class Helper + { + private static object mIsLinux; + private static OperatingSystem mOs; + + /// + /// Gets the class. + /// + public static OperatingSystem OSVersion + { + get + { + if (ReferenceEquals(mOs, null)) + mOs = Environment.OSVersion; + + return mOs; + } + } + + /// + /// True if running on a unix-like operating system. + /// False if using the Libusb-1.0 windows backend driver. + /// + public static bool IsLinux + { + get + { + if (ReferenceEquals(mIsLinux, null)) + { + switch (OSVersion.Platform.ToString()) + { + case "Win32S": + case "Win32Windows": + case "Win32NT": + case "WinCE": + case "Xbox": + mIsLinux = false; + break; + case "Unix": + case "MacOSX": + mIsLinux = true; + break; + default: + throw new NotSupportedException(string.Format("Operating System:{0} not supported.", OSVersion)); + } + } + return (bool)mIsLinux; + } + } + + /// + /// Copies bytes to a blittable object. + /// + /// bytes to copy + /// Start index + /// number of bytes to copy + /// blittable destination object + 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(); + } + + /// + /// Returns a dictionary object of enumeration names and values. + /// + /// They of enumeration. + /// A enumeration of names and values. + public static Dictionary GetEnumData(Type type) + { + Dictionary dictEnum = new Dictionary(); + FieldInfo[] enumFields = type.GetFields(); + for (int iField = 1; iField < enumFields.Length; iField++) + { + object oValue = enumFields[iField].GetRawConstantValue(); + dictEnum.Add(enumFields[iField].Name, Convert.ToInt32(oValue)); + } + + return dictEnum; + } + + + /// + /// Swaps low and high bytes on big endian systems. Has no effect on little endian systems. + /// + /// The value to convert. + /// a swapped value an big endian system, the same value on little endian systems + public static short HostEndianToLE16(short swapValue) + { + HostEndian16BitValue rtn = new HostEndian16BitValue(swapValue); + return (short)rtn.U16; + } + + /// + /// Converts standard values to decorated hex string values. + /// + /// The value to convert. + /// A string representing in hex display format. + public static string ShowAsHex(object standardValue) + { + if (standardValue == null) return ""; + if (standardValue is Int64) return "0x" + ((Int64)standardValue).ToString("X16"); + if (standardValue is UInt32) return "0x" + ((UInt32)standardValue).ToString("X8"); + if (standardValue is Int32) return "0x" + ((Int32)standardValue).ToString("X8"); + if (standardValue is UInt16) return "0x" + ((UInt16)standardValue).ToString("X4"); + if (standardValue is Int16) return "0x" + ((Int16)standardValue).ToString("X4"); + if (standardValue is Byte) return "0x" + ((Byte)standardValue).ToString("X2"); + if (standardValue is String) return HexString(standardValue as byte[], "", " "); + + return ""; + } + + /// + /// Builds a delimited string of names and values. + /// + /// Inserted and the begining of the entity. + /// The list of names for the object values. + /// Inserted between the name and value. + /// The values for the names. + /// Inserted and the end of the entity. + /// The formatted string. + 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(); + } + + #region Nested Types + + [StructLayout(LayoutKind.Explicit, Pack = 1)] + internal struct HostEndian16BitValue + { + public HostEndian16BitValue(short x) + { + U16 = 0; + B1 = (byte)(x >> 8); + B0 = (byte)(x & 0xff); + } + + [FieldOffset(0)] + public readonly ushort U16; + + [FieldOffset(0)] + public readonly byte B0; + + [FieldOffset(1)] + public readonly byte B1; + } + + #endregion + + /// + /// Builds a formatted hexidecimal string from an array of bytes. + /// + /// the byte array + /// string to place before each byte + /// string to place after each byte + /// a formatted hex string + public static string HexString(byte[] data, string prefix, string suffix) + { + if (prefix == null) prefix = String.Empty; + if (suffix == null) suffix = String.Empty; + + StringBuilder sb = new StringBuilder((data.Length * 2) + (data.Length * prefix.Length) + (data.Length * suffix.Length)); + foreach (byte b in data) + sb.Append(prefix + b.ToString("X2") + suffix); + + return sb.ToString(); + } + + } + /// + /// Used for allocating a to access the underlying pointer of an object. + /// + public class PinnedHandle : IDisposable + { + private readonly IntPtr mPtr = IntPtr.Zero; + private bool mFreeGcBuffer; + private GCHandle mGcObject; + + + /// + /// Creates a pinned object. + /// + /// + /// The object can be any blittable class, or array. If a is passed it will be used "as-is" and no pinning will take place. + /// + public PinnedHandle(object objectToPin) + { + if (!ReferenceEquals(objectToPin, null)) + { + mFreeGcBuffer = GetPinnedObjectHandle(objectToPin, out mGcObject); + mPtr = mGcObject.AddrOfPinnedObject(); + } + } + + /// + /// The raw pointer in memory of the pinned object. + /// + public IntPtr Handle + { + get { return mPtr; } + } + + #region IDisposable Members + + /// + /// Frees and disposes the for this pinned object. + /// + /// 2 + public void Dispose() + { + if ((mFreeGcBuffer) && mGcObject.IsAllocated) + { + mFreeGcBuffer = false; + mGcObject.Free(); + } + GC.SuppressFinalize(this); + } + + #endregion + + /// + /// Disposes the gchande for the object if ibe is allocated. + /// + ~PinnedHandle() { Dispose(); } + + private static bool GetPinnedObjectHandle(object objectToPin, out GCHandle pinnedObject) + { + bool bFreeGcBuffer = false; + + if (objectToPin is GCHandle) + pinnedObject = (GCHandle)objectToPin; + else + { + pinnedObject = GCHandle.Alloc(objectToPin, GCHandleType.Pinned); + bFreeGcBuffer = true; + } + + return bFreeGcBuffer; + } + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/LegacyUsbRegistry.cs b/LibWinUsb/Main/LegacyUsbRegistry.cs new file mode 100644 index 0000000..37c7f67 --- /dev/null +++ b/LibWinUsb/Main/LegacyUsbRegistry.cs @@ -0,0 +1,245 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Collections.Generic; +using LibUsbDotNet.Internal.LibUsb; +using LibUsbDotNet.LibUsb; +using LibUsbDotNet.LudnMonoLibUsb; +using Microsoft.Win32.SafeHandles; +using Debug=System.Diagnostics.Debug; + +namespace LibUsbDotNet.Main +{ + /// + /// LibUsb specific members for device registry settings. + /// This legacy class does not actually query the windows registry as the other Registry classes do. + /// Instead, it wraps a and queries descriptors directly from the device + /// using usb IO control messages. + /// + public class LegacyUsbRegistry : UsbRegistry + { + + private readonly UsbDevice mUSBDevice; + internal LegacyUsbRegistry(UsbDevice usbDevice) + { + mUSBDevice = usbDevice; + GetPropertiesSPDRP(mUSBDevice, mDeviceProperties); + } + + /// + /// Opens the USB device for communucation. + /// + /// Return a new instance of the class. + /// If the device fails to open a null refrence is return. For extended error + /// information use the . + /// + public override UsbDevice Device + { + get + { + UsbDevice libUsbDevice; + Open(out libUsbDevice); + return libUsbDevice; + } + } + + /// + /// Gets the DeviceInterfaceGuids for the WinUsb device. + /// + public override Guid[] DeviceInterfaceGuids + { + get + { + if (ReferenceEquals(mDeviceInterfaceGuids, null)) + { + if (!mDeviceProperties.ContainsKey(LIBUSB_INTERFACE_GUIDS)) return new Guid[0]; + + string[] saDeviceInterfaceGuids = mDeviceProperties[LIBUSB_INTERFACE_GUIDS] as string[]; + if (ReferenceEquals(saDeviceInterfaceGuids, null)) return new Guid[0]; + + mDeviceInterfaceGuids = new Guid[saDeviceInterfaceGuids.Length]; + + for (int i = 0; i < saDeviceInterfaceGuids.Length; i++) + { + string sGuid = saDeviceInterfaceGuids[i].Trim(new char[] {' ', '{', '}', '[', ']', '\0'}); + mDeviceInterfaceGuids[i] = new Guid(sGuid); + } + } + return mDeviceInterfaceGuids; + } + } + + /// + /// Check this value to determine if the usb device is still connected to the bus and ready to open. + /// + /// + /// Uses the symbolic name as a unique id to determine if this device instance is still attached. + /// + /// An exception is thrown if the property is null or empty. + public override bool IsAlive + { + get + { + if (String.IsNullOrEmpty(SymbolicName)) throw new UsbException(this, "A symbolic name is required for this property."); + List deviceList = DeviceList; + foreach (LegacyUsbRegistry registry in deviceList) + { + if (String.IsNullOrEmpty(registry.SymbolicName)) continue; + + if (registry.SymbolicName == SymbolicName) + return true; + } + return false; + } + } + + /// + /// Gets a list of available LibUsb devices. + /// + /// + public static List DeviceList + { + get + { + List deviceList = new List(); + if (UsbDevice.IsLinux) + { + List legacyLibUsbDeviceList = MonoUsbDevice.MonoUsbDeviceList; + foreach (MonoUsbDevice usbDevice in legacyLibUsbDeviceList) + { + deviceList.Add(new LegacyUsbRegistry(usbDevice)); + } + } + else + { + for (int i = 1; i < UsbConstants.MAX_DEVICES; i++) + { + string deviceFileName = LibUsbDriverIO.GetDeviceNameString(i); + + SafeFileHandle deviceHandle = LibUsbDriverIO.OpenDevice(deviceFileName); + if (deviceHandle != null && !deviceHandle.IsInvalid && !deviceHandle.IsClosed) + { + try + { + LibUsbDevice newUsbDevice = new LibUsbDevice(UsbDevice.LibUsbApi, deviceHandle, deviceFileName); + + LegacyUsbRegistry regInfo = new LegacyUsbRegistry(newUsbDevice); + + deviceList.Add(regInfo); + } + catch (Exception ex) + { + Debug.Print(ex.Message); + } + } + if (deviceHandle != null && !deviceHandle.IsClosed) deviceHandle.Close(); + } + } + return deviceList; + } + } + + ///// + ///// ProductID + ///// + //public override int Pid + //{ + // get { return (int)((ushort)mUSBDevice.Info.Descriptor.ProductID); } + //} + + ///// + ///// VendorID + ///// + //public override int Vid + //{ + // get { return (int)((ushort)mUSBDevice.Info.Descriptor.VendorID); } + //} + + /// + /// Usb device revision number. + /// + public override int Rev + { + get + { + int bcdRev; + string s = mUSBDevice.Info.Descriptor.BcdDevice.ToString("X4"); + if (int.TryParse(s, out bcdRev)) + { + return bcdRev; + } + return (int)((ushort)mUSBDevice.Info.Descriptor.BcdDevice); + } + } + + internal static string GetRegistryHardwareID(ushort vid, ushort pid, ushort rev) + { + return string.Format("Vid_{0:X4}&Pid_{1:X4}&Rev_{2}", vid, pid, rev.ToString("0000")); + } + + /// + /// Opens the USB device for communucation. + /// + /// The newly created UsbDevice. + /// True on success. + public override bool Open(out UsbDevice usbDevice) + { + usbDevice = null; + bool bSuccess = mUSBDevice.Open(); + if (bSuccess) + { + usbDevice = mUSBDevice; + usbDevice.mUsbRegistry = this; + } + + return bSuccess; + } + + internal static void GetPropertiesSPDRP(UsbDevice usbDevice, Dictionary deviceProperties) + { + + + deviceProperties.Add(DevicePropertyType.Mfg.ToString(), + usbDevice.Info.Descriptor.ManufacturerStringIndex > 0 ? usbDevice.Info.ManufacturerString : string.Empty); + + deviceProperties.Add(DevicePropertyType.DeviceDesc.ToString(), + usbDevice.Info.Descriptor.ProductStringIndex > 0 ? usbDevice.Info.ProductString : string.Empty); + + deviceProperties.Add("SerialNumber", + usbDevice.Info.Descriptor.SerialStringIndex > 0 ? usbDevice.Info.SerialString : string.Empty); + + string fakeHardwareIds = GetRegistryHardwareID((ushort)usbDevice.Info.Descriptor.VendorID, + (ushort)usbDevice.Info.Descriptor.ProductID, + (ushort)usbDevice.Info.Descriptor.BcdDevice); + + deviceProperties.Add(DevicePropertyType.HardwareId.ToString(), new string[] { fakeHardwareIds }); + + string fakeSymbolicName = fakeHardwareIds + "{" + Guid.Empty + " }"; + + if (usbDevice.Info.Descriptor.SerialStringIndex > 0) + { + fakeSymbolicName += "#" + deviceProperties["SerialNumber"] + "#"; + } + deviceProperties.Add(SYMBOLIC_NAME_KEY, fakeSymbolicName); + } + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/ReadEndpointID.cs b/LibWinUsb/Main/ReadEndpointID.cs new file mode 100644 index 0000000..0ae4ec8 --- /dev/null +++ b/LibWinUsb/Main/ReadEndpointID.cs @@ -0,0 +1,90 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +namespace LibUsbDotNet.Main +{ + /// + /// Availabled endpoint numbers/ids for reading. + /// + public enum ReadEndpointID : byte + { + /// + /// Endpoint 1 + /// + Ep01 = 0x81, + /// + /// Endpoint 2 + /// + Ep02 = 0x82, + /// + /// Endpoint 3 + /// + Ep03 = 0x83, + /// + /// Endpoint 4 + /// + Ep04 = 0x84, + /// + /// Endpoint 5 + /// + Ep05 = 0x85, + /// + /// Endpoint 6 + /// + Ep06 = 0x86, + /// + /// Endpoint 7 + /// + Ep07 = 0x87, + /// + /// Endpoint 8 + /// + Ep08 = 0x88, + /// + /// Endpoint 9 + /// + Ep09 = 0x89, + /// + /// Endpoint 10 + /// + Ep10 = 0x8A, + /// + /// Endpoint 11 + /// + Ep11 = 0x8B, + /// + /// Endpoint 12 + /// + Ep12 = 0x8C, + /// + /// Endpoint 13 + /// + Ep13 = 0x8D, + /// + /// Endpoint 14 + /// + Ep14 = 0x8E, + /// + /// Endpoint 15 + /// + Ep15 = 0x8F, + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/SPDRP.cs b/LibWinUsb/Main/SPDRP.cs new file mode 100644 index 0000000..0973a03 --- /dev/null +++ b/LibWinUsb/Main/SPDRP.cs @@ -0,0 +1,110 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; + +namespace LibUsbDotNet.Main +{ + /// + /// Device registry property codes + /// + [Flags] + public enum SPDRP + { + /// + /// Requests a string describing the device, such as "Microsoft PS/2 Port Mouse", typically defined by the manufacturer. + /// + DeviceDesc = (0x00000000), + /// + /// Requests the hardware IDs provided by the device that identify the device. + /// + HardwareId = (0x00000001), + /// + /// Requests the compatible IDs reported by the device. + /// + CompatibleIds = (0x00000002), + /// + /// Requests the name of the device's setup class, in text format. + /// + Class = (0x00000007), + /// + /// Requests the GUID for the device's setup class. + /// + ClassGuid = (0x00000008), + /// + /// Requests the name of the driver-specific registry key. + /// + Driver = (0x00000009), + /// + /// Requests a string identifying the manufacturer of the device. + /// + Mfg = (0x0000000B), + /// + /// Requests a string that can be used to distinguish between two similar devices, typically defined by the class installer. + /// + FriendlyName = (0x0000000C), + /// + /// Requests information about the device's location on the bus; the interpretation of this information is bus-specific. + /// + LocationInformation = (0x0000000D), + /// + /// Requests the name of the PDO for this device. + /// + PhysicalDeviceObjectName = (0x0000000E), + /// + /// Requests a number associated with the device that can be displayed in the user interface. + /// + UiNumber = (0x00000010), + /// + /// Requests the GUID for the bus that the device is connected to. + /// + BusTypeGuid = (0x00000013), + /// + /// Requests the bus type, such as PCIBus or PCMCIABus. + /// + LegacyBusType = (0x00000014), + /// + /// Requests the legacy bus number of the bus the device is connected to. + /// + BusNumber = (0x00000015), + /// + /// Requests the name of the enumerator for the device, such as "USB". + /// + EnumeratorName = (0x00000016), + /// + /// Requests the address of the device on the bus. + /// + Address = (0x0000001C), + /// + /// (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. + /// + RemovalPolicy = (0x0000001F), + /// + /// Windows XP and later.) Requests the device's installation state. + /// + InstallState = (0x00000022), + /// + /// Device Location Paths (R) + /// + LocationPaths=(0x00000023), + + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/SafeContextHandle.cs b/LibWinUsb/Main/SafeContextHandle.cs new file mode 100644 index 0000000..5d0b04e --- /dev/null +++ b/LibWinUsb/Main/SafeContextHandle.cs @@ -0,0 +1,65 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; + +namespace LibUsbDotNet.Main +{ + /// + /// Base class for all critial handles. + /// + public abstract class SafeContextHandle : SafeHandle + { + /// + /// + /// + /// + /// + protected SafeContextHandle(IntPtr pHandle, bool ownsHandle) + : base(IntPtr.Zero, ownsHandle) { SetHandle(pHandle); } + /// + /// + /// + /// + protected SafeContextHandle(IntPtr pHandleToOwn) + : this(pHandleToOwn, true) { } + + /// + /// Gets a value indicating whether the handle value is invalid. + /// + /// + /// true if the handle value is invalid; otherwise, false. + /// + /// + public override bool IsInvalid + { + get + { + if (handle != IntPtr.Zero) + { + return (handle == new IntPtr(-1)); + } + return true; + } + } + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/SetupApiRegistry.cs b/LibWinUsb/Main/SetupApiRegistry.cs new file mode 100644 index 0000000..1878b3e --- /dev/null +++ b/LibWinUsb/Main/SetupApiRegistry.cs @@ -0,0 +1,210 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using LibUsbDotNet.Internal; +using LibUsbDotNet.LudnMonoLibUsb; +using Microsoft.Win32; +using MonoLibUsb; +using System.Runtime.InteropServices; + +namespace LibUsbDotNet.Main +{ + internal static class SetupApiRegistry + { + private static readonly Object mLockSetupApiRegistry = new object(); + private static readonly MasterList mMasterSetupApiDeviceList = new MasterList(); + private static DateTime mLastRefreshTime = DateTime.MinValue; + public const string DEVICE_ID_KEY = "DeviceInstanceID"; + + public static bool NeedsRefresh + { + get + { + lock (mLockSetupApiRegistry) + { + if ((DateTime.Now - mLastRefreshTime).TotalMilliseconds >= 1000) + return true; + return false; + } + } + } + + private class MasterItem : Dictionary + { + public Dictionary> DevicePaths = new Dictionary>(); + } + + private class MasterList : List + { + } + + public static bool FillDeviceProperties(UsbRegistry usbRegistry, UsbDevice usbDevice) + { + + lock (mLockSetupApiRegistry) + { + if (NeedsRefresh) BuildMasterList(); + if (usbDevice is MonoUsbDevice && !Helper.IsLinux) + return FillWindowsMonoUsbDeviceRegistry(usbRegistry, (MonoUsbDevice) usbDevice); + + string fakeHwId = LegacyUsbRegistry.GetRegistryHardwareID((ushort) usbDevice.Info.Descriptor.VendorID, + (ushort) usbDevice.Info.Descriptor.ProductID, + (ushort) usbDevice.Info.Descriptor.BcdDevice); + bool bFound = false; + string hwIdToFind = fakeHwId.ToLower(); + foreach (MasterItem masterItem in mMasterSetupApiDeviceList) + { + string[] hwIds = masterItem[SPDRP.HardwareId.ToString()] as string[]; + if (ReferenceEquals(hwIds, null)) continue; + foreach (string hwID in hwIds) + { + if (hwID.ToLower().Contains(hwIdToFind)) + { + usbRegistry.mDeviceProperties = masterItem; + bFound = true; + break; + } + } + if (bFound) break; + } + return bFound; + } + } + + private static bool FillWindowsMonoUsbDeviceRegistry(UsbRegistry usbRegistry, MonoUsbDevice usbDevice) + { + MonoLibUsb.MonoUsbApi.internal_windows_device_priv priv = MonoLibUsb.MonoUsbApi.GetWindowsPriv(usbDevice.Profile.ProfileHandle); + string path; + for (int i = 0; i < 32; i++) + { + if (priv.usb_interfaces[i].path == IntPtr.Zero) break; + path = Marshal.PtrToStringAnsi(priv.usb_interfaces[i].path); + //Debug.Print("Intf:{0} Path:{1}",i,path); + } + path = Marshal.PtrToStringAnsi(priv.path); + + bool bFound = false; + + //System.Diagnostics.Debug.WriteLine(sb.ToString()); + path = path.ToString().ToLower().Replace("#", "\\"); + foreach (MasterItem masterItem in mMasterSetupApiDeviceList) + { + if (path.Contains(masterItem[DEVICE_ID_KEY].ToString().ToLower())) + { + usbRegistry.mDeviceProperties = masterItem; + bFound = true; + break; + } + } + return bFound; + } + + public static void BuildMasterList() + { + lock (mLockSetupApiRegistry) + { + mMasterSetupApiDeviceList.Clear(); + SetupApi.EnumClassDevs(null, SetupApi.DICFG.PRESENT | SetupApi.DICFG.ALLCLASSES, BuildMasterCallback, mMasterSetupApiDeviceList); + mLastRefreshTime = DateTime.Now; + } + } + + private static bool BuildMasterCallback(IntPtr deviceInfoSet, int deviceindex, ref SetupApi.SP_DEVINFO_DATA deviceInfoData, object userData) + { + MasterList deviceList = userData as MasterList; + MasterItem deviceItem = new MasterItem(); + StringBuilder sb=new StringBuilder(256); + + if (SetupApi.CM_Get_Device_ID(deviceInfoData.DevInst, sb, sb.Capacity, 0)!=SetupApi.CR.SUCCESS) + return false; + + deviceItem.Add(DEVICE_ID_KEY,sb.ToString()); + deviceList.Add(deviceItem); + + + RegistryValueKind propertyType; + byte[] propBuffer = new byte[256]; + int requiredSize; + bool bSuccess = SetupApi.SetupDiGetCustomDeviceProperty(deviceInfoSet, + ref deviceInfoData, + UsbRegistry.DEVICE_INTERFACE_GUIDS, + SetupApi.DICUSTOMDEVPROP.NONE, + out propertyType, + propBuffer, + propBuffer.Length, + out requiredSize); + if (bSuccess) + { + string[] devInterfaceGuids = UsbRegistry.GetAsStringArray(propBuffer, requiredSize); + + deviceItem.Add(UsbRegistry.DEVICE_INTERFACE_GUIDS, devInterfaceGuids); + foreach (string s in devInterfaceGuids) + { + Guid g = new Guid(s); + List devicePathList; + if (WinUsb.WinUsbRegistry.GetDevicePathList(g, out devicePathList)) + { + deviceItem.DevicePaths.Add(g, devicePathList); + } + } + } + else + { + bSuccess = SetupApi.SetupDiGetCustomDeviceProperty(deviceInfoSet, + ref deviceInfoData, + UsbRegistry.LIBUSB_INTERFACE_GUIDS, + SetupApi.DICUSTOMDEVPROP.NONE, + out propertyType, + propBuffer, + propBuffer.Length, + out requiredSize); + if (bSuccess) + { + string[] devInterfaceGuids = UsbRegistry.GetAsStringArray(propBuffer, requiredSize); + + deviceItem.Add(UsbRegistry.LIBUSB_INTERFACE_GUIDS, devInterfaceGuids); + } + } + + bSuccess = + SetupApi.SetupDiGetCustomDeviceProperty(deviceInfoSet, + ref deviceInfoData, + UsbRegistry.SYMBOLIC_NAME_KEY, + SetupApi.DICUSTOMDEVPROP.NONE, + out propertyType, + propBuffer, + propBuffer.Length, + out requiredSize); + if (bSuccess) + { + string symbolicName = UsbRegistry.GetAsString(propBuffer, requiredSize); + deviceItem.Add(UsbRegistry.SYMBOLIC_NAME_KEY, symbolicName); + } + SetupApi.getSPDRPProperties(deviceInfoSet, ref deviceInfoData, deviceItem); + + return false; + } + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/UsbConstants.cs b/LibWinUsb/Main/UsbConstants.cs new file mode 100644 index 0000000..2649653 --- /dev/null +++ b/LibWinUsb/Main/UsbConstants.cs @@ -0,0 +1,66 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +namespace LibUsbDotNet.Main +{ + /// Various USB constants. + /// + public static class UsbConstants + { + /// + /// Default timeout for all USB IO operations. + /// + public const int DEFAULT_TIMEOUT = 1000; + + internal const bool EXIT_CONTEXT = false; + + /// + /// Maximum size of a config descriptor. + /// + public const int MAX_CONFIG_SIZE = 4096; + + /// + /// Maximum number of USB devices. + /// + public const int MAX_DEVICES = 128; + + /// + /// Maximum number of endpoints per device. + /// + public const int MAX_ENDPOINTS = 32; + + /// + /// Endpoint direction mask. + /// + public const byte ENDPOINT_DIR_MASK = 0x80; + + /// + /// Endpoint number mask. + /// + public const byte ENDPOINT_NUMBER_MASK = 0xf; + + ///// + ///// See . Number of RETRIES before failed regardless of the handled field value. + ///// + //public const int MAX_FAIL_RETRIES_ON_HANDLED_ERROR = 4; + + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/UsbCtrlFlags.cs b/LibWinUsb/Main/UsbCtrlFlags.cs new file mode 100644 index 0000000..d1a6fcd --- /dev/null +++ b/LibWinUsb/Main/UsbCtrlFlags.cs @@ -0,0 +1,73 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +// ReSharper disable InconsistentNaming +namespace LibUsbDotNet.Main +{ + ///For Convienience Endpoint direction, recipient of the request, and request type on one enumeration. + [Flags] + public enum UsbCtrlFlags : byte + { + /// + /// In Direction + /// + Direction_In = 0x80, + /// + /// Out Direction + /// + Direction_Out = 0x00, + + /// + /// Device is recipient. + /// + Recipient_Device = 0x00, + /// + /// Endpoint is recipient. + /// + Recipient_Endpoint = 0x02, + /// + /// Interface is recipient. + /// + Recipient_Interface = 0x01, + /// + /// Other is recipient. + /// + Recipient_Other = 0x03, + + /// + /// Class specific request. + /// + RequestType_Class = (0x01 << 5), + /// + /// RESERVED. + /// + RequestType_Reserved = (0x03 << 5), + /// + /// Standard request. + /// + RequestType_Standard = (0x00 << 5), + /// + /// Vendor specific request. + /// + RequestType_Vendor = (0x02 << 5), + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/UsbDeviceFinder.cs b/LibWinUsb/Main/UsbDeviceFinder.cs new file mode 100644 index 0000000..2c3e632 --- /dev/null +++ b/LibWinUsb/Main/UsbDeviceFinder.cs @@ -0,0 +1,319 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; + +namespace LibUsbDotNet.Main +{ + /// + /// Finds and identifies usb devices. Used for easily locating + /// + /// + /// + /// + /// Instances of this class can optionally be passed directly into + /// + /// to quickly find and open a specific usb device in one step. + /// + /// + /// Pass instances of this class into the + /// , + /// , + /// or + /// functions of a + /// instance to find connected usb devices without opening devices or interrogating the bus. + /// After locating the required instance, call the + /// method to start using the instance. + /// + /// + /// + /// + /// + /// + public class UsbDeviceFinder : ISerializable + { + /// The "exclude from search" value for . + public const int NO_PID = int.MaxValue; + + /// The "exclude from search" value for . + public const int NO_REV = int.MaxValue; + + /// The "exclude from search" value for . + public const string NO_SERIAL = null; + + /// The "exclude from search" value for . + public const int NO_VID = int.MaxValue; + + /// The "exclude from search" value for . + public static readonly Guid NO_GUID = Guid.Empty; + + private Guid mDeviceInterfaceGuid = Guid.Empty; + private int mPid = int.MaxValue; + private int mRevision = int.MaxValue; + private string mSerialNumber; + private int mVid = int.MaxValue; + + /// + /// Creates a UsbDeviceFinder class for locating and identifying usb devices. + /// + /// The vendor id of the usb device to find, or to ignore. + /// The product id of the usb device to find, or to ignore. + /// The revision number of the usb device to find, or to ignore. + /// The serial number of the usb device to find, or null to ignore. + /// The unique guid of the usb device to find, or to ignore. + public UsbDeviceFinder(int vid, int pid, int revision, string serialNumber, Guid deviceInterfaceGuid) + { + mVid = vid; + mPid = pid; + mRevision = revision; + mSerialNumber = serialNumber; + mDeviceInterfaceGuid = deviceInterfaceGuid; + } + + /// + /// Creates a UsbDeviceFinder class for locating usb devices by VendorID, ProductID, and Serial number. + /// + /// The vendor id of the usb device to find. + /// The product id of the usb device to find. + /// The serial number of the usb device to find. + public UsbDeviceFinder(int vid, int pid, string serialNumber) + : this(vid, pid, int.MaxValue, serialNumber, Guid.Empty) { } + + /// + /// Creates a UsbDeviceFinder class for locating usb devices by VendorID, ProuctID, and Revision code. + /// + /// The vendor id of the usb device to find. + /// The product id of the usb device to find. + /// The revision number of the usb device to find. + public UsbDeviceFinder(int vid, int pid, int revision) + : this(vid, pid, revision, null, Guid.Empty) { } + + /// + /// Creates a UsbDeviceFinder class for locating usb devices vendor and product ID. + /// + /// The vendor id of the usb device to find. + /// The product id of the usb device to find. + public UsbDeviceFinder(int vid, int pid) + : this(vid, pid, int.MaxValue, null, Guid.Empty) { } + + /// + /// Creates a UsbDeviceFinder class for locating usb devices. + /// + /// The vendor id of the usb device to find. + public UsbDeviceFinder(int vid) + : this(vid, int.MaxValue, int.MaxValue, null, Guid.Empty) { } + + /// + /// Creates a UsbDeviceFinder class for locating usb devices by a serial number. + /// + /// The serial number of the usb device to find. + public UsbDeviceFinder(string serialNumber) + : this(int.MaxValue, int.MaxValue, int.MaxValue, serialNumber, Guid.Empty) { } + + /// + /// Creates a UsbDeviceFinder class for locating usb devices by a unique string. + /// + /// The unique to find. + public UsbDeviceFinder(Guid deviceInterfaceGuid) + : this(int.MaxValue, int.MaxValue, int.MaxValue, null, deviceInterfaceGuid) { } + + /// + /// Use a serialization stream to fill the class. + /// + /// + /// + protected UsbDeviceFinder(SerializationInfo info, StreamingContext context) + { + if (info == null) + throw new ArgumentNullException("info"); + + mVid = (int) info.GetValue("Vid", typeof (int)); + mPid = (int) info.GetValue("Pid", typeof (int)); + mRevision = (int) info.GetValue("Revision", typeof (int)); + mSerialNumber = (string) info.GetValue("SerialNumber", typeof (string)); + mDeviceInterfaceGuid = (Guid) info.GetValue("DeviceInterfaceGuid", typeof (Guid)); + } + + /// + /// + /// + protected UsbDeviceFinder() { } + + /// + /// The device interface guid string to find, or to ignore. + /// + public Guid DeviceInterfaceGuid + { + get { return mDeviceInterfaceGuid; } + set { mDeviceInterfaceGuid = value; } + } + + /// + /// The serial number of the device to find. + /// + /// + /// Set to null to ignore. + /// + public string SerialNumber + { + get { return mSerialNumber; } + set { mSerialNumber = value; } + } + + /// + /// The revision number of the device to find. + /// + /// + /// Set to to ignore. + /// + public int Revision + { + get { return mRevision; } + set { mRevision = value; } + } + + /// + /// The product id of the device to find. + /// + /// + /// Set to to ignore. + /// + public int Pid + { + get { return mPid; } + set { mPid = value; } + } + + /// + /// The vendor id of the device to find. + /// + /// + /// Set to to ignore. + /// + public int Vid + { + get { return mVid; } + set { mVid = value; } + } + + #region ISerializable Members + + /// + /// Store this class as a binary serializtion object. + /// + /// The serialization instance to populate. + /// + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + if (info == null) + throw new ArgumentNullException("info"); + + info.AddValue("Vid", mVid); + info.AddValue("Pid", mPid); + info.AddValue("Revision", mRevision); + info.AddValue("SerialNumber", mSerialNumber); + info.AddValue("DeviceInterfaceGuid", mDeviceInterfaceGuid); + } + + #endregion + + /// + /// Load usb device finder properties from a binary stream. + /// + /// The binary stream containing a + /// instance. + /// A pre-loaded instance. + public static UsbDeviceFinder Load(Stream deviceFinderStream) + { + BinaryFormatter formatter = new BinaryFormatter(); + return formatter.Deserialize(deviceFinderStream) as UsbDeviceFinder; + } + + /// + /// Saves a instance to a stream. + /// + /// + /// + public static void Save(UsbDeviceFinder usbDeviceFinder, Stream outStream) + { + BinaryFormatter formatter = new BinaryFormatter(); + formatter.Serialize(outStream, usbDeviceFinder); + } + + /// + /// Dynamic predicate find function. Pass this function into any method that has a parameter. + /// + /// + /// Override this member when inheriting the class to change/alter the matching behavior. + /// + /// The UsbRegistry device to check. + /// True if the instance matches the properties. + public virtual bool Check(UsbRegistry usbRegistry) + { + if (mVid != int.MaxValue) + if (usbRegistry.Vid != mVid) return false; + if (mPid != int.MaxValue) + if (usbRegistry.Pid != mPid) return false; + if (mRevision != int.MaxValue) + if (usbRegistry.Rev != mRevision) return false; + + if (!String.IsNullOrEmpty(mSerialNumber)) + { + if (String.IsNullOrEmpty(usbRegistry.SymbolicName)) return false; + + UsbSymbolicName usbSymbolicName = UsbSymbolicName.Parse(usbRegistry.SymbolicName); + if (mSerialNumber != usbSymbolicName.SerialNumber) return false; + } + if (mDeviceInterfaceGuid != Guid.Empty) + { + List deviceGuids = new List(usbRegistry.DeviceInterfaceGuids); + if (!deviceGuids.Contains(mDeviceInterfaceGuid)) return false; + } + return true; + } + /// + /// Dynamic predicate find function. Pass this function into any method that has a parameter. + /// + /// + /// Override this member when inheriting the class to change/alter the matching behavior. + /// + /// The UsbDevice to check. + /// True if the instance matches the properties. + public virtual bool Check(UsbDevice usbDevice) + { + if (mVid != int.MaxValue) + if (((ushort)usbDevice.Info.Descriptor.VendorID) != mVid) return false; + if (mPid != int.MaxValue) + if (((ushort)usbDevice.Info.Descriptor.ProductID) != mPid) return false; + if (mRevision != int.MaxValue) + if (((ushort)usbDevice.Info.Descriptor.BcdDevice) != mRevision) return false; + + if (!String.IsNullOrEmpty(mSerialNumber)) + if (mSerialNumber!=usbDevice.Info.SerialString) return false; + + return true; + } + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/UsbEndpointBase.cs b/LibWinUsb/Main/UsbEndpointBase.cs new file mode 100644 index 0000000..f679775 --- /dev/null +++ b/LibWinUsb/Main/UsbEndpointBase.cs @@ -0,0 +1,391 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Collections.ObjectModel; +using System.Runtime.InteropServices; +using LibUsbDotNet.Info; +using LibUsbDotNet.Internal; + +namespace LibUsbDotNet.Main +{ + /// + /// Endpoint members common to Read, Write, Bulk, and Interrupt . + /// + public abstract class UsbEndpointBase : IDisposable + { + /// + /// The maximum transfer payload size for all usb endpoints. + /// + /// + /// Transfers greater than this amount are automatically split into + /// multiple transfers. This applies to all endpoint transfer methods + /// (reads and writes). The default is 4megs (4,194,304 bytes) + /// + public static int MaxReadWrite = 65536; + + internal readonly byte mEpNum; + internal readonly UsbApiBase mUsbApi; + private readonly UsbDevice mUsbDevice; + private readonly SafeHandle mUsbHandle; + private bool mIsDisposed; + internal TransferDelegate mPipeTransferSubmit; + private UsbTransfer mTransferContext; + private UsbEndpointInfo mUsbEndpointInfo; + private EndpointType mEndpointType; + private UsbInterfaceInfo mUsbInterfacetInfo; + + internal UsbEndpointBase(UsbDevice usbDevice, byte epNum, EndpointType endpointType) + { + mUsbDevice = usbDevice; + mUsbApi = mUsbDevice.mUsbApi; + mUsbHandle = mUsbDevice.Handle; + mEpNum = epNum; + mEndpointType = endpointType; + if ((mEpNum & 0x80) > 0) + { + mPipeTransferSubmit = ReadPipe; + } + else + mPipeTransferSubmit = WritePipe; + } + + + internal virtual TransferDelegate PipeTransferSubmit + { + get { return mPipeTransferSubmit; } + } + + internal UsbTransfer TransferContext + { + get + { + if (ReferenceEquals(mTransferContext, null)) + { + mTransferContext = CreateTransferContext(); + } + return mTransferContext; + } + } + + /// + /// Gets a value indicating if the object is disposed. + /// + public bool IsDisposed + { + get { return mIsDisposed; } + } + + /// + /// Gets the class this endpoint belongs to. + /// + public UsbDevice Device + { + get { return mUsbDevice; } + } + + + internal SafeHandle Handle + { + get { return mUsbHandle; } + } + + /// + /// Gets the endpoint ID for this class. + /// + public byte EpNum + { + get + { + return mEpNum; + } + } + + /// + /// Returns the for this endpoint. + /// + public EndpointType Type + { + get { return mEndpointType; } + } + + /// + /// Returns the descriptor for this endpoint. + /// + public UsbEndpointInfo EndpointInfo + { + get + { + if (ReferenceEquals(mUsbEndpointInfo, null)) + { + if (!LookupEndpointInfo(Device.Configs[0], mEpNum, out mUsbInterfacetInfo, out mUsbEndpointInfo)) + { + // throw new UsbException(this, String.Format("Failed locating endpoint {0} for the current usb configuration.", mEpNum)); + return null; + } + } + return mUsbEndpointInfo; + } + } + + #region IDisposable Members + + /// + /// Frees resources associated with the endpoint. Once disposed this cannot be used. + /// + public virtual void Dispose() { DisposeAndRemoveFromList(); } + + #endregion + + internal abstract UsbTransfer CreateTransferContext(); + + /// + /// Aborts pending IO operation on this enpoint of one exists. + /// + /// True on success or if no pending IO operation exits. + public virtual bool Abort() + { + if (mIsDisposed) throw new ObjectDisposedException(GetType().Name); + bool bSuccess = TransferContext.Cancel() == ErrorCode.Success; + + return bSuccess; + } + + /// + /// Discards any data that is cached in this endpoint. + /// + /// True on success. + public virtual bool Flush() + { + if (mIsDisposed) throw new ObjectDisposedException(GetType().Name); + + bool bSuccess = mUsbApi.FlushPipe(mUsbHandle, EpNum); + + if (!bSuccess) UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "FlushPipe", this); + + return bSuccess; + } + + /// + /// Resets the data toggle and clears the stall condition on an enpoint. + /// + /// True on success. + public virtual bool Reset() + { + if (mIsDisposed) throw new ObjectDisposedException(GetType().Name); + + bool bSuccess = mUsbApi.ResetPipe(mUsbHandle, EpNum); + + if (!bSuccess) UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "ResetPipe", this); + + return bSuccess; + } + + /// + /// Synchronous bulk/interrupt transfer function. + /// + /// An to a caller-allocated buffer. + /// Position in buffer that transferring begins. + /// Number of bytes, starting from thr offset parameter to transfer. + /// Maximum time to wait for the transfer to complete. + /// Number of bytes actually transferred. + /// True on success. + public virtual ErrorCode Transfer(IntPtr buffer, int offset, int length, int timeout, out int transferLength) { return UsbTransfer.SyncTransfer(TransferContext, buffer, offset, length, timeout, out transferLength); } + + /// + /// Creates, fills and submits an asynchronous context. + /// + /// + /// This is a non-blocking asynchronous transfer function. This function returns immediately after the context is created and submitted. + /// + /// A caller-allocated buffer for the data that is transferred. + /// Position in buffer that transferring begins. + /// Number of bytes, starting from thr offset parameter to transfer. + /// Maximum time to wait for the transfer to complete. + /// On , a new transfer context. + /// if the transfer context was created and succeeded. + /// + /// + public virtual ErrorCode SubmitAsyncTransfer(object buffer, int offset, int length, int timeout, out UsbTransfer transferContext) + { + transferContext = CreateTransferContext(); + transferContext.Fill(buffer, offset, length, timeout); + + ErrorCode ec = transferContext.Submit(); + if (ec != ErrorCode.None) + { + transferContext.Dispose(); + transferContext = null; + UsbError.Error(ec, 0, "SubmitAsyncTransfer Failed", this); + } + + return ec; + } + + /// + /// Creates, fills and submits an asynchronous context. + /// + /// + /// This is a non-blocking asynchronous transfer function. This function returns immediately after the context is created and submitted. + /// + /// A caller-allocated buffer for the data that is transferred. + /// Position in buffer that transferring begins. + /// Number of bytes, starting from thr offset parameter to transfer. + /// Maximum time to wait for the transfer to complete. + /// On , a new transfer context. + /// if the transfer context was created and succeeded. + /// + /// + public virtual ErrorCode SubmitAsyncTransfer(IntPtr buffer, int offset, int length, int timeout, out UsbTransfer transferContext) + { + transferContext = CreateTransferContext(); + transferContext.Fill(buffer, offset, length, timeout); + + ErrorCode ec = transferContext.Submit(); + if (ec != ErrorCode.None) + { + transferContext.Dispose(); + transferContext = null; + UsbError.Error(ec, 0, "SubmitAsyncTransfer Failed", this); + } + + return ec; + } + /// + /// Creates a context for asynchronous transfers. + /// + /// + /// This method returns a new, empty transfer context. Unlike SubmitAsyncTransfer, this context is not filled and submitted. + /// This is a non-blocking asynchronous transfer function. This function returns immediately after the context created. + /// + /// A new context. + /// + /// + public UsbTransfer NewAsyncTransfer() + { + UsbTransfer transfer = CreateTransferContext(); + return transfer; + } + + /// + /// Looks up endpoint/interface information in a configuration. + /// + /// The config to seach. + /// The endpoint address to look for. + /// On success, the class for this endpoint. + /// On success, the class for this endpoint. + /// True of the endpoint was found, otherwise false. + public static bool LookupEndpointInfo(UsbConfigInfo currentConfigInfo, byte endpointAddress, out UsbInterfaceInfo usbInterfaceInfo, out UsbEndpointInfo usbEndpointInfo) + { + bool found = false; + + usbInterfaceInfo = null; + usbEndpointInfo = null; + foreach (UsbInterfaceInfo interfaceInfo in currentConfigInfo.InterfaceInfoList) + { + foreach (UsbEndpointInfo endpointInfo in interfaceInfo.EndpointInfoList) + { + if ((endpointAddress & UsbConstants.ENDPOINT_NUMBER_MASK) == 0) + { + // find first read/write endpoint + if ((endpointAddress & UsbConstants.ENDPOINT_DIR_MASK) == 0 && + (endpointInfo.Descriptor.EndpointID & UsbConstants.ENDPOINT_DIR_MASK) == 0) + { + // first write endpoint + found = true; + } + if ((endpointAddress & UsbConstants.ENDPOINT_DIR_MASK) != 0 && + (endpointInfo.Descriptor.EndpointID & UsbConstants.ENDPOINT_DIR_MASK) != 0) + { + // first read endpoint + found = true; + } + } + else if (endpointInfo.Descriptor.EndpointID == endpointAddress) + { + found = true; + } + + if (found) + { + usbInterfaceInfo = interfaceInfo; + usbEndpointInfo = endpointInfo; + return true; + } + } + } + return false; + } + + /// + /// Synchronous bulk/interrupt transfer function. + /// + /// A caller-allocated buffer for the transfer data. This object is pinned using . + /// Position in buffer that transferring begins. + /// Number of bytes, starting from thr offset parameter to transfer. + /// Maximum time to wait for the transfer to complete. + /// Number of bytes actually transferred. + /// True on success. + public ErrorCode Transfer(object buffer, int offset, int length, int timeout, out int transferLength) + { + PinnedHandle pinned = new PinnedHandle(buffer); + ErrorCode eReturn = Transfer(pinned.Handle, offset, length, timeout, out transferLength); + pinned.Dispose(); + return eReturn; + } + + private void DisposeAndRemoveFromList() + { + if (!mIsDisposed) + { + UsbEndpointReader epReader = this as UsbEndpointReader; + if (!ReferenceEquals(epReader, null)) + { + if (epReader.DataReceivedEnabled) epReader.DataReceivedEnabled = false; + } + Abort(); + mUsbDevice.ActiveEndpoints.RemoveFromList(this); + } + mIsDisposed = true; + } + + private int ReadPipe(IntPtr pBuffer, int bufferLength, out int lengthTransferred, int isoPacketSize, IntPtr pOverlapped) + { + bool bSuccess = mUsbApi.ReadPipe(this, pBuffer, bufferLength, out lengthTransferred, isoPacketSize, pOverlapped); + if (!bSuccess) return Marshal.GetLastWin32Error(); + return 0; + } + + + private int WritePipe(IntPtr pBuffer, int bufferLength, out int lengthTransferred, int isoPacketSize, IntPtr pOverlapped) + { + bool bSuccess = mUsbApi.WritePipe(this, pBuffer, bufferLength, out lengthTransferred, isoPacketSize, pOverlapped); + if (!bSuccess) return Marshal.GetLastWin32Error(); + return 0; + } + + #region Nested type: TransferDelegate + + internal delegate int TransferDelegate(IntPtr pBuffer, int bufferLength, out int lengthTransferred, int isoPacketSize, IntPtr pOverlapped); + + #endregion + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/UsbEndpointDirection.cs b/LibWinUsb/Main/UsbEndpointDirection.cs new file mode 100644 index 0000000..89f15f9 --- /dev/null +++ b/LibWinUsb/Main/UsbEndpointDirection.cs @@ -0,0 +1,40 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; + +namespace LibUsbDotNet.Main +{ + ///Endpoint direction. + /// + [Flags] + public enum UsbEndpointDirection : byte + { + /// + /// In Direction + /// + EndpointIn = 0x80, + /// + /// Out Direction + /// + EndpointOut = 0x00, + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/UsbEndpointList.cs b/LibWinUsb/Main/UsbEndpointList.cs new file mode 100644 index 0000000..7e6ef8d --- /dev/null +++ b/LibWinUsb/Main/UsbEndpointList.cs @@ -0,0 +1,147 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System.Collections; +using System.Collections.Generic; + +namespace LibUsbDotNet.Main +{ + /// Endpoint list. + /// + public class UsbEndpointList : IEnumerable + { + private readonly List mEpList = new List(); + + internal UsbEndpointList() { } + + /// + /// Gets the item at the specified index. + /// + /// The zero-based index of the item. + /// The item at the specified index. + ///index is not a valid index in the . + public UsbEndpointBase this[int index] + { + get { return mEpList[index]; } + } + + /// + ///Gets the number of elements contained in the . + /// + /// + /// + ///The number of elements contained in the . + /// + /// + public int Count + { + get { return mEpList.Count; } + } + + #region IEnumerable Members + + /// + ///Returns enumerator that iterates through the collection. + /// + /// + /// + ///A enumerator that can be used to iterate through the collection. + /// + public IEnumerator GetEnumerator() { return mEpList.GetEnumerator(); } + + /// + ///Returns an enumerator that iterates through a collection. + /// + /// + /// + ///An object that can be used to iterate through the collection. + /// + ///2 + IEnumerator IEnumerable.GetEnumerator() { return mEpList.GetEnumerator(); } + + #endregion + + /// + ///Removes all items from the . + /// + public void Clear() + { + while (mEpList.Count > 0) + Remove(mEpList[0]); + } + + /// + ///Determines whether the contains a specific value. + /// + /// + /// + ///true if item is found in the ; otherwise, false. + /// + /// + ///The to locate in the . + public bool Contains(UsbEndpointBase item) { return mEpList.Contains(item); } + + + /// + ///Determines the index of a specific in the . + /// + /// + /// + ///The index of item if found in the list; otherwise, -1. + /// + /// + ///The to locate in the . + public int IndexOf(UsbEndpointBase item) { return mEpList.IndexOf(item); } + + /// + ///Removes the specified in the . + /// + /// + ///The to remove in the . + public void Remove(UsbEndpointBase item) { item.Dispose(); } + + /// + ///Removes the item at the specified index. + /// + /// + ///The zero-based index of the item to remove. + ///index is not a valid index in the . + public void RemoveAt(int index) + { + UsbEndpointBase item = mEpList[index]; + Remove(item); + } + + + internal UsbEndpointBase Add(UsbEndpointBase item) + { + foreach (UsbEndpointBase endpoint in mEpList) + { + if (endpoint.EpNum == item.EpNum) + return endpoint; + } + mEpList.Add(item); + return item; + } + + internal bool RemoveFromList(UsbEndpointBase item) { return mEpList.Remove(item); } + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/UsbException.cs b/LibWinUsb/Main/UsbException.cs new file mode 100644 index 0000000..54ffcb4 --- /dev/null +++ b/LibWinUsb/Main/UsbException.cs @@ -0,0 +1,46 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +namespace LibUsbDotNet.Main +{ + /// + /// Represents an exception generated by a USB operation. + /// + public class UsbException : Exception + { + private readonly object mSender; + + /// + /// LibUsbDotNet USB exception. + /// + internal UsbException(object sender, string description) + : base(description) { mSender = sender; } + + /// + /// The object that caused the exception. + /// + public object Sender + { + get { return mSender; } + } + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/UsbKernelVersion.cs b/LibWinUsb/Main/UsbKernelVersion.cs new file mode 100644 index 0000000..b29e713 --- /dev/null +++ b/LibWinUsb/Main/UsbKernelVersion.cs @@ -0,0 +1,91 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System.Runtime.InteropServices; + +namespace LibUsbDotNet.Main +{ + /// + /// Contains version information for the LibUsb Sys driver. + /// + /// + /// This version is not related to LibUsbDotNet. TO get the LibUsbDotNet version use .NET reflections. + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct UsbKernelVersion + { + /// + /// True if Major == 0 and Minor == 0 and Micro == 0 and Nano == 0. + /// + 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; + } + + /// + /// LibUsb-Win32 Major version + /// + public readonly int Major; + + /// + /// LibUsb-Win32 Minor version + /// + public readonly int Minor; + + /// + /// LibUsb-Win32 Micro version + /// + public readonly int Micro; + + /// + /// LibUsb-Win32 Nano version + /// + public readonly int Nano; + + /// + /// The LibUsbDotNet - LibUsb-Win32 binary mod code. if not running the LibUsbDotNet LibUsb-Win32 modified kernel driver, this value is 0. + /// + public readonly int BcdLibUsbDotNetKernelMod; + + + /// + ///The full LibUsb-Win32 kernel driver version (libusb0.sys). + /// + /// + /// + ///A containing the full LibUsb-Win32 version. + /// + public override string ToString() { return string.Format("{0}.{1}.{2}.{3}", Major, Minor, Micro, Nano); } + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/UsbLockStyle.cs b/LibWinUsb/Main/UsbLockStyle.cs new file mode 100644 index 0000000..5f90598 --- /dev/null +++ b/LibWinUsb/Main/UsbLockStyle.cs @@ -0,0 +1,146 @@ +// Copyright © 2006-2009 Travis Robinson. All rights reserved. +// +// website: sourceforge.net/projects/libusbdotnet/ +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +namespace LibUsbDotNet.Main +{ + /// Contains the locking strategy for a and it's associated endpoints. + /// Locking styles are use to change the way proccess/threads are allowed to communcate with a USB device and/or endpoints. + /// See the , , and enumerations for a description of the various locking styles. + /// + public class UsbLockStyle + { + private ControlEpLockType mControlEpLock; + private DataEpLockType mDataEpLock; + private DeviceLockType mDeviceLockType; + private int mEndpointControlTimeout; + private int mEndpointLockTimeout; + + /// + /// Create a device lock style class. + /// + /// See . + /// See . + /// See . + public UsbLockStyle(DeviceLockType deviceLockType, ControlEpLockType controlEpLockType, DataEpLockType dataEpLockType) + : this(deviceLockType, controlEpLockType, dataEpLockType, 1000, 1000) + { + } + + /// + /// Create a device lock style class. + /// + /// See . + /// See . + /// See . + /// Number of milliseconds to wait for an endpoint 0 lock before returning a timeout errorcode. + /// Number of milliseconds to wait for an endpoint lock before returning a timeout errorcode. + public UsbLockStyle(DeviceLockType deviceLockType, + ControlEpLockType controlEpLockType, + DataEpLockType dataEpLockType, + int endpoint0Timeout, + int endpointLockTimeout) + { + mDeviceLockType = deviceLockType; + mControlEpLock = controlEpLockType; + mDataEpLock = dataEpLockType; + mEndpointControlTimeout = endpoint0Timeout; + mEndpointLockTimeout = endpointLockTimeout; + } + + /// + /// Locking strategy for the device. See for more information. + /// + public DeviceLockType DeviceLockType + { + get + { + return mDeviceLockType; + } + set + { + mDeviceLockType = value; + } + } + + /// + /// Locking strategy for Endpoint0 operations. This property will generally always be , See for more information. + /// + public ControlEpLockType ControlEpLock + { + get + { + return mControlEpLock; + } + set + { + mControlEpLock = value; + } + } + + /// + /// Locking strategy for the endpoint operations. See for more information. + /// + public DataEpLockType DataEpLock + { + get + { + return mDataEpLock; + } + set + { + mDataEpLock = value; + } + } + + /// + /// Timeout value used when attempting to aquire an when is set to a value other than . + /// + public int EndpointControlTimeout + { + get + { + return mEndpointControlTimeout; + } + set + { + mEndpointControlTimeout = value; + } + } + + /// + /// Maximum time(ms) to wait for an endpoint to become idle before returning a error code. + /// + /// + /// This property has no affect unless the includes the enumeration. + /// + public int EndpointLockTimeout + { + get + { + return mEndpointLockTimeout; + } + set + { + mEndpointLockTimeout = value; + } + } + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/UsbRegDeviceList.cs b/LibWinUsb/Main/UsbRegDeviceList.cs new file mode 100644 index 0000000..574dca3 --- /dev/null +++ b/LibWinUsb/Main/UsbRegDeviceList.cs @@ -0,0 +1,179 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Collections; +using System.Collections.Generic; + +namespace LibUsbDotNet.Main +{ + /// + /// Array of USB device available for communication via LibUsb or WinUsb. + /// + public class UsbRegDeviceList : IEnumerable + { + private readonly List mUsbRegistryList; + + /// + /// Creates an empty instance. + /// + public UsbRegDeviceList() { mUsbRegistryList = new List(); } + + private UsbRegDeviceList(IEnumerable usbRegDeviceList) { mUsbRegistryList = new List(usbRegDeviceList); } + + /// + ///Gets the element at the specified index. + /// + /// + /// + ///The element at the specified index. + /// + /// + ///The zero-based index of the element to get or set. + ///index is not a valid index in the . + ///The property is set and the is read-only. + public UsbRegistry this[int index] + { + get { return mUsbRegistryList[index]; } + } + + /// + ///Gets the number of elements contained in the . + /// + /// + /// + ///The number of elements contained in the . + /// + /// + public int Count + { + get { return mUsbRegistryList.Count; } + } + + #region IEnumerable Members + + /// + ///Returns an enumerator that iterates through the collection. + /// + /// + /// + ///A that can be used to iterate through the collection. + /// + IEnumerator IEnumerable.GetEnumerator() { return mUsbRegistryList.GetEnumerator(); } + + /// + ///Returns an enumerator that iterates through a collection. + /// + /// + /// + ///An object that can be used to iterate through the collection. + /// + public IEnumerator GetEnumerator() { return ((IEnumerable) this).GetEnumerator(); } + + #endregion + + /// + /// Find the first UsbRegistry device that matches the FindUsbPredicate. + /// + /// The predicate function to use. + /// A valid usb registry class if the device was found or Null if the device was not found. + public UsbRegistry Find(Predicate findUsbPredicate) { return mUsbRegistryList.Find(findUsbPredicate); } + + /// + /// Find all UsbRegistry devices that matches the FindUsbPredicate. + /// + /// The predicate function to use. + /// All usb registry classes that match. + public UsbRegDeviceList FindAll(Predicate findUsbPredicate) { return new UsbRegDeviceList(mUsbRegistryList.FindAll(findUsbPredicate)); } + + /// + /// Find the last a UsbRegistry device that matches the FindUsbPredicate. + /// + /// The predicate function to use. + /// A valid usb registry class if the device was found or Null if the device was not found. + public UsbRegistry FindLast(Predicate findUsbPredicate) { return mUsbRegistryList.FindLast(findUsbPredicate); } + + /// + /// Find the first UsbRegistry device using a instance. + /// + /// The instance used to locate the usb registry devices. + /// A valid usb registry class if the device was found or Null if the device was not found. + public UsbRegistry Find(UsbDeviceFinder usbDeviceFinder) { return mUsbRegistryList.Find((Predicate) usbDeviceFinder.Check); } + + /// + /// Find all UsbRegistry devices using a instance. + /// + /// The instance used to locate the usb registry devices. + /// All usb registry classes that match. + public UsbRegDeviceList FindAll(UsbDeviceFinder usbDeviceFinder) { return FindAll((Predicate)usbDeviceFinder.Check); } + + /// + /// Find the last UsbRegistry devices using a instance. + /// + /// The instance used to locate the usb registry devices. + /// A valid usb registry class if the device was found or Null if the device was not found. + public UsbRegistry FindLast(UsbDeviceFinder usbDeviceFinder) { return mUsbRegistryList.FindLast((Predicate)usbDeviceFinder.Check); } + + /// + ///Determines whether the contains a specific value. + /// + /// + /// + ///true if item is found in the ; otherwise, false. + /// + /// + ///The object to locate in the . + public bool Contains(UsbRegistry item) { return mUsbRegistryList.Contains(item); } + + /// + ///Copies the elements of the to an , starting at a particular index. + /// + /// + ///The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. + ///The zero-based index in Array at which copying begins. + ///Offset is less than 0. + ///Array is null. + ///Array is multidimensional.-or-Offset is equal to or greater than the length of Array.-or-The number of elements in the source is greater than the available space from Offset to the end of the destination Array.-or-Type T cannot be cast automatically to the type of the destination Array. + public void CopyTo(UsbRegistry[] array, int offset) { mUsbRegistryList.CopyTo(array, offset); } + + /// + ///Determines the index of a specific item in the . + /// + /// + /// + ///The index of item if found in the list; otherwise, -1. + /// + /// + ///The object to locate in the . + public int IndexOf(UsbRegistry item) { return mUsbRegistryList.IndexOf(item); } + + internal bool Add(UsbRegistry item) + { + //for (int i = 0; i < Count; i++) + //{ + // if (mUsbRegistryList[i] == item) + // return false; + //} + mUsbRegistryList.Add(item); + return true; + } + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/UsbRegistry.cs b/LibWinUsb/Main/UsbRegistry.cs new file mode 100644 index 0000000..f957c59 --- /dev/null +++ b/LibWinUsb/Main/UsbRegistry.cs @@ -0,0 +1,332 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Collections.Generic; +using System.Text; +using LibUsbDotNet.Descriptors; + +namespace LibUsbDotNet.Main +{ + /// USB device registry members common to both LibUsb and WinUsb devices. + /// + public abstract class UsbRegistry //: IEquatable + { + internal const string DEVICE_INTERFACE_GUIDS = "DeviceInterfaceGuids"; + internal const string LIBUSB_INTERFACE_GUIDS = "LibUsbInterfaceGUIDs"; + + internal const string SYMBOLIC_NAME_KEY = "SymbolicName"; + internal const string DEVICE_ID_KEY = "DeviceID"; + + private static readonly char[] ChNull = new char[] {'\0'}; + + /// + /// If true, LibUsbDotNet will use the vid, pid and revision of the + /// descriptor to lookup additional device information in the windows registry via the setupapi. + /// Setting this field to false will cause all device information to come directly from the + /// device descriptors. + /// + /// + /// + /// If using WinUSB or the LibUsbDotNet-libusb-win32 native driver, information provided by + /// the class will come from the registry regardless of this setting + /// because these drivers have direct support for this. + /// + /// + /// The Libusb-1.0 windows-backend driver and the legacy libusb-win32 driver have their own methods + /// for listing, finding, and opening devices. For these drivers, the can + /// be set to do a "reverse lookup" via the setupapi using only the vid, pid and revision of the + /// . The class is then populated with + /// all available properties, device interface guids, winusb device paths, etc. + /// + /// + public static bool ForceSetupApi = true; + + /// + /// Guid array of all assigned to this device. + /// + internal Guid[] mDeviceInterfaceGuids=new Guid[0]; + + internal Dictionary mDeviceProperties = new Dictionary(); + + private UsbSymbolicName mSymHardwareId; + + /// + /// Collection of known usb device properties (from the registry). + /// + public Dictionary DeviceProperties + { + get { return mDeviceProperties; } + } + + /// + /// Check this value to determine if the usb device is still connected to the bus and ready to open. + /// + /// + /// Uses the symbolic name as a unique id to determine if this device instance is still attached. + /// + /// An exception is thrown if the property is null or empty. + public abstract bool IsAlive { get; } + + /// + /// The unique "SymbolicName" of the device. + /// + public string SymbolicName + { + get + { + if (mDeviceProperties.ContainsKey(SYMBOLIC_NAME_KEY)) + return (string) mDeviceProperties[SYMBOLIC_NAME_KEY]; + return null; + } + } + + /// + /// The unique "SymbolicName" of the device. + /// + public abstract Guid[] DeviceInterfaceGuids { get; } + + /// + /// VendorID + /// + public virtual int Vid + { + get + { + if (ReferenceEquals(mSymHardwareId, null)) + { + string[] saHardwareIds = mDeviceProperties[SPDRP.HardwareId.ToString()] as string[]; + if (saHardwareIds != null && saHardwareIds.Length > 0) + { + mSymHardwareId = UsbSymbolicName.Parse(saHardwareIds[0]); + } + } + if (!ReferenceEquals(mSymHardwareId, null)) + { + return mSymHardwareId.Vid; + } + + return 0; + } + } + + /// + /// ProductID + /// + public virtual int Pid + { + get + { + if (ReferenceEquals(mSymHardwareId, null)) + { + string[] saHardwareIds = mDeviceProperties[SPDRP.HardwareId.ToString()] as string[]; + if (saHardwareIds != null && saHardwareIds.Length > 0) + { + mSymHardwareId = UsbSymbolicName.Parse(saHardwareIds[0]); + } + } + if (!ReferenceEquals(mSymHardwareId, null)) + { + return mSymHardwareId.Pid; + } + + return 0; + } + } + + /// + /// Gets a device property/key from the registry. + /// + /// The name of the property to retrieve. + /// + public object this[string name] + { + get + { + object temp; + mDeviceProperties.TryGetValue(name, out temp); + return temp; + } + } + + /// + /// Gets a device property/key from the registry. See the enumeration for more information. + /// + /// The name of the property to retrieve. + /// + public object this[SPDRP spdrp] + { + get + { + object temp; + mDeviceProperties.TryGetValue(spdrp.ToString(), out temp); + return temp; + } + } + + /// + /// Gets a property from the registry. See the enumeration for more information. + /// + /// The name of the property to retrieve. + /// + public object this[DevicePropertyType devicePropertyType] + { + get + { + object temp; + mDeviceProperties.TryGetValue(devicePropertyType.ToString(), out temp); + return temp; + } + } + + /// + /// Gets the short name of the usb device. + /// + /// This is the device decription as it is defined in the setup/inf file. + public string Name + { + get + { + string deviceDesc = this[SPDRP.DeviceDesc] as string; + if (String.IsNullOrEmpty(deviceDesc)) return string.Empty; + return deviceDesc; + } + } + + /// + /// Gets the manufacturer followed by the device decription in the format 'Mfu - Description' + /// + /// This property works best for a display name. It does additional proccessing on the manufacturer and device description that make it more user readable. + public string FullName + { + get + { + string deviceDesc = Name; + string mfg = this[SPDRP.Mfg] as string; + if (mfg == null) mfg = String.Empty; + deviceDesc = deviceDesc.Trim(); + mfg = mfg.Trim(); + + int firstMfuSpace = mfg.IndexOf(' '); + int firstDescSpace = deviceDesc.IndexOf(' '); + while (firstMfuSpace == firstDescSpace && firstDescSpace != -1) + { + if (mfg.Substring(0, firstMfuSpace).Equals(deviceDesc.Substring(0, firstDescSpace))) + { + deviceDesc = deviceDesc.Remove(0, firstDescSpace + 1); + firstMfuSpace = mfg.IndexOf(' '); + firstDescSpace = deviceDesc.IndexOf(' '); + } + else + { + break; + } + } + + if (deviceDesc.ToLower().Contains(mfg.ToLower())) + return deviceDesc; + + if (mfg == string.Empty) mfg = "[Not Provided]"; + if (deviceDesc == string.Empty) deviceDesc = "[Not Provided]"; + + return (mfg + " - " + deviceDesc); + } + } + + /// + /// Number of properties in the array. + /// + public int Count + { + get { return mDeviceProperties.Count; } + } + + /// + /// Usb device revision number. + /// + public virtual int Rev + { + get + { + if (ReferenceEquals(mSymHardwareId, null)) + { + string[] saHardwareIds = mDeviceProperties[SPDRP.HardwareId.ToString()] as string[]; + if (saHardwareIds != null && saHardwareIds.Length > 0) + { + mSymHardwareId = UsbSymbolicName.Parse(saHardwareIds[0]); + } + } + if (!ReferenceEquals(mSymHardwareId, null)) + { + return mSymHardwareId.Rev; + } + + return 0; + } + } + + /// + /// Opens the USB device for communucation. + /// + /// Return a new instance of the class. + /// If the device fails to open a null refrence is return. For extended error + /// information see the . + /// + public abstract UsbDevice Device { get; } + + /// + /// Opens the USB device for communucation. + /// + /// The newly created UsbDevice. + /// True on success. + public abstract bool Open(out UsbDevice usbDevice); + + internal static Guid GetAsGuid(byte[] buffer, int len) + { + Guid rtn = Guid.Empty; + if (len == 16) + { + byte[] guidBytes = new byte[len]; + Array.Copy(buffer, guidBytes, guidBytes.Length); + rtn = new Guid(guidBytes); + } + + return rtn; + } + + internal static string GetAsString(byte[] buffer, int len) + { + if (len > 2) return Encoding.Unicode.GetString(buffer, 0, len).TrimEnd(ChNull); + + return ""; + } + + internal static string[] GetAsStringArray(byte[] buffer, int len) { return GetAsString(buffer, len).Split(new char[] {'\0'}, StringSplitOptions.RemoveEmptyEntries); } + + internal static Int32 GetAsStringInt32(byte[] buffer, int len) + { + Int32 iRtn = 0; + if (len == 4) + iRtn = buffer[0] | ((buffer[1]) << 8) | ((buffer[2]) << 16) | ((buffer[3]) << 24); + return iRtn; + } + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/UsbRequestRecipient.cs b/LibWinUsb/Main/UsbRequestRecipient.cs new file mode 100644 index 0000000..8ac943c --- /dev/null +++ b/LibWinUsb/Main/UsbRequestRecipient.cs @@ -0,0 +1,48 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; + +namespace LibUsbDotNet.Main +{ + ///Recipient of the request. + /// + [Flags] + public enum UsbRequestRecipient : byte + { + /// + /// Device is recipient. + /// + RecipDevice = 0x00, + /// + /// Endpoint is recipient. + /// + RecipEndpoint = 0x02, + /// + /// Interface is recipient. + /// + RecipInterface = 0x01, + /// + /// Other is recipient. + /// + RecipOther = 0x03, + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/UsbRequestType.cs b/LibWinUsb/Main/UsbRequestType.cs new file mode 100644 index 0000000..7c82c9a --- /dev/null +++ b/LibWinUsb/Main/UsbRequestType.cs @@ -0,0 +1,50 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; + +namespace LibUsbDotNet.Main +{ + /// + /// Standard USB requests. + /// + /// + [Flags] + public enum UsbRequestType : byte + { + /// + /// Class specific request. + /// + TypeClass = (0x01 << 5), + /// + /// RESERVED. + /// + TypeReserved = (0x03 << 5), + /// + /// Standard request. + /// + TypeStandard = (0x00 << 5), + /// + /// Vendor specific request. + /// + TypeVendor = (0x02 << 5), + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/UsbSetupPacket.cs b/LibWinUsb/Main/UsbSetupPacket.cs new file mode 100644 index 0000000..fb045e8 --- /dev/null +++ b/LibWinUsb/Main/UsbSetupPacket.cs @@ -0,0 +1,95 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System.Runtime.InteropServices; + +namespace LibUsbDotNet.Main +{ + /// Transfers data to the main control endpoint (Endpoint 0). + /// + /// 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. + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct UsbSetupPacket + { + /// + /// 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. + /// + /// + ///
    Characteristics of request: + ///
  • D7: Data transfer direction
  • + ///
  • 0 = Host-to-device
  • + ///
  • 1 = Device-to-host
  • + ///
  • D6...5: Type
  • + ///
  • 0 = Standard
  • + ///
  • 1 = Class
  • + ///
  • 2 = Vendor
  • + ///
  • 3 = Reserved
  • + ///
  • D4...0: Recipient
  • + ///
  • 0 = Device
  • + ///
  • 1 = Interface
  • + ///
  • 2 = Endpoint
  • + ///
  • 3 = Other
  • + ///
  • 4...31 = Reserved
  • + ///
+ ///
+ public byte RequestType; + + /// + /// 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. + /// + public byte Request; + + /// + /// The contents of this field vary according to the request. It is used to pass a parameter to the device, specific to the request. + /// + public short Value; + + /// + /// The contents of this field vary according to the request. It is used to pass a parameter to the device, specific to the request. + /// + public short Index; + + /// + /// 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 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. + /// + public short Length; + + /// + /// Creates a new instance of a and initializes all the fields with the following parameters. + /// + /// See . + /// See . + /// See . + /// See . + /// See . + public UsbSetupPacket(byte requestType, byte request, short value, short index, short length) + { + RequestType = requestType; + Request = request; + Value = value; + Index = index; + Length = length; + } + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/UsbStandardRequest.cs b/LibWinUsb/Main/UsbStandardRequest.cs new file mode 100644 index 0000000..301ef89 --- /dev/null +++ b/LibWinUsb/Main/UsbStandardRequest.cs @@ -0,0 +1,78 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// + +using System; + +namespace LibUsbDotNet.Main +{ + /// + /// Standard Device Requests. + /// + [Flags] + public enum UsbStandardRequest : byte + { + /// + /// Clear or disable a specific feature. + /// + ClearFeature = 0x01, + /// + /// Returns the current device Configuration value. + /// + GetConfiguration = 0x08, + /// + /// Returns the specified descriptor if the descriptor exists. + /// + GetDescriptor = 0x06, + /// + /// Returns the selected alternate setting for the specified interface. + /// + GetInterface = 0x0A, + /// + /// Returns status for the specified recipient. + /// + GetStatus = 0x00, + /// + /// Sets the device address for all future device accesses. + /// + SetAddress = 0x05, + /// + /// Sets the device Configuration. + /// + SetConfiguration = 0x09, + /// + /// Optional and may be used to update existing descriptors or new descriptors may be added. + /// + SetDescriptor = 0x07, + /// + /// used to set or enable a specific feature. + /// + SetFeature = 0x03, + /// + /// Allows the host to select an alternate setting for the specified interface. + /// + SetInterface = 0x0B, + /// + /// Used to set and then report an endpoint’s synchronization frame. + /// + SynchFrame = 0x0C, + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/UsbStatusClodes.cs b/LibWinUsb/Main/UsbStatusClodes.cs new file mode 100644 index 0000000..c2fe4b1 --- /dev/null +++ b/LibWinUsb/Main/UsbStatusClodes.cs @@ -0,0 +1,31 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +namespace LibUsbDotNet.Main +{ + internal enum UsbStatusClodes + { + /// + /// Returned bo overlapped IO functions when data is still pending. + /// + ErrorIoPending = 997 + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/UsbStream.cs b/LibWinUsb/Main/UsbStream.cs new file mode 100644 index 0000000..542f65d --- /dev/null +++ b/LibWinUsb/Main/UsbStream.cs @@ -0,0 +1,286 @@ +// Copyright © 2006-2009 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Threading; +using System.Windows.Forms; + +namespace LibUsbDotNet.Main +{ + public class IOCancelledException : IOException + { + public IOCancelledException(string message) : base(message) { } + } + + public class UsbStreamAsyncTransfer : IAsyncResult + { + internal readonly int mCount; + internal readonly int mOffset; + internal readonly object mState; + private readonly int mTimeout; + internal AsyncCallback mCallback; + internal ManualResetEvent mCompleteEvent = new ManualResetEvent(false); + internal GCHandle mGCBuffer; + internal bool mIsComplete; + private ErrorCode mResult; + private int mTrasferredLength; + internal UsbEndpointBase mUsbEndpoint; + + public UsbStreamAsyncTransfer(UsbEndpointBase usbEndpoint, + byte[] buffer, + int offset, + int count, + AsyncCallback callback, + object state, + int timeout) + { + mUsbEndpoint = usbEndpoint; + mOffset = offset; + mCount = count; + mState = state; + mTimeout = timeout; + mCallback = callback; + mGCBuffer = GCHandle.Alloc(buffer, GCHandleType.Pinned); + } + + public ErrorCode Result + { + get { return mResult; } + } + + public int TransferredLength + { + get { return mTrasferredLength; } + } + + #region IAsyncResult Members + + public bool IsCompleted + { + get { return mIsComplete; } + } + + public WaitHandle AsyncWaitHandle + { + get { return mCompleteEvent; } + } + + public object AsyncState + { + get { return mState; } + } + + public bool CompletedSynchronously + { + get { return false; } + } + + #endregion + + public ErrorCode SyncTransfer() + { + mResult = mUsbEndpoint.Transfer(mGCBuffer.AddrOfPinnedObject(), mOffset, mCount, mTimeout, out mTrasferredLength); + mGCBuffer.Free(); + mIsComplete = true; + if (mCallback != null) mCallback(this as IAsyncResult); + mCompleteEvent.Set(); + return mResult; + } + } + + public class UsbStream : Stream + { + private readonly UsbEndpointBase mUsbEndpoint; + private int mTimeout = UsbConstants.DEFAULT_TIMEOUT; + private Thread mWaitThread; + + public UsbStream(UsbEndpointBase usbEndpoint) { mUsbEndpoint = usbEndpoint; } + + #region NOT SUPPORTED + + public override long Length + { + get { throw new NotSupportedException(); } + } + + public override long Position + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + + + public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } + + public override void SetLength(long value) { throw new NotSupportedException(); } + + #endregion + + #region Overridden Members + + public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + { + UsbStreamAsyncTransfer asyncTransfer = new UsbStreamAsyncTransfer(mUsbEndpoint, buffer, offset, count, callback, state, ReadTimeout); + WaitThread.Start(asyncTransfer); + return asyncTransfer; + } + private Thread WaitThread + { + get + { + if (ReferenceEquals(mWaitThread,null)) + mWaitThread=new Thread(AsyncTransferFn); + + while (mWaitThread.IsAlive)Application.DoEvents(); + + return mWaitThread; + } + } + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + { + UsbStreamAsyncTransfer asyncTransfer = new UsbStreamAsyncTransfer(mUsbEndpoint, buffer, offset, count, callback, state, WriteTimeout); + WaitThread.Start(asyncTransfer); + return asyncTransfer; + } + + public override bool CanRead + { + get { return (mUsbEndpoint.EpNum & 0x80) == 0x80; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanTimeout + { + get { return true; } + } + + public override bool CanWrite + { + get { return (mUsbEndpoint.EpNum & 0x80) == 0; } + } + + public override int EndRead(IAsyncResult asyncResult) + { + UsbStreamAsyncTransfer asyncTransfer = (UsbStreamAsyncTransfer) asyncResult; + asyncTransfer.mCompleteEvent.WaitOne(); + + if (asyncTransfer.Result == ErrorCode.Success) return asyncTransfer.TransferredLength; + + if (asyncTransfer.Result == ErrorCode.IoTimedOut) + throw new TimeoutException(String.Format("{0}:Endpoint 0x{1:X2} IO timed out.", asyncTransfer.Result, mUsbEndpoint.EpNum)); + if (asyncTransfer.Result == ErrorCode.IoCancelled) + throw new IOCancelledException(String.Format("{0}:Endpoint 0x{1:X2} IO was cancelled.", asyncTransfer.Result, mUsbEndpoint.EpNum)); + + throw new IOException(string.Format("{0}:Failed reading from endpoint:{1}", asyncTransfer.Result, mUsbEndpoint.EpNum)); + } + + public override void EndWrite(IAsyncResult asyncResult) + { + UsbStreamAsyncTransfer asyncTransfer = (UsbStreamAsyncTransfer) asyncResult; + asyncTransfer.mCompleteEvent.WaitOne(); + + if (asyncTransfer.Result == ErrorCode.Success && asyncTransfer.mCount == asyncTransfer.TransferredLength) return; + + if (asyncTransfer.Result == ErrorCode.IoTimedOut) + throw new TimeoutException(String.Format("{0}:Endpoint 0x{1:X2} IO timed out.", asyncTransfer.Result, mUsbEndpoint.EpNum)); + if (asyncTransfer.Result == ErrorCode.IoCancelled) + throw new IOCancelledException(String.Format("{0}:Endpoint 0x{1:X2} IO was cancelled.", asyncTransfer.Result, mUsbEndpoint.EpNum)); + if (asyncTransfer.mCount != asyncTransfer.TransferredLength) + throw new IOException(String.Format("{0}:Failed writing {1} byte(s) to endpoint 0x{2:X2}.", + asyncTransfer.Result, + asyncTransfer.mCount - asyncTransfer.TransferredLength, + mUsbEndpoint.EpNum)); + + throw new IOException(String.Format("{0}:Failed writing to endpoint 0x{1:X2}", asyncTransfer.Result, mUsbEndpoint.EpNum)); + } + + public override void Flush() { return; } + + public override int Read(byte[] buffer, int offset, int count) + { + if (!CanRead) + throw new InvalidOperationException(String.Format("Cannot read from WriteEndpoint {0}.", (WriteEndpointID) mUsbEndpoint.EpNum)); + + int transferred; + ErrorCode ec = mUsbEndpoint.Transfer(buffer, offset, count, ReadTimeout, out transferred); + + if (ec == ErrorCode.Success) return transferred; + + if (ec == ErrorCode.IoTimedOut) throw new TimeoutException(String.Format("{0}:Endpoint 0x{1:X2} IO timed out.", ec, mUsbEndpoint.EpNum)); + if (ec == ErrorCode.IoCancelled) + throw new IOCancelledException(String.Format("{0}:Endpoint 0x{1:X2} IO was cancelled.", ec, mUsbEndpoint.EpNum)); + + throw new IOException(string.Format("{0}:Failed reading from endpoint:{1}", ec, mUsbEndpoint.EpNum)); + } + + public override int ReadTimeout + { + get { return mTimeout; } + set { mTimeout = value; } + } + + public override void Write(byte[] buffer, int offset, int count) + { + if (!CanWrite) + throw new InvalidOperationException(String.Format("Cannot write to ReadEndpoint {0}.", (ReadEndpointID) mUsbEndpoint.EpNum)); + + int transferred; + ErrorCode ec = mUsbEndpoint.Transfer(buffer, offset, count, WriteTimeout, out transferred); + + if (ec == ErrorCode.Success && count == transferred) return; + + if (ec == ErrorCode.IoTimedOut) throw new TimeoutException(String.Format("{0}:Endpoint 0x{1:X2} IO timed out.", ec, mUsbEndpoint.EpNum)); + if (ec == ErrorCode.IoCancelled) + throw new IOCancelledException(String.Format("{0}:Endpoint 0x{1:X2} IO was cancelled.", ec, mUsbEndpoint.EpNum)); + if (count != transferred) + throw new IOException(String.Format("{0}:Failed writing {1} byte(s) to endpoint 0x{2:X2}.", + ec, + count - transferred, + mUsbEndpoint.EpNum)); + + throw new IOException(String.Format("{0}:Failed writing to endpoint 0x{1:X2}", ec, mUsbEndpoint.EpNum)); + } + + public override int WriteTimeout + { + get { return mTimeout; } + set { mTimeout = value; } + } + + #endregion + + #region STATIC Members + + private static void AsyncTransferFn(object oContext) + { + UsbStreamAsyncTransfer context = oContext as UsbStreamAsyncTransfer; + context.SyncTransfer(); + } + + #endregion + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/UsbSymbolicName.cs b/LibWinUsb/Main/UsbSymbolicName.cs new file mode 100644 index 0000000..0bf268f --- /dev/null +++ b/LibWinUsb/Main/UsbSymbolicName.cs @@ -0,0 +1,227 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Globalization; +using System.Text.RegularExpressions; +using LibUsbDotNet.Internal.UsbRegex; + +namespace LibUsbDotNet.Main +{ + /// USB device symbolic names are persistent accrossed boots and uniquely identify each device. + /// + /// As well as uniquely identify connected devices, the UsbSymbolicName class parses the symbolic name key into usable fields. + /// + public class UsbSymbolicName + { + private static RegHardwareID _regHardwareId; + private static RegSymbolicName _regSymbolicName; + private readonly string mSymbolicName; + + private Guid mClassGuid = Guid.Empty; + private bool mIsParsed; + private int mProductID; + private int mRevisionCode; + private string mSerialNumber = String.Empty; + private int mVendorID; + + internal UsbSymbolicName(string symbolicName) { mSymbolicName = symbolicName; } + + private static RegSymbolicName RegSymbolicName + { + get + { + if (ReferenceEquals(_regSymbolicName, null)) + { + _regSymbolicName = new RegSymbolicName(); + } + + return _regSymbolicName; + } + } + + private static RegHardwareID RegHardwareId + { + get + { + if (ReferenceEquals(_regHardwareId, null)) + { + _regHardwareId = new RegHardwareID(); + } + + return _regHardwareId; + } + } + + /// + /// The full symbolic name of the device. + /// + public string FullName + { + get + { + if (mSymbolicName != null) return mSymbolicName.TrimStart(new char[] {'\\', '?'}); + return String.Empty; + } + } + + /// + /// VendorId parsed out of the + /// + public int Vid + { + get + { + Parse(); + return mVendorID; + } + } + + /// + /// ProductId parsed out of the + /// + public int Pid + { + get + { + Parse(); + return mProductID; + } + } + + /// + /// SerialNumber parsed out of the + /// + public string SerialNumber + { + get + { + Parse(); + return mSerialNumber; + } + } + + /// + /// Device class parsed out of the + /// + public Guid ClassGuid + { + get + { + Parse(); + return mClassGuid; + } + } + + /// + /// Usb device revision number. + /// + public int Rev + { + get + { + Parse(); + return mRevisionCode; + } + } + + + /// + /// Parses registry strings containing USB information. This function can Parse symbolic names as well as hardware ids, compatible ids, etc. + /// + /// + /// A class with all the available information from the string. + /// + /// + /// List<UsbRegistryDeviceInfo> regDeviceList = UsbGlobals.RegFindDevices(); + /// foreach (UsbRegistryDeviceInfo regDevice in mDevList) + /// { + /// string[] hardwareIds = (string[])regDevice.Properties[DevicePropertyType.HardwareID]; + /// UsbSymbolicName usbHardwareID = UsbSymbolicName.Parse(hardwareIds[0]); + /// Debug.Print(string.Format("Vid:0x{0:X4} Pid:0x{1:X4}", usbHardwareID.Vid, usbHardwareID.Pid)); + /// } + /// + /// + public static UsbSymbolicName Parse(string identifiers) { return new UsbSymbolicName(identifiers); } + + /// + ///Returns a that represents the current . + /// + /// + /// + ///A that represents the current . + /// + public override string ToString() + { + object[] o = new object[] {FullName, Vid.ToString("X4"), Pid.ToString("X4"), SerialNumber, ClassGuid}; + return string.Format("FullName:{0}\r\nVid:0x{1}\r\nPid:0x{2}\r\nSerialNumber:{3}\r\nClassGuid:{4}\r\n", o); + } + + + private void Parse() + { + if (!mIsParsed) + { + mIsParsed = true; + if (mSymbolicName != null) + { + MatchCollection matches = RegSymbolicName.Matches(mSymbolicName); + foreach (Match match in matches) + { + Group gVid = match.Groups[(int) NamedGroupType.Vid]; + Group gPid = match.Groups[(int) NamedGroupType.Pid]; + Group gRev = match.Groups[(int) NamedGroupType.Rev]; + Group gString = match.Groups[(int) NamedGroupType.String]; + Group gClass = match.Groups[(int) NamedGroupType.ClassGuid]; + + if (gVid.Success && mVendorID == 0) + { + int.TryParse(gVid.Captures[0].Value, NumberStyles.HexNumber, null, out mVendorID); + } + if (gPid.Success && mProductID == 0) + { + int.TryParse(gPid.Captures[0].Value, NumberStyles.HexNumber, null, out mProductID); + } + if (gRev.Success && mRevisionCode == 0) + { + int.TryParse(gRev.Captures[0].Value, out mRevisionCode); + } + if ((gString.Success) && mSerialNumber == String.Empty) + { + mSerialNumber = gString.Captures[0].Value; + } + if ((gClass.Success) && mClassGuid == Guid.Empty) + { + try + { + mClassGuid = new Guid(gClass.Captures[0].Value); + } + catch (Exception) + { + mClassGuid = Guid.Empty; + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/UsbTransfer.cs b/LibWinUsb/Main/UsbTransfer.cs new file mode 100644 index 0000000..52646d1 --- /dev/null +++ b/LibWinUsb/Main/UsbTransfer.cs @@ -0,0 +1,629 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Diagnostics; +using System.Threading; + +namespace LibUsbDotNet.Main +{ + /// + /// Base class for async transfer context. + /// + public abstract class UsbTransfer : IDisposable,IAsyncResult + { + private readonly UsbEndpointBase mEndpointBase; + + private IntPtr mBuffer; + private int mCurrentOffset; + private int mCurrentRemaining; + private int mCurrentTransmitted; + + /// + protected int mIsoPacketSize; + + /// + protected int mOriginalCount; + /// + protected int mOriginalOffset; + private PinnedHandle mPinnedHandle; + + /// + protected int mTimeout; + + /// + protected bool mHasWaitBeenCalled = true; + + /// + protected readonly object mTransferLOCK = new object(); + + /// + protected ManualResetEvent mTransferCancelEvent = new ManualResetEvent(false); + /// + protected internal ManualResetEvent mTransferCompleteEvent = new ManualResetEvent(true); + + /// + protected UsbTransfer(UsbEndpointBase endpointBase) { mEndpointBase = endpointBase; } + + /// + /// Returns the or this transfer context is associated with. + /// + public UsbEndpointBase EndpointBase + { + get { return mEndpointBase; } + } + + /// + /// Number of bytes that will be requested for the next transfer. + /// + protected int RequestCount + { + get { return (mCurrentRemaining > UsbEndpointBase.MaxReadWrite ? UsbEndpointBase.MaxReadWrite : mCurrentRemaining); } + } + + ///// + //protected int FailRetries + //{ + // get { return mFailRetries; } + //} + + /// + protected IntPtr NextBufPtr + { + get { return new IntPtr(mBuffer.ToInt64() + mCurrentOffset); } + } + + /// + /// True if the transfer has been cacelled with . + /// + public bool IsCancelled + { + get { return mTransferCancelEvent.WaitOne(0, UsbConstants.EXIT_CONTEXT); } + } + + /// + /// Gets the for the cancel event. + /// + public WaitHandle CancelWaitHandle + { + get { return mTransferCancelEvent; } + } + + /// + /// Gets the size of each isochronous packet. + /// + /// + /// To change the packet size see + /// + public int IsoPacketSize + { + get { return mIsoPacketSize; } + } + + + #region IDisposable Members + + /// + /// Cancels any pending transfer and frees resources. + /// + public virtual void Dispose() + { + if (!IsCancelled) Cancel(); + + int dummy; + if (!mHasWaitBeenCalled) Wait(out dummy); + if (mPinnedHandle != null) mPinnedHandle.Dispose(); + mPinnedHandle = null; + } + + #endregion + + ~UsbTransfer() { Dispose(); } + + /// + /// Cancels a pending transfer that was previously submitted with . + /// + /// + public virtual ErrorCode Cancel() + { + mTransferCancelEvent.Set(); + mTransferCompleteEvent.WaitOne(5000, false); + + return ErrorCode.Success; + } + + /// + /// Submits the transfer. + /// + /// + /// This functions submits the USB transfer and return immediately. + /// + /// + /// if the submit succeeds, + /// otherwise one of the other codes. + /// + public abstract ErrorCode Submit(); + + /// + /// Wait for the transfer to complete, timeout, or get cancelled. + /// + /// The number of bytes transferred on . + /// If true, the transfer is cancelled if it does not complete within the time specified in . + /// if the transfer completes successfully, otherwise one of the other codes. + public abstract ErrorCode Wait(out int transferredCount, bool cancel); + + /// + /// Wait for the transfer to complete, timeout, or get cancelled. + /// + /// The number of bytes transferred on . + /// if the transfer completes successfully, otherwise one of the other codes. + public ErrorCode Wait(out int transferredCount) { return Wait(out transferredCount, true); } + + /// + /// Fills the transfer with the data to . + /// + /// The buffer; See for more details. + /// The offset on the buffer where the transfer should read/write. + /// The number of bytes to transfer. + /// Time (milliseconds) to wait before the transfer times out. + public virtual void Fill(object buffer, int offset, int count, int timeout) + { + if (mPinnedHandle != null) mPinnedHandle.Dispose(); + mPinnedHandle = new PinnedHandle(buffer); + Fill(mPinnedHandle.Handle, offset, count, timeout); + } + /// + /// Fills the transfer with the data to an isochronous transfer. + /// + /// The buffer; See for more details. + /// The offset on the buffer where the transfer should read/write. + /// The number of bytes to transfer. + /// Time (milliseconds) to wait before the transfer times out. + /// Size of each isochronous packet. + public virtual void Fill(object buffer, int offset, int count, int timeout, int isoPacketSize) + { + if (mPinnedHandle != null) mPinnedHandle.Dispose(); + mPinnedHandle = new PinnedHandle(buffer); + Fill(mPinnedHandle.Handle, offset, count, timeout, isoPacketSize); + } + /// + /// Fills the transfer with the data to . + /// + /// The buffer. + /// The offset on the buffer where the transfer should read/write. + /// The number of bytes to transfer. + /// Time (milliseconds) to wait before the transfer times out. + public virtual void Fill(IntPtr buffer, int offset, int count, int timeout) + { + mBuffer = buffer; + + mOriginalOffset = offset; + mOriginalCount = count; + mTimeout = timeout; + Reset(); + } + /// + /// Fills the transfer with the data to an isochronous transfer. + /// + /// The buffer. + /// The offset on the buffer where the transfer should read/write. + /// The number of bytes to transfer. + /// Time (milliseconds) to wait before the transfer times out. + /// Size of each isochronous packet. + public virtual void Fill(IntPtr buffer, int offset, int count, int timeout, int isoPacketSize) + { + mBuffer = buffer; + + mOriginalOffset = offset; + mOriginalCount = count; + mTimeout = timeout; + mIsoPacketSize = isoPacketSize; + Reset(); + } + internal static ErrorCode SyncTransfer(UsbTransfer transferContext, + IntPtr buffer, + int offset, + int length, + int timeout, + out int transferLength) + { + return SyncTransfer(transferContext, buffer, offset, length, timeout, 0, out transferLength); + } + internal static ErrorCode SyncTransfer(UsbTransfer transferContext, + IntPtr buffer, + int offset, + int length, + int timeout, + int isoPacketSize, + out int transferLength) + { + if (ReferenceEquals(transferContext, null)) throw new NullReferenceException("Invalid transfer context."); + if (offset < 0) throw new ArgumentException("must be >=0", "offset"); + if (isoPacketSize == 0 && transferContext.EndpointBase.Type == EndpointType.Isochronous) + { + Info.UsbEndpointInfo endpointInfo = transferContext.EndpointBase.EndpointInfo; + if (endpointInfo!=null) + isoPacketSize = endpointInfo.Descriptor.MaxPacketSize; + } + lock (transferContext.mTransferLOCK) + { + transferLength = 0; + + int transferred; + ErrorCode ec; + transferContext.Fill(buffer, offset, length, timeout, isoPacketSize); + + while (true) + { + ec = transferContext.Submit(); + if (ec != ErrorCode.Success) return ec; + + ec = transferContext.Wait(out transferred); + if (ec != ErrorCode.Success) return ec; + + transferLength += transferred; + + if ((ec != ErrorCode.None || transferred != UsbEndpointBase.MaxReadWrite) || + !transferContext.IncrementTransfer(transferred)) + break; + } + + return ec; + } + } + + /// + /// Increments the internal counters to the next transfer batch (for transfers greater than ) + /// + /// This will usually be the total transferred on the previous batch. + /// True if the buffer still has data available and internal counters were successfully incremented. + public bool IncrementTransfer(int amount) + { + mCurrentTransmitted += amount; + mCurrentRemaining -= amount; + mCurrentOffset += amount; + + if ((mCurrentRemaining) <= 0) + { + Debug.Assert(mCurrentRemaining == 0); + return false; + } + + return true; + } + + /// + /// Totoal number of bytes transferred. + /// + public int Transmitted + { + get + { + return mCurrentTransmitted; + } + } + + /// + /// Remaining bytes in the transfer data buffer. + /// + public int Remaining + { + get + { + return mCurrentRemaining; + } + } + /// + /// Resets the transfer to its orignal state. + /// + /// + /// Prepares a to be resubmitted. + /// + public void Reset() + { + mCurrentOffset = mOriginalOffset; + mCurrentRemaining = mOriginalCount; + mCurrentTransmitted = 0; + + mTransferCancelEvent.Reset(); + } + + /// + /// Gets an indication whether the asynchronous operation has completed. + /// + /// + /// true if the operation is complete; otherwise, false. + /// + /// 2 + public bool IsCompleted + { + get { return mTransferCompleteEvent.WaitOne(0, UsbConstants.EXIT_CONTEXT); } + } + + + /// + /// Gets a that is used to wait for an asynchronous operation to complete. + /// + /// + /// A that is used to wait for an asynchronous operation to complete. + /// + /// 2 + public WaitHandle AsyncWaitHandle + { + get { return mTransferCompleteEvent; } + } + + /// + /// Gets a user-defined object that qualifies or contains information about an asynchronous operation. + /// + /// + /// A user-defined object that qualifies or contains information about an asynchronous operation. + /// + /// 2 + public object AsyncState + { + get { throw new NotImplementedException(); } + } + + /// + /// Gets an indication of whether the asynchronous operation completed synchronously. + /// + /// + /// true if the asynchronous operation completed synchronously; otherwise, false. + /// + /// 2 + public bool CompletedSynchronously + { + get { return false; } + } + } + + /// + /// Helper class for maintaining a user defined number of outstanding aync transfers on an endpoint. + /// + public class UsbTransferQueue + { + /// + /// Creates a new transfer queue instance. + /// + /// The endpoint to transfer data to/from. + /// The number of transfers to before waiting for a completion. + /// The size of each data buffer. + /// The maximum time to wait for each transfer. + /// For isochronous use only. The iso packet size. If 0, the endpoints max packet size is used. + public UsbTransferQueue(UsbEndpointBase endpointBase, int maxOutstandingIO, int bufferSize, int timeout, int isoPacketSize) + { + EndpointBase = endpointBase; + IsoPacketSize = isoPacketSize; + Timeout = timeout; + BufferSize = bufferSize; + MaxOutstandingIO = maxOutstandingIO; + + mTransferHandles = new Handle[maxOutstandingIO]; + + mBuffer = new byte[maxOutstandingIO][]; + for(int i=0; i < maxOutstandingIO; i++) + mBuffer[i] = new byte[bufferSize]; + + IsoPacketSize = isoPacketSize > 0 ? isoPacketSize : endpointBase.EndpointInfo.Descriptor.MaxPacketSize; + } + + /// + /// Endpoint for I/O operations. + /// + public readonly UsbEndpointBase EndpointBase; + + /// + /// Maximum outstanding I/O operations before waiting for a completion. + /// This is also the number of data buffers allocated for this transfer queue. + /// + public readonly int MaxOutstandingIO; + + /// + /// Size (in bytes) of each data buffer in this transfer queue. + /// + public readonly int BufferSize; + + /// + /// Time (in milliseconds) to wait for a transfer to complete before returning . + /// + public readonly int Timeout; + + /// + /// For isochronous use only. The iso packet size. + /// + public readonly int IsoPacketSize; + + private int mOutstandingTransferCount; + private readonly Handle[] mTransferHandles; + private readonly byte[][] mBuffer; + private int mTransferHandleNextIndex; + private int mTransferHandleWaitIndex; + + /// + /// A transfer queue handle. + /// + public class Handle + { + internal Handle(UsbTransfer context, byte[] data) + { + Context = context; + Data = data; + + } + + /// + /// Transfer context. + /// + public readonly UsbTransfer Context; + + /// + /// Data buffer. + /// + public readonly byte[] Data; + + /// + /// Number of bytes sent/received. + /// + public int Transferred; + + internal bool InUse; + + } + + /// + /// Gets the transfer data buffer at the specified index. + /// + /// The index of the buffer to retrieve. + /// The byte array for a transfer. + public byte[] this[int index] + { + get{ return mBuffer[index]; } + } + + /// + /// Gets a two dimensional array of data buffers. The first index represents the transfer the second represents the data buffer. + /// + public byte[][] Buffer + { + get { return mBuffer; } + } + + private static void IncWithRoll(ref int incField, int rollOverValue) + { + if ((++incField) >= rollOverValue) + incField = 0; + } + + /// + /// Submits transfers until is reached then waits for the oldest transfer to complete. + /// + /// The queue handle to the that completed. + /// if data was transferred, or another on error. + public ErrorCode Transfer(out Handle handle) + { + return transfer(this, out handle); + } + private static ErrorCode transfer(UsbTransferQueue transferParam, out Handle handle) + { + handle = null; + ErrorCode ret = ErrorCode.Success; + + // Submit transfers until the maximum number of outstanding transfer(s) is reached. + while (transferParam.mOutstandingTransferCount < transferParam.MaxOutstandingIO) + { + if (ReferenceEquals(transferParam.mTransferHandles[transferParam.mTransferHandleNextIndex], null)) + { + handle = transferParam.mTransferHandles[transferParam.mTransferHandleNextIndex] = + new Handle(transferParam.EndpointBase.NewAsyncTransfer(), transferParam.mBuffer[transferParam.mTransferHandleNextIndex]); + + // Get the next available benchmark transfer handle. + handle.Context.Fill(handle.Data, 0, handle.Data.Length, transferParam.Timeout, transferParam.IsoPacketSize); + } + else + { + // Get the next available benchmark transfer handle. + handle = transferParam.mTransferHandles[transferParam.mTransferHandleNextIndex]; + + } + + handle.Transferred = 0; + + // Submit this transfer now. + handle.Context.Reset(); + ret = handle.Context.Submit(); + if (ret != ErrorCode.Success) goto Done; + + // Mark this handle has InUse. + handle.InUse = true; + + // When transfers ir successfully submitted, OutstandingTransferCount goes up; when + // they are completed it goes down. + // + transferParam.mOutstandingTransferCount++; + + // Move TransferHandleNextIndex to the next available transfer. + IncWithRoll(ref transferParam.mTransferHandleNextIndex, transferParam.MaxOutstandingIO); + } + + // If the number of outstanding transfers has reached the limit, wait for the + // oldest outstanding transfer to complete. + // + if (transferParam.mOutstandingTransferCount == transferParam.MaxOutstandingIO) + { + // TransferHandleWaitIndex is the index of the oldest outstanding transfer. + handle = transferParam.mTransferHandles[transferParam.mTransferHandleWaitIndex]; + ret = handle.Context.Wait(out handle.Transferred, false); + if (ret != ErrorCode.Success) + goto Done; + + // Mark this handle has no longer InUse. + handle.InUse = false; + + // When transfers ir successfully submitted, OutstandingTransferCount goes up; when + // they are completed it goes down. + // + transferParam.mOutstandingTransferCount--; + + // Move TransferHandleWaitIndex to the oldest outstanding transfer. + IncWithRoll(ref transferParam.mTransferHandleWaitIndex, transferParam.MaxOutstandingIO); + + return ErrorCode.Success; + } + + Done: + return ret; + } + + /// + /// Cancels and frees all oustanding transfers. + /// + public void Free() + { + free(this); + } + + private static void free(UsbTransferQueue transferParam) + { + for (int i = 0; i < transferParam.MaxOutstandingIO; i++) + { + if (!ReferenceEquals(transferParam.mTransferHandles[i], null)) + { + if (transferParam.mTransferHandles[i].InUse) + { + if (!transferParam.mTransferHandles[i].Context.IsCompleted) + { + transferParam.EndpointBase.Abort(); + Thread.Sleep(1); + } + + transferParam.mTransferHandles[i].InUse = false; + transferParam.mTransferHandles[i].Context.Dispose(); + } + transferParam.mTransferHandles[i] = null; + } + } + transferParam.mOutstandingTransferCount = 0; + transferParam.mTransferHandleNextIndex = 0; + transferParam.mTransferHandleWaitIndex = 0; + } + } +} \ No newline at end of file diff --git a/LibWinUsb/Main/WriteEndpointID.cs b/LibWinUsb/Main/WriteEndpointID.cs new file mode 100644 index 0000000..feac114 --- /dev/null +++ b/LibWinUsb/Main/WriteEndpointID.cs @@ -0,0 +1,89 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +namespace LibUsbDotNet.Main +{ + /// Availabled endpoint numbers/ids for writing. + /// + public enum WriteEndpointID : byte + { + /// + /// Endpoint 1 + /// + Ep01 = 0x01, + /// + /// Endpoint 2 + /// + Ep02 = 0x02, + /// + /// Endpoint 3 + /// + Ep03 = 0x03, + /// + /// Endpoint 4 + /// + Ep04 = 0x04, + /// + /// Endpoint 5 + /// + Ep05 = 0x05, + /// + /// Endpoint 6 + /// + Ep06 = 0x06, + /// + /// Endpoint 7 + /// + Ep07 = 0x07, + /// + /// Endpoint 8 + /// + Ep08 = 0x08, + /// + /// Endpoint 9 + /// + Ep09 = 0x09, + /// + /// Endpoint 10 + /// + Ep10 = 0x0A, + /// + /// Endpoint 11 + /// + Ep11 = 0x0B, + /// + /// Endpoint 12 + /// + Ep12 = 0x0C, + /// + /// Endpoint 13 + /// + Ep13 = 0x0D, + /// + /// Endpoint 14 + /// + Ep14 = 0x0E, + /// + /// Endpoint 15 + /// + Ep15 = 0x0F, + } +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/CallbackDelegates.cs b/LibWinUsb/MonoLibUsb/CallbackDelegates.cs new file mode 100644 index 0000000..10011fc --- /dev/null +++ b/LibWinUsb/MonoLibUsb/CallbackDelegates.cs @@ -0,0 +1,31 @@ +using System; +using System.Runtime.InteropServices; +using MonoLibUsb.Transfer; + +namespace MonoLibUsb +{ + /// + /// Asynchronous transfer callback delegate + /// + /// The transfer previously allocated with . + [UnmanagedFunctionPointer(MonoUsbApi.CC)] + public delegate void MonoUsbTransferDelegate(MonoUsbTransfer transfer); + + /// + /// Callback delegate, invoked when a new file descriptor should be added to the set of file descriptors monitored for events. + /// + /// The new file descriptor. + /// Events to monitor for, see PollfdItem for a description. + /// User data pointer specified in call. + [UnmanagedFunctionPointer(MonoUsbApi.CC)] + public delegate void PollfdAddedDelegate(int fd, short events, IntPtr user_data); + + /// + /// Callback delegate, invoked when a file descriptor should be removed from the set of file descriptors being monitored for events. + /// + /// After returning from this callback, do not use that file descriptor again. + /// The file descriptor to stop monitoring. + /// User data pointer specified in call. + [UnmanagedFunctionPointer(MonoUsbApi.CC)] + public delegate void PollfdRemovedDelegate(int fd, IntPtr user_data); +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/Descriptors/MonoUsbAltInterfaceDescriptor.cs b/LibWinUsb/MonoLibUsb/Descriptors/MonoUsbAltInterfaceDescriptor.cs new file mode 100644 index 0000000..c3b8571 --- /dev/null +++ b/LibWinUsb/MonoLibUsb/Descriptors/MonoUsbAltInterfaceDescriptor.cs @@ -0,0 +1,103 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using LibUsbDotNet.Descriptors; + +namespace MonoLibUsb.Descriptors +{ + /// + /// 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, Pack = MonoUsbApi.LIBUSB_PACK)] + public class MonoUsbAltInterfaceDescriptor + { + ///Size of this descriptor (in bytes) + public readonly Byte bLength; + + ///Descriptor type. Will have value LIBUSB_DT_INTERFACE in this context. + public readonly DescriptorType bDescriptorType; + + ///Number of this interface + public readonly Byte bInterfaceNumber; + + ///Value used to select this alternate setting for this interface + public readonly Byte bAlternateSetting; + + /// Number of endpoints used by this interface (excluding the control endpoint). + public readonly Byte bNumEndpoints; + + /// USB-IF class code for this interface. See ClassCodeType. + public readonly ClassCodeType bInterfaceClass; + + /// USB-IF subclass code for this interface, qualified by the bInterfaceClass value + public readonly Byte bInterfaceSubClass; + + /// USB-IF protocol code for this interface, qualified by the bInterfaceClass and bInterfaceSubClass values + public readonly Byte bInterfaceProtocol; + + /// Index of string descriptor describing this interface + public readonly Byte iInterface; + + /// Array of endpoint descriptors. This length of this array is determined by the bNumEndpoints field. + private readonly IntPtr pEndpointDescriptors; + + /// Extra descriptors. If libusb encounters unknown interface descriptors, it will store them here, should you wish to parse them. + private IntPtr pExtraBytes; + + /// Length of the extra descriptors, in bytes. + public readonly int ExtraLength; + + /// Extra descriptors. If libusb encounters unknown interface descriptors, it will store them here, should you wish to parse them. + public byte[] ExtraBytes + { + get + { + byte[] bytes = new byte[ExtraLength]; + Marshal.Copy(pExtraBytes, bytes, 0, bytes.Length); + return bytes; + } + } + + /// Array of endpoint descriptors. This length of this array is determined by the bNumEndpoints field. + public List EndpointList + { + get + { + List endpointList = new List(); + int iEndpoint; + for (iEndpoint = 0; iEndpoint < bNumEndpoints; iEndpoint++) + { + IntPtr pNextInterface = new IntPtr(pEndpointDescriptors.ToInt64() + (Marshal.SizeOf(typeof (MonoUsbEndpointDescriptor))*iEndpoint)); + MonoUsbEndpointDescriptor monoUsbEndpoint = new MonoUsbEndpointDescriptor(); + Marshal.PtrToStructure(pNextInterface, monoUsbEndpoint); + endpointList.Add(monoUsbEndpoint); + } + + return endpointList; + } + } + } +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/Descriptors/MonoUsbConfigDescriptor.cs b/LibWinUsb/MonoLibUsb/Descriptors/MonoUsbConfigDescriptor.cs new file mode 100644 index 0000000..f10297d --- /dev/null +++ b/LibWinUsb/MonoLibUsb/Descriptors/MonoUsbConfigDescriptor.cs @@ -0,0 +1,115 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + + +using LibUsbDotNet.Descriptors; +using MonoLibUsb.Profile; + +namespace MonoLibUsb.Descriptors +{ + ///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. + /// + [StructLayout(LayoutKind.Sequential, Pack = MonoUsbApi.LIBUSB_PACK)] + public class MonoUsbConfigDescriptor + { + internal MonoUsbConfigDescriptor() + { + } + + /// + /// Create a new instance from a . + /// + /// A config handle. + public MonoUsbConfigDescriptor(MonoUsbConfigHandle configHandle) + { + Marshal.PtrToStructure(configHandle.DangerousGetHandle(), this); + } + + /// Size of this descriptor (in bytes) + public readonly byte bLength; + + /// Descriptor type. Will have value LIBUSB_DT_CONFIG in this context. + public readonly DescriptorType bDescriptorType; + + /// Total length of data returned for this configuration + public readonly short wTotalLength; + + /// Number of interfaces supported by this configuration + public readonly byte bNumInterfaces; + + /// Identifier value for this configuration + public readonly byte bConfigurationValue; + + /// Index of string descriptor describing this configuration + public readonly byte iConfiguration; + + /// Configuration characteristics + public readonly 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. + public readonly byte MaxPower; + + /// Array of interfaces supported by this configuration. The length of this array is determined by the bNumInterfaces field. + private readonly IntPtr pInterfaces; + + /// Extra descriptors. If libusb encounters unknown configuration descriptors, it will store them here, should you wish to parse them. + private readonly IntPtr pExtraBytes; + + /// Length of the extra descriptors, in bytes. + public readonly int ExtraLength; + + /// Extra descriptors. If libusb encounters unknown configuration descriptors, it will store them here, should you wish to parse them. + public byte[] ExtraBytes + { + get + { + byte[] bytes = new byte[ExtraLength]; + Marshal.Copy(pExtraBytes, bytes, 0, bytes.Length); + return bytes; + } + } + + /// Array of interfaces supported by this configuration. The length of this array is determined by the bNumInterfaces field. + public List InterfaceList + { + get + { + List interfaceList = new List(); + int iInterface; + for (iInterface = 0; iInterface < bNumInterfaces; iInterface++) + { + IntPtr pNextInterface = new IntPtr(pInterfaces.ToInt64() + (Marshal.SizeOf(typeof (MonoUsbInterface))*iInterface)); + MonoUsbInterface monoUsbInterface = new MonoUsbInterface(); + Marshal.PtrToStructure(pNextInterface, monoUsbInterface); + interfaceList.Add(monoUsbInterface); + } + + return interfaceList; + } + } + } +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/Descriptors/MonoUsbDeviceDescriptor.cs b/LibWinUsb/MonoLibUsb/Descriptors/MonoUsbDeviceDescriptor.cs new file mode 100644 index 0000000..6330e68 --- /dev/null +++ b/LibWinUsb/MonoLibUsb/Descriptors/MonoUsbDeviceDescriptor.cs @@ -0,0 +1,134 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; +using LibUsbDotNet.Descriptors; +using LibUsbDotNet.Main; + +namespace MonoLibUsb.Descriptors +{ + ///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 = MonoUsbApi.LIBUSB_PACK)] + public class MonoUsbDeviceDescriptor + { + /// + /// Total size of this structure in bytes. + /// + public static readonly int Size = Marshal.SizeOf(typeof (MonoUsbDeviceDescriptor)); + + /// + /// Length of structure reported by the associated usb device. + /// + public byte Length; + + /// + /// Type of structure reported by the associated usb device. + /// + public DescriptorType DescriptorType; + + /// + /// USB Specification Number which device complies too. + /// + public readonly short BcdUsb; + + /// + /// Class Code (Assigned by USB Org) + /// If equal to Zero, each interface specifies it’s own class code; If equal to 0xFF, the class code is vendor specified; Otherwise field is valid Class Code. + /// + public readonly ClassCodeType Class; + + /// + /// Subclass Code (Assigned by USB Org) + /// + public readonly byte SubClass; + + /// + /// Protocol Code (Assigned by USB Org) + /// + public readonly byte Protocol; + + /// + /// Maximum Packet Size for Zero Endpoint. Valid Sizes are 8, 16, 32, 64 + /// + public readonly byte MaxPacketSize0; + + /// + /// Vendor ID (Assigned by USB Org) + /// + public readonly short VendorID; + + /// + /// Product ID (Assigned by Manufacturer) + /// + public readonly short ProductID; + + /// + /// Device Release Number + /// + public readonly short BcdDevice; + + /// + /// Index of Manufacturer String Descriptor + /// + public readonly byte ManufacturerStringIndex; + + /// + /// Index of Product String Descriptor + /// + public readonly byte ProductStringIndex; + + /// + /// Index of Serial Number String Descriptor + /// + public readonly byte SerialStringIndex; + + /// + /// Number of Possible Configurations + /// + public readonly byte ConfigurationCount; + + /// + ///Returns a that represents the current . + /// + /// + /// + ///A that represents the current . + /// + public override string ToString() + { + Object[] values = { + Length, DescriptorType, "0x" + BcdUsb.ToString("X4"), Class, SubClass, Protocol, MaxPacketSize0, + "0x" + VendorID.ToString("X4"), "0x" + ProductID.ToString("X4"), BcdDevice, + ManufacturerStringIndex, ProductStringIndex, SerialStringIndex, ConfigurationCount + }; + string[] names = { + "Length", "DescriptorType", "BcdUsb", "Class", "SubClass", "Protocol", "MaxPacketSize0", "VendorID", "ProductID", + "BcdDevice", + "ManufacturerStringIndex", "ProductStringIndex", "SerialStringIndex", "ConfigurationCount" + }; + return Helper.ToString("", names, ":", values, "\r\n"); + + } + } +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/Descriptors/MonoUsbEndpointDescriptor.cs b/LibWinUsb/MonoLibUsb/Descriptors/MonoUsbEndpointDescriptor.cs new file mode 100644 index 0000000..82f6052 --- /dev/null +++ b/LibWinUsb/MonoLibUsb/Descriptors/MonoUsbEndpointDescriptor.cs @@ -0,0 +1,77 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; +using LibUsbDotNet.Descriptors; + +namespace MonoLibUsb.Descriptors +{ + /// + /// 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, Pack = MonoUsbApi.LIBUSB_PACK)] + public class MonoUsbEndpointDescriptor + { + /// Size of this descriptor (in bytes) + public readonly Byte bLength; + + /// Descriptor type. Will have value LIBUSB_DT_ENDPOINT in this context. + public readonly DescriptorType 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. + public readonly 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. + public readonly Byte bmAttributes; + + /// Maximum packet size this endpoint is capable of sending/receiving. + public readonly short wMaxPacketSize; + + /// Interval for polling endpoint for data transfers. + public readonly Byte bInterval; + + /// For audio devices only: the rate at which synchronization feedback is provided. + public readonly Byte bRefresh; + + /// For audio devices only: the address if the synch endpoint + public readonly Byte bSynchAddress; + + /// Extra descriptors. If libusb encounters unknown endpoint descriptors, it will store them here, should you wish to parse them. + private readonly IntPtr pExtraBytes; + + /// Length of the extra descriptors, in bytes. + public readonly int ExtraLength; + + /// Extra descriptors. If libusb encounters unknown endpoint descriptors, it will store them here, should you wish to parse them. + public byte[] ExtraBytes + { + get + { + byte[] bytes = new byte[ExtraLength]; + Marshal.Copy(pExtraBytes, bytes, 0, bytes.Length); + return bytes; + } + } + } +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/Descriptors/MonoUsbInterface.cs b/LibWinUsb/MonoLibUsb/Descriptors/MonoUsbInterface.cs new file mode 100644 index 0000000..d31e1b0 --- /dev/null +++ b/LibWinUsb/MonoLibUsb/Descriptors/MonoUsbInterface.cs @@ -0,0 +1,59 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace MonoLibUsb.Descriptors +{ + ///A collection of alternate settings for a particular USB interface. + [StructLayout(LayoutKind.Sequential, Pack = MonoUsbApi.LIBUSB_PACK)] + public class MonoUsbInterface + { + /// Array of interface descriptors. The length of this array is determined by the num_altsetting field. + private IntPtr pAltSetting; + + /// The number of alternate settings that belong to this interface + public readonly int num_altsetting; + + + /// Array of interface descriptors. The length of this array is determined by the num_altsetting field. + public List AltInterfaceList + { + get + { + List altInterfaceList = new List(); + int iAltInterface; + for (iAltInterface = 0; iAltInterface < num_altsetting; iAltInterface++) + { + IntPtr pNextInterface = new IntPtr(pAltSetting.ToInt64() + (Marshal.SizeOf(typeof (MonoUsbAltInterfaceDescriptor))*iAltInterface)); + MonoUsbAltInterfaceDescriptor monoUSBAltInterfaceDescriptor = new MonoUsbAltInterfaceDescriptor(); + Marshal.PtrToStructure(pNextInterface, monoUSBAltInterfaceDescriptor); + + altInterfaceList.Add(monoUSBAltInterfaceDescriptor); + } + + return altInterfaceList; + } + } + } +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/MonoLibUsbApi.cs b/LibWinUsb/MonoLibUsb/MonoLibUsbApi.cs new file mode 100644 index 0000000..45b44f4 --- /dev/null +++ b/LibWinUsb/MonoLibUsb/MonoLibUsbApi.cs @@ -0,0 +1,1470 @@ +#pragma warning disable 0649 +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using LibUsbDotNet.Descriptors; +using LibUsbDotNet.Main; +using MonoLibUsb.Descriptors; +using MonoLibUsb.Profile; +using MonoLibUsb.Transfer; +using System.Threading; + +namespace MonoLibUsb +{ + /// + /// Libusb-1.0 low-level API library. + /// + public static class MonoUsbApi + { + internal const CallingConvention CC = 0; + internal const string LIBUSB_DLL = "libusb-1.0.dll"; + internal const int LIBUSB_PACK = 0; + + #region Private Members + + private static readonly MonoUsbTransferDelegate DefaultAsyncDelegate = DefaultAsyncCB; + private static void DefaultAsyncCB(MonoUsbTransfer transfer) + { + ManualResetEvent completeEvent = GCHandle.FromIntPtr(transfer.PtrUserData).Target as ManualResetEvent; + completeEvent.Set(); + } + + #endregion + #region API LIBRARY FUNCTIONS - Initialization & Deinitialization + + + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_init")] + internal static extern int Init(ref IntPtr pContext); + + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_exit")] + internal static extern void Exit(IntPtr pContext); + + + /// Set message verbosity. + /// A valid . + /// Debug level to set. + /// + /// + /// Level 0: no messages ever printed by the library. (default) + /// Level 1: error messages are printed to stderr. + /// Level 2: warning and error messages are printed to stderr. + /// Level 3: informational messages are printed to stdout, warning and error messages are printed to stderr + /// + /// The default level is 0, which means no messages are ever printed. If you choose to increase the message verbosity level, ensure that your application does not close the stdout/stderr file descriptors. + /// You are advised to set level 3. libusb is conservative with its message logging and most of the time, will only log messages that explain error conditions and other oddities. This will help you debug your software. + /// If the LIBUSB_DEBUG environment variable was set when libusb was initialized, this function does nothing: the message verbosity is fixed to the value in the environment variable. + /// If libusb was compiled without any message logging, this function does nothing: you'll never get any messages. + /// If libusb was compiled with verbose debug message logging, this function does nothing: you'll always get messages from all levels. + /// + /// + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_set_debug")] + public static extern void SetDebug([In]MonoUsbSessionHandle sessionHandle, int level); + + #endregion + + #region API LIBRARY FUNCTIONS - Device handling and enumeration + + /// + /// Returns a list of USB devices currently attached to the system. + /// + /// + /// This is your entry point into finding a USB device to operate. + /// + /// + /// A valid . + /// output location for a list of devices. + /// The number of devices in the outputted list, or on memory allocation failure. + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_get_device_list")] + public static extern int GetDeviceList([In]MonoUsbSessionHandle sessionHandle, [Out] out MonoUsbProfileListHandle monoUSBProfileListHandle); + + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_free_device_list")] + internal static extern void FreeDeviceList(IntPtr pHandleList, int unrefDevices); + + /// + /// Get the number of the bus that a device is connected to. + /// + /// + /// + /// + /// The bus number. + /// A device profile handle. + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_get_bus_number")] + public static extern byte GetBusNumber([In] MonoUsbProfileHandle deviceProfileHandle); + + + /// + /// Get the address of the device on the bus it is connected to. + /// + /// + /// + /// + /// The device address. + /// A device profile handle. + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_get_device_address")] + public static extern byte GetDeviceAddress([In] MonoUsbProfileHandle deviceProfileHandle); + + /// + /// Convenience function to retrieve the wMaxPacketSize value for a particular endpoint in the active device configuration. + /// + /// A device profile handle. + /// Endpoint address to retrieve the max packet size for. + /// + /// + /// This function was originally intended to be of assistance when setting up isochronous transfers, but a design mistake resulted in this function instead. It simply returns the value without considering its contents. If you're dealing with isochronous transfers, you probably want instead. + /// + /// The + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_get_max_packet_size")] + public static extern int GetMaxPacketSize([In] MonoUsbProfileHandle deviceProfileHandle, byte endpoint); + + /// + /// Calculate the maximum packet size which a specific endpoint is capable is sending or receiving in the duration of 1 microframe. + /// + /// + /// Only the active configuration is examined. The calculation is based on the wMaxPacketSize field in the endpoint descriptor as described in section 9.6.6 in the USB 2.0 specifications. + /// If acting on an isochronous or interrupt endpoint, this function will multiply the value found in bits 0:10 by the number of transactions per microframe (determined by bits 11:12). Otherwise, this function just returns the numeric value found in bits 0:10. + /// This function is useful for setting up isochronous transfers, for example you might pass the return value from this function to libusb_set_iso_packet_lengths in order to set the length field of every isochronous packet in a transfer. + /// + /// + /// A device profile handle. + /// Endpoint address to retrieve the max packet size for. + /// The maximum packet size which can be sent/received on this endpoint. + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_get_max_iso_packet_size")] + public static extern int GetMaxIsoPacketSize([In] MonoUsbProfileHandle deviceProfileHandle, byte endpoint); + + + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_ref_device")] + internal static extern IntPtr RefDevice(IntPtr pDeviceProfileHandle); + + + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_unref_device")] + internal static extern IntPtr UnrefDevice(IntPtr pDeviceProfileHandle); + + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_open")] + internal static extern int Open([In] MonoUsbProfileHandle deviceProfileHandle, ref IntPtr deviceHandle); + + + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_open_device_with_vid_pid")] + private static extern IntPtr OpenDeviceWithVidPidInternal([In]MonoUsbSessionHandle sessionHandle, short vendorID, short productID); + + /// + /// Convenience function for finding a device with a particular idVendor/idProduct combination. + /// + /// + /// + /// + /// A valid . + /// The idVendor value to search for. + /// The idProduct value to search for. + /// Null if the device was not opened or not found, otherwise an opened device handle. + public static MonoUsbDeviceHandle OpenDeviceWithVidPid([In]MonoUsbSessionHandle sessionHandle, short vendorID, short productID) + { + IntPtr pHandle = OpenDeviceWithVidPidInternal(sessionHandle, vendorID, productID); + if (pHandle == IntPtr.Zero) return null; + return new MonoUsbDeviceHandle(pHandle); + } + + + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_close")] + internal static extern void Close(IntPtr deviceHandle); + + + /// + /// Get a for a . + /// + /// + /// + /// This function differs from the Libusb-1.0 C API in that when the new is returned, the device profile reference count + /// is incremented ensuring the profile will remain valid as long as it is in-use. + /// + /// + /// + /// A device handle. + /// The underlying profile handle. + public static MonoUsbProfileHandle GetDevice(MonoUsbDeviceHandle devicehandle) { return new MonoUsbProfileHandle(GetDeviceInternal(devicehandle)); } + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_get_device")] + private static extern IntPtr GetDeviceInternal([In] MonoUsbDeviceHandle devicehandle); + + /// + /// Determine the of the currently active configuration. + /// + /// + /// You could formulate your own control request to obtain this information, but this function has the advantage that it may be able to retrieve the information from operating system caches (no I/O involved). + /// If the OS does not cache this information, then this function will block while a control transfer is submitted to retrieve the information. + /// This function will return a value of 0 in the parameter if the device is in unconfigured state. + /// + /// + /// A device handle. + /// Output location for the of the active configuration. (only valid for return code 0) + /// + /// + /// 0 on success + /// if the device has been disconnected + /// another code on other failure + /// + /// + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_get_configuration")] + public static extern int GetConfiguration([In] MonoUsbDeviceHandle deviceHandle, ref int configuration); + + /// + /// Set the active configuration for a device. + /// + /// + /// The operating system may or may not have already set an active configuration on the device. It is up to your application to ensure the correct configuration is selected before you attempt to claim interfaces and perform other operations. + /// If you call this function on a device already configured with the selected configuration, then this function will act as a lightweight device reset: it will issue a SET_CONFIGURATION request using the current configuration, causing most USB-related device state to be reset (altsetting reset to zero, endpoint halts cleared, toggles reset). + /// You cannot change/reset configuration if your application has claimed interfaces - you should free them with first. You cannot change/reset configuration if other applications or drivers have claimed interfaces. + /// A configuration value of -1 will put the device in unconfigured state. The USB specifications state that a configuration value of 0 does this, however buggy devices exist which actually have a configuration 0. + /// You should always use this function rather than formulating your own SET_CONFIGURATION control request. This is because the underlying operating system needs to know when such changes happen. + /// This is a blocking function. + /// + /// + /// A device handle. + /// The of the configuration you wish to activate, or -1 if you wish to put the device in unconfigured state + /// + /// + /// 0 on success + /// if the requested configuration does not exist + /// if interfaces are currently claimed + /// if the device has been disconnected + /// another code on other failure + /// + /// + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_set_configuration")] + public static extern int SetConfiguration([In] MonoUsbDeviceHandle deviceHandle, int configuration); + + /// + /// Claim an interface on a given device handle. + /// + /// + /// You must claim the interface you wish to use before you can perform I/O on any of its endpoints. + /// It is legal to attempt to claim an already-claimed interface, in which case libusb just returns 0 without doing anything. + /// Claiming of interfaces is a purely logical operation; it does not cause any requests to be sent over the bus. Interface claiming is used to instruct the underlying operating system that your application wishes to take ownership of the interface. + /// + /// + /// A device handle. + /// the of the interface you wish to claim. + /// + /// + /// 0 on success + /// if the requested interface does not exist + /// if another program or driver has claimed the interface + /// if the device has been disconnected + /// another code on other failure + /// + /// + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_claim_interface")] + public static extern int ClaimInterface([In] MonoUsbDeviceHandle deviceHandle, int interfaceNumber); + + /// + /// Release an interface previously claimed with . + /// + /// + /// You should release all claimed interfaces before closing a device handle. + /// This is a blocking function. A SET_INTERFACE control request will be sent to the device, resetting interface state to the first alternate setting. + /// + /// + /// A device handle. + /// the of the interface you wish to claim. + /// + /// + /// 0 on success + /// if the interface was not claimed + /// if the device has been disconnected + /// another code on other failure + /// + /// + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_release_interface")] + public static extern int ReleaseInterface([In] MonoUsbDeviceHandle deviceHandle, int interfaceNumber); + + /// + /// Activate an alternate setting for an interface. + /// + /// + /// The interface must have been previously claimed with . + /// You should always use this function rather than formulating your own SET_INTERFACE control request. This is because the underlying operating system needs to know when such changes happen. + /// This is a blocking function. + /// + /// + /// A device handle. + /// The of the previously-claimed interface. + /// The of the alternate setting to activate. + /// + /// + /// 0 on success + /// if the interface was not claimed, or the requested alternate setting does not exist + /// if the device has been disconnected + /// another code on other failure + /// + /// + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_set_interface_alt_setting")] + public static extern int SetInterfaceAltSetting([In] MonoUsbDeviceHandle deviceHandle, int interfaceNumber, int alternateSetting); + + /// + /// Clear the halt/stall condition for an endpoint. + /// + /// + /// Endpoints with halt status are unable to receive or transmit data until the halt condition is stalled. + /// You should cancel all pending transfers before attempting to clear the halt condition. + /// This is a blocking function. + /// + /// + /// A device handle. + /// The endpoint to clear halt status. + /// + /// + /// 0 on success + /// if the endpoint does not exist + /// if the device has been disconnected + /// another code on other failure + /// + /// + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_clear_halt")] + public static extern int ClearHalt([In] MonoUsbDeviceHandle deviceHandle, byte endpoint); + + /// + /// Perform a USB port reset to reinitialize a device. + /// + /// + /// The system will attempt to restore the previous configuration and alternate settings after the reset has completed. + /// If the reset fails, the descriptors change, or the previous state cannot be restored, the device will appear to be disconnected and reconnected. This means that the device handle is no longer valid (you should close it) and rediscover the device. A return code of indicates when this is the case. + /// This is a blocking function which usually incurs a noticeable delay. + /// + /// + /// A device handle. + /// + /// + /// 0 on success + /// if re-enumeration is required, or if the device has been disconnected + /// another code on other failure + /// + /// + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_reset_device")] + public static extern int ResetDevice([In] MonoUsbDeviceHandle deviceHandle); + + /// + /// Determine if a kernel driver is active on an interface. + /// + /// + /// + /// + /// A device handle. + /// The interface to check. + /// + /// + /// 0 if no kernel driver is active. + /// 1 if a kernel driver is active. + /// if the device has been disconnected. + /// Another code on other failure. + /// + /// + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_kernel_driver_active")] + public static extern int KernelDriverActive([In] MonoUsbDeviceHandle deviceHandle, int interfaceNumber); + + /// + /// Detach a kernel driver from an interface. + /// + /// + /// If successful, you will then be able to claim the interface and perform I/O. + /// + /// + /// A device handle. + /// The interface to detach the driver from. + /// + /// + /// 0 on success. + /// if no kernel driver was active. + /// if the interface does not exist. + /// if the device has been disconnected + /// Another code on other failure. + /// + /// + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_detach_kernel_driver")] + public static extern int DetachKernelDriver([In] MonoUsbDeviceHandle deviceHandle, int interfaceNumber); + + /// + /// Re-attach an interface's kernel driver, which was previously detached using . + /// + /// + /// + /// + /// A device handle. + /// The interface to attach the driver from. + /// + /// + /// 0 on success. + /// if no kernel driver was active. + /// if the interface does not exist. + /// if the device has been disconnected. + /// if the driver cannot be attached because the interface is claimed by a program or driver. + /// Another code on other failure. + /// + /// + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_attach_kernel_driver")] + public static extern int AttachKernelDriver([In] MonoUsbDeviceHandle deviceHandle, int interfaceNumber); + + #endregion + + #region API LIBRARY FUNCTIONS - USB descriptors + + /// + /// Gets the standard device descriptor. + /// + /// + /// This is a non-blocking function which does not involve any requests being sent to the device. + /// + /// + /// A device profile handle. + /// The clas that will hold the data. + /// 0 on success or a code on failure. + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_get_device_descriptor")] + public static extern int GetDeviceDescriptor([In] MonoUsbProfileHandle deviceProfileHandle, + [Out] MonoUsbDeviceDescriptor deviceDescriptor); + + /// + /// Get the USB configuration descriptor for the currently active configuration. + /// + /// + /// This is a non-blocking function which does not involve any requests being sent to the device. + /// + /// + /// A device profile handle. + /// A config handle. + /// + /// + /// 0 on success + /// if the device is in unconfigured state + /// another code on error + /// + /// + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_get_active_config_descriptor")] + public static extern int GetActiveConfigDescriptor([In] MonoUsbProfileHandle deviceProfileHandle, + [Out] out MonoUsbConfigHandle configHandle); + + + /// + /// Get a USB configuration descriptor based on its index. + /// + /// + /// This is a non-blocking function which does not involve any requests being sent to the device. + /// + /// + /// A device profile handle. + /// The index of the configuration you wish to retrieve. + /// A config handle. + /// + /// + /// 0 on success + /// if the device is in unconfigured state + /// another code on error + /// + /// + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_get_config_descriptor")] + public static extern int GetConfigDescriptor([In] MonoUsbProfileHandle deviceProfileHandle, + byte configIndex, + [Out] out MonoUsbConfigHandle configHandle); + + /// + /// Get a USB configuration descriptor with a specific bConfigurationValue. + /// + /// + /// This is a non-blocking function which does not involve any requests being sent to the device. + /// + /// + /// A device profile handle. + /// The bConfigurationValue of the configuration you wish to retrieve. + /// A config handle. + /// + /// + /// 0 on success + /// if the device is in unconfigured state + /// another code on error + /// + /// + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_get_config_descriptor_by_value")] + public static extern int GetConfigDescriptorByValue([In] MonoUsbProfileHandle deviceProfileHandle, + byte bConfigurationValue, + [Out] out MonoUsbConfigHandle configHandle); + + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_free_config_descriptor")] + internal static extern void FreeConfigDescriptor(IntPtr pConfigDescriptor); + + /// + /// Retrieve a descriptor from the default control pipe. + /// + /// + /// This is a convenience function which formulates the appropriate control message to retrieve the descriptor. + /// + /// + /// Retrieve a descriptor from the default control pipe. + /// The descriptor type, + /// The index of the descriptor to retrieve. + /// Output buffer for descriptor. + /// Size of data buffer. + /// Number of bytes returned in data, or a code on failure. + public static int GetDescriptor(MonoUsbDeviceHandle deviceHandle, byte descType, byte descIndex, IntPtr pData, int length) + { + return ControlTransfer(deviceHandle, + (byte) UsbEndpointDirection.EndpointIn, + (byte) UsbStandardRequest.GetDescriptor, + (short) ((descType << 8) | descIndex), + 0, + pData, + (short) length, + 1000); + } + + /// + /// Retrieve a descriptor from the default control pipe. + /// + /// + /// This is a convenience function which formulates the appropriate control message to retrieve the descriptor. + /// + /// + /// Retrieve a descriptor from the default control pipe. + /// The descriptor type, + /// The index of the descriptor to retrieve. + /// Output buffer for descriptor. This object is pinned using . + /// Size of data buffer. + /// Number of bytes returned in data, or code on failure. + public static int GetDescriptor(MonoUsbDeviceHandle deviceHandle, byte descType, byte descIndex, object data, int length) + { + PinnedHandle p = new PinnedHandle(data); + return GetDescriptor(deviceHandle, descType, descIndex, p.Handle, length); + } + + #endregion + + #region API LIBRARY FUNCTIONS - Asynchronous device I/O + + + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_alloc_transfer")] + internal static extern IntPtr AllocTransfer(int isoPackets); + + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_free_transfer")] + internal static extern void FreeTransfer(IntPtr pTransfer); + + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_submit_transfer")] + internal static extern int SubmitTransfer(IntPtr pTransfer); + + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_cancel_transfer")] + internal static extern int CancelTransfer(IntPtr pTransfer); + + #endregion + + #region API LIBRARY FUNCTIONS - Polling and timing + + /// + /// Attempt to acquire the event handling lock. + /// + /// + /// This lock is used to ensure that only one thread is monitoring libusb event sources at any one time. + /// You only need to use this lock if you are developing an application which calls poll() or select() on libusb's file descriptors directly. If you stick to libusb's event handling loop functions (e.g. libusb_handle_events) then you do not need to be concerned with this locking. + /// While holding this lock, you are trusted to actually be handling events. If you are no longer handling events, you must call libusb_unlock_events as soon as possible. + /// + /// + /// A valid . + /// + /// + /// 0 if the lock was obtained successfully. + /// 1 if the lock was not obtained. (i.e. another thread holds the lock) + /// + /// + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_try_lock_events")] + public static extern int TryLockEvents([In]MonoUsbSessionHandle sessionHandle); + + /// + /// Acquire the event handling lock, blocking until successful acquisition if it is contended. + /// + /// + /// This lock is used to ensure that only one thread is monitoring libusb event sources at any one time. + /// You only need to use this lock if you are developing an application which calls poll() or select() on libusb's file descriptors directly. If you stick to libusb's event handling loop functions (e.g. libusb_handle_events) then you do not need to be concerned with this locking. + /// While holding this lock, you are trusted to actually be handling events. If you are no longer handling events, you must call libusb_unlock_events as soon as possible. + /// + /// + /// A valid . + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_lock_events")] + public static extern void LockEvents([In]MonoUsbSessionHandle sessionHandle); + + /// + /// Release the lock previously acquired with libusb_try_lock_events or libusb_lock_events. + /// + /// + /// Releasing this lock will wake up any threads blocked on libusb_wait_for_event. + /// + /// + /// A valid . + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_unlock_events")] + public static extern void UnlockEvents([In]MonoUsbSessionHandle sessionHandle); + + /// + /// Determine if it is still OK for this thread to be doing event handling. + /// + /// + /// Sometimes, libusb needs to temporarily pause all event handlers, and this is the function you should use before polling file descriptors to see if this is the case. + /// If this function instructs your thread to give up the events lock, you should just continue the usual logic that is documented in Multi-threaded applications and asynchronous I/O. On the next iteration, your thread will fail to obtain the events lock, and will hence become an event waiter. + /// This function should be called while the events lock is held: you don't need to worry about the results of this function if your thread is not the current event handler. + /// + /// + /// A valid . + /// + /// + /// 1 if event handling can start or continue. + /// 0 if this thread must give up the events lock. + /// + /// + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_event_handling_ok")] + public static extern int EventHandlingOk([In]MonoUsbSessionHandle sessionHandle); + + /// + /// Determine if an active thread is handling events (i.e. if anyone is holding the event handling lock). + /// + /// + /// + /// + /// A valid . + /// + /// + /// 1 if a thread is handling events. + /// 0 if there are no threads currently handling events. + /// + /// + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_event_handler_active")] + public static extern int EventHandlerActive([In]MonoUsbSessionHandle sessionHandle); + + /// + /// Acquire the event waiters lock. + /// + /// + /// This lock is designed to be obtained under the situation where you want to be aware when events are completed, but some other thread is event handling so calling libusb_handle_events is not allowed. + /// You then obtain this lock, re-check that another thread is still handling events, then call libusb_wait_for_event. + /// You only need to use this lock if you are developing an application which calls poll() or select() on libusb's file descriptors directly, and may potentially be handling events from 2 threads simultaenously. If you stick to libusb's event handling loop functions (e.g. libusb_handle_events) then you do not need to be concerned with this locking. + /// + /// + /// A valid . + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_lock_event_waiters")] + public static extern void LockEventWaiters([In]MonoUsbSessionHandle sessionHandle); + + /// + /// Release the event waiters lock. + /// + /// + /// + /// + /// A valid . + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_unlock_event_waiters")] + public static extern void UnlockEventWaiters([In]MonoUsbSessionHandle sessionHandle); + + /// + /// Wait for another thread to signal completion of an event. + /// + /// + /// + /// This function will block until any of the following conditions are met: + /// + /// The timeout expires. + /// A transfer completes. + /// A thread releases the event handling lock through libusb_unlock_events. + /// + /// + /// Condition 1 is obvious. Condition 2 unblocks your thread after the callback for the transfer has completed. Condition 3 is important because it means that the thread that was previously handling events is no longer doing so, so if any events are to complete, another thread needs to step up and start event handling. + /// This function releases the event waiters lock before putting your thread to sleep, and reacquires the lock as it is being woken up. + /// + /// + /// A valid . + /// Maximum timeout for this blocking function. + /// + /// + /// 0 after a transfer completes or another thread stops event handling. + /// 1 if the timeout expired. + /// + /// + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_wait_for_event")] + public static extern int WaitForEvent([In]MonoUsbSessionHandle sessionHandle, ref UnixNativeTimeval timeval); + + /// + /// Handle any pending events. + /// + /// + /// libusb determines "pending events" by checking if any timeouts have expired and by checking the set of file descriptors for activity. + /// If a non-zero timeval is passed and no events are currently pending, this function will block waiting for events to handle up until the specified timeout. If an event arrives or a signal is raised, this function will return early. + /// + /// + /// A valid . + /// The maximum time to block waiting for events, or zero for non-blocking mode + /// 0 on success, or a code on other failure. + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_handle_events_timeout")] + public static extern int HandleEventsTimeout([In]MonoUsbSessionHandle sessionHandle, ref UnixNativeTimeval tv); + + /// + /// Handle any pending events in blocking mode with a sensible timeout. + /// + /// + /// This timeout is currently hardcoded at 2 seconds but we may change this if we decide other values are more sensible. For finer control over whether this function is blocking or non-blocking, or the maximum timeout, use libusb_handle_events_timeout instead. + /// + /// + /// A valid . + /// 0 on success, or a code on other failure. + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_handle_events")] + public static extern int HandleEvents([In]MonoUsbSessionHandle sessionHandle); + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_handle_events")] + private static extern int HandleEvents(IntPtr pSessionHandle); + + /// + /// Handle any pending events by polling file descriptors, without checking if any other threads are already doing so. + /// + /// + /// Must be called with the event lock held, see libusb_lock_events. + /// This function is designed to be called under the situation where you have taken the event lock and are calling poll()/select() directly on libusb's file descriptors (as opposed to using libusb_handle_events or similar). You detect events on libusb's descriptors, so you then call this function with a zero timeout value (while still holding the event lock). + /// + /// + /// A valid . + /// The maximum time to block waiting for events, or zero for non-blocking mode + /// 0 on success, or a code on other failure. + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_handle_events_locked")] + public static extern int HandleEventsLocked([In]MonoUsbSessionHandle sessionHandle, ref UnixNativeTimeval tv); + + /// + /// Determines whether your application must apply special timing considerations when monitoring libusb's file descriptors. + /// + /// + /// This function is only useful for applications which retrieve and poll libusb's file descriptors in their own main loop (The more advanced option). + /// Ordinarily, libusb's event handler needs to be called into at specific moments in time (in addition to times when there is activity on the file descriptor set). The usual approach is to use libusb_get_next_timeout to learn about when the next timeout occurs, and to adjust your poll()/select() timeout accordingly so that you can make a call into the library at that time. + /// Some platforms supported by libusb do not come with this baggage - any events relevant to timing will be represented by activity on the file descriptor set, and libusb_get_next_timeout will always return 0. This function allows you to detect whether you are running on such a platform. + /// Since v1.0.5. + /// + /// + /// A valid . + /// 0 if you must call into libusb at times determined by libusb_get_next_timeout, or 1 if all timeout events are handled internally or through regular activity on the file descriptors. + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_pollfds_handle_timeouts")] + public static extern int PollfdsHandleTimeouts([In]MonoUsbSessionHandle sessionHandle); + + /// + /// Determine the next internal timeout that libusb needs to handle. + /// + /// + /// You only need to use this function if you are calling poll() or select() or similar on libusb's file descriptors yourself - you do not need to use it if you are calling libusb_handle_events or a variant directly. + /// You should call this function in your main loop in order to determine how long to wait for select() or poll() to return results. libusb needs to be called into at this timeout, so you should use it as an upper bound on your select() or poll() call. + /// When the timeout has expired, call into libusb_handle_events_timeout (perhaps in non-blocking mode) so that libusb can handle the timeout. + /// This function may return 1 (success) and an all-zero timeval. If this is the case, it indicates that libusb has a timeout that has already expired so you should call libusb_handle_events_timeout or similar immediately. A return code of 0 indicates that there are no pending timeouts. + /// On some platforms, this function will always returns 0 (no pending timeouts). See Notes on time-based events. + /// + /// + /// A valid . + /// The maximum time to block waiting for events, or zero for non-blocking mode + /// 0 if there are no pending timeouts, 1 if a timeout was returned, or on failure. + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_get_next_timeout")] + public static extern int GetNextTimeout([In]MonoUsbSessionHandle sessionHandle, ref UnixNativeTimeval tv); + + /// + /// Register notification functions for file descriptor additions/removals. + /// + /// + /// To remove notifiers, pass NULL values for the function pointers. + /// Note that file descriptors may have been added even before you register these notifiers (e.g. when a new is created). + /// Additionally, note that the removal notifier may be called during (e.g. when it is closing file descriptors that were opened and added to the poll set when a new was created). If you don't want this, remove the notifiers immediately before calling MonoUsbSessionHandle.Close(). + /// + /// + /// A valid . + /// Function delegate for addition notifications. + /// Function delegate for removal notifications. + /// User data to be passed back to callbacks (useful for passing sessionHandle information). + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_set_pollfd_notifiers")] + public static extern void SetPollfdNotifiers([In]MonoUsbSessionHandle sessionHandle, + PollfdAddedDelegate addedDelegate, + PollfdRemovedDelegate removedDelegate, + IntPtr pUserData); + + + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_get_pollfds")] + private static extern IntPtr GetPollfdsInternal([In]MonoUsbSessionHandle sessionHandle); + + /// + /// Retrieve a list of file descriptors that should be polled by your main loop as libusb event sources. + /// + /// + /// + /// + /// A valid . + /// A list of PollfdItem structures, or null on error. + public static List GetPollfds(MonoUsbSessionHandle sessionHandle) + { + List rtnList = new List(); + IntPtr pList = GetPollfdsInternal(sessionHandle); + if (pList == IntPtr.Zero) return null; + + IntPtr pNext = pList; + IntPtr pPollfd; + while ((((pNext != IntPtr.Zero))) && (pPollfd = Marshal.ReadIntPtr(pNext)) != IntPtr.Zero) + { + PollfdItem pollfdItem = new PollfdItem(pPollfd); + rtnList.Add(pollfdItem); + pNext = new IntPtr(pNext.ToInt64() + IntPtr.Size); + } + Marshal.FreeHGlobal(pList); + + return rtnList; + } + + #endregion + + #region API LIBRARY FUNCTIONS - Synchronous device I/O + + /// + /// Perform a USB control transfer. + /// + /// + /// The direction of the transfer is inferred from the bmRequestType field of the setup packet. + /// The wValue, wIndex and wLength fields values should be given in host-endian byte order. + /// + /// + /// A handle for the device to communicate with. + /// The request type field for the setup packet. + /// The request field for the setup packet. + /// The value field for the setup packet + /// The index field for the setup packet. + /// A suitably-sized data buffer for either input or output (depending on direction bits within bmRequestType). + /// The length field for the setup packet. The data buffer should be at least this size. + /// timeout (in milliseconds) that this function should wait before giving up due to no response being received. For an unlimited timeout, use value 0. + /// + /// + /// on success, the number of bytes actually transferred + /// if the transfer timed out + /// if the control request was not supported by the device. + /// if the device has been disconnected + /// another code on other failures + /// + /// + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_control_transfer")] + public static extern int ControlTransfer([In] MonoUsbDeviceHandle deviceHandle, + byte requestType, + byte request, + short value, + short index, + IntPtr pData, + short dataLength, + int timeout); + + + /// + /// Perform a USB control transfer for multi-threaded applications using the class. + /// + /// + /// The direction of the transfer is inferred from the bmRequestType field of the setup packet. + /// The wValue, wIndex and wLength fields values should be given in host-endian byte order. + /// + /// + /// A handle for the device to communicate with. + /// The request type field for the setup packet. + /// The request field for the setup packet. + /// The value field for the setup packet + /// The index field for the setup packet. + /// A suitably-sized data buffer for either input or output (depending on direction bits within bmRequestType). + /// The length field for the setup packet. The data buffer should be at least this size. + /// timeout (in milliseconds) that this function should wait before giving up due to no response being received. For an unlimited timeout, use value 0. + /// + /// + /// on success, the number of bytes actually transferred + /// if the transfer timed out + /// if the control request was not supported by the device. + /// if the device has been disconnected + /// another code on other failures + /// + /// + public static int ControlTransferAsync([In] MonoUsbDeviceHandle deviceHandle, + byte requestType, + byte request, + short value, + short index, + IntPtr pData, + short dataLength, + int timeout) + { + MonoUsbControlSetupHandle setupHandle = new MonoUsbControlSetupHandle(requestType, request, value, index, pData, dataLength); + MonoUsbTransfer transfer = new MonoUsbTransfer(0); + ManualResetEvent completeEvent = new ManualResetEvent(false); + GCHandle gcCompleteEvent = GCHandle.Alloc(completeEvent); + + transfer.FillControl(deviceHandle, setupHandle, DefaultAsyncDelegate, GCHandle.ToIntPtr(gcCompleteEvent), timeout); + + int r = (int)transfer.Submit(); + if (r < 0) + { + transfer.Free(); + gcCompleteEvent.Free(); + return r; + } + IntPtr pSessionHandle; + MonoUsbSessionHandle sessionHandle = MonoUsbEventHandler.SessionHandle; + if (sessionHandle == null) + pSessionHandle = IntPtr.Zero; + else + pSessionHandle = sessionHandle.DangerousGetHandle(); + + if (MonoUsbEventHandler.IsStopped) + { + while (!completeEvent.WaitOne(0, false)) + { + r = HandleEvents(pSessionHandle); + if (r < 0) + { + if (r == (int)MonoUsbError.ErrorInterrupted) + continue; + transfer.Cancel(); + while (!completeEvent.WaitOne(0, false)) + if (HandleEvents(pSessionHandle) < 0) + break; + transfer.Free(); + gcCompleteEvent.Free(); + return r; + } + } + } + else + { + completeEvent.WaitOne(Timeout.Infinite, UsbConstants.EXIT_CONTEXT); + } + + if (transfer.Status == MonoUsbTansferStatus.TransferCompleted) + { + r = transfer.ActualLength; + if (r > 0) + { + byte[] ctrlDataBytes = setupHandle.ControlSetup.GetData(r); + Marshal.Copy(ctrlDataBytes, 0, pData, Math.Min(ctrlDataBytes.Length, dataLength)); + } + + } + else + r = (int)MonoLibUsbErrorFromTransferStatus(transfer.Status); + + transfer.Free(); + gcCompleteEvent.Free(); + return r; + } + + /// + /// Perform a USB control transfer. + /// + /// + /// The direction of the transfer is inferred from the bmRequestType field of the setup packet. + /// The wValue, wIndex and wLength fields values should be given in host-endian byte order. + /// + /// + /// A handle for the device to communicate with. + /// The request type field for the setup packet. + /// The request field for the setup packet. + /// The value field for the setup packet + /// The index field for the setup packet. + /// + /// A suitably-sized data buffer for either input or output (depending on direction bits within bmRequestType). + /// This value can be: + /// + /// An of bytes or other blittable types. + /// An already allocated, pinned . In this case is used for the buffer address. + /// An . + /// + /// + /// The length field for the setup packet. The data buffer should be at least this size. + /// timeout (in milliseconds) that this function should wait before giving up due to no response being received. For an unlimited timeout, use value 0. + /// + /// + /// on success, the number of bytes actually transferred + /// if the transfer timed out + /// if the control request was not supported by the device. + /// if the device has been disconnected + /// another code on other failures + /// + /// + public static int ControlTransfer([In] MonoUsbDeviceHandle deviceHandle, + byte requestType, + byte request, + short value, + short index, + object data, + short dataLength, + int timeout) + { + PinnedHandle p = new PinnedHandle(data); + int ret = ControlTransfer(deviceHandle, requestType, request, value, index, p.Handle, dataLength, timeout); + p.Dispose(); + return ret; + } + +#if NOT_USED + /// + /// Perform a USB control transfer. + /// + /// + /// The direction of the transfer is inferred from the bmRequestType field of the setup packet. + /// The wValue, wIndex and wLength fields values should be given in host-endian byte order. + /// + /// A handle for the device to communicate with. + /// The setup packet. + /// A suitably-sized data buffer for either input or output (depending on direction bits within bmRequestType). + /// The length field for the setup packet. The data buffer should be at least this size. + /// timeout (in millseconds) that this function should wait before giving up due to no response being received. For an unlimited timeout, use value 0. + /// on success, the number of bytes actually transferred, Other wise a . + public static int libusb_control_transfer(MonoUsbDeviceHandle deviceHandle, + ref libusb_control_setup setupPacket, + IntPtr pData, + short dataLength, + int timeout) + { + return libusb_control_transfer(deviceHandle, + setupPacket.bmRequestType, + setupPacket.bRequest, + setupPacket.wValue, + setupPacket.wIndex, + pData, + dataLength, + timeout); + } +#endif + + /// + /// Perform a USB bulk transfer. + /// + /// + /// The direction of the transfer is inferred from the direction bits of the endpoint address. + /// + /// For bulk reads, the length field indicates the maximum length of data you are expecting to receive. + /// If less data arrives than expected, this function will return that data, so be sure to check the + /// transferred output parameter. + /// + /// + /// You should also check the transferred parameter for bulk writes. Not all of the data may have been + /// written. Also check transferred when dealing with a timeout error code. libusb may have to split + /// your transfer into a number of chunks to satisfy underlying O/S requirements, meaning that the + /// timeout may expire after the first few chunks have completed. libusb is careful not to lose any + /// data that may have been transferred; do not assume that timeout conditions indicate a complete lack + /// of I/O. + /// + /// + /// + /// A handle for the device to communicate with. + /// The address of a valid endpoint to communicate with. + /// + /// A suitably-sized data buffer for either input or output (depending on endpoint). + /// For bulk writes, the number of bytes from data to be sent. for bulk reads, the maximum number of bytes to receive into the data buffer. + /// Output location for the number of bytes actually transferred. + /// Timeout (in milliseconds) that this function should wait before giving up due to no response being received. For an unlimited timeout, use value 0. + /// + /// + /// 0 on success (and populates ) + /// if the transfer timed out + /// if the endpoint halted + /// if the device offered more data, see Packets and overflows + /// if the device has been disconnected + /// another code on other failures + /// + /// + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_bulk_transfer")] + public static extern int BulkTransfer([In] MonoUsbDeviceHandle deviceHandle, + byte endpoint, + IntPtr pData, + int length, + out int actualLength, + int timeout); + + /// + /// Perform a USB bulk transfer. + /// + /// + /// The direction of the transfer is inferred from the direction bits of the endpoint address. + /// + /// For bulk reads, the length field indicates the maximum length of data you are expecting to receive. + /// If less data arrives than expected, this function will return that data, so be sure to check the + /// transferred output parameter. + /// + /// + /// You should also check the transferred parameter for bulk writes. Not all of the data may have been + /// written. Also check transferred when dealing with a timeout error code. libusb may have to split + /// your transfer into a number of chunks to satisfy underlying O/S requirements, meaning that the + /// timeout may expire after the first few chunks have completed. libusb is careful not to lose any + /// data that may have been transferred; do not assume that timeout conditions indicate a complete lack + /// of I/O. + /// + /// + /// + /// A handle for the device to communicate with. + /// The address of a valid endpoint to communicate with. + /// + /// A suitably-sized data buffer for either input or output (depending on endpoint). + /// This value can be: + /// + /// An of bytes or other blittable types. + /// An already allocated, pinned . In this case is used for the buffer address. + /// An . + /// + /// + /// For bulk writes, the number of bytes from data to be sent. for bulk reads, the maximum number of bytes to receive into the data buffer. + /// Output location for the number of bytes actually transferred. + /// Timeout (in milliseconds) that this function should wait before giving up due to no response being received. For an unlimited timeout, use value 0. + /// + /// + /// 0 on success (and populates ) + /// if the transfer timed out + /// if the endpoint halted + /// if the device offered more data, see Packets and overflows + /// if the device has been disconnected + /// another code on other failures + /// + /// + public static int BulkTransfer([In] MonoUsbDeviceHandle deviceHandle, + byte endpoint, + object data, + int length, + out int actualLength, + int timeout) + { + PinnedHandle p = new PinnedHandle(data); + int ret = BulkTransfer(deviceHandle, endpoint, p.Handle, length, out actualLength, timeout); + p.Dispose(); + return ret; + } + + /// + /// Perform a USB interrupt transfer. + /// + /// + /// + /// The direction of the transfer is inferred from the direction bits of the endpoint address. + /// + /// For interrupt reads, the length field indicates the maximum length of data you are expecting to receive. + /// If less data arrives than expected, this function will return that data, so be sure to check the + /// transferred output parameter. + /// + /// You should also check the transferred parameter for interrupt writes. Not all of the data may have been + /// written. Also check transferred when dealing with a timeout error code. libusb may have to split + /// your transfer into a number of chunks to satisfy underlying O/S requirements, meaning that the + /// timeout may expire after the first few chunks have completed. libusb is careful not to lose any + /// data that may have been transferred; do not assume that timeout conditions indicate a complete lack + /// of I/O. + /// + /// + /// + /// A handle for the device to communicate with. + /// The address of a valid endpoint to communicate with. + /// A suitably-sized data buffer for either input or output (depending on endpoint). + /// For interrupt writes, the number of bytes from data to be sent. for interrupt reads, the maximum number of bytes to receive into the data buffer. + /// Output location for the number of bytes actually transferred. + /// Timeout (in milliseconds) that this function should wait before giving up due to no response being received. For an unlimited timeout, use value 0. + /// + /// + /// 0 on success (and populates ) + /// if the transfer timed out + /// if the endpoint halted + /// if the device offered more data, see Packets and overflows + /// if the device has been disconnected + /// another code on other failures + /// + /// + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_interrupt_transfer")] + public static extern int InterruptTransfer([In] MonoUsbDeviceHandle deviceHandle, + byte endpoint, + IntPtr pData, + int length, + out int actualLength, + int timeout); + + + /// + /// Perform a USB interrupt transfer. + /// + /// + /// + /// The direction of the transfer is inferred from the direction bits of the endpoint address. + /// + /// For interrupt reads, the length field indicates the maximum length of data you are expecting to receive. + /// If less data arrives than expected, this function will return that data, so be sure to check the + /// transferred output parameter. + /// + /// You should also check the transferred parameter for interrupt writes. Not all of the data may have been + /// written. Also check transferred when dealing with a timeout error code. libusb may have to split + /// your transfer into a number of chunks to satisfy underlying O/S requirements, meaning that the + /// timeout may expire after the first few chunks have completed. libusb is careful not to lose any + /// data that may have been transferred; do not assume that timeout conditions indicate a complete lack + /// of I/O. + /// + /// + /// + /// A handle for the device to communicate with. + /// The address of a valid endpoint to communicate with. + /// + /// A suitably-sized data buffer for either input or output (depending on endpoint). + /// This value can be: + /// + /// An of bytes or other blittable types. + /// An already allocated, pinned . In this case is used for the buffer address. + /// An . + /// + /// + /// For interrupt writes, the number of bytes from data to be sent. for interrupt reads, the maximum number of bytes to receive into the data buffer. + /// Output location for the number of bytes actually transferred. + /// Timeout (in milliseconds) that this function should wait before giving up due to no response being received. For an unlimited timeout, use value 0. + /// + /// + /// 0 on success (and populates ) + /// if the transfer timed out + /// if the endpoint halted + /// if the device offered more data, see Packets and overflows + /// if the device has been disconnected + /// another code on other failures + /// + /// + public static int InterruptTransfer([In] MonoUsbDeviceHandle deviceHandle, + byte endpoint, + object data, + int length, + out int actualLength, + int timeout) + { + PinnedHandle p = new PinnedHandle(data); + int ret = InterruptTransfer(deviceHandle, endpoint, p.Handle, length, out actualLength, timeout); + p.Dispose(); + return ret; + } + + #endregion + + #region API LIBRARY FUNCTIONS - Misc + + [DllImport(LIBUSB_DLL, CallingConvention = CC, SetLastError = false, EntryPoint = "libusb_strerror")] + private static extern IntPtr StrError(int errcode); + + /// + /// Get a string describing a . + /// + /// The code to retrieve a description for. + /// A string describing the code. + public static string StrError(MonoUsbError errcode) + { + switch (errcode) + { + case MonoUsbError.Success: + return "Success"; + case MonoUsbError.ErrorIO: + return "Input/output error"; + case MonoUsbError.ErrorInvalidParam: + return "Invalid parameter"; + case MonoUsbError.ErrorAccess: + return "Access denied (insufficient permissions)"; + case MonoUsbError.ErrorNoDevice: + return "No such device (it may have been disconnected)"; + case MonoUsbError.ErrorBusy: + return "Resource busy"; + case MonoUsbError.ErrorTimeout: + return "Operation timed out"; + case MonoUsbError.ErrorOverflow: + return "Overflow"; + case MonoUsbError.ErrorPipe: + return "Pipe error or endpoint halted"; + case MonoUsbError.ErrorInterrupted: + return "System call interrupted (perhaps due to signal)"; + case MonoUsbError.ErrorNoMem: + return "Insufficient memory"; + case MonoUsbError.ErrorIOCancelled: + return "Transfer was canceled"; + case MonoUsbError.ErrorNotSupported: + return "Operation not supported or unimplemented on this platform"; + default: + return "Unknown error:" + errcode; + } + } + + #endregion + + #region API LIBRARY - Windows Testing Only +#if WINDOWS_TESTING + internal static internal_windows_device_priv GetWindowsPriv(MonoUsbProfileHandle profileHandle) + { + internal_windows_device_priv priv = new internal_windows_device_priv(); + IntPtr pPriv = new IntPtr(profileHandle.DangerousGetHandle().ToInt64() + Marshal.SizeOf(typeof(internal_libusb_device))); + Marshal.PtrToStructure(pPriv, priv); + return priv; + } + + [StructLayout(LayoutKind.Sequential,Pack=0)] + internal class internal_libusb_device + { + public readonly IntPtr mutexLock; + public readonly int refCnt; /*QL - changed short to int*/ + + public readonly IntPtr ctx; + + public readonly byte busNumber; + public readonly byte deviceAddress; + public readonly byte numConfigurations; + + public readonly internal_list_head list = new internal_list_head(); + public readonly uint sessionData; + //public readonly IntPtr temp; + } + + [StructLayout(LayoutKind.Sequential, Pack = 0)] + internal class internal_list_head + { + public readonly IntPtr prev; + public readonly IntPtr next; + } + + internal struct internal_usb_interface + { + public readonly IntPtr path; // each interface needs a Windows device interface path, + public readonly IntPtr apib; // an API backend (multiple drivers support), + public readonly byte nb_endpoints; // and a set of endpoint addresses (USB_MAXENDPOINTS) + public readonly IntPtr endpoint; /*QL - added */ + public readonly bool restricted_functionality; /*QL - added */ + } + +[StructLayout(LayoutKind.Sequential, Pack = 0)] + internal class internal_windows_device_priv + { + public readonly IntPtr parent_dev; // access to parent is required for usermode ops + public readonly uint connection_index; // also required for some usermode ops + public readonly IntPtr path; // path used by Windows to reference the USB node + + public readonly IntPtr apib; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public readonly internal_usb_interface[] usb_interfaces=new internal_usb_interface[32]; + + public readonly byte composite_api_flags; // HID and composite devices require additional data + public readonly IntPtr hid; + public readonly byte active_config; + + public readonly IntPtr dev_descriptor; /*QL - added*/ + public readonly IntPtr config_descriptor; /*QL - added*/ + //USB_DEVICE_DESCRIPTOR dev_descriptor; + //char **config_descriptor; // list of pointers to the cached config descriptors + } +#endif + #endregion + + /// + /// Converts a enum to a enum. + /// + /// the to convert. + /// A that represents . + public static MonoUsbError MonoLibUsbErrorFromTransferStatus(MonoUsbTansferStatus status) + { + switch (status) + { + case MonoUsbTansferStatus.TransferCompleted: + return MonoUsbError.Success; + case MonoUsbTansferStatus.TransferError: + return MonoUsbError.ErrorPipe; + case MonoUsbTansferStatus.TransferTimedOut: + return MonoUsbError.ErrorTimeout; + case MonoUsbTansferStatus.TransferCancelled: + return MonoUsbError.ErrorIOCancelled; + case MonoUsbTansferStatus.TransferStall: + return MonoUsbError.ErrorPipe; + case MonoUsbTansferStatus.TransferNoDevice: + return MonoUsbError.ErrorNoDevice; + case MonoUsbTansferStatus.TransferOverflow: + return MonoUsbError.ErrorOverflow; + default: + return MonoUsbError.ErrorOther; + } + } + + /// + /// Calls and if = true. + /// + internal static void InitAndStart() + { + if (!MonoUsbEventHandler.IsStopped) return; + MonoUsbEventHandler.Init(); + MonoUsbEventHandler.Start(); + } + + /// + /// Calls and . + /// + internal static void StopAndExit() + { +#if LIBUSBDOTNET + if (LibUsbDotNet.LudnMonoLibUsb.MonoUsbDevice.mMonoUSBProfileList != null) LibUsbDotNet.LudnMonoLibUsb.MonoUsbDevice.mMonoUSBProfileList.Close(); + LibUsbDotNet.LudnMonoLibUsb.MonoUsbDevice.mMonoUSBProfileList = null; +#endif + MonoUsbEventHandler.Stop(true); + MonoUsbEventHandler.Exit(); + } + + +#if LIBUSBDOTNET + internal static ErrorCode ErrorCodeFromLibUsbError(int ret, out string description) + { + description = string.Empty; + if (ret == 0) return ErrorCode.Success; + + switch ((MonoUsbError) ret) + { + case MonoUsbError.Success: + description += "Success"; + return ErrorCode.Success; + case MonoUsbError.ErrorIO: + description += "Input/output error"; + return ErrorCode.IoSyncFailed; + case MonoUsbError.ErrorInvalidParam: + description += "Invalid parameter"; + return ErrorCode.InvalidParam; + case MonoUsbError.ErrorAccess: + description += "Access denied (insufficient permissions)"; + return ErrorCode.AccessDenied; + case MonoUsbError.ErrorNoDevice: + description += "No such device (it may have been disconnected)"; + return ErrorCode.DeviceNotFound; + case MonoUsbError.ErrorBusy: + description += "Resource busy"; + return ErrorCode.ResourceBusy; + case MonoUsbError.ErrorTimeout: + description += "Operation timed out"; + return ErrorCode.IoTimedOut; + case MonoUsbError.ErrorOverflow: + description += "Overflow"; + return ErrorCode.Overflow; + case MonoUsbError.ErrorPipe: + description += "Pipe error or endpoint halted"; + return ErrorCode.PipeError; + case MonoUsbError.ErrorInterrupted: + description += "System call interrupted (perhaps due to signal)"; + return ErrorCode.Interrupted; + case MonoUsbError.ErrorNoMem: + description += "Insufficient memory"; + return ErrorCode.InsufficientMemory; + case MonoUsbError.ErrorIOCancelled: + description += "Transfer was canceled"; + return ErrorCode.IoCancelled; + case MonoUsbError.ErrorNotSupported: + description += "Operation not supported or unimplemented on this platform"; + return ErrorCode.NotSupported; + default: + description += "Unknown error:" + ret; + return ErrorCode.UnknownError; + } + } +#endif + } +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/MonoUsbDevice.cs b/LibWinUsb/MonoLibUsb/MonoUsbDevice.cs new file mode 100644 index 0000000..8e92992 --- /dev/null +++ b/LibWinUsb/MonoLibUsb/MonoUsbDevice.cs @@ -0,0 +1,522 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Runtime.InteropServices; +using LibUsbDotNet.Descriptors; +using LibUsbDotNet.Info; +using LibUsbDotNet.Main; +using MonoLibUsb; +using MonoLibUsb.Descriptors; +using MonoLibUsb.Profile; + +namespace LibUsbDotNet.LudnMonoLibUsb +{ + /// This is the LibUsbDotNet Libusb-1.0 implementation of a . + /// + /// + /// This class is used for perform I/O and other operations on Libusb-1.0 devices using with LibUsbDotNet. + /// This class is not a part of the low-level MonLibUsb API. This is class LibUsbDotNet uses to implement the low-level MonoLibUsb API. + /// + public class MonoUsbDevice : UsbDevice, IUsbDevice + { + internal static readonly object OLockDeviceList = new object(); + internal static MonoUsbProfileList mMonoUSBProfileList; + private readonly MonoUsbProfile mMonoUSBProfile; + + private int mClaimedInteface; + + internal MonoUsbDevice(ref MonoUsbProfile monoUSBProfile) + : base(null, null) + { + mMonoUSBProfile = monoUSBProfile; + mCachedDeviceDescriptor = new UsbDeviceDescriptor(monoUSBProfile.DeviceDescriptor); + } + + internal static MonoUsbProfileList ProfileList + { + get + { + lock (OLockDeviceList) + { + MonoUsbApi.InitAndStart(); + if (mMonoUSBProfileList == null) + { + mMonoUSBProfileList = new MonoUsbProfileList(); + } + return mMonoUSBProfileList; + } + } + } + + /// + /// Gets a list of Libusb-1.0 devices. + /// + /// + /// Using the property will request a device list directly from the Libusb-1.0 driver. + /// Libusb-1.0 is compatible with several platforms including windows. + /// You can force LibUsbDotNet to always use Libusb-1.0 with the member. + /// + /// + /// + public static List MonoUsbDeviceList + { + get + { + lock (OLockDeviceList) + { + MonoUsbApi.InitAndStart(); + if (mMonoUSBProfileList == null) + { + mMonoUSBProfileList = new MonoUsbProfileList(); + } + int ret = (int) mMonoUSBProfileList.Refresh(MonoUsbEventHandler.SessionHandle); + if (ret < 0) return null; + List rtnList = new List(); + for (int iProfile = 0; iProfile < mMonoUSBProfileList.Count; iProfile++) + { + MonoUsbProfile monoUSBProfile = mMonoUSBProfileList[iProfile]; + if (monoUSBProfile.DeviceDescriptor.BcdUsb == 0) continue; + MonoUsbDevice newDevice = new MonoUsbDevice(ref monoUSBProfile); + rtnList.Add(newDevice); + } + + return rtnList; + } + } + } + + /// + /// Gets the instance address the device is using. + /// + public byte DeviceAddress + { + get { return mMonoUSBProfile.DeviceAddress; } + } + + /// + /// Gets the bus number the device is connected to. + /// + public byte BusNumber + { + get { return mMonoUSBProfile.BusNumber; } + } + + #region IUsbDevice Members + + /// + /// Sends a usb device reset command. + /// + /// + /// After calling , the instance is disposed and + /// no longer usable. A new instance must be obtained from the device list. + /// + /// True on success. + public bool ResetDevice() + { + int ret; + if (!IsOpen) throw new UsbException(this, "Device is not opened."); + ActiveEndpoints.Clear(); + + if ((ret = MonoUsbApi.ResetDevice((MonoUsbDeviceHandle) mUsbHandle)) != 0) + { + UsbError.Error(ErrorCode.MonoApiError, ret, "ResetDevice Failed", this); + } + else + { + Close(); + } + + return ret == 0; + } + + /// + /// Returns the DriverMode this USB device is using. + /// + public override DriverModeType DriverMode + { + get + { + if (IsLinux) + return DriverModeType.MonoLibUsb; + + return DriverModeType.LibUsbWinBack; + } + } + + /// + /// Closes the and disposes any . + /// + /// True on success. + public override bool Close() + { + ActiveEndpoints.Clear(); + if (IsOpen) mUsbHandle.Close(); + + return true; + } + + + /// + /// Transmits control data over a default control endpoint. + /// + /// An 8-byte setup packet which contains parameters for the control request. + /// See section 9.3 USB Device Requests of the Universal Serial Bus Specification Revision 2.0 for more information. + /// Data to be sent/received from the device. + /// Length of the buffer param. + /// Number of bytes sent or received (depends on the direction of the control transfer). + /// True on success. + public override bool ControlTransfer(ref UsbSetupPacket setupPacket, IntPtr buffer, int bufferLength, out int lengthTransferred) + { + Debug.WriteLine(GetType().Name + ".ControlTransfer() Before", "Libusb-1.0"); + int ret = MonoUsbApi.ControlTransferAsync((MonoUsbDeviceHandle) mUsbHandle, + setupPacket.RequestType, + setupPacket.Request, + setupPacket.Value, + setupPacket.Index, + buffer, + (short) bufferLength, + UsbConstants.DEFAULT_TIMEOUT); + + Debug.WriteLine(GetType().Name + ".ControlTransfer() Error:" + ((MonoUsbError) ret).ToString(), "Libusb-1.0"); + if (ret < 0) + { + UsbError.Error(ErrorCode.MonoApiError, ret, "ControlTransfer Failed", this); + lengthTransferred = 0; + return false; + } + lengthTransferred = ret; + return true; + } + + /// + /// Gets a descriptor from the device. See for more information. + /// + /// The descriptor type ID to retrieve; this is usually one of the enumerations. + /// Descriptor index. + /// Descriptor language id. + /// Memory to store the returned descriptor in. + /// Length of the buffer parameter in bytes. + /// The number of bytes transferred to buffer upon success. + /// True on success. + public override bool GetDescriptor(byte descriptorType, byte index, short langId, IntPtr buffer, int bufferLength, out int transferLength) + { + transferLength = 0; + bool bSuccess = false; + bool wasOpen = IsOpen; + if (!wasOpen) Open(); + if (!IsOpen) return false; + + int ret = MonoUsbApi.GetDescriptor((MonoUsbDeviceHandle) mUsbHandle, descriptorType, index, buffer, (ushort) bufferLength); + + if (ret < 0) + { + UsbError.Error(ErrorCode.MonoApiError, ret, "GetDescriptor Failed", this); + } + else + { + bSuccess = true; + transferLength = ret; + } + + if (!wasOpen && IsOpen) Close(); + + return bSuccess; + } + + /// + /// Opens the USB device handle. + /// + /// + ///True if the device is already opened or was opened successfully. + ///False if the device does not exists or is no longer valid. + /// + public override bool Open() + { + if (IsOpen) return true; + MonoUsbDeviceHandle handle = new MonoUsbDeviceHandle(mMonoUSBProfile.ProfileHandle); + if (handle.IsInvalid) + { + UsbError.Error(ErrorCode.MonoApiError, (int) MonoUsbDeviceHandle.LastErrorCode, "MonoUsbDevice.Open Failed", this); + mUsbHandle = null; + return false; + } + mUsbHandle = handle; + if (IsOpen) return true; + + mUsbHandle.Close(); + return false; + } + + /// + /// Gets the for this usb device. + /// + public MonoUsbProfile Profile + { + get + { + return mMonoUSBProfile; + } + } + /// + /// Opens an endpoint for reading + /// + /// Endpoint number for read operations. + /// Size of the read buffer allocated for the event. + /// The type of endpoint to open. + /// A class ready for reading. If the specified endpoint is already been opened, the original class is returned. + public override UsbEndpointReader OpenEndpointReader(ReadEndpointID readEndpointID, int readBufferSize, EndpointType endpointType) + { + foreach (UsbEndpointBase activeEndpoint in mActiveEndpoints) + if (activeEndpoint.EpNum == (byte)readEndpointID) + return (UsbEndpointReader)activeEndpoint; + + UsbEndpointReader epNew = new MonoUsbEndpointReader(this, readBufferSize, readEndpointID, endpointType); + return (UsbEndpointReader) ActiveEndpoints.Add(epNew); + } + + /// + /// Opens an endpoint for writing + /// + /// Endpoint number for read operations. + /// The type of endpoint to open. + /// A class ready for writing. If the specified endpoint is already been opened, the original class is returned. + public override UsbEndpointWriter OpenEndpointWriter(WriteEndpointID writeEndpointID, EndpointType endpointType) + { + foreach (UsbEndpointBase activeEndpoint in ActiveEndpoints) + if (activeEndpoint.EpNum == (byte)writeEndpointID) + return (UsbEndpointWriter)activeEndpoint; + + UsbEndpointWriter epNew = new MonoUsbEndpointWriter(this, writeEndpointID, endpointType); + return (UsbEndpointWriter) mActiveEndpoints.Add(epNew); + } + + /// + /// Sets the USB devices active configuration value. + /// + /// The active configuration value. A zero value means the device is not configured and a non-zero value indicates the device is configured. + /// True on success. + /// + /// A USB device can have several different configurations, but only one active configuration. + /// + public bool SetConfiguration(byte config) + { + int ret = MonoUsbApi.SetConfiguration((MonoUsbDeviceHandle) mUsbHandle, config); + if (ret != 0) + { + UsbError.Error(ErrorCode.MonoApiError, ret, "SetConfiguration Failed", this); + return false; + } + mCurrentConfigValue = config; + return true; + } + + /// + /// Gets the USB devices active configuration value. + /// + /// The active configuration value. A zero value means the device is not configured and a non-zero value indicates the device is configured. + /// True on success. + public override bool GetConfiguration(out byte config) + { + config = 0; + int iconfig = 0; + int ret = MonoUsbApi.GetConfiguration((MonoUsbDeviceHandle) mUsbHandle, ref iconfig); + if (ret != 0) + { + UsbError.Error(ErrorCode.MonoApiError, ret, "GetConfiguration Failed", this); + return false; + } + config = (byte) iconfig; + mCurrentConfigValue = config; + + return true; + } + + /// + /// Gets the class that opened the device, or null if the device was not opened by the class. + /// + public override UsbRegistry UsbRegistryInfo + { + get { return null; } + } + + /// + /// Gets the available configurations for this + /// + /// + /// The first time this property is accessed it will query the for all configurations. Subsequent request will return a cached copy of all configurations. + /// + public override ReadOnlyCollection Configs + { + get + { + if (ReferenceEquals(mConfigs, null)) + { + if (!IsOpen) + { + //Console.WriteLine("Device Not Opened!"); + return null; + } + GetConfigs(this, out mConfigs); + } + + return mConfigs.AsReadOnly(); + } + } + + /// + /// Gets the actual device descriptor the the current . + /// + public override UsbDeviceInfo Info + { + get + { + if (ReferenceEquals(mDeviceInfo, null)) + { + mDeviceInfo = new UsbDeviceInfo(this, mMonoUSBProfile.DeviceDescriptor); + } + return mDeviceInfo; + } + } + + /// + /// Claims the specified interface of the device. + /// + /// The interface to claim. + /// True on success. + public bool ClaimInterface(int interfaceID) + { + int ret = MonoUsbApi.ClaimInterface((MonoUsbDeviceHandle) mUsbHandle, interfaceID); + if (ret != 0) + { + UsbError.Error(ErrorCode.MonoApiError, ret, "ClaimInterface Failed", this); + return false; + } + mClaimedInteface = interfaceID; + return true; + } + + /// + /// Releases an interface that was previously claimed with . + /// + /// The interface to release. + /// True on success. + public bool ReleaseInterface(int interfaceID) + { + int ret = MonoUsbApi.ReleaseInterface((MonoUsbDeviceHandle) mUsbHandle, interfaceID); + if (ret != 0) + { + UsbError.Error(ErrorCode.MonoApiError, ret, "ReleaseInterface Failed", this); + return false; + } + return true; + } + + /// + /// Sets an alternate interface for the most recent claimed interface. + /// + /// The alternate interface to select for the most recent claimed interface See . + /// True on success. + public bool SetAltInterface(int alternateID) + { + int ret = MonoUsbApi.SetInterfaceAltSetting((MonoUsbDeviceHandle) mUsbHandle, mClaimedInteface, alternateID); + if (ret != 0) + { + UsbError.Error(ErrorCode.MonoApiError, ret, "SetAltInterface Failed", this); + return false; + } + return true; + } + + #endregion + + #region IDisposable implementation + + #endregion + + private static ErrorCode GetConfigs(MonoUsbDevice usbDevice, out List configInfoListRtn) + { + configInfoListRtn = new List(); + UsbError usbError = null; + List configList = new List(); + int iConfigs = usbDevice.Info.Descriptor.ConfigurationCount; + + for (int iConfig = 0; iConfig < iConfigs; iConfig++) + { + MonoUsbConfigHandle nextConfigHandle; + int ret = MonoUsbApi.GetConfigDescriptor(usbDevice.mMonoUSBProfile.ProfileHandle, (byte) iConfig, out nextConfigHandle); + Debug.Print("GetConfigDescriptor:{0}", ret); + if (ret != 0 || nextConfigHandle.IsInvalid) + { + usbError = UsbError.Error(ErrorCode.MonoApiError, + ret, + String.Format("GetConfigDescriptor Failed at index:{0}", iConfig), + usbDevice); + return usbError.ErrorCode; + } + try + { + MonoUsbConfigDescriptor nextConfig = new MonoUsbConfigDescriptor(); + Marshal.PtrToStructure(nextConfigHandle.DangerousGetHandle(), nextConfig); + + UsbConfigInfo nextConfigInfo = new UsbConfigInfo(usbDevice, nextConfig); + configInfoListRtn.Add(nextConfigInfo); + } + catch (Exception ex) + { + UsbError.Error(ErrorCode.InvalidConfig, Marshal.GetLastWin32Error(), ex.ToString(), usbDevice); + } + finally + { + if (!nextConfigHandle.IsInvalid) + nextConfigHandle.Close(); + } + } + + return ErrorCode.Success; + } + + internal static int RefreshProfileList() + { + lock (OLockDeviceList) + { + MonoUsbApi.InitAndStart(); + if (mMonoUSBProfileList == null) + { + mMonoUSBProfileList = new MonoUsbProfileList(); + } + return (int) mMonoUSBProfileList.Refresh(MonoUsbEventHandler.SessionHandle); + } + } + + /// + /// Initializes the with and starts the static handle events thread with . + /// + /// + /// This is done automatically when needed. + /// Usually there is no need to call this functions externally. + /// + public static void Init() { MonoUsbApi.InitAndStart(); } + } +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/MonoUsbDeviceHandle.cs b/LibWinUsb/MonoLibUsb/MonoUsbDeviceHandle.cs new file mode 100644 index 0000000..a9b977d --- /dev/null +++ b/LibWinUsb/MonoLibUsb/MonoUsbDeviceHandle.cs @@ -0,0 +1,136 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using LibUsbDotNet.Main; +using MonoLibUsb.Profile; + +namespace MonoLibUsb +{ + /// + /// Represents a Libusb-1.0 device handle. + /// + /// + /// To close a device, see the method. + /// A is roughly equivalent to a libusb_device_handle. + /// + /// + /// MonoUsbDeviceHandle deviceHandle = new MonoUsbDeviceHandle(profileHandle); + /// if (deviceHandle.IsInvalid) throw new Exception("Invalid device context."); + /// + public class MonoUsbDeviceHandle : SafeContextHandle + { + private static Object handleLOCK = new object(); + private static MonoUsbError mLastReturnCode; + private static String mLastReturnString = String.Empty; + + /// + /// If the device handle is , gets a descriptive string for the . + /// + public static string LastErrorString + { + get + { + lock (handleLOCK) + { + return mLastReturnString; + } + } + } + /// + /// If the device handle is , gets the status code indicating the reason. + /// + public static MonoUsbError LastErrorCode + { + get + { + lock (handleLOCK) + { + return mLastReturnCode; + } + } + } + /// Open a device handle from . + /// + /// A handle allows you to perform I/O on the device in question. + /// To close a device handle call its method. + /// This is a non-blocking function; no requests are sent over the bus. + /// The constructor is roughly equivalent to libusb_open(). + /// + /// A device profile handle. + public MonoUsbDeviceHandle(MonoUsbProfileHandle profileHandle) + : base(IntPtr.Zero) + { + IntPtr pDeviceHandle = IntPtr.Zero; + int ret = MonoUsbApi.Open(profileHandle, ref pDeviceHandle); + if (ret < 0 || pDeviceHandle==IntPtr.Zero) + { + lock (handleLOCK) + { + mLastReturnCode = (MonoUsbError) ret; + mLastReturnString = MonoUsbApi.StrError(mLastReturnCode); + } + SetHandleAsInvalid(); + } + else + { + SetHandle(pDeviceHandle); + } + + } + + internal MonoUsbDeviceHandle(IntPtr pDeviceHandle) + : base(pDeviceHandle) + { + } + /// + ///Closes the . + /// + /// + ///true if the is released successfully; otherwise, in the event of a catastrophic failure, false. In this case, it generates a ReleaseHandleFailed Managed Debugging Assistant. + /// + protected override bool ReleaseHandle() + { + if (!IsInvalid) + { + Debug.WriteLine(GetType().Name + ".ReleaseHandle() Before", "Libusb-1.0"); + MonoUsbApi.Close(handle); + Debug.WriteLine(GetType().Name + ".ReleaseHandle() After", "Libusb-1.0"); + SetHandleAsInvalid(); + } + return true; + } + + /// + /// Closes the reference. When all references are no longer is use, the device + /// is closed in the finalizer. + /// + /// + /// The method is roughly equivalent to libusb_close(). + /// + public new void Close() + { + base.Close(); + } + } +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/MonoUsbEndpointReader.cs b/LibWinUsb/MonoLibUsb/MonoUsbEndpointReader.cs new file mode 100644 index 0000000..079411d --- /dev/null +++ b/LibWinUsb/MonoLibUsb/MonoUsbEndpointReader.cs @@ -0,0 +1,81 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using LibUsbDotNet.Internal; +using LibUsbDotNet.Main; +using LibUsbDotNet.LudnMonoLibUsb.Internal; +using MonoLibUsb; + +namespace LibUsbDotNet.LudnMonoLibUsb +{ + /// + /// Implements mono-linux libusb 1.x methods for reading data from a or endpoints. + /// + public class MonoUsbEndpointReader : UsbEndpointReader + { + private MonoUsbTransferContext mMonoTransferContext; + + internal MonoUsbEndpointReader(UsbDevice usbDevice, int readBufferSize, ReadEndpointID readEndpointID, EndpointType endpointType) + : base(usbDevice, readBufferSize, readEndpointID, endpointType) { } + + /// + /// Frees resources associated with the endpoint. Once disposed this class cannot be used. + /// + public override void Dispose() + { + base.Dispose(); + if (ReferenceEquals(mMonoTransferContext, null)) return; + mMonoTransferContext.Dispose(); + mMonoTransferContext = null; + } + + /// + /// Calling this methods is that same as calling + /// + /// True an success. + public override bool Flush() + { + if (IsDisposed) throw new ObjectDisposedException(GetType().Name); + return ReadFlush() == ErrorCode.Success; + } + + /// + /// Cancels pending transfers and clears the halt condition on an enpoint. + /// + /// True on success. + public override bool Reset() + { + if (IsDisposed) throw new ObjectDisposedException(GetType().Name); + Abort(); + int ret = MonoUsbApi.ClearHalt((MonoUsbDeviceHandle) Device.Handle, EpNum); + if (ret < 0) + { + UsbError.Error(ErrorCode.MonoApiError, ret, "Endpoint Reset Failed", this); + return false; + } + return true; + } + + + internal override UsbTransfer CreateTransferContext() { return new MonoUsbTransferContext(this); } + } +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/MonoUsbEndpointWriter.cs b/LibWinUsb/MonoLibUsb/MonoUsbEndpointWriter.cs new file mode 100644 index 0000000..b9d9f2b --- /dev/null +++ b/LibWinUsb/MonoLibUsb/MonoUsbEndpointWriter.cs @@ -0,0 +1,76 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using LibUsbDotNet.Internal; +using LibUsbDotNet.Main; +using LibUsbDotNet.LudnMonoLibUsb.Internal; +using MonoLibUsb; + +namespace LibUsbDotNet.LudnMonoLibUsb +{ + /// + /// Implements mono-linux libusb 1.x methods for writing to methods for writing data to a or endpoints. + /// + public class MonoUsbEndpointWriter : UsbEndpointWriter + { + private MonoUsbTransferContext mMonoTransferContext; + + internal MonoUsbEndpointWriter(UsbDevice usbDevice, WriteEndpointID writeEndpointID,EndpointType endpointType) + : base(usbDevice, writeEndpointID, endpointType) { } + + /// + /// Frees resources associated with the endpoint. Once disposed this class cannot be used. + /// + public override void Dispose() + { + base.Dispose(); + if (ReferenceEquals(mMonoTransferContext, null)) return; + mMonoTransferContext.Dispose(); + mMonoTransferContext = null; + } + + /// + /// This method has no effect on write endpoints, andalways returs true. + /// + /// True + public override bool Flush() { return true; } + + /// + /// Cancels pending transfers and clears the halt condition on an enpoint. + /// + /// True on success. + public override bool Reset() + { + if (IsDisposed) throw new ObjectDisposedException(GetType().Name); + Abort(); + int ret = MonoUsbApi.ClearHalt((MonoUsbDeviceHandle) Device.Handle, EpNum); + if (ret < 0) + { + UsbError.Error(ErrorCode.MonoApiError, ret, "Endpoint Reset Failed", this); + return false; + } + return true; + } + + internal override UsbTransfer CreateTransferContext() { return new MonoUsbTransferContext(this); } + } +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/MonoUsbError.cs b/LibWinUsb/MonoLibUsb/MonoUsbError.cs new file mode 100644 index 0000000..3079f8f --- /dev/null +++ b/LibWinUsb/MonoLibUsb/MonoUsbError.cs @@ -0,0 +1,106 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// + +namespace MonoLibUsb +{ + /// + /// Error codes. + /// Most libusb functions return 0 on success or one of these codes on failure. + /// + public enum MonoUsbError + { + /// + /// Success (no error) + /// + Success = 0, + + /// + /// Input/output error + /// + ErrorIO = -1, + + /// + /// Invalid parameter + /// + ErrorInvalidParam = -2, + + /// + /// Access denied (insufficient permissions) + /// + ErrorAccess = -3, + + /// + /// No such device (it may have been disconnected) + /// + ErrorNoDevice = -4, + + /// + /// Entity not found + /// + ErrorNotFound = -5, + + /// + /// Resource busy + /// + ErrorBusy = -6, + + /// + /// Operation timed out + /// + ErrorTimeout = -7, + + /// + /// Overflow + /// + ErrorOverflow = -8, + + /// + /// Pipe error + /// + ErrorPipe = -9, + + /// + /// System call interrupted (perhaps due to signal) + /// + ErrorInterrupted = -10, + + /// + /// Insufficient memory + /// + ErrorNoMem = -11, + + /// + /// Operation not supported or unimplemented on this platform + /// + ErrorNotSupported = -12, + + /// + /// Cancel IO failed. + /// + ErrorIOCancelled = -13, + + /// + /// Other error + /// + ErrorOther = -99, + } ; +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/MonoUsbEventHandler.cs b/LibWinUsb/MonoLibUsb/MonoUsbEventHandler.cs new file mode 100644 index 0000000..3b5a272 --- /dev/null +++ b/LibWinUsb/MonoLibUsb/MonoUsbEventHandler.cs @@ -0,0 +1,192 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Threading; +using LibUsbDotNet.Main; + +namespace MonoLibUsb +{ + /// + /// Manages a static Libusb-1.0 and "handle_events" thread for simplified asynchronous IO. + /// + /// + /// This class contains its own that is initialized with one of the overloaded MonoUsbEventHandler.Init() functions. + /// This class contains a static thread that execute . See the and methods. + /// + public static class MonoUsbEventHandler + { + private static readonly ManualResetEvent mIsStoppedEvent = new ManualResetEvent(true); + private static bool mRunning; + private static MonoUsbSessionHandle mSessionHandle; + internal static Thread mUsbEventThread; + private static ThreadPriority mPriority = ThreadPriority.Normal; + + private static UnixNativeTimeval mWaitUnixNativeTimeval; + + /// + /// Gets the session handle. + /// + /// + /// Used for MonoLibUsb members that require the parameter. + /// + public static MonoUsbSessionHandle SessionHandle + { + get { return mSessionHandle; } + } + + /// + /// False if the handle events thread is running. + /// + public static bool IsStopped + { + get { return mIsStoppedEvent.WaitOne(0, false); } + } + + /// + /// Thread proirity to use for the handle events thread. + /// + public static ThreadPriority Priority + { + get { return mPriority; } + set {mPriority=value;} + } + + /// + /// Stops the handle events thread and closes the session handle. + /// + public static void Exit() + { + Stop(true); + if (mSessionHandle == null) return; + + if (mSessionHandle.IsInvalid) return; + mSessionHandle.Close(); + mSessionHandle = null; + } + + private static void HandleEventFn(object oHandle) + { + MonoUsbSessionHandle sessionHandle = oHandle as MonoUsbSessionHandle; + + mIsStoppedEvent.Reset(); + + while (mRunning) + MonoUsbApi.HandleEventsTimeout(sessionHandle, ref mWaitUnixNativeTimeval); + + mIsStoppedEvent.Set(); + } + + + /// + /// Initializes the and sets a custom polling interval. + /// + /// polling interval seconds + /// polling interval milliseconds + /// + /// + public static void Init(long tvSec, long tvUsec) { Init(new UnixNativeTimeval(tvSec, tvUsec)); } + + /// + /// Initializes the . + /// + /// + /// If the session has already been initialized, this method does nothing. + /// The handle events thread is not started until the method is called. + /// Uses the MonoLibUsb polling interval for . + /// + public static void Init() { Init(UnixNativeTimeval.Default); } + + private static void Init(UnixNativeTimeval unixNativeTimeval) + { + if (IsStopped && !mRunning && mSessionHandle==null) + { + mWaitUnixNativeTimeval = unixNativeTimeval; + mSessionHandle=new MonoUsbSessionHandle(); + if (mSessionHandle.IsInvalid) + { + mSessionHandle = null; + throw new UsbException(typeof (MonoUsbApi), String.Format("Init:libusb_init Failed:Invalid Session Handle")); + } + } + } + + /// + /// Starts the handle events thread. + /// + /// + /// If the thread is already running, this method does nothing. + /// + /// Using a seperate thread which executes can simplify asynchronous I/O + /// and improve performance in multi-threaded applications which use multiple endpoints. + /// + /// + /// + /// True if the thread is started or is already running. + /// + public static bool Start() + { + if (IsStopped && !mRunning && mSessionHandle!=null) + { + mRunning = true; + mUsbEventThread = new Thread(HandleEventFn); + mUsbEventThread.Priority = mPriority; + mUsbEventThread.Start(mSessionHandle); + + } + return true; + } + + /// + /// Stops the handle events thread. + /// + /// + /// Calling this method when the thread is not running will have no affect. + /// + /// If the thread is running, this method must be called before the application exits. + /// Failure to do so will cause the application to hang. + /// + /// + /// If true, wait for the thread to exit before returning. + public static void Stop(bool bWait) + { + if (!IsStopped && mRunning) + { + mRunning = false; + + if (bWait) + { + bool bSuccess = mUsbEventThread.Join((int)((mWaitUnixNativeTimeval.tv_sec * 1000 + mWaitUnixNativeTimeval.tv_usec) * 1.2)); + //bool bSuccess = mIsStoppedEvent.WaitOne((int)((mWaitUnixNativeTimeval.tv_sec * 1000 + mWaitUnixNativeTimeval.tv_usec) * 1.2), false); + if (!bSuccess) + { + mUsbEventThread.Abort(); + throw new UsbException(typeof(MonoUsbEventHandler), "Critical timeout failure! MonoUsbApi.HandleEventsTimeout did not return within the allotted time."); + //LibUsbDotNet.UsbError.Error(ErrorCode.UnknownError, 0, "Critical timeout failure!", typeof(MonoUsbEventHandler)); + //mIsStoppedEvent.Set(); + } + } + mUsbEventThread = null; + + } + } + } +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/MonoUsbSessionHandle.cs b/LibWinUsb/MonoLibUsb/MonoUsbSessionHandle.cs new file mode 100644 index 0000000..ef1e0cd --- /dev/null +++ b/LibWinUsb/MonoLibUsb/MonoUsbSessionHandle.cs @@ -0,0 +1,116 @@ +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using LibUsbDotNet.Main; + +namespace MonoLibUsb +{ + /// + /// Class representing a Libusb-1.0 session session handle. + /// Session handled are wrapped in a . + /// + /// + /// The concept of individual Libusb-1.0 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 will not affect the other + /// user of the library, and will not destroy resources that the + /// other user is still using. + /// Sessions are created when a new instance is created and destroyed through . + /// A instance must be created before calling any other Libusb-1.0 API function. + /// Session handles are equivalent to a libusb_context. + /// + public class MonoUsbSessionHandle:SafeContextHandle + { + private static Object sessionLOCK = new object(); + private static MonoUsbError mLastReturnCode; + private static String mLastReturnString=String.Empty; + private static int mSessionCount; + private static string DLL_NOT_FOUND_LINUX = "libusb-1.0 library not found. This is often an indication that libusb-1.0 was installed to '/usr/local/lib' and mono.net is not looking for it there. To resolve this, add the path '/usr/local/lib' to '/etc/ld.so.conf' and run 'ldconfig' as root. (http://www.mono-project.com/DllNotFoundException)"; + private static string DLL_NOT_FOUND_WINDOWS = "libusb-1.0.dll not found. If this is a 64bit operating system, ensure that the 64bit version of libusb-1.0.dll exists in the '\\Windows\\System32' directory."; + + /// + /// If the session handle is , gets the status code indicating the reason. + /// + public static MonoUsbError LastErrorCode + { + get + { + lock (sessionLOCK) + { + return mLastReturnCode; + } + } + } + /// + /// If the session handle is , gets a descriptive string for the . + /// + public static string LastErrorString + { + get + { + lock (sessionLOCK) + { + return mLastReturnString; + } + } + } + + /// + /// Creates and initialize a Libusb-1.0 USB session handle. + /// + /// + /// A instance must be created before calling any other Libusb-1.0 API function. + /// + public MonoUsbSessionHandle() : base(IntPtr.Zero, true) + { + lock (sessionLOCK) + { + IntPtr pNewSession = IntPtr.Zero; + try + { + mLastReturnCode = (MonoUsbError)MonoUsbApi.Init(ref pNewSession); + } + catch (DllNotFoundException dllNotFound) + { + if (Helper.IsLinux) + { + throw new DllNotFoundException(DLL_NOT_FOUND_LINUX, dllNotFound); + } + else + { + throw new DllNotFoundException(DLL_NOT_FOUND_WINDOWS, dllNotFound); + } + } + if ((int)mLastReturnCode < 0) + { + mLastReturnString = MonoUsbApi.StrError(mLastReturnCode); + SetHandleAsInvalid(); + } + else + { + SetHandle(pNewSession); + mSessionCount++; + } + } + } + /// + /// + /// + /// + protected override bool ReleaseHandle() + { + if (!IsInvalid) + { + lock (sessionLOCK) + { + MonoUsbApi.Exit(handle); + SetHandleAsInvalid(); + mSessionCount--; + Debug.Print(GetType().Name + " : ReleaseHandle #{0}", mSessionCount); + + } + } + return true; + } + } +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/Profile/AddRemoveEventArgs.cs b/LibWinUsb/MonoLibUsb/Profile/AddRemoveEventArgs.cs new file mode 100644 index 0000000..3f6f2d0 --- /dev/null +++ b/LibWinUsb/MonoLibUsb/Profile/AddRemoveEventArgs.cs @@ -0,0 +1,34 @@ +using System; + +namespace MonoLibUsb.Profile +{ + /// + /// Describes a device arrival/removal notification event + /// + public class AddRemoveEventArgs : EventArgs + { + private readonly AddRemoveType mAddRemoveType; + private readonly MonoUsbProfile mMonoUSBProfile; + + internal AddRemoveEventArgs(MonoUsbProfile monoUSBProfile, AddRemoveType addRemoveType) + { + mMonoUSBProfile = monoUSBProfile; + mAddRemoveType = addRemoveType; + } + /// + /// The that was added or removed. + /// + public MonoUsbProfile MonoUSBProfile + { + get { return mMonoUSBProfile; } + } + + /// + /// The type of event that occured. + /// + public AddRemoveType EventType + { + get { return mAddRemoveType; } + } + } +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/Profile/AddRemoveType.cs b/LibWinUsb/MonoLibUsb/Profile/AddRemoveType.cs new file mode 100644 index 0000000..b9bbbbf --- /dev/null +++ b/LibWinUsb/MonoLibUsb/Profile/AddRemoveType.cs @@ -0,0 +1,38 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +namespace MonoLibUsb.Profile +{ + /// + /// Event type. + /// + public enum AddRemoveType + { + /// + /// A usb device was attached. + /// + Added, + /// + /// A usb device was detached. + /// + Removed + } +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/Profile/MonoUsbConfigHandle.cs b/LibWinUsb/MonoLibUsb/Profile/MonoUsbConfigHandle.cs new file mode 100644 index 0000000..4c4ea93 --- /dev/null +++ b/LibWinUsb/MonoLibUsb/Profile/MonoUsbConfigHandle.cs @@ -0,0 +1,41 @@ +using System; +using System.Runtime.InteropServices; +using LibUsbDotNet.Main; +using MonoLibUsb.Descriptors; + +namespace MonoLibUsb.Profile +{ + /// + /// The class hold the internal pointer to a libusb . + /// + /// + /// + /// To acquire a use: + /// + /// + /// + /// + /// + /// + /// To access configuration information see . + /// + /// + public class MonoUsbConfigHandle:SafeContextHandle + { + private MonoUsbConfigHandle() : base(IntPtr.Zero,true) {} + + /// + /// + /// + /// + protected override bool ReleaseHandle() + { + if (!IsInvalid) + { + MonoUsbApi.FreeConfigDescriptor(handle); + SetHandleAsInvalid(); + } + return true; + } + } +} diff --git a/LibWinUsb/MonoLibUsb/Profile/MonoUsbProfile.cs b/LibWinUsb/MonoLibUsb/Profile/MonoUsbProfile.cs new file mode 100644 index 0000000..d82b58e --- /dev/null +++ b/LibWinUsb/MonoLibUsb/Profile/MonoUsbProfile.cs @@ -0,0 +1,186 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// + +using LibUsbDotNet; +using LibUsbDotNet.Main; +using MonoLibUsb.Descriptors; + +namespace MonoLibUsb.Profile +{ + /// + /// Representing a USB device that can be opened and used by Libusb-1.0. + /// + public class MonoUsbProfile + { + private readonly byte mBusNumber; + private readonly byte mDeviceAddress; + private readonly MonoUsbDeviceDescriptor mMonoUsbDeviceDescriptor = new MonoUsbDeviceDescriptor(); + private readonly MonoUsbProfileHandle mMonoUSBProfileHandle; + internal bool mDiscovered; + + internal MonoUsbProfile(MonoUsbProfileHandle monoUSBProfileHandle) + { + mMonoUSBProfileHandle = monoUSBProfileHandle; + mBusNumber = MonoUsbApi.GetBusNumber(mMonoUSBProfileHandle); + mDeviceAddress = MonoUsbApi.GetDeviceAddress(mMonoUSBProfileHandle); + GetDeviceDescriptor(out mMonoUsbDeviceDescriptor); + +//#if DEBUG +// Console.WriteLine("Vid:{0:X4} Pid:{1:X4} BusNumber:{2} DeviceAddress:{3}", +// mMonoUsbDeviceDescriptor.VendorID, +// mMonoUsbDeviceDescriptor.ProductID, +// mBusNumber, +// mDeviceAddress); +//#endif + } + + /// + /// Gets the standard usb device descriptor. + /// + public MonoUsbDeviceDescriptor DeviceDescriptor + { + get { return mMonoUsbDeviceDescriptor; } + } + + /// + /// Gets the bus number the is resides on. + /// + public byte BusNumber + { + get { return mBusNumber; } + } + + /// + /// Gets the device address that belongs to the usb device this profile represents. + /// + public byte DeviceAddress + { + get { return mDeviceAddress; } + } + + /// + /// Gets the internal profile handle need for some api calls. + /// + public MonoUsbProfileHandle ProfileHandle + { + get { return mMonoUSBProfileHandle; } + } + + /// + /// Determines whether the specified is equal to the current . + /// + /// + /// true if the specified is equal to the current ; otherwise, false. + /// + /// The to compare with the current . The parameter is null.2 + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != typeof (MonoUsbProfile)) return false; + return Equals((MonoUsbProfile) obj); + } + + /// + /// Serves as a hash function for a particular type. + /// + /// + /// A hash code for the current . + /// + /// 2 + public override int GetHashCode() + { + unchecked + { + return (mBusNumber.GetHashCode()*397) ^ mDeviceAddress.GetHashCode(); + } + } + + /// + /// true if the types are equal. + /// + /// + /// types are considered equal they have the same and . + /// + /// on the left. + /// on the right. + ///True if the types are equal. + public static bool operator ==(MonoUsbProfile left, MonoUsbProfile right) { return Equals(left, right); } + + /// + /// true if the types are not equal. + /// + /// + /// types are considered equal they have the same and . + /// + /// on the left. + /// on the right. + ///True if the types are not equal. + public static bool operator !=(MonoUsbProfile left, MonoUsbProfile right) { return !Equals(left, right); } + + private MonoUsbError GetDeviceDescriptor(out MonoUsbDeviceDescriptor monoUsbDeviceDescriptor) + { + MonoUsbError ec = MonoUsbError.Success; + + monoUsbDeviceDescriptor = new MonoUsbDeviceDescriptor(); + //Console.WriteLine("MonoUsbProfile:GetDeviceDescriptor"); + ec = (MonoUsbError) MonoUsbApi.GetDeviceDescriptor(mMonoUSBProfileHandle, monoUsbDeviceDescriptor); + if (ec != MonoUsbError.Success) + { +#if LIBUSBDOTNET + UsbError.Error(ErrorCode.MonoApiError, (int) ec, "GetDeviceDescriptor Failed", this); +#endif + monoUsbDeviceDescriptor = null; + } + return ec; + } + + /// + /// Closes the internal . + /// + public void Close() + { + if (!mMonoUSBProfileHandle.IsClosed) + mMonoUSBProfileHandle.Close(); + } + + /// + /// Convenience function to open the device handle this profile handle represents. + /// + /// + /// A new instance. Created with constructor. + /// + public MonoUsbDeviceHandle OpenDeviceHandle() { return new MonoUsbDeviceHandle(ProfileHandle); } + + /// + /// Compares a with this one. + /// + /// The other . + /// True if the and are equal. + public bool Equals(MonoUsbProfile other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return other.mBusNumber == mBusNumber && other.mDeviceAddress == mDeviceAddress; + } + } +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/Profile/MonoUsbProfileHandle.cs b/LibWinUsb/MonoLibUsb/Profile/MonoUsbProfileHandle.cs new file mode 100644 index 0000000..3d93900 --- /dev/null +++ b/LibWinUsb/MonoLibUsb/Profile/MonoUsbProfileHandle.cs @@ -0,0 +1,110 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using LibUsbDotNet.Main; + +namespace MonoLibUsb.Profile +{ + /// + /// Wraps a profile handle into a . + /// Profile handles are used for getting device descriptor information and opening the device. Profile handles + /// are known connected and usually supported usb device that can be opened and used. + /// + /// + /// + /// When a instance is created and wrapped around the + /// libusb_device + /// pointer, is called. When all references to this + /// instance are out-of-scope or have all been closed, this profile handle is de-referenced with + /// . + /// When the reference count equals zero, memory is freed and resources are released. + /// + /// + /// The class ensures all device profiles get closed and freed + /// regardless of abnormal program terminations or coding errors. + /// + /// + /// Certain operations can be performed using just the , but in order to do + /// any I/O you will have to first obtain a using . + /// + /// + public class MonoUsbProfileHandle : SafeContextHandle + { + + + /// + /// Wraps a raw usb device profile handle pointer in a class. + /// + /// the profile handle to wrap. + public MonoUsbProfileHandle(IntPtr pProfileHandle) : base(pProfileHandle,true) + { + lock (oDeviceProfileRefLock) + { + MonoUsbApi.RefDevice(pProfileHandle); + mDeviceProfileRefCount++; + } + } + + #region Overridden Members + + /// + /// When overridden in a derived class, executes the code required to free the handle. + /// + /// + /// true if the handle is released successfully; otherwise, in the event of a catastrophic failure, false. In this case, it generates a ReleaseHandleFailed Managed Debugging Assistant. + /// + protected override bool ReleaseHandle() + { + lock (oDeviceProfileRefLock) + { + if (!IsInvalid) + { + MonoUsbApi.UnrefDevice(handle); + mDeviceProfileRefCount--; + SetHandleAsInvalid(); + Debug.Print(GetType().Name + " : ReleaseHandle #{0}", mDeviceProfileRefCount); + } + return true; + } + } + + #endregion + + #region STATIC Members + + internal static int DeviceProfileRefCount + { + get + { + lock (oDeviceProfileRefLock) + return mDeviceProfileRefCount; + } + } + + private static int mDeviceProfileRefCount; + private static readonly object oDeviceProfileRefLock = new object(); + + #endregion + } +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/Profile/MonoUsbProfileHandleEnumerator.cs b/LibWinUsb/MonoLibUsb/Profile/MonoUsbProfileHandleEnumerator.cs new file mode 100644 index 0000000..6c65417 --- /dev/null +++ b/LibWinUsb/MonoLibUsb/Profile/MonoUsbProfileHandleEnumerator.cs @@ -0,0 +1,111 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace MonoLibUsb.Profile +{ + /// + /// A forward-only enumerator for iterating a device lists. + /// + internal class MonoUsbProfileHandleEnumerator : IEnumerator + { + private readonly MonoUsbProfileListHandle mProfileListHandle; + private MonoUsbProfileHandle mCurrentProfile; + private int mNextDeviceProfilePos; + + + internal MonoUsbProfileHandleEnumerator(MonoUsbProfileListHandle profileListHandle) + { + mProfileListHandle = profileListHandle; + Reset(); + } + + #region IEnumerator Members + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + /// 2 + public void Dispose() { Reset(); } + + + /// + /// Advances the enumerator to the next element of the collection. + /// + /// + /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection. + /// + /// The collection was modified after the enumerator was created. 2 + public bool MoveNext() + { + IntPtr pNextProfileHandle = + Marshal.ReadIntPtr(new IntPtr(mProfileListHandle.DangerousGetHandle().ToInt64() + (mNextDeviceProfilePos*IntPtr.Size))); + if (pNextProfileHandle != IntPtr.Zero) + { + mCurrentProfile = new MonoUsbProfileHandle(pNextProfileHandle); + mNextDeviceProfilePos++; + return true; + } + mCurrentProfile = null; + return false; + } + + + /// + /// Sets the enumerator to its initial position, which is before the first element in the collection. + /// + /// The collection was modified after the enumerator was created. 2 + public void Reset() + { + mNextDeviceProfilePos = 0; + mCurrentProfile = null; + } + + /// + /// Gets the element in the collection at the current position of the enumerator. + /// + /// + /// The current element. + /// + public MonoUsbProfileHandle Current + { + get { return mCurrentProfile; } + } + + /// + /// Gets the current element in the collection. + /// + /// + /// The current element. + /// + /// The enumerator is positioned before the first element of the collection or after the last element.-or- The collection was modified after the enumerator was created.2 + object IEnumerator.Current + { + get { return Current; } + } + + #endregion + } +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/Profile/MonoUsbProfileList.cs b/LibWinUsb/MonoLibUsb/Profile/MonoUsbProfileList.cs new file mode 100644 index 0000000..05d4fc7 --- /dev/null +++ b/LibWinUsb/MonoLibUsb/Profile/MonoUsbProfileList.cs @@ -0,0 +1,259 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using LibUsbDotNet; +using LibUsbDotNet.Main; + +namespace MonoLibUsb.Profile +{ + /// + /// Manages the device list. This class is thread safe. + /// + public class MonoUsbProfileList : IEnumerable + { + private object LockProfileList = new object(); + + private static bool FindDiscoveredFn(MonoUsbProfile check) { return check.mDiscovered; } + private static bool FindUnDiscoveredFn(MonoUsbProfile check) { return !check.mDiscovered; } + + private List mList=new List(); + private void FireAddRemove(MonoUsbProfile monoUSBProfile, AddRemoveType addRemoveType) + { + EventHandler temp = AddRemoveEvent; + if (!ReferenceEquals(temp, null)) + { + temp(this, new AddRemoveEventArgs(monoUSBProfile, addRemoveType)); + } + } + + private void SetDiscovered(bool discovered) + { + foreach (MonoUsbProfile deviceProfile in this) + { + deviceProfile.mDiscovered = discovered; + } + } + + private void syncWith(MonoUsbProfileList newList) + { + SetDiscovered(false); + newList.SetDiscovered(true); + + int iNewProfiles = newList.mList.Count; + for (int iNewProfile = 0; iNewProfile < iNewProfiles; iNewProfile++) + { + MonoUsbProfile newProfile = newList.mList[iNewProfile]; + int iFoundOldIndex; + if ((iFoundOldIndex = mList.IndexOf(newProfile)) == -1) + { + //Console.WriteLine("DeviceDiscovery: Added: {0}", newProfile.ProfileHandle.DangerousGetHandle()); + newProfile.mDiscovered = true; + mList.Add(newProfile); + FireAddRemove(newProfile, AddRemoveType.Added); + } + else + { + //Console.WriteLine("DeviceDiscovery: Unchanged: Orig:{0} New:{1}", mList[iFoundOldIndex].ProfileHandle.DangerousGetHandle(), newProfile.ProfileHandle.DangerousGetHandle()); + mList[iFoundOldIndex].mDiscovered = true; + newProfile.mDiscovered = false; + + } + } + + newList.mList.RemoveAll(FindDiscoveredFn); + newList.Close(); + + foreach (MonoUsbProfile deviceProfile in mList) + { + if (!deviceProfile.mDiscovered) + { + // Close Unplugged device profiles. + //Console.WriteLine("DeviceDiscovery: Removed: {0}", deviceProfile.ProfileHandle.DangerousGetHandle()); + FireAddRemove(deviceProfile, AddRemoveType.Removed); + deviceProfile.Close(); + } + } + + // Remove Unplugged device profiles. + mList.RemoveAll(FindUnDiscoveredFn); + } + + + /// + /// Refreshes the list. + /// + /// + /// This is your entry point into finding a USB device to operate. + /// This return value of this function indicates the number of devices in the resultant list. + /// The has a crude form of built-in device notification that works on all platforms. By adding an event handler to the changes in the device profile list are reported when is called. + /// + /// A valid . + /// The number of devices in the outputted list, or on memory allocation failure. + /// + /// + /// + public int Refresh(MonoUsbSessionHandle sessionHandle) + { + lock (LockProfileList) + { + MonoUsbProfileList newList = new MonoUsbProfileList(); + MonoUsbProfileListHandle monoUSBProfileListHandle; + + int ret = MonoUsbApi.GetDeviceList(sessionHandle, out monoUSBProfileListHandle); + if (ret < 0 || monoUSBProfileListHandle.IsInvalid) + { +#if LIBUSBDOTNET + UsbError.Error(ErrorCode.MonoApiError, ret, "Refresh:GetDeviceList Failed", this); +#else + System.Diagnostics.Debug.Print("libusb_get_device_list failed:{0} {1}", + (MonoUsbError) ret, + MonoUsbApi.StrError((MonoUsbError) ret)); +#endif + return ret; + } + int stopCount = ret; + foreach (MonoUsbProfileHandle deviceProfileHandle in monoUSBProfileListHandle) + { + newList.mList.Add(new MonoUsbProfile(deviceProfileHandle)); + stopCount--; + if (stopCount <= 0) break; + } + syncWith(newList); + monoUSBProfileListHandle.Close(); + + return ret; + } + } + + /// + /// Frees all unreferenced profiles contained in the list. + /// + /// + /// + /// s that are in-use are never closed until all reference(s) have gone + /// out-of-scope or specifically been closed with the method. + /// + /// + public void Close() + { + lock (LockProfileList) + { + foreach (MonoUsbProfile profile in mList) + profile.Close(); + + mList.Clear(); + } + } + + /// + /// Usb device arrival/removal notification handler. + /// This event only reports when the method is called. + /// + /// + /// could be used for a crude form for receiving usb + /// device arrival/removal notification. + /// + /// + /// + /// // Startup code + /// MonoUsbProfileList profileList = new MonoUsbProfileList(); + /// profileList.AddRemoveEvent += OnDeviceAddRemove; + /// + /// // Device AddRemove event template + /// private void OnDeviceAddRemove(object sender, AddRemoveEventArgs addRemoveArgs) + /// { + /// // This method will only report when Refresh() is called. + /// } + /// + /// // Refresh profile list. + /// // Any devices added or removed since the last call to Refresh() will be returned + /// // in the OnDeviceAddRemove method. + /// profileList.Refresh(); + /// + /// + public event EventHandler AddRemoveEvent; + + /// + /// Returns an enumerator that iterates through the collection. + /// + /// + /// A that can be used to iterate through the collection. + /// + /// 1 + public IEnumerator GetEnumerator() + { + lock(LockProfileList) + return mList.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + + /// + /// Returns the number of instances in the list. + /// + public int Count + { + get + { + lock (LockProfileList) + return mList.Count; + } + } + /// + /// Gets a of instances. + /// + /// + /// + /// The uses an internal list that is locked when changes must be made. + /// The method returns a copy of this list that can be searched and modified as needed by the user. + /// + /// + /// The returned generic contains many more functions for finding devices. + /// It may be desirable to use these members, such as or to find a instead of iterating through the one-by-one. + /// + /// + /// A of instances. + public List GetList() + { + lock (LockProfileList) + return new List(mList); + } + + /// + /// Gets the at the specfied index. + /// + /// The index of the to retrieve. + /// The instance at the specified . + /// If index is invalid. + public MonoUsbProfile this[int index] + { + get + { + lock (LockProfileList) + return mList[index]; + } + } + } +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/Profile/MonoUsbProfileListHandle.cs b/LibWinUsb/MonoLibUsb/Profile/MonoUsbProfileListHandle.cs new file mode 100644 index 0000000..e1c56c7 --- /dev/null +++ b/LibWinUsb/MonoLibUsb/Profile/MonoUsbProfileListHandle.cs @@ -0,0 +1,74 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Collections; +using System.Collections.Generic; +using LibUsbDotNet.Main; + +namespace MonoLibUsb.Profile +{ + /// + /// Used to iterate through the collection contained in the . + /// + /// + /// Wraps a device list handle into a + /// + /// + public class MonoUsbProfileListHandle : SafeContextHandle, IEnumerable + { + private MonoUsbProfileListHandle() + : base(IntPtr.Zero) { } + + internal MonoUsbProfileListHandle(IntPtr pHandleToOwn) + : base(pHandleToOwn) { } + + #region IEnumerable Members + + /// + /// Gets a forward-only device list enumerator. + /// + /// A profile handle enumerator used iterating through the classes. + public IEnumerator GetEnumerator() { return new MonoUsbProfileHandleEnumerator(this); } + + IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + + #endregion + + /// + /// When overridden in a derived class, executes the code required to free the handle. + /// + /// + /// true if the handle is released successfully; otherwise, in the event of a catastrophic failure, false. In this case, it generates a ReleaseHandleFailed Managed Debugging Assistant. + /// + protected override bool ReleaseHandle() + { + if (!IsInvalid) + { + MonoUsbApi.FreeDeviceList(handle, 1); + //Console.WriteLine("FreeDeviceList:{0}", handle); + SetHandleAsInvalid(); + } + + return true; + } + } +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/Profile/PollfdItem.cs b/LibWinUsb/MonoLibUsb/Profile/PollfdItem.cs new file mode 100644 index 0000000..901c29d --- /dev/null +++ b/LibWinUsb/MonoLibUsb/Profile/PollfdItem.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; + +namespace MonoLibUsb.Profile +{ + /// + /// File descriptor for polling. More.. + /// + [StructLayout(LayoutKind.Sequential)] + public class PollfdItem + { + internal PollfdItem(IntPtr pPollfd) + { + Marshal.PtrToStructure(pPollfd, this); + } + /// + /// Numeric file descriptor. + /// + public readonly int fd; + + /// + /// Event flags to poll for from poll.h. + /// + public readonly short events; + } +} diff --git a/LibWinUsb/MonoLibUsb/Transfer/Internal/libusb_control_setup.cs b/LibWinUsb/MonoLibUsb/Transfer/Internal/libusb_control_setup.cs new file mode 100644 index 0000000..1066eb3 --- /dev/null +++ b/LibWinUsb/MonoLibUsb/Transfer/Internal/libusb_control_setup.cs @@ -0,0 +1,35 @@ +using System.Runtime.InteropServices; +using LibUsbDotNet.Main; + +namespace MonoLibUsb.Transfer.Internal +{ + [StructLayout(LayoutKind.Sequential)] + internal class 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. + */ + public readonly 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. */ + public readonly byte bRequest; + + /** Value. Varies according to request */ + public readonly short wValue; + + /** Index. Varies according to request, typically used to pass an index + * or offset */ + public readonly short wIndex; + + /** Number of bytes to transfer */ + public readonly short wLength; + + } +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/Transfer/Internal/libusb_iso_packet_descriptor.cs b/LibWinUsb/MonoLibUsb/Transfer/Internal/libusb_iso_packet_descriptor.cs new file mode 100644 index 0000000..58a1255 --- /dev/null +++ b/LibWinUsb/MonoLibUsb/Transfer/Internal/libusb_iso_packet_descriptor.cs @@ -0,0 +1,29 @@ +using System.Runtime.InteropServices; + +namespace MonoLibUsb.Transfer.Internal +{ + /// + /// This class is never instantiated in .NET. Instead it is used as a template by the class. + /// + [StructLayout(LayoutKind.Sequential, Pack = MonoUsbApi.LIBUSB_PACK)] + internal class libusb_iso_packet_descriptor + { + /// + /// Length of data to request in this packet + /// + uint length; + + /// + /// Amount of data that was actually transferred + /// + uint actual_length; + + /// + /// Status code for this packet + /// + MonoUsbTansferStatus status; + + private libusb_iso_packet_descriptor() { } + + } +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/Transfer/Internal/libusb_transfer.cs b/LibWinUsb/MonoLibUsb/Transfer/Internal/libusb_transfer.cs new file mode 100644 index 0000000..49ddeeb --- /dev/null +++ b/LibWinUsb/MonoLibUsb/Transfer/Internal/libusb_transfer.cs @@ -0,0 +1,52 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; + +using LibUsbDotNet.Main; + +namespace MonoLibUsb.Transfer.Internal +{ + /// + /// This class is never instantiated in .NET. Instead it is used as a template by the class. + /// + [StructLayout(LayoutKind.Sequential, Pack = MonoUsbApi.LIBUSB_PACK)] + internal class libusb_transfer + { + IntPtr deviceHandle; + MonoUsbTransferFlags flags; + byte endpoint; + EndpointType type; + uint timeout; + MonoUsbTansferStatus status; + int length; + int actual_length; + IntPtr pCallbackFn; + IntPtr pUserData; + IntPtr pBuffer; + int num_iso_packets; + IntPtr iso_packets; + + private libusb_transfer() { } + + } ; +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/Transfer/MonoUsbControlSetup.cs b/LibWinUsb/MonoLibUsb/Transfer/MonoUsbControlSetup.cs new file mode 100644 index 0000000..d5c5438 --- /dev/null +++ b/LibWinUsb/MonoLibUsb/Transfer/MonoUsbControlSetup.cs @@ -0,0 +1,145 @@ +using System; +using System.Runtime.InteropServices; +using LibUsbDotNet.Main; +using MonoLibUsb.Transfer.Internal; + +namespace MonoLibUsb.Transfer +{ + /// + /// Reads/writes a Libusb-1.0 control setup packet pointer. Control setup packets should be allocated with . + /// + /// + /// This class that reads and writes values directly from/to the setup packet using . + /// This type is used for asynchronous control transfers only. + /// + /// + [StructLayout(LayoutKind.Sequential)] + public class MonoUsbControlSetup + { + /// + /// Size of a Libusb-1.0 setup packet. + /// + public static int SETUP_PACKET_SIZE = Marshal.SizeOf(typeof(libusb_control_setup)); + + private static readonly int OfsRequestType = Marshal.OffsetOf(typeof(libusb_control_setup), "bmRequestType").ToInt32(); + private static readonly int OfsRequest = Marshal.OffsetOf(typeof(libusb_control_setup), "bRequest").ToInt32(); + private static readonly int OfsValue = Marshal.OffsetOf(typeof(libusb_control_setup), "wValue").ToInt32(); + private static readonly int OfsIndex = Marshal.OffsetOf(typeof(libusb_control_setup), "wIndex").ToInt32(); + private static readonly int OfsLength = Marshal.OffsetOf(typeof(libusb_control_setup), "wLength").ToInt32(); + private static readonly int OfsPtrData = SETUP_PACKET_SIZE; + + + private IntPtr handle; + + /// + /// Creates a structure for a control setup packet pointer. + /// + /// + /// The pointer must be a pointer in memory to a valid Libusb-1.0 libusb__control__setup that was allocated with . + /// + /// Pointer to the setup packet. This will usually be MonoUsbTransfer.PtrBuffer + public MonoUsbControlSetup(IntPtr pControlSetup) + { + handle = pControlSetup; + } + + /// + /// The request type. + /// + public byte RequestType + { + get { return Marshal.ReadByte(handle, OfsRequestType); } + set { Marshal.WriteByte(handle, OfsRequestType, value); } + } + + /// + /// The request. + /// + public byte Request + { + get { return Marshal.ReadByte(handle, OfsRequest); } + set { Marshal.WriteByte(handle, OfsRequest, value); } + } + /// + /// The wValue. + /// + /// + /// The get/set accessors automatically manage the little-endian to host-endian/host-endian to little-endian conversions using the method. + /// + public short Value + { + get { return Helper.HostEndianToLE16(Marshal.ReadInt16(handle, OfsValue)); } + set { Marshal.WriteInt16(handle, OfsValue, Helper.HostEndianToLE16(value)); } + + } + /// + /// The wIndex. + /// + /// + /// The get/set accessors automatically manage the little-endian to host-endian/host-endian to little-endian conversions using the method. + /// + public short Index + { + get { return Helper.HostEndianToLE16(Marshal.ReadInt16(handle, OfsIndex)); } + set { Marshal.WriteInt16(handle, OfsIndex, Helper.HostEndianToLE16(value)); } + } + /// + /// Number of bytes to transfer. + /// + /// + /// The get/set accessors automatically manage the little-endian to host-endian/host-endian to little-endian conversions using the method. + /// + public short Length + { + get { return Helper.HostEndianToLE16(Marshal.ReadInt16(handle, OfsLength)); } + set { Marshal.WriteInt16(handle, OfsLength, Helper.HostEndianToLE16(value)); } + } + + /// + /// Gets a pointer to the control data buffer. + /// + /// This is the to the control data inside of the setup packet, not to the setup packet itself. + public IntPtr PtrData + { + get + { + return new IntPtr(handle.ToInt64() + OfsPtrData); + } + } + /// + /// Copies data into . + /// + /// + /// Data buffer to copy into for an output control transfer. + /// This value can be: + /// + /// An of bytes or other blittable types. + /// An already allocated, pinned . In this case is used for the buffer address. + /// An . + /// + /// + /// The offset in to begin copying. + /// Number of to copy. + public void SetData(object data, int offset, int length) + { + PinnedHandle p = new PinnedHandle(data); + Byte[] temp = new byte[length]; + Marshal.Copy(p.Handle, temp, offset, length); + p.Dispose(); + Marshal.Copy(temp, 0, PtrData, length); + } + + /// + /// Gets control data as bytes. + /// + /// The number of bytes to copy out of . This will usually come from MonoUsbTransfer.ActualLength. + /// A new byte array of control data. + public Byte[] GetData(int transferLength) + { + byte[] data = new byte[transferLength]; + Marshal.Copy(PtrData,data,0,data.Length); + return data; + } + + } +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/Transfer/MonoUsbControlSetupHandle.cs b/LibWinUsb/MonoLibUsb/Transfer/MonoUsbControlSetupHandle.cs new file mode 100644 index 0000000..9f72127 --- /dev/null +++ b/LibWinUsb/MonoLibUsb/Transfer/MonoUsbControlSetupHandle.cs @@ -0,0 +1,113 @@ +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using LibUsbDotNet.Main; + +namespace MonoLibUsb.Transfer +{ + /// + /// Allocates memory and fills an asynchronous control setup packet. + /// + /// + /// This type is used for asynchronous control transfers only. + /// + /// + public class MonoUsbControlSetupHandle:SafeContextHandle + { + private MonoUsbControlSetup mSetupPacket; + /// + /// Allocates memory and sets up a control setup packet. Copies control data into the control data buffer + /// + /// + /// This constructor is used when has the flag and this request will contain control data (more than just the setup packet). + /// Allocates + .Length for the setup packet. The setup packet is stored first then the control data. + /// The array is copied into the setup packet starting at . + /// + /// This contructor is similar to + /// libusb_fill_control_setup(). + /// + /// + /// The request type field for the setup packet. + /// The request field for the setup packet. + /// The value field for the setup packet + /// The index field for the setup packet. + /// The control data buffer to copy into the setup packet. + /// Size of in bytes. This value is also used for the wLength field of the setup packet. + public MonoUsbControlSetupHandle(byte requestType, byte request, short value, short index, object data, int length) + : this(requestType, request, value, index, (short)(ushort)length) + { + if (data != null) + mSetupPacket.SetData(data, 0, length); + } + + /// + /// Allocates memory and sets up a control setup packet. + /// + /// + /// This constructor is used when: + /// + /// has the flag and this request will not contain extra data (just the setup packet). + /// does not have the flag. + /// + /// + /// + /// This contructor is similar to + /// libusb_fill_control_setup(). + /// + /// Allocates + for the setup packet. The setup packet is stored first then the control data. + /// + /// The request type field for the setup packet. + /// The request field for the setup packet. + /// The value field for the setup packet + /// The index field for the setup packet. + /// The length to allocate for the data portion of the setup packet. + public MonoUsbControlSetupHandle(byte requestType, byte request, short value, short index, short length) + :base(IntPtr.Zero,true) + { + ushort wlength = (ushort) length; + int packetSize; + if (wlength > 0) + packetSize = MonoUsbControlSetup.SETUP_PACKET_SIZE + wlength + (IntPtr.Size - (wlength % IntPtr.Size)); + else + packetSize = MonoUsbControlSetup.SETUP_PACKET_SIZE; + + IntPtr pConfigMem = Marshal.AllocHGlobal(packetSize); + if (pConfigMem == IntPtr.Zero) throw new OutOfMemoryException(String.Format("Marshal.AllocHGlobal failed allocating {0} bytes", packetSize)); + SetHandle(pConfigMem); + + mSetupPacket = new MonoUsbControlSetup(pConfigMem); + + mSetupPacket.RequestType = requestType; + mSetupPacket.Request = request; + mSetupPacket.Value = value; + mSetupPacket.Index = index; + mSetupPacket.Length = (short) wlength; + + } + + /// + /// Returns the for this handle. + /// + public MonoUsbControlSetup ControlSetup + { + get + { + return mSetupPacket; + } + } + /// + /// + /// + /// + protected override bool ReleaseHandle() + { + if (!IsInvalid) + { + Marshal.FreeHGlobal(handle); + SetHandleAsInvalid(); + Debug.Print(GetType().Name + " : ReleaseHandle"); + } + return true; + } + } +} diff --git a/LibWinUsb/MonoLibUsb/Transfer/MonoUsbIsoPacket.cs b/LibWinUsb/MonoLibUsb/Transfer/MonoUsbIsoPacket.cs new file mode 100644 index 0000000..ff2e877 --- /dev/null +++ b/LibWinUsb/MonoLibUsb/Transfer/MonoUsbIsoPacket.cs @@ -0,0 +1,58 @@ +using System; +using System.Runtime.InteropServices; +using MonoLibUsb.Transfer.Internal; + +namespace MonoLibUsb.Transfer +{ + /// + /// Wraps an iso packet structure + /// + [StructLayout(LayoutKind.Sequential)] + public class MonoUsbIsoPacket + { + private static readonly int OfsActualLength = Marshal.OffsetOf(typeof(libusb_iso_packet_descriptor), "actual_length").ToInt32(); + private static readonly int OfsLength = Marshal.OffsetOf(typeof(libusb_iso_packet_descriptor), "length").ToInt32(); + private static readonly int OfsStatus = Marshal.OffsetOf(typeof(libusb_iso_packet_descriptor), "status").ToInt32(); + + private IntPtr mpMonoUsbIsoPacket = IntPtr.Zero; + + /// + /// Creates a structure that wraps an iso packet. + /// + /// The pointer to the iso packet to wrap. + public MonoUsbIsoPacket(IntPtr isoPacketPtr) { mpMonoUsbIsoPacket = isoPacketPtr; } + + /// + /// Returns the location in memory of this iso packet. + /// + public IntPtr PtrIsoPacket + { + get { return mpMonoUsbIsoPacket; } + } + /// + /// Amount of data that was actually transferred. + /// + public int ActualLength + { + get { return Marshal.ReadInt32(mpMonoUsbIsoPacket, OfsActualLength); } + set { Marshal.WriteInt32(mpMonoUsbIsoPacket, OfsActualLength, value); } + } + /// + /// Length of data to request in this packet. + /// + public int Length + { + get { return Marshal.ReadInt32(mpMonoUsbIsoPacket, OfsLength); } + set { Marshal.WriteInt32(mpMonoUsbIsoPacket, OfsLength, value); } + } + /// + /// Status code for this packet. + /// + public MonoUsbTansferStatus Status + { + get { return (MonoUsbTansferStatus)Marshal.ReadInt32(mpMonoUsbIsoPacket, OfsStatus); } + set { Marshal.WriteInt32(mpMonoUsbIsoPacket, OfsStatus, (int)value); } + } + + } +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/Transfer/MonoUsbTansferStatus.cs b/LibWinUsb/MonoLibUsb/Transfer/MonoUsbTansferStatus.cs new file mode 100644 index 0000000..36e3513 --- /dev/null +++ b/LibWinUsb/MonoLibUsb/Transfer/MonoUsbTansferStatus.cs @@ -0,0 +1,65 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// + +namespace MonoLibUsb.Transfer +{ + /// + /// Transfer status codes. + /// + public enum MonoUsbTansferStatus + { + /// + /// Transfer completed without error. Note that this does not indicate that the entire amount of requested data was transferred. + /// + TransferCompleted, + + /// + /// Transfer failed + /// + TransferError, + + /// + /// Transfer timed out + /// + TransferTimedOut, + + /// + /// Transfer was cancelled + /// + TransferCancelled, + + /// + /// For bulk/interrupt endpoints: halt condition detected (endpoint stalled). For control endpoints: control request not supported. + /// + TransferStall, + + /// + /// Device was disconnected + /// + TransferNoDevice, + + /// + /// Device sent more data than requested + /// + TransferOverflow + } ; +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/Transfer/MonoUsbTransfer.cs b/LibWinUsb/MonoLibUsb/Transfer/MonoUsbTransfer.cs new file mode 100644 index 0000000..df55540 --- /dev/null +++ b/LibWinUsb/MonoLibUsb/Transfer/MonoUsbTransfer.cs @@ -0,0 +1,519 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; + +using LibUsbDotNet.Main; +using MonoLibUsb.Transfer.Internal; + +namespace MonoLibUsb.Transfer +{ + /// + /// Reads/writes a Libusb-1.0 transfer pointer. Transfer should be allocated with . + /// + /// + /// The user populates this structure and then submits it in order to request a transfer. + /// After the transfer has completed, the library populates the transfer with the results + /// and passes it back to the user. + /// + /// The structure is roughly equivalent to + /// the struct libusb_transfer. + /// + /// + [StructLayout(LayoutKind.Sequential)] + public struct MonoUsbTransfer + { + private static readonly int OfsActualLength = Marshal.OffsetOf(typeof (libusb_transfer), "actual_length").ToInt32(); + private static readonly int OfsEndpoint = Marshal.OffsetOf(typeof (libusb_transfer), "endpoint").ToInt32(); + private static readonly int OfsFlags = Marshal.OffsetOf(typeof (libusb_transfer), "flags").ToInt32(); + private static readonly int OfsLength = Marshal.OffsetOf(typeof (libusb_transfer), "length").ToInt32(); + private static readonly int OfsPtrBuffer = Marshal.OffsetOf(typeof (libusb_transfer), "pBuffer").ToInt32(); + private static readonly int OfsPtrCallbackFn = Marshal.OffsetOf(typeof (libusb_transfer), "pCallbackFn").ToInt32(); + private static readonly int OfsPtrDeviceHandle = Marshal.OffsetOf(typeof (libusb_transfer), "deviceHandle").ToInt32(); + private static readonly int OfsPtrUserData = Marshal.OffsetOf(typeof (libusb_transfer), "pUserData").ToInt32(); + private static readonly int OfsStatus = Marshal.OffsetOf(typeof (libusb_transfer), "status").ToInt32(); + private static readonly int OfsTimeout = Marshal.OffsetOf(typeof (libusb_transfer), "timeout").ToInt32(); + private static readonly int OfsType = Marshal.OffsetOf(typeof (libusb_transfer), "type").ToInt32(); + private static readonly int OfsNumIsoPackets = Marshal.OffsetOf(typeof (libusb_transfer), "num_iso_packets").ToInt32(); + private static readonly int OfsIsoPackets = Marshal.OffsetOf(typeof (libusb_transfer), "iso_packets").ToInt32(); + + private IntPtr handle; + /// + /// Allocate a libusb transfer with a specified number of isochronous packet descriptors + /// + /// + /// The transfer is pre-initialized for you. When the new transfer is no longer needed, it should be freed with . + /// Transfers intended for non-isochronous endpoints (e.g. control, bulk, interrupt) should specify an iso_packets count of zero. + /// For transfers intended for isochronous endpoints, specify an appropriate number of packet descriptors to be allocated as part of the transfer. The returned transfer is not specially initialized for isochronous I/O; you are still required to set the and fields accordingly. + /// It is safe to allocate a transfer with some isochronous packets and then use it on a non-isochronous endpoint. If you do this, ensure that at time of submission, is 0 and that type is set appropriately. + /// + /// number of isochronous packet descriptors to allocate. + public MonoUsbTransfer(int numIsoPackets) + { + handle = MonoUsbApi.AllocTransfer(numIsoPackets); + } + + /// + /// Creates a new wrapper for transfers allocated by , + /// + /// The pointer to the transfer that was previously allocated with. + internal MonoUsbTransfer(IntPtr pTransfer) + { + handle = pTransfer; + } + + /// + /// Gets the buffer data pointer. + /// + public IntPtr PtrBuffer + { + get { return Marshal.ReadIntPtr(handle, OfsPtrBuffer); } + set { Marshal.WriteIntPtr(handle, OfsPtrBuffer, value); } + } + + /// + /// User context data to pass to the callback function. + /// + public IntPtr PtrUserData + { + get { return Marshal.ReadIntPtr(handle, OfsPtrUserData); } + set { Marshal.WriteIntPtr(handle, OfsPtrUserData, value); } + } + + /// + /// Callback function pointer. + /// + /// + /// The callback function must be declared as a . + /// + public IntPtr PtrCallbackFn + { + get { return Marshal.ReadIntPtr(handle, OfsPtrCallbackFn); } + set { Marshal.WriteIntPtr(handle, OfsPtrCallbackFn, value); } + } + + /// + /// Actual length of data that was transferred. + /// + public int ActualLength + { + get { return Marshal.ReadInt32(handle, OfsActualLength); } + set { Marshal.WriteInt32(handle, OfsActualLength, value); } + } + + /// + /// Length of the data buffer. + /// + public int Length + { + get { return Marshal.ReadInt32(handle, OfsLength); } + set { Marshal.WriteInt32(handle, OfsLength, value); } + } + + /// + /// The status of the transfer. + /// + public MonoUsbTansferStatus Status + { + get { return (MonoUsbTansferStatus)Marshal.ReadInt32(handle, OfsStatus); } + set { Marshal.WriteInt32(handle, OfsStatus, (int)value); } + } + + /// + /// Timeout for this transfer in millseconds. + /// + public int Timeout + { + get { return Marshal.ReadInt32(handle, OfsTimeout); } + set { Marshal.WriteInt32(handle, OfsTimeout, value); } + } + + /// + /// Type of the endpoint. + /// + public EndpointType Type + { + get { return (EndpointType)Marshal.ReadByte(handle, OfsType); } + set { Marshal.WriteByte(handle, OfsType, (byte)value); } + } + + /// + /// Enpoint address. + /// + public byte Endpoint + { + get { return Marshal.ReadByte(handle, OfsEndpoint); } + set { Marshal.WriteByte(handle, OfsEndpoint, value); } + } + + /// + /// A bitwise OR combination of . + /// + public MonoUsbTransferFlags Flags + { + get { return (MonoUsbTransferFlags)Marshal.ReadByte(handle, OfsFlags); } + set { Marshal.WriteByte(handle, OfsFlags, (byte)value); } + } + + /// + /// Raw device handle pointer. + /// + public IntPtr PtrDeviceHandle + { + get { return Marshal.ReadIntPtr(handle, OfsPtrDeviceHandle); } + set { Marshal.WriteIntPtr(handle, OfsPtrDeviceHandle, value); } + } + + /// + /// Number of isochronous packets. + /// + public int NumIsoPackets + { + get { return Marshal.ReadInt32(handle, OfsNumIsoPackets); } + set { Marshal.WriteInt32(handle, OfsNumIsoPackets, value); } + } + + /// + /// Frees this transfer. + /// + /// + /// + /// is roughly equivalent to + /// libusb_free_transfer(). + /// + /// + /// Calling on a transfer that has already been freed will result in a double free. + /// + /// + public void Free() + { + if (handle!=IntPtr.Zero) + { + MonoUsbApi.FreeTransfer(handle); + handle = IntPtr.Zero; + } + } + + /// + /// Gets a unqiue name for this transfer. + /// + /// A unqiue name for this transfer. + public String UniqueName() + { + String guidString = String.Format("_-EP[{0}]EP-_", handle); + return guidString; + } + + /// + /// Gets a that represents the specified iso packet descriptor. + /// + /// The iso packet descriptor to return. + /// The that represents . + public MonoUsbIsoPacket IsoPacket(int packetNumber) + { + if (packetNumber > NumIsoPackets) throw new ArgumentOutOfRangeException("packetNumber"); + IntPtr pIsoPacket = + new IntPtr(handle.ToInt64() + OfsIsoPackets + (packetNumber * Marshal.SizeOf(typeof(libusb_iso_packet_descriptor)))); + + return new MonoUsbIsoPacket(pIsoPacket); + } + + /// + /// True if the transfer is allocated. + /// + public bool IsInvalid + { + get + { + return (handle == IntPtr.Zero); + } + } + /// + /// Cancels this transfer. + /// + /// + /// + /// is roughly equivalent to + /// libusb_cancel_transfer(). + /// + /// + /// if the cancel succeeds, otherwise one of the other codes. + public MonoUsbError Cancel() + { + if (IsInvalid) return MonoUsbError.ErrorNoMem; + + return (MonoUsbError) MonoUsbApi.CancelTransfer(handle); + } + /// + /// Helper function to populate the required properties for a bulk transfer. + /// + /// + /// + /// is similar to + /// libusb_fill_bulk_transfer(). + /// + /// + /// handle of the device that will handle the transfer + /// address of the endpoint where this transfer will be sent + /// data buffer + /// length of data buffer + /// callback function to be invoked on transfer completion + /// user data to pass to callback function + /// timeout for the transfer in milliseconds + public void FillBulk(MonoUsbDeviceHandle devHandle, + byte endpoint, + IntPtr buffer, + int length, + Delegate callback, + IntPtr userData, + int timeout) + { + PtrDeviceHandle = devHandle.DangerousGetHandle(); + Endpoint = endpoint; + PtrBuffer = buffer; + Length = length; + PtrCallbackFn = Marshal.GetFunctionPointerForDelegate(callback); + PtrUserData = userData; + Timeout = timeout; + Type = EndpointType.Bulk; + Flags = MonoUsbTransferFlags.None; + NumIsoPackets = 0; + ActualLength = 0; + + + } + + /// + /// Helper function to populate the required properties for an interrupt transfer. + /// + /// + /// + /// is roughly equivalent to + /// libusb_fill_interrupt_transfer(). + /// + /// + /// handle of the device that will handle the transfer + /// address of the endpoint where this transfer will be sent + /// data buffer + /// length of data buffer + /// callback function to be invoked on transfer completion + /// user data to pass to callback function + /// timeout for the transfer in milliseconds + public void FillInterrupt(MonoUsbDeviceHandle devHandle, + byte endpoint, + IntPtr buffer, + int length, + Delegate callback, + IntPtr userData, + int timeout) + { + PtrDeviceHandle = devHandle.DangerousGetHandle(); + Endpoint = endpoint; + PtrBuffer = buffer; + Length = length; + PtrCallbackFn = Marshal.GetFunctionPointerForDelegate(callback); + PtrUserData = userData; + Timeout = timeout; + Type = EndpointType.Interrupt; + Flags = MonoUsbTransferFlags.None; + } + + /// + /// Helper function to populate the required properties for an isochronous transfer. + /// + /// + /// + /// Isochronous transfers are not supported on windows. + /// + /// + /// is similar to + /// libusb_fill_iso_transfer(). + /// + /// + /// handle of the device that will handle the transfer + /// address of the endpoint where this transfer will be sent + /// data buffer + /// length of data buffer + /// the number of isochronous packets + /// callback function to be invoked on transfer completion + /// user data to pass to callback function + /// timeout for the transfer in milliseconds + public void FillIsochronous(MonoUsbDeviceHandle devHandle, + byte endpoint, + IntPtr buffer, + int length,int numIsoPackets, + Delegate callback, + IntPtr userData, + int timeout) + { + PtrDeviceHandle = devHandle.DangerousGetHandle(); + Endpoint = endpoint; + PtrBuffer = buffer; + Length = length; + PtrCallbackFn = Marshal.GetFunctionPointerForDelegate(callback); + PtrUserData = userData; + Timeout = timeout; + Type = EndpointType.Isochronous; + Flags = MonoUsbTransferFlags.None; + NumIsoPackets = numIsoPackets; + } + + /// + /// Convenience function to locate the position of an isochronous packet within the buffer of an isochronous transfer. + /// + /// + /// This is a thorough function which loops through all preceding packets, accumulating their lengths to find the position of the specified packet. Typically you will assign equal lengths to each packet in the transfer, and hence the above method is sub-optimal. You may wish to use instead. + /// + /// is roughly equivalent to + /// libusb_get_iso_packet_buffer(). + /// + /// + /// The packet to return the address of. + /// the base address of the packet buffer inside the transfer buffer. + /// This exception is thrown if the packet requested is >= . + public IntPtr GetIsoPacketBuffer(int packet) + { + if (packet >= NumIsoPackets) throw new ArgumentOutOfRangeException("packet", "GetIsoPacketBuffer: packet must be < NumIsoPackets"); + long offset = PtrBuffer.ToInt64(); + + for (int i = 0; i < packet; i++) + offset += IsoPacket(i).Length; + + return new IntPtr(offset); + } + + /// + /// Convenience function to locate the position of an isochronous packet within the buffer of an isochronous transfer, for transfers where each packet is of identical size. + /// + /// + /// This function relies on the assumption that every packet within the transfer is of identical size to the first packet. Calculating the location of the packet buffer is then just a simple calculation: buffer + (packet_size * packet) + /// Do not use this function on transfers other than those that have identical packet lengths for each packet. + /// + /// is roughly equivalent to + /// libusb_get_iso_packet_buffer_simple(). + /// + /// + /// The packet to return the address of. + /// the base address of the packet buffer inside the transfer buffer. + /// This exception is thrown if the packet requested is >= . + public IntPtr GetIsoPacketBufferSimple(int packet) + { + if (packet >= NumIsoPackets) throw new ArgumentOutOfRangeException("packet", "GetIsoPacketBufferSimple: packet must be < NumIsoPackets"); + + return new IntPtr((PtrBuffer.ToInt64() + (IsoPacket(0).Length * packet))); + + } + + /// + /// Convenience function to set the length of all packets in an isochronous transfer, based on the num_iso_packets field in the transfer structure. + /// + /// + /// + /// is roughly equivalent to + /// libusb_set_iso_packet_lengths(). + /// + /// + /// The length to set in each isochronous packet descriptor. + public void SetIsoPacketLengths(int length) + { + int packetCount = NumIsoPackets; + for (int i = 0; i < packetCount; i++) + IsoPacket(i).Length = length; + + } + /// + /// Submits this transfer. + /// + /// + /// This functions submits the USB transfer and return immediately. + /// + /// is roughly equivalent to + /// libusb_submit_transfer(). + /// + /// + /// + /// if the submit succeeds, + /// otherwise one of the other codes. + /// + public MonoUsbError Submit() + { + if (IsInvalid) return MonoUsbError.ErrorNoMem; + return (MonoUsbError)MonoUsbApi.SubmitTransfer(handle); + } + + /// + /// Allocate a libusb transfer with a specified number of isochronous packet descriptors + /// + /// + /// The returned transfer is pre-initialized for you. When the new transfer is no longer needed, it should be freed with . + /// Transfers intended for non-isochronous endpoints (e.g. control, bulk, interrupt) should specify an iso_packets count of zero. + /// For transfers intended for isochronous endpoints, specify an appropriate number of packet descriptors to be allocated as part of the transfer. The returned transfer is not specially initialized for isochronous I/O; you are still required to set the and fields accordingly. + /// It is safe to allocate a transfer with some isochronous packets and then use it on a non-isochronous endpoint. If you do this, ensure that at time of submission, is 0 and that type is set appropriately. + /// + /// is roughly equivalent to + /// libusb_alloc_transfer(). + /// + /// + /// number of isochronous packet descriptors to allocate. + /// A newly allocated . + /// If the transfer was not allocated. + public static MonoUsbTransfer Alloc(int numIsoPackets) + { + IntPtr p = MonoUsbApi.AllocTransfer(numIsoPackets); + if (p == IntPtr.Zero) throw new OutOfMemoryException("AllocTransfer"); + return new MonoUsbTransfer(p); + } + + /// + /// Helper function to populate the required properties for a control transfer. + /// + /// + /// + /// Isochronous transfers are not supported on windows. + /// + /// + /// is similar to + /// libusb_fill_control_transfer(). + /// + /// + /// handle of the device that will handle the transfer + /// the setup packet/control data to transfer. + /// callback function to be invoked on transfer completion + /// user data to pass to callback function + /// timeout for the transfer in milliseconds + public void FillControl(MonoUsbDeviceHandle devHandle, MonoUsbControlSetupHandle controlSetupHandle, Delegate callback, IntPtr userData, int timeout) + { + PtrDeviceHandle = devHandle.DangerousGetHandle(); + Endpoint = 0; + PtrCallbackFn = Marshal.GetFunctionPointerForDelegate(callback); + PtrUserData = userData; + Timeout = timeout; + Type = EndpointType.Control; + Flags = MonoUsbTransferFlags.None; + + IntPtr pSetupPacket = controlSetupHandle.DangerousGetHandle(); + PtrBuffer = pSetupPacket; + MonoUsbControlSetup w = new MonoUsbControlSetup(pSetupPacket); + Length = MonoUsbControlSetup.SETUP_PACKET_SIZE + w.Length; + } + } +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/Transfer/MonoUsbTransferContext.cs b/LibWinUsb/MonoLibUsb/Transfer/MonoUsbTransferContext.cs new file mode 100644 index 0000000..c8b466b --- /dev/null +++ b/LibWinUsb/MonoLibUsb/Transfer/MonoUsbTransferContext.cs @@ -0,0 +1,232 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; +using System.Threading; +using LibUsbDotNet.Main; +using MonoLibUsb; +using MonoLibUsb.Transfer; + +namespace LibUsbDotNet.LudnMonoLibUsb.Internal +{ + internal class MonoUsbTransferContext : UsbTransfer, IDisposable + { + private bool mOwnsTransfer; + + private static readonly MonoUsbTransferDelegate mMonoUsbTransferCallbackDelegate = TransferCallback; + private GCHandle mCompleteEventHandle; + private MonoUsbTransfer mTransfer; + + public MonoUsbTransferContext(UsbEndpointBase endpointBase) + : base(endpointBase) + { + } + + #region IDisposable Members + + public new void Dispose() + { + freeTransfer(); + } + + #endregion + private void allocTransfer(UsbEndpointBase endpointBase, bool ownsTransfer, int isoPacketSize, int count) + { + int numIsoPackets = 0; + if (isoPacketSize > 0) + numIsoPackets = count/isoPacketSize; + freeTransfer(); + mTransfer = MonoUsbTransfer.Alloc(numIsoPackets); + mOwnsTransfer = ownsTransfer; + mTransfer.Type = endpointBase.Type; + mTransfer.Endpoint = endpointBase.EpNum; + mTransfer.NumIsoPackets = numIsoPackets; + + if (!mCompleteEventHandle.IsAllocated) + mCompleteEventHandle = GCHandle.Alloc(mTransferCompleteEvent); + mTransfer.PtrUserData = GCHandle.ToIntPtr(mCompleteEventHandle); + + if (numIsoPackets > 0) + mTransfer.SetIsoPacketLengths(isoPacketSize); + + + } + private void freeTransfer() + { + if (mTransfer.IsInvalid || mOwnsTransfer == false) return; + mTransferCancelEvent.Set(); + mTransferCompleteEvent.WaitOne(200, UsbConstants.EXIT_CONTEXT); + mTransfer.Free(); + + if (mCompleteEventHandle.IsAllocated) + mCompleteEventHandle.Free(); + + + } + + /// + /// Fills the transfer with the data to . + /// + /// The buffer. + /// The offset on the buffer where the transfer should read/write. + /// The number of bytes to transfer. + /// Time (milliseconds) to wait before the transfer times out. + public override void Fill(IntPtr buffer, int offset, int count, int timeout) + { + allocTransfer(EndpointBase, true, 0, count); + + base.Fill(buffer, offset, count, timeout); + + mTransfer.Timeout = timeout; + mTransfer.PtrDeviceHandle = EndpointBase.Handle.DangerousGetHandle(); + + mTransfer.PtrCallbackFn = Marshal.GetFunctionPointerForDelegate(mMonoUsbTransferCallbackDelegate); + + mTransfer.Type = EndpointBase.Type; + mTransfer.Endpoint = EndpointBase.EpNum; + + mTransfer.ActualLength = 0; + mTransfer.Status = 0; + mTransfer.Flags = MonoUsbTransferFlags.None; + } + + /// + /// Fills the transfer with the data to an isochronous transfer. + /// + /// The buffer. + /// The offset on the buffer where the transfer should read/write. + /// The number of bytes to transfer. + /// Time (milliseconds) to wait before the transfer times out. + /// Size of each isochronous packet. + public override void Fill(IntPtr buffer, int offset, int count, int timeout, int isoPacketSize) + { + allocTransfer(EndpointBase, true, isoPacketSize, count); + + base.Fill(buffer, offset, count, timeout, isoPacketSize); + + mTransfer.Timeout = timeout; + mTransfer.PtrDeviceHandle = EndpointBase.Handle.DangerousGetHandle(); + + mTransfer.PtrCallbackFn = Marshal.GetFunctionPointerForDelegate(mMonoUsbTransferCallbackDelegate); + + mTransfer.Type = EndpointBase.Type; + mTransfer.Endpoint = EndpointBase.EpNum; + + mTransfer.ActualLength = 0; + mTransfer.Status = 0; + mTransfer.Flags = MonoUsbTransferFlags.None; + } + // Clean up the globally allocated memory. + + ~MonoUsbTransferContext() { Dispose(); } + + /// + /// Submits the transfer. + /// + /// + /// This functions submits the USB transfer and return immediately. + /// + /// + /// if the submit succeeds, + /// otherwise one of the other codes. + /// + public override ErrorCode Submit() + { + if (mTransferCancelEvent.WaitOne(0, false)) return ErrorCode.IoCancelled; + + if (!mTransferCompleteEvent.WaitOne(0, UsbConstants.EXIT_CONTEXT)) return ErrorCode.ResourceBusy; + + mTransfer.PtrBuffer = NextBufPtr; + mTransfer.Length = RequestCount; + + mTransferCompleteEvent.Reset(); + + int ret = (int)mTransfer.Submit(); + if (ret < 0) + { + mTransferCompleteEvent.Set(); + UsbError usbErr = UsbError.Error(ErrorCode.MonoApiError, ret, "SubmitTransfer", EndpointBase); + return usbErr.ErrorCode; + } + + return ErrorCode.Success; + } + + /// + /// Wait for the transfer to complete, timeout, or get cancelled. + /// + /// The number of bytes transferred on . + /// Not used for libusb-1.0. Transfers are always cancelled on timeout or error. + /// if the transfer completes successfully, otherwise one of the other codes. + public override ErrorCode Wait(out int transferredCount, bool cancel) + { + transferredCount = 0; + int ret = 0; + MonoUsbError monoError; + ErrorCode ec; + + int iWait = WaitHandle.WaitAny(new WaitHandle[] {mTransferCompleteEvent, mTransferCancelEvent}, + Timeout.Infinite, + UsbConstants.EXIT_CONTEXT); + switch (iWait) + { + case 0: // TransferCompleteEvent + + if (mTransfer.Status == MonoUsbTansferStatus.TransferCompleted) + { + transferredCount = mTransfer.ActualLength; + return ErrorCode.Success; + } + + string s; + monoError = MonoUsbApi.MonoLibUsbErrorFromTransferStatus(mTransfer.Status); + ec = MonoUsbApi.ErrorCodeFromLibUsbError((int)monoError, out s); + UsbError.Error(ErrorCode.MonoApiError, (int)monoError, "Wait:" + s, EndpointBase); + return ec; + case 1: // TransferCancelEvent + ret = (int)mTransfer.Cancel(); + bool bTransferComplete = mTransferCompleteEvent.WaitOne(100, UsbConstants.EXIT_CONTEXT); + mTransferCompleteEvent.Set(); + + if (ret != 0 || !bTransferComplete) + { + ec = ret == 0 ? ErrorCode.CancelIoFailed : ErrorCode.MonoApiError; + UsbError.Error(ec, ret, String.Format("Wait:Unable to cancel transfer or the transfer did not return after it was cancelled. Cancelled:{0} TransferCompleted:{1}", (MonoUsbError)ret, bTransferComplete), EndpointBase); + return ec; + } + return ErrorCode.IoCancelled; + default: // Critical failure timeout + mTransfer.Cancel(); + ec = ((EndpointBase.mEpNum & (byte)UsbCtrlFlags.Direction_In) > 0) ? ErrorCode.ReadFailed : ErrorCode.WriteFailed; + mTransferCompleteEvent.Set(); + UsbError.Error(ec, ret, String.Format("Wait:Critical timeout failure! The transfer callback function was not called within the allotted time."), EndpointBase); + return ec; + } + } + + private static void TransferCallback(MonoUsbTransfer pTransfer) + { + ManualResetEvent completeEvent = GCHandle.FromIntPtr(pTransfer.PtrUserData).Target as ManualResetEvent; + completeEvent.Set(); + } + } +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/Transfer/MonoUsbTransferFlags.cs b/LibWinUsb/MonoLibUsb/Transfer/MonoUsbTransferFlags.cs new file mode 100644 index 0000000..e4b7c55 --- /dev/null +++ b/LibWinUsb/MonoLibUsb/Transfer/MonoUsbTransferFlags.cs @@ -0,0 +1,51 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +namespace MonoLibUsb.Transfer +{ + /// + /// Transfer flags. + /// + public enum MonoUsbTransferFlags : byte + { + /// + /// No transfer flags. + /// + None = 0, + /// + /// Report short frames as errors + /// + TransferShortNotOk = 1 << 0, + + /// + /// Automatically free() transfer buffer during MonoUsbTransfer.Free(). + /// + TransferFreeBuffer = 1 << 1, + + /// + /// Automatically call MonoUsbTransfer.Free() after callback returns. + /// + /// + /// If this flag is set, it is illegal to call from your transfer callback, as this will result in a double-free when this flag is acted upon. + /// + TransferFreeTransfer = 1 << 2, + } ; +} \ No newline at end of file diff --git a/LibWinUsb/MonoLibUsb/UnixNativeTimeval.cs b/LibWinUsb/MonoLibUsb/UnixNativeTimeval.cs new file mode 100644 index 0000000..9486090 --- /dev/null +++ b/LibWinUsb/MonoLibUsb/UnixNativeTimeval.cs @@ -0,0 +1,69 @@ +using System; +using System.Runtime.InteropServices; +using LibUsbDotNet.Main; + +namespace MonoLibUsb +{ + /// + /// Unix mono.net timeval structure. + /// + [StructLayout(LayoutKind.Sequential)] + public struct UnixNativeTimeval + { + private IntPtr mTvSecInternal; + private IntPtr mTvUSecInternal; + + /// + /// Default used by the on windows platforms. + /// + public static UnixNativeTimeval WindowsDefault + { + get { return new UnixNativeTimeval(2, 0); } + } + + /// + /// Default used by the on unix-like platforms. + /// + public static UnixNativeTimeval LinuxDefault + { + get { return new UnixNativeTimeval(2, 0); } + } + + /// + /// Default . + /// + public static UnixNativeTimeval Default + { + get { return Helper.IsLinux ? LinuxDefault : WindowsDefault; } + } + + /// + /// Timeval seconds property. + /// + public long tv_sec + { + get { return mTvSecInternal.ToInt64(); } + set { mTvSecInternal = new IntPtr(value); } + } + + /// + /// Timeval milliseconds property. + /// + public long tv_usec + { + get { return mTvUSecInternal.ToInt64(); } + set { mTvUSecInternal = new IntPtr(value); } + } + + /// + /// Timeval constructor. + /// + /// seconds + /// milliseconds + public UnixNativeTimeval(long tvSec, long tvUsec) + { + mTvSecInternal = new IntPtr(tvSec); + mTvUSecInternal = new IntPtr(tvUsec); + } + } +} \ No newline at end of file diff --git a/LibWinUsb/UsbDevice.Common.cs b/LibWinUsb/UsbDevice.Common.cs new file mode 100644 index 0000000..95ba24e --- /dev/null +++ b/LibWinUsb/UsbDevice.Common.cs @@ -0,0 +1,249 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Collections.Generic; +using LibUsbDotNet.Internal.LibUsb; +using LibUsbDotNet.LibUsb; +using LibUsbDotNet.Main; +using LibUsbDotNet.LudnMonoLibUsb; +using LibUsbDotNet.WinUsb.Internal; +using Debug=System.Diagnostics.Debug; + +namespace LibUsbDotNet +{ + public abstract partial class UsbDevice + { + private static LibUsbAPI _libUsbApi; + private static WinUsbAPI _winUsbApi; + private static object mHasWinUsbDriver; + private static object mHasLibUsbWinBackDriver; + + private static LibUsbKernelType mLibUsbKernelType; + private static UsbKernelVersion mUsbKernelVersion; + + /// + /// Gets a list of all available USB devices (WinUsb, LibUsb, Linux LibUsb v1.x). + /// + /// + /// Use this property to get a list of USB device that can be accessed by LibUsbDotNet. + /// Using this property as opposed to and + /// will ensure your source code is platform-independent. + /// + public static UsbRegDeviceList AllDevices + { + get + { + UsbRegDeviceList regDevReturnList = new UsbRegDeviceList(); + + UsbRegDeviceList winUsbList = AllWinUsbDevices; + foreach (UsbRegistry winUsbRegistry in winUsbList) + regDevReturnList.Add(winUsbRegistry); + + UsbRegDeviceList libUsbList = AllLibUsbDevices; + foreach (UsbRegistry libUsbRegistry in libUsbList) + regDevReturnList.Add(libUsbRegistry); + + return regDevReturnList; + } + } + + /// + /// Gets a list of all available libusb-win32 USB devices. + /// + /// + /// + /// On windows, gets a list of libusb-win32 USB devices . If + /// is true, gets a list of libusb-1.0 devices. + /// + /// + /// On linux/mac, gets a list of libusb-1.0 devices. + /// + /// + public static UsbRegDeviceList AllLibUsbDevices + { + get + { + UsbRegDeviceList regDevList = new UsbRegDeviceList(); + if (HasLibUsbWinBackDriver && ForceLibUsbWinBack) + { + List deviceList = MonoUsbDevice.MonoUsbDeviceList; + foreach (MonoUsbDevice usbDevice in deviceList) + { + regDevList.Add(new LegacyUsbRegistry(usbDevice)); + } + } + else + { + if (!ForceLegacyLibUsb && KernelType == LibUsbKernelType.NativeLibUsb) + { + List libUsbRegistry = LibUsbRegistry.DeviceList; + foreach (LibUsbRegistry usbRegistry in libUsbRegistry) + regDevList.Add(usbRegistry); + } + else + { + List libUsbRegistry = LegacyUsbRegistry.DeviceList; + foreach (LegacyUsbRegistry usbRegistry in libUsbRegistry) + regDevList.Add(usbRegistry); + } + } + return regDevList; + } + } + + /// + /// Returns the last error number reported by LibUsbDotNet. + /// + public static int LastErrorNumber + { + get { return UsbError.mLastErrorNumber; } + } + + /// + /// Returns the last error string reported by LibUsbDotNet. + /// + public static string LastErrorString + { + get { return UsbError.mLastErrorString; } + } + + internal static LibUsbAPI LibUsbApi + { + get + { + if (ReferenceEquals(_libUsbApi, null)) + _libUsbApi = new LibUsbAPI(); + return _libUsbApi; + } + } + + internal static WinUsbAPI WinUsbApi + { + get + { + if (ReferenceEquals(_winUsbApi, null)) + _winUsbApi = new WinUsbAPI(); + return _winUsbApi; + } + } + + + + /// + /// Opens the usb device that matches the . + /// + /// The class used to find the usb device. + /// An valid/open usb device class if the device was found or Null if the device was not found. + public static UsbDevice OpenUsbDevice(UsbDeviceFinder usbDeviceFinder) + { + return OpenUsbDevice((Predicate) usbDeviceFinder.Check); + } + + /// + /// Opens the usb device that matches the find predicate. + /// + /// The predicate function used to find the usb device. + /// An valid/open usb device class if the device was found or Null if the device was not found. + public static UsbDevice OpenUsbDevice(Predicate findDevicePredicate) + { + UsbDevice usbDeviceFound; + + UsbRegDeviceList allDevices = AllDevices; + UsbRegistry regDeviceFound = allDevices.Find(findDevicePredicate); + + if (ReferenceEquals(regDeviceFound, null)) return null; + + usbDeviceFound = regDeviceFound.Device; + + return usbDeviceFound; + } + + /// + /// Opens a WinUsb device by its DeviceInterfaceGUID. + /// + /// + /// This is the Microsoft-recommended way for opening a WinUsb device. + /// LibUsb device can be opened in this way as well. In order to open + /// LibUsb devices in this manner, an entry must be added to the driver + /// inf file: + /// [Install.HW] + /// Addreg=Add_LibUsb_Guid_Reg + /// [Add_LibUsb_Guid_Reg] + /// HKR,,LibUsbInterfaceGUIDs,0x10000,"{Your-Unique-Guid-String}" + /// + /// Device Interface GUID of the usb device to open. + /// On success, a new instance. + /// True on success. + public static bool OpenUsbDevice(ref Guid devInterfaceGuid, out UsbDevice usbDevice) + { + usbDevice = null; + UsbRegDeviceList usbRegDevices = AllDevices; + foreach (UsbRegistry usbRegistry in usbRegDevices) + { + foreach (Guid guid in usbRegistry.DeviceInterfaceGuids) + { + if (guid == devInterfaceGuid) + { + usbDevice = usbRegistry.Device; + if (usbDevice != null) return true; + } + } + } + + return false; + } + + /// + /// Global static error event for all Usb errors. + /// + /// + /// Sample code to reset an endpoint if a critical error occurs. + /// + /// // Hook the usb error handler function + /// UsbGlobals.UsbErrorEvent += UsbErrorEvent; + ///private void UsbErrorEvent(object sender, UsbError e) + ///{ + /// // If the error is from a usb endpoint + /// if (sender is UsbEndpointBase) + /// { + /// // If the endpoint transfer failed + /// if (e.Win32ErrorNumber == 31) + /// { + /// // If the USB device is still open, connected, and valid + /// if (usb.IsOpen) + /// { + /// // Try to reset then endpoint + /// if (((UsbEndpointBase) sender).Reset()) + /// { + /// // Endpoint reset successful. + /// // Tell LibUsbDotNet to ignore this error and continue. + /// e.Handled = true; + /// } + /// } + /// } + /// } + /// } + /// + /// + public static event EventHandler UsbErrorEvent; + } +} \ No newline at end of file diff --git a/LibWinUsb/UsbDevice.Error.cs b/LibWinUsb/UsbDevice.Error.cs new file mode 100644 index 0000000..733660f --- /dev/null +++ b/LibWinUsb/UsbDevice.Error.cs @@ -0,0 +1,166 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using LibUsbDotNet.Internal; +using LibUsbDotNet.Main; +using MonoLibUsb; + +namespace LibUsbDotNet +{ + partial class UsbDevice + { + internal static void FireUsbError(object sender, UsbError usbError) + { + EventHandler temp = UsbErrorEvent; + if (!ReferenceEquals(null, temp)) + temp(sender, usbError); + } + } + + /// Describes a Usb error or setup API error. + /// + public class UsbError : EventArgs + { + internal static int mLastErrorNumber; + internal static string mLastErrorString = String.Empty; + + ///// + ///// The the error is field is set to true for errors resulting from endpoint read/write errors. The operation will retry instead of exiting with an error code. + ///// + //public bool Handled; + + internal string mDescription; + + internal ErrorCode mErrorCode; + private object mSender; + internal int mWin32ErrorNumber; + internal string mWin32ErrorString = "None"; + + internal UsbError(ErrorCode errorCode, int win32ErrorNumber, string win32ErrorString, string description, object sender) + { + mSender = sender; + string senderText = String.Empty; + if ((mSender is UsbEndpointBase)|| (mSender is UsbTransfer)) + { + UsbEndpointBase ep; + if (mSender is UsbTransfer) + ep = ((UsbTransfer)mSender).EndpointBase; + else + ep = mSender as UsbEndpointBase; + + if (ep.mEpNum != 0) + { + + senderText = senderText+=string.Format(" Ep 0x{0:X2} ", ep.mEpNum); + } + } + else if (mSender is Type) + { + Type t = mSender as Type; + senderText = senderText += string.Format(" {0} ", t.Name); + } + mErrorCode = errorCode; + mWin32ErrorNumber = win32ErrorNumber; + mWin32ErrorString = win32ErrorString; + mDescription = description + senderText; + } + + /// + /// The sender of the exception. + /// + public object Sender + { + get { return mSender; } + } + + /// + /// Gets the general errorcode. + /// + public ErrorCode ErrorCode + { + get { return mErrorCode; } + } + + /// + /// Gets the Windows specific error number. Only valid when is set to .. + /// + public int Win32ErrorNumber + { + get { return mWin32ErrorNumber; } + } + + /// + /// Gets the general description for the error. + /// + public string Description + { + get { return mDescription; } + } + + /// + /// Gets the Windows specific error string. Only valid when is set to .. + /// + public string Win32ErrorString + { + get { return mWin32ErrorString; } + } + + + /// + ///Returns a that represents the current . + /// + /// + /// + ///A that represents the current . + /// + public override string ToString() + { + if (Win32ErrorNumber != 0) + { + return String.Format("{0}:{1}\r\n{2}:{3}", ErrorCode, Description, Win32ErrorNumber, mWin32ErrorString); + } + return String.Format("{0}:{1}", ErrorCode, Description); + } + + internal static UsbError Error(ErrorCode errorCode, int ret, string description, object sender) + { + string win32Error = String.Empty; + if (errorCode == ErrorCode.Win32Error && !UsbDevice.IsLinux && ret != 0) + { + win32Error = Kernel32.FormatSystemMessage(ret); + } + else if (errorCode == ErrorCode.MonoApiError && ret != 0) + { + win32Error = ((MonoUsbError) ret) + ":" + MonoUsbApi.StrError((MonoUsbError) ret); + } + UsbError err = new UsbError(errorCode, ret, win32Error, description, sender); + lock (mLastErrorString) + { + mLastErrorNumber = (int) err.ErrorCode; + mLastErrorString = err.ToString(); + } + UsbDevice.FireUsbError(sender, err); + + return err; + } + } +} \ No newline at end of file diff --git a/LibWinUsb/UsbDevice.OS.Specific.cs b/LibWinUsb/UsbDevice.OS.Specific.cs new file mode 100644 index 0000000..f8120d0 --- /dev/null +++ b/LibWinUsb/UsbDevice.OS.Specific.cs @@ -0,0 +1,291 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; +using LibUsbDotNet.Internal.LibUsb; +using LibUsbDotNet.LibUsb; +using LibUsbDotNet.Main; +using LibUsbDotNet.LudnMonoLibUsb; +using LibUsbDotNet.WinUsb; +using MonoLibUsb; + +namespace LibUsbDotNet +{ + public abstract partial class UsbDevice + { + /// + /// + /// + private static readonly bool ForceLegacyLibUsb = IsLinux; + + /// + /// Setting this field to will force to use the Libusb-1.0 Windows-backend driver. For platforms other than windows, this setting has no effect. + /// + /// + /// If this is , will return only s in the list. + /// + public static bool ForceLibUsbWinBack = false; + + + /// + /// Gets a list of all available WinUSB USB devices. + /// + /// + /// On windows, gets a list of WinUSB devices. On linux always returns null. + /// + /// Using the property instead will ensure your source code is platform-independent. + /// + /// + public static UsbRegDeviceList AllWinUsbDevices + { + get + { + UsbRegDeviceList regDevList = new UsbRegDeviceList(); + if (IsLinux || ForceLibUsbWinBack) return regDevList; + + if (HasWinUsbDriver) + { + List winUsbRegistry = WinUsbRegistry.DeviceList; + foreach (WinUsbRegistry usbRegistry in winUsbRegistry) + regDevList.Add(usbRegistry); + } + + return regDevList; + } + } + + /// + /// True if the LibUsb driver is found on the system. + /// + [Obsolete("Always returns true")] + public static bool HasLibUsbDriver + { + get + { + return true; + } + } + /* + public static bool HasLibUsbDriver + { + get + { + if (mHasLibUsbDriver == null) + { + if (IsLinux) + { + mHasLibUsbDriver = true; + } + else + { + mHasLibUsbDriver = false; + string sysDriver = Path.Combine(Environment.SystemDirectory, "drivers"); + DirectoryInfo diSysDriver = new DirectoryInfo(sysDriver); + if (diSysDriver.Exists) + { + FileInfo[] libUsbSysFileInfo = diSysDriver.GetFiles(LIBUSB_SYS); + if (libUsbSysFileInfo.Length > 0) + mHasLibUsbDriver = true; + } + } + } + return (bool) mHasLibUsbDriver; + } + } + */ + + /// + /// True if the WinUSB API is available. + /// + /// + /// + public static bool HasWinUsbDriver + { + get + { + if (mHasWinUsbDriver == null) + { + if (IsLinux) + { + mHasWinUsbDriver = false; + } + else + { + try + { + WinUsb.Internal.WinUsbAPI.WinUsb_Free(IntPtr.Zero); + mHasWinUsbDriver = true; + } + catch (Exception) + { + mHasWinUsbDriver = false; + + } + } + } + return (bool) mHasWinUsbDriver; + } + } + + /// + /// True if the libusb-1.0 API is available. + /// + public static bool HasLibUsbWinBackDriver + { + get + { + if (mHasLibUsbWinBackDriver == null) + { + if (IsLinux) + { + mHasLibUsbWinBackDriver = false; + } + else + { + try + { + MonoUsbApi.StrError(MonoUsbError.Success); + mHasLibUsbWinBackDriver = true; + } + catch(Exception) + { + mHasLibUsbWinBackDriver = false; + + } + } + } + return (bool)mHasLibUsbWinBackDriver; + } + } + /// + /// Returns true if the system is a linux/unix-like operating system. + /// + /// + public static bool IsLinux + { + get + { + return Helper.IsLinux; + + } + } + + /// + /// Gets the kernel driver type in use by LibUsbDotNet. + /// If is returned, LibUsbDotNet using using its + /// native kernel driver. Basic usb device information is retreived from the windows registry + /// which reduces USB IO overhead. + /// If is returned, LibUsbDotNet is using the orginal kernel + /// available at the libusb-win32.sourceforge.net page and true windows registry support + /// is unavailable. + /// Under linux, is always returned. + /// + public static LibUsbKernelType KernelType + { + get + { + if (mLibUsbKernelType == LibUsbKernelType.Unknown) + { + if (IsLinux) + { + mLibUsbKernelType = LibUsbKernelType.MonoLibUsb; + } + else + { + UsbKernelVersion libUsbVersion = KernelVersion; + if (!libUsbVersion.IsEmpty) + { + mLibUsbKernelType = libUsbVersion.BcdLibUsbDotNetKernelMod != 0 + ? LibUsbKernelType.NativeLibUsb + : LibUsbKernelType.LegacyLibUsb; + } + } + } + + return mLibUsbKernelType; + } + } + + /// + /// Gets the kernel driver version in use by LibUsbDotNet. + /// + /// if is non-zero then the kernel driver is native. + /// + /// + public static UsbKernelVersion KernelVersion + { + get + { + if (mUsbKernelVersion.IsEmpty) + { + if (IsLinux) + { + mUsbKernelVersion = new UsbKernelVersion(1, 0, 0, 0, 0); + } + else + { + for (int i = 1; i < UsbConstants.MAX_DEVICES; i++) + { + LibUsbDevice newLibUsbDevice; + string deviceFileName = LibUsbDriverIO.GetDeviceNameString(i); + if (!LibUsbDevice.Open(deviceFileName, out newLibUsbDevice)) continue; + LibUsbRequest request = new LibUsbRequest(); + GCHandle gcReq = GCHandle.Alloc(request, GCHandleType.Pinned); + + int transferred; + bool bSuccess = newLibUsbDevice.UsbIoSync(LibUsbIoCtl.GET_VERSION, + request, + LibUsbRequest.Size, + gcReq.AddrOfPinnedObject(), + LibUsbRequest.Size, + out transferred); + + gcReq.Free(); + newLibUsbDevice.Close(); + if (bSuccess && transferred == LibUsbRequest.Size) + { + mUsbKernelVersion = request.Version; + break; + } + } + } + } + + return mUsbKernelVersion; + } + } + + + /// + /// Gets a object that contains the current platform identifier and version number. + /// + public static OperatingSystem OSVersion + { + get + { + return Helper.OSVersion; + } + } + } +} \ No newline at end of file diff --git a/LibWinUsb/UsbDevice.cs b/LibWinUsb/UsbDevice.cs new file mode 100644 index 0000000..c4f1dfc --- /dev/null +++ b/LibWinUsb/UsbDevice.cs @@ -0,0 +1,495 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Runtime.InteropServices; +using LibUsbDotNet.Descriptors; +using LibUsbDotNet.Info; +using LibUsbDotNet.Internal; +using LibUsbDotNet.LudnMonoLibUsb; +using LibUsbDotNet.Main; +using MonoLibUsb; + +namespace LibUsbDotNet +{ + /// Contains non-driver specific USB device communication members. + /// + /// This class is compatible with WinUSB, LibUsb-Win32, and linux libusb v1.x. + /// Platform independent applications should only use usb device members from this class. + /// If more functionality is required, it is up to the application to handle multi-driver + /// and/or multi-platfrom requirements. + /// + public abstract partial class UsbDevice + { + #region Enumerations + + /// + /// Driver modes enumeration. See the UsbDevice. property. + /// + public enum DriverModeType + { + /// + /// Not yet determined. + /// + Unknown, + /// + /// Using LibUsb kernel driver (Legacy or Native) on windows. + /// + LibUsb, + /// + /// Using WinUsb user-mode driver on windows. + /// + WinUsb, + /// + /// Using Libusb 1.0 driver on linux. + /// + MonoLibUsb, + /// + /// Using Libusb 1.0 windows backend driver on windows. + /// + LibUsbWinBack + } + + #endregion + + internal readonly UsbEndpointList mActiveEndpoints; + internal readonly UsbApiBase mUsbApi; + internal UsbDeviceDescriptor mCachedDeviceDescriptor; + internal List mConfigs; + internal int mCurrentConfigValue = -1; + internal UsbDeviceInfo mDeviceInfo; + internal SafeHandle mUsbHandle; + internal UsbRegistry mUsbRegistry; + + internal UsbDevice(UsbApiBase usbApi, SafeHandle usbHandle) + { + mUsbApi = usbApi; + mUsbHandle = usbHandle; + mActiveEndpoints = new UsbEndpointList(); + } + + /// + /// Gets all available configurations for this + /// + /// + /// The first time this property is accessed it will query the for all configurations. + /// Subsequent request will return a cached copy of all configurations. + /// + public virtual ReadOnlyCollection Configs + { + get + { + if ((ReferenceEquals(mConfigs, null))) + { + mConfigs = GetDeviceConfigs(this); + } + return mConfigs.AsReadOnly(); + } + } + + /// + /// Gets the actual device descriptor the the current . + /// + public virtual UsbDeviceInfo Info + { + get + { + if (ReferenceEquals(mDeviceInfo, null)) + { + mDeviceInfo = new UsbDeviceInfo(this); + } + return mDeviceInfo; + } + } + + /// + /// Gets the class that opened the device, or null if the device was not opened by the class. + /// + public virtual UsbRegistry UsbRegistryInfo + { + get { return mUsbRegistry; } + } + + /// + /// Gets a value indication if the device handle is valid. + /// + public bool IsOpen + { + get { return ((mUsbHandle != null) && !mUsbHandle.IsClosed) && !mUsbHandle.IsInvalid; } + } + + /// + /// A list of endpoints that have beened opened by this class. + /// + public UsbEndpointList ActiveEndpoints + { + get { return mActiveEndpoints; } + } + + + internal SafeHandle Handle + { + get { return mUsbHandle; } + } + + /// + /// Returns the DriverMode this USB device is using. + /// + public abstract DriverModeType DriverMode { get; } + + + /// + /// Closes the and disposes any . + /// + /// True on success. + public abstract bool Close(); + + /// + /// Opens the USB device handle. + /// + /// + ///True if the device is already opened or was opened successfully. + ///False if the device does not exists or is no longer valid. + /// + public abstract bool Open(); + + /// + /// Transmits control data over a default control endpoint. + /// + /// An 8-byte setup packet which contains parameters for the control request. + /// See section 9.3 USB Device Requests of the Universal Serial Bus Specification Revision 2.0 for more information. + /// Data to be sent/received from the device. + /// Length of the buffer param. + /// Number of bytes sent or received (depends on the direction of the control transfer). + /// True on success. + public virtual bool ControlTransfer(ref UsbSetupPacket setupPacket, IntPtr buffer, int bufferLength, out int lengthTransferred) + { + bool bSuccess = mUsbApi.ControlTransfer(mUsbHandle, setupPacket, buffer, bufferLength, out lengthTransferred); + + if (!bSuccess) + UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "ControlTransfer", this); + + return bSuccess; + } + + /// + /// Transmits control data over a default control endpoint. + /// + /// An 8-byte setup packet which contains parameters for the control request. + /// See section 9.3 USB Device Requests of the Universal Serial Bus Specification Revision 2.0 for more information. + /// Data to be sent/received from the device. + /// Length of the buffer param. + /// Number of bytes sent or received (depends on the direction of the control transfer). + /// True on success. + public virtual bool ControlTransfer(ref UsbSetupPacket setupPacket, object buffer, int bufferLength, out int lengthTransferred) + { + PinnedHandle pinned = new PinnedHandle(buffer); + bool bSuccess = ControlTransfer(ref setupPacket, pinned.Handle, bufferLength, out lengthTransferred); + pinned.Dispose(); + + return bSuccess; + } + + /// + /// Gets the USB devices active configuration value. + /// + /// The active configuration value. A zero value means the device is not configured and a non-zero value indicates the device is configured. + /// True on success. + public virtual bool GetConfiguration(out byte config) + { + config = 0; + byte[] buf = new byte[1]; + int uTransferLength; + + UsbSetupPacket setupPkt = new UsbSetupPacket(); + setupPkt.RequestType = (byte) UsbEndpointDirection.EndpointIn | (byte) UsbRequestType.TypeStandard | + (byte) UsbRequestRecipient.RecipDevice; + setupPkt.Request = (byte) UsbStandardRequest.GetConfiguration; + setupPkt.Value = 0; + setupPkt.Index = 0; + setupPkt.Length = 1; + + bool bSuccess = ControlTransfer(ref setupPkt, buf, buf.Length, out uTransferLength); + if (bSuccess && uTransferLength == 1) + { + config = buf[0]; + mCurrentConfigValue = config; + return true; + } + UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "GetConfiguration", this); + return false; + } + + /// + /// Gets a descriptor from the device. See for more information. + /// + /// The descriptor type ID to retrieve; this is usually one of the enumerations. + /// Descriptor index. + /// Descriptor language id. + /// Memory to store the returned descriptor in. + /// Length of the buffer parameter in bytes. + /// The number of bytes transferred to buffer upon success. + /// True on success. + public virtual bool GetDescriptor(byte descriptorType, byte index, short langId, IntPtr buffer, int bufferLength, out int transferLength) + { + transferLength = 0; + + bool wasOpen = IsOpen; + if (!wasOpen) Open(); + if (!IsOpen) return false; + + bool bSuccess = mUsbApi.GetDescriptor(mUsbHandle, descriptorType, index, (ushort) langId, buffer, bufferLength, out transferLength); + + if (!bSuccess) + UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "GetDescriptor", this); + + if (!wasOpen && IsOpen) Close(); + + return bSuccess; + } + + + /// + /// Opens a endpoint for writing + /// + /// Endpoint number for read operations. + /// A class ready for writing. If the specified endpoint is already been opened, the original class is returned. + public virtual UsbEndpointWriter OpenEndpointWriter(WriteEndpointID writeEndpointID) { return OpenEndpointWriter(writeEndpointID, EndpointType.Bulk); } + + /// + /// Opens an endpoint for writing + /// + /// Endpoint number for read operations. + /// The type of endpoint to open. + /// A class ready for writing. If the specified endpoint is already been opened, the original class is returned. + public virtual UsbEndpointWriter OpenEndpointWriter(WriteEndpointID writeEndpointID, EndpointType endpointType) + { + foreach (UsbEndpointBase activeEndpoint in ActiveEndpoints) + if (activeEndpoint.EpNum == (byte) writeEndpointID) + return (UsbEndpointWriter) activeEndpoint; + + UsbEndpointWriter epNew = new UsbEndpointWriter(this, writeEndpointID, endpointType); + return (UsbEndpointWriter) mActiveEndpoints.Add(epNew); + } + + internal static List GetDeviceConfigs(UsbDevice usbDevice) + { + List rtnConfigs = new List(); + + byte[] cfgBuffer = new byte[UsbConstants.MAX_CONFIG_SIZE]; + + int iConfigs = usbDevice.Info.Descriptor.ConfigurationCount; + for (int iConfig = 0; iConfig < iConfigs; iConfig++) + { + int iBytesTransmitted; + bool bSuccess = usbDevice.GetDescriptor((byte) DescriptorType.Configuration, 0, 0, cfgBuffer, cfgBuffer.Length, out iBytesTransmitted); + if (bSuccess) + { + if (iBytesTransmitted >= UsbConfigDescriptor.Size && cfgBuffer[1] == (byte) DescriptorType.Configuration) + { + UsbConfigDescriptor configDescriptor = new UsbConfigDescriptor(); + Helper.BytesToObject(cfgBuffer, 0, Math.Min(UsbConfigDescriptor.Size, cfgBuffer[0]), configDescriptor); + + if (configDescriptor.TotalLength == iBytesTransmitted) + { + List rawDescriptorList = new List(); + int iRawLengthPosition = configDescriptor.Length; + while (iRawLengthPosition < configDescriptor.TotalLength) + { + byte[] rawDescriptor = new byte[cfgBuffer[iRawLengthPosition]]; + if (iRawLengthPosition + rawDescriptor.Length > iBytesTransmitted) + throw new UsbException(usbDevice, "Descriptor length is out of range."); + + Array.Copy(cfgBuffer, iRawLengthPosition, rawDescriptor, 0, rawDescriptor.Length); + rawDescriptorList.Add(rawDescriptor); + iRawLengthPosition += rawDescriptor.Length; + } + rtnConfigs.Add(new UsbConfigInfo(usbDevice, configDescriptor, ref rawDescriptorList)); + } + else + UsbError.Error(ErrorCode.InvalidConfig, + 0, + "GetDeviceConfigs: USB config descriptor length doesn't match the length received.", + usbDevice); + } + else + UsbError.Error(ErrorCode.InvalidConfig, 0, "GetDeviceConfigs: USB config descriptor is invalid.", usbDevice); + } + else + UsbError.Error(ErrorCode.InvalidConfig, 0, "GetDeviceConfigs", usbDevice); + } + return rtnConfigs; + } + + /// + /// Gets a descriptor from the device. See for more information. + /// + /// The descriptor type ID to retrieve; this is usually one of the enumerations. + /// Descriptor index. + /// Descriptor language id. + /// Memory to store the returned descriptor in. + /// Length of the buffer parameter in bytes. + /// The number of bytes transferred to buffer upon success. + /// True on success. + public bool GetDescriptor(byte descriptorType, byte index, short langId, object buffer, int bufferLength, out int transferLength) + { + PinnedHandle pinned = new PinnedHandle(buffer); + bool bSuccess = GetDescriptor(descriptorType, index, langId, pinned.Handle, bufferLength, out transferLength); + pinned.Dispose(); + + return bSuccess; + } + + + /// + /// Asking for the zero'th index is special - it returns a string + /// descriptor that contains all the language IDs supported by the + /// device. Typically there aren't many - often only one. The + /// language IDs are 16 bit numbers, and they start at the third byte + /// in the descriptor. See USB 2.0 specification, section 9.6.7, for + /// more information on this. + /// + /// A collection of LCIDs that the current supports. + public bool GetLangIDs(out short[] langIDs) + { + LangStringDescriptor sd = new LangStringDescriptor(UsbDescriptor.Size + (16*sizeof (short))); + + int ret; + bool bSuccess = GetDescriptor((byte) DescriptorType.String, 0, 0, sd.Ptr, sd.MaxSize, out ret); + if (bSuccess && ret == sd.Length) + { + bSuccess = sd.Get(out langIDs); + } + else + { + langIDs = new short[0]; + UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "GetLangIDs", this); + } + sd.Free(); + return bSuccess; + } + + /// + /// Gets a descriptor from the device. + /// + /// Buffer to store the returned string in upon success. + /// The language ID to retrieve the string in. (0x409 for english). + /// The string index to retrieve. + /// True on success. + public bool GetString(out string stringData, short langId, byte stringIndex) + { + stringData = null; + int iTransferLength; + LangStringDescriptor sd = new LangStringDescriptor(255); + bool bSuccess = GetDescriptor((byte) DescriptorType.String, stringIndex, langId, sd.Ptr, sd.MaxSize, out iTransferLength); + + if (bSuccess && iTransferLength > UsbDescriptor.Size && sd.Length == iTransferLength) + bSuccess = sd.Get(out stringData); + else if (!bSuccess) + UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "GetString:GetDescriptor", this); + else + stringData = String.Empty; + + return bSuccess; + } + + + /// + /// Opens a endpoint for reading + /// + /// Endpoint number for read operations. + /// A class ready for reading. If the specified endpoint is already been opened, the original class is returned. + public UsbEndpointReader OpenEndpointReader(ReadEndpointID readEndpointID) { return OpenEndpointReader(readEndpointID, UsbEndpointReader.DefReadBufferSize); } + + /// + /// Opens a endpoint for reading + /// + /// Endpoint number for read operations. + /// Size of the read buffer allocated for the event. + /// A class ready for reading. If the specified endpoint is already been opened, the original class is returned. + public UsbEndpointReader OpenEndpointReader(ReadEndpointID readEndpointID, int readBufferSize) { return OpenEndpointReader(readEndpointID, readBufferSize, EndpointType.Bulk); } + + /// + /// Opens an endpoint for reading + /// + /// Endpoint number for read operations. + /// Size of the read buffer allocated for the event. + /// The type of endpoint to open. + /// A class ready for reading. If the specified endpoint is already been opened, the original class is returned. + public virtual UsbEndpointReader OpenEndpointReader(ReadEndpointID readEndpointID, int readBufferSize, EndpointType endpointType) + { + foreach (UsbEndpointBase activeEndpoint in mActiveEndpoints) + if (activeEndpoint.EpNum == (byte) readEndpointID) + return (UsbEndpointReader) activeEndpoint; + + UsbEndpointReader epNew = new UsbEndpointReader(this, readBufferSize, readEndpointID, endpointType); + return (UsbEndpointReader) mActiveEndpoints.Add(epNew); + } + + /// + /// Gets the selected alternate interface of the specified interface. + /// + /// The interface settings number (index) to retrieve the selected alternate interface setting for. + /// The alternate interface setting selected for use with the specified interface. + /// True on success. + public bool GetAltInterfaceSetting(byte interfaceID, out byte selectedAltInterfaceID) + { + byte[] buf = new byte[1]; + int uTransferLength; + + UsbSetupPacket setupPkt = new UsbSetupPacket(); + setupPkt.RequestType = (byte) UsbEndpointDirection.EndpointIn | (byte) UsbRequestType.TypeStandard | + (byte) UsbRequestRecipient.RecipInterface; + setupPkt.Request = (byte) UsbStandardRequest.GetInterface; + setupPkt.Value = 0; + setupPkt.Index = interfaceID; + setupPkt.Length = 1; + + bool bSuccess = ControlTransfer(ref setupPkt, buf, buf.Length, out uTransferLength); + if (bSuccess && uTransferLength == 1) + selectedAltInterfaceID = buf[0]; + else + selectedAltInterfaceID = 0; + + return bSuccess; + } + + /// + /// De-initializes the USB driver. + /// + /// + /// If this method is not called before the application exits, it can cause it to hang indefinitely. + /// Calling this method multiple times will have no effect. + /// + public static void Exit() + { + lock (MonoUsbDevice.OLockDeviceList) + { + if (MonoUsbDevice.mMonoUSBProfileList != null) + MonoUsbDevice.mMonoUSBProfileList.Close(); + MonoUsbDevice.mMonoUSBProfileList = null; + } + MonoUsbApi.StopAndExit(); + } + } +} \ No newline at end of file diff --git a/LibWinUsb/UsbEndpointReader.cs b/LibWinUsb/UsbEndpointReader.cs new file mode 100644 index 0000000..0e12d2b --- /dev/null +++ b/LibWinUsb/UsbEndpointReader.cs @@ -0,0 +1,290 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; +using System.Threading; +using System.Windows.Forms; +using LibUsbDotNet.Internal; +using LibUsbDotNet.Main; + +namespace LibUsbDotNet +{ + /// + /// Contains methods for retrieving data from a or endpoint using the overloaded functions or a event. + /// + /// + /// + /// Before using the event, the property must be set to true. + /// While the property is True, the overloaded functions cannot be used. + /// + /// + public class UsbEndpointReader : UsbEndpointBase + { + private static int mDefReadBufferSize = 4096; + + private bool mDataReceivedEnabled; + private int mReadBufferSize; + private Thread mReadThread; + private ThreadPriority mReadThreadPriority = ThreadPriority.Normal; + + internal UsbEndpointReader(UsbDevice usbDevice, int readBufferSize, ReadEndpointID readEndpointID, EndpointType endpointType) + : base(usbDevice, (Byte) readEndpointID, endpointType) { mReadBufferSize = readBufferSize; } + + /// + /// Default read buffer size when using the event. + /// + /// + /// This value can be bypassed using the second parameter of the method. + /// The default is 4096. + /// + public static int DefReadBufferSize + { + get { return mDefReadBufferSize; } + set { mDefReadBufferSize = value; } + } + + /// + /// Gets/Sets a value indicating if the event should be used. + /// + /// + /// If DataReceivedEnabled is true the functions cannot be used. + /// + public virtual bool DataReceivedEnabled + { + get { return mDataReceivedEnabled; } + set + { + if (value != mDataReceivedEnabled) + { + StartStopReadThread(); + } + } + } + + + /// + /// Size of the read buffer in bytes for the event. + /// + /// + /// Setting a large values, for example 64K will yield a lower number of and a higher data rate. + /// + public int ReadBufferSize + { + get { return mReadBufferSize; } + set { mReadBufferSize = value; } + } + + /// + /// Gets/Sets the Priority level for the read thread when is true. + /// + public ThreadPriority ReadThreadPriority + { + get { return mReadThreadPriority; } + set { mReadThreadPriority = value; } + } + + + /// + /// Reads data from the current . + /// + /// The buffer to store the recieved data in. + /// Maximum time to wait for the transfer to complete. If the transfer times out, the IO operation will be cancelled. + /// Number of bytes actually transferred. + /// + /// . on success. + /// + public virtual ErrorCode Read(byte[] buffer, int timeout, out int transferLength) { return Read(buffer, 0, buffer.Length, timeout, out transferLength); } + + /// + /// Reads data from the current . + /// + /// The buffer to store the recieved data in. + /// The position in buffer to start storing the data. + /// The maximum number of bytes to receive. + /// Maximum time to wait for the transfer to complete. If the transfer times out, the IO operation will be cancelled. + /// Number of bytes actually transferred. + /// + /// . on success. + /// + public virtual ErrorCode Read(IntPtr buffer, int offset, int count, int timeout, out int transferLength) { return Transfer(buffer, offset, count, timeout, out transferLength); } + + /// + /// Reads data from the current . + /// + /// The buffer to store the recieved data in. + /// The position in buffer to start storing the data. + /// The maximum number of bytes to receive. + /// Maximum time to wait for the transfer to complete. If the transfer times out, the IO operation will be cancelled. + /// Number of bytes actually transferred. + /// + /// . on success. + /// + public virtual ErrorCode Read(byte[] buffer, int offset, int count, int timeout, out int transferLength) { return Transfer(buffer, offset, count, timeout, out transferLength); } + + /// + /// Reads data from the current . + /// + /// The buffer to store the recieved data in. + /// The position in buffer to start storing the data. + /// The maximum number of bytes to receive. + /// Maximum time to wait for the transfer to complete. If the transfer times out, the IO operation will be cancelled. + /// Number of bytes actually transferred. + /// + /// . on success. + /// + public virtual ErrorCode Read(object buffer, int offset, int count, int timeout, out int transferLength) { return Transfer(buffer, offset, count, timeout, out transferLength); } + + /// + /// Reads data from the current . + /// + /// The buffer to store the recieved data in. + /// Maximum time to wait for the transfer to complete. If the transfer times out, the IO operation will be cancelled. + /// Number of bytes actually transferred. + /// + /// . on success. + /// + public virtual ErrorCode Read(object buffer, int timeout, out int transferLength) { return Transfer(buffer, 0, Marshal.SizeOf(buffer), timeout, out transferLength); } + + /// + /// Reads/discards data from the enpoint until no more data is available. + /// + /// Alwats returns + public virtual ErrorCode ReadFlush() + { + byte[] bufDummy = new byte[64]; + int iTransferred; + int iBufCount = 0; + while (Read(bufDummy, 10, out iTransferred) == ErrorCode.None && iBufCount < 128) + { + iBufCount++; + } + + return ErrorCode.None; + } + + + private static void ReadData(object context) + { + UsbTransfer overlappedTransferContext = (UsbTransfer) context; + UsbEndpointReader reader = (UsbEndpointReader) overlappedTransferContext.EndpointBase; + reader.mDataReceivedEnabled = true; + EventHandler dataReceivedEnabledChangedEvent; + + dataReceivedEnabledChangedEvent = reader.DataReceivedEnabledChanged; + if (!ReferenceEquals(dataReceivedEnabledChangedEvent,null)) + dataReceivedEnabledChangedEvent(reader, new DataReceivedEnabledChangedEventArgs(reader.mDataReceivedEnabled)); + + overlappedTransferContext.Reset(); + + byte[] buf = new byte[reader.mReadBufferSize]; + try + { + while (!overlappedTransferContext.IsCancelled) + { + int iTransferLength; + ErrorCode eReturn = reader.Transfer(buf, 0, buf.Length, Timeout.Infinite, out iTransferLength); + if (eReturn == ErrorCode.None) + { + EventHandler temp = reader.DataReceived; + if (!ReferenceEquals(temp, null) && !overlappedTransferContext.IsCancelled) + { + temp(reader, new EndpointDataEventArgs(buf, iTransferLength)); + } + continue; + } + if (eReturn != ErrorCode.IoTimedOut) break; + } + } + catch (ThreadAbortException) + { + UsbError.Error(ErrorCode.ReceiveThreadTerminated,0, "ReadData:Read thread aborted.", reader); + } + finally + { + reader.Abort(); + reader.mDataReceivedEnabled = false; + + dataReceivedEnabledChangedEvent = reader.DataReceivedEnabledChanged; + if (!ReferenceEquals(dataReceivedEnabledChangedEvent, null)) + dataReceivedEnabledChangedEvent(reader, new DataReceivedEnabledChangedEventArgs(reader.mDataReceivedEnabled)); + + } + } + + private void StartReadThread() + { + mReadThread = new Thread(ReadData); + mReadThread.Priority = ReadThreadPriority; + mReadThread.Start(TransferContext); + Thread.Sleep(1); + Application.DoEvents(); + } + + private bool StopReadThread() + { + Abort(); + Thread.Sleep(1); + Application.DoEvents(); + DateTime dtStart = DateTime.Now; + while (mReadThread.IsAlive && ((DateTime.Now - dtStart).TotalSeconds < 5)) // 5 sec fail-safe + { + Thread.Sleep(100); + Application.DoEvents(); + } + if (mReadThread.IsAlive) + { + UsbError.Error(ErrorCode.ReceiveThreadTerminated,0, "Failed stopping read thread.", this); + mReadThread.Abort(); + return false; + } + return true; + } + + private void StartStopReadThread() + { + if (IsDisposed) throw new ObjectDisposedException(GetType().FullName); + + if (mDataReceivedEnabled) + { + StopReadThread(); + } + else + { + StartReadThread(); + } + } + + + /// + /// The DataReceived Event is fired when new data arrives for the current . + /// + /// To use the DataReceived event, must be set to truw. + public virtual event EventHandler DataReceived; + + /// + /// The Event is fired when the event is started or stopped. + /// + public virtual event EventHandler DataReceivedEnabledChanged; + + internal override UsbTransfer CreateTransferContext() { return new OverlappedTransferContext(this); } + } +} \ No newline at end of file diff --git a/LibWinUsb/UsbEndpointWriter.cs b/LibWinUsb/UsbEndpointWriter.cs new file mode 100644 index 0000000..05499f8 --- /dev/null +++ b/LibWinUsb/UsbEndpointWriter.cs @@ -0,0 +1,100 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; +using LibUsbDotNet.Internal; +using LibUsbDotNet.Main; + +namespace LibUsbDotNet +{ + /// Contains methods for writing data to a or endpoint using the overloaded functions. + /// + public class UsbEndpointWriter : UsbEndpointBase + { + internal UsbEndpointWriter(UsbDevice usbDevice, WriteEndpointID writeEndpointID, EndpointType endpointType) + : base(usbDevice, (byte)writeEndpointID, endpointType) { } + + + /// + /// Writes data to the current . + /// + /// The buffer storing the data to write. + /// Maximum time to wait for the transfer to complete. If the transfer times out, the IO operation will be cancelled. + /// Number of bytes actually transferred. + /// + /// . on success. + /// + public virtual ErrorCode Write(byte[] buffer, int timeout, out int transferLength) { return Write(buffer, 0, buffer.Length, timeout, out transferLength); } + + /// + /// Writes data to the current . + /// + /// The buffer storing the data to write. + /// The position in buffer to start writing the data from. + /// The number of bytes to write. + /// Maximum time to wait for the transfer to complete. If the transfer times out, the IO operation will be cancelled. + /// Number of bytes actually transferred. + /// + /// . on success. + /// + public virtual ErrorCode Write(IntPtr pBuffer, int offset, int count, int timeout, out int transferLength) { return Transfer(pBuffer, offset, count, timeout, out transferLength); } + + /// + /// Writes data to the current . + /// + /// The buffer storing the data to write. + /// The position in buffer to start writing the data from. + /// The number of bytes to write. + /// Maximum time to wait for the transfer to complete. If the transfer times out, the IO operation will be cancelled. + /// Number of bytes actually transferred. + /// + /// . on success. + /// + public virtual ErrorCode Write(byte[] buffer, int offset, int count, int timeout, out int transferLength) { return Transfer(buffer, offset, count, timeout, out transferLength); } + + /// + /// Writes data to the current . + /// + /// The buffer storing the data to write. + /// The position in buffer to start writing the data from. + /// The number of bytes to write. + /// Maximum time to wait for the transfer to complete. If the transfer times out, the IO operation will be cancelled. + /// Number of bytes actually transferred. + /// + /// . on success. + /// + public virtual ErrorCode Write(object buffer, int offset, int count, int timeout, out int transferLength) { return Transfer(buffer, offset, count, timeout, out transferLength); } + + /// + /// Writes data to the current . + /// + /// The buffer storing the data to write. + /// Maximum time to wait for the transfer to complete. If the transfer times out, the IO operation will be cancelled. + /// Number of bytes actually transferred. + /// + /// . on success. + /// + public virtual ErrorCode Write(object buffer, int timeout, out int transferLength) { return Write(buffer, 0, Marshal.SizeOf(buffer), timeout, out transferLength); } + + internal override UsbTransfer CreateTransferContext() { return new OverlappedTransferContext(this); } + } +} \ No newline at end of file diff --git a/LibWinUsb/UsbGlobals.cs b/LibWinUsb/UsbGlobals.cs new file mode 100644 index 0000000..f1246df --- /dev/null +++ b/LibWinUsb/UsbGlobals.cs @@ -0,0 +1,34 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using LibUsbDotNet.LibUsb; +using LibUsbDotNet.Main; + +namespace LibUsbDotNet +{ + /// + /// Static class for opening, enumerating and finding USB devices. + /// + public static class UsbGlobals + { + } +} \ No newline at end of file diff --git a/LibWinUsb/WinUsb/DeviceInformationTypes.cs b/LibWinUsb/WinUsb/DeviceInformationTypes.cs new file mode 100644 index 0000000..c4c3dd6 --- /dev/null +++ b/LibWinUsb/WinUsb/DeviceInformationTypes.cs @@ -0,0 +1,33 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +namespace LibUsbDotNet.WinUsb +{ + /// Types of information that can be retrieved with the WinUsb QueryDevice function. + /// + public enum DeviceInformationTypes : byte + { + /// + /// The device speed. + /// + DeviceSpeed = 0x01 + } +} \ No newline at end of file diff --git a/LibWinUsb/WinUsb/DeviceSpeedTypes.cs b/LibWinUsb/WinUsb/DeviceSpeedTypes.cs new file mode 100644 index 0000000..91e8532 --- /dev/null +++ b/LibWinUsb/WinUsb/DeviceSpeedTypes.cs @@ -0,0 +1,45 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +namespace LibUsbDotNet.WinUsb +{ + /// Device speed types + /// + public enum DeviceSpeedTypes : byte + { + /// + /// Unknown + /// + Undefined = 0x00, + /// + /// Low speed device. + /// + LowSpeed = 0x01, + /// + /// Full speed device. + /// + FullSpeed = 0x02, + /// + /// High speed device. + /// + HighSpeed = 0x03, + } +} \ No newline at end of file diff --git a/LibWinUsb/WinUsb/Internal/SafeWinUsbInterfaceHandle.cs b/LibWinUsb/WinUsb/Internal/SafeWinUsbInterfaceHandle.cs new file mode 100644 index 0000000..c376cbc --- /dev/null +++ b/LibWinUsb/WinUsb/Internal/SafeWinUsbInterfaceHandle.cs @@ -0,0 +1,67 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; +using LibUsbDotNet.WinUsb.Internal; + +namespace LibUsbDotNet.Internal.WinUsb +{ + internal class SafeWinUsbInterfaceHandle : SafeHandle + { + public SafeWinUsbInterfaceHandle() + : base(IntPtr.Zero, true) { } + + public SafeWinUsbInterfaceHandle(IntPtr handle) + : base(handle, true) { } + + /// + ///Gets a value indicating whether the value is invalid. + /// + /// + /// + ///true if the is valid; otherwise, false. + /// + public override bool IsInvalid + { + get { return (handle == IntPtr.Zero || handle.ToInt64() == -1); } + } + + /// + ///Executes the code required to free the . + /// + /// + /// + ///true if the is released successfully; otherwise, in the event of a catastrophic failure, false. In this case, it generates a ReleaseHandleFailed Managed Debugging Assistant. + /// + /// + protected override bool ReleaseHandle() + { + bool bSuccess = true; + if (!IsInvalid) + { + bSuccess = WinUsbAPI.WinUsb_Free(handle); + handle = IntPtr.Zero; + } + return bSuccess; + } + } +} \ No newline at end of file diff --git a/LibWinUsb/WinUsb/Internal/WinUsbAPI.cs b/LibWinUsb/WinUsb/Internal/WinUsbAPI.cs new file mode 100644 index 0000000..cfb994a --- /dev/null +++ b/LibWinUsb/WinUsb/Internal/WinUsbAPI.cs @@ -0,0 +1,226 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; +using System.Security; +using LibUsbDotNet.Descriptors; +using LibUsbDotNet.Internal; +using LibUsbDotNet.Internal.WinUsb; +using LibUsbDotNet.Main; +using Microsoft.Win32.SafeHandles; + +// ReSharper disable InconsistentNaming + +namespace LibUsbDotNet.WinUsb.Internal +{ + [SuppressUnmanagedCodeSecurity] + internal class WinUsbAPI : UsbApiBase + { + internal const string WIN_USB_DLL = "winusb.dll"; + + + [DllImport(WIN_USB_DLL, EntryPoint = "WinUsb_AbortPipe", SetLastError = true)] + private static extern bool WinUsb_AbortPipe([In] SafeHandle InterfaceHandle, byte PipeID); + + [DllImport(WIN_USB_DLL, EntryPoint = "WinUsb_ControlTransfer", SetLastError = true)] + private static extern bool WinUsb_ControlTransfer([In] SafeHandle InterfaceHandle, + [In] UsbSetupPacket SetupPacket, + IntPtr Buffer, + int BufferLength, + out int LengthTransferred, + IntPtr pOVERLAPPED); + + [DllImport(WIN_USB_DLL, EntryPoint = "WinUsb_FlushPipe", SetLastError = true)] + private static extern bool WinUsb_FlushPipe([In] SafeHandle InterfaceHandle, byte PipeID); + + [DllImport(WIN_USB_DLL, EntryPoint = "WinUsb_Free", SetLastError = true)] + internal static extern bool WinUsb_Free([In] IntPtr InterfaceHandle); + + [DllImport(WIN_USB_DLL, EntryPoint = "WinUsb_GetAssociatedInterface", SetLastError = true)] + internal static extern bool WinUsb_GetAssociatedInterface([In] SafeHandle InterfaceHandle, + byte AssociatedInterfaceIndex, + ref IntPtr AssociatedInterfaceHandle); + + [DllImport(WIN_USB_DLL, EntryPoint = "WinUsb_GetCurrentAlternateSetting", SetLastError = true)] + internal static extern bool WinUsb_GetCurrentAlternateSetting([In] SafeHandle InterfaceHandle, out byte SettingNumber); + + + [DllImport(WIN_USB_DLL, EntryPoint = "WinUsb_GetDescriptor", SetLastError = true)] + private static extern bool WinUsb_GetDescriptor([In] SafeHandle InterfaceHandle, + byte DescriptorType, + byte Index, + ushort LanguageID, + IntPtr Buffer, + int BufferLength, + out int LengthTransferred); + + [DllImport(WIN_USB_DLL, EntryPoint = "WinUsb_GetOverlappedResult", SetLastError = true)] + private static extern bool WinUsb_GetOverlappedResult([In] SafeHandle InterfaceHandle, + IntPtr pOVERLAPPED, + out int lpNumberOfBytesTransferred, + bool Wait); + + [DllImport(WIN_USB_DLL, EntryPoint = "WinUsb_GetPipePolicy", SetLastError = true)] + internal static extern bool WinUsb_GetPipePolicy([In] SafeHandle InterfaceHandle, + byte PipeID, + PipePolicyType policyType, + ref int ValueLength, + IntPtr Value); + + [DllImport(WIN_USB_DLL, EntryPoint = "WinUsb_GetPowerPolicy", SetLastError = true)] + internal static extern bool WinUsb_GetPowerPolicy([In] SafeHandle InterfaceHandle, + PowerPolicyType policyType, + ref int ValueLength, + IntPtr Value); + + [DllImport(WIN_USB_DLL, EntryPoint = "WinUsb_Initialize", SetLastError = true)] + internal static extern bool WinUsb_Initialize([In] SafeHandle DeviceHandle, [Out, In] ref SafeWinUsbInterfaceHandle InterfaceHandle); + + [DllImport(WIN_USB_DLL, EntryPoint = "WinUsb_QueryDeviceInformation", SetLastError = true)] + internal static extern bool WinUsb_QueryDeviceInformation([In] SafeHandle InterfaceHandle, + DeviceInformationTypes InformationType, + ref int BufferLength, + [MarshalAs(UnmanagedType.AsAny), In, Out] object Buffer); + + [DllImport(WIN_USB_DLL, EntryPoint = "WinUsb_QueryInterfaceSettings", SetLastError = true)] + internal static extern bool WinUsb_QueryInterfaceSettings([In] SafeHandle InterfaceHandle, + byte AlternateInterfaceNumber, + [MarshalAs(UnmanagedType.LPStruct), In, Out] UsbInterfaceDescriptor + UsbAltInterfaceDescriptor); + + [DllImport(WIN_USB_DLL, EntryPoint = "WinUsb_QueryPipe", SetLastError = true)] + internal static extern bool WinUsb_QueryPipe([In] SafeHandle InterfaceHandle, + byte AlternateInterfaceNumber, + byte PipeIndex, + [MarshalAs(UnmanagedType.LPStruct), In, Out] PipeInformation PipeInformation); + + [DllImport(WIN_USB_DLL, EntryPoint = "WinUsb_ReadPipe", SetLastError = true)] + private static extern bool WinUsb_ReadPipe([In] SafeHandle InterfaceHandle, + byte PipeID, + Byte[] Buffer, + int BufferLength, + out int LengthTransferred, + IntPtr pOVERLAPPED); + + [DllImport(WIN_USB_DLL, EntryPoint = "WinUsb_ReadPipe", SetLastError = true)] + private static extern bool WinUsb_ReadPipe([In] SafeHandle InterfaceHandle, + byte PipeID, + IntPtr pBuffer, + int BufferLength, + out int LengthTransferred, + IntPtr pOVERLAPPED); + + [DllImport(WIN_USB_DLL, EntryPoint = "WinUsb_ResetPipe", SetLastError = true)] + private static extern bool WinUsb_ResetPipe([In] SafeHandle InterfaceHandle, byte PipeID); + + [DllImport(WIN_USB_DLL, EntryPoint = "WinUsb_SetPipePolicy", SetLastError = true)] + internal static extern bool WinUsb_SetPipePolicy([In] SafeHandle InterfaceHandle, + byte PipeID, + PipePolicyType policyType, + int ValueLength, + IntPtr Value); + + [DllImport(WIN_USB_DLL, EntryPoint = "WinUsb_SetPowerPolicy", SetLastError = true)] + internal static extern bool WinUsb_SetPowerPolicy([In] SafeHandle InterfaceHandle, PowerPolicyType policyType, int ValueLength, IntPtr Value); + + [DllImport(WIN_USB_DLL, EntryPoint = "WinUsb_WritePipe", SetLastError = true)] + private static extern bool WinUsb_WritePipe([In] SafeHandle InterfaceHandle, + byte PipeID, + Byte[] Buffer, + int BufferLength, + out int LengthTransferred, + IntPtr pOVERLAPPED); + + [DllImport(WIN_USB_DLL, EntryPoint = "WinUsb_WritePipe", SetLastError = true)] + private static extern bool WinUsb_WritePipe([In] SafeHandle InterfaceHandle, + byte PipeID, + IntPtr pBuffer, + int BufferLength, + out int LengthTransferred, + IntPtr pOVERLAPPED); + + + public override bool AbortPipe(SafeHandle InterfaceHandle, byte PipeID) { return WinUsb_AbortPipe(InterfaceHandle, PipeID); } + + public override bool ControlTransfer(SafeHandle InterfaceHandle, + UsbSetupPacket SetupPacket, + IntPtr Buffer, + int BufferLength, + out int LengthTransferred) { return WinUsb_ControlTransfer(InterfaceHandle, SetupPacket, Buffer, BufferLength, out LengthTransferred, IntPtr.Zero); } + + public override bool FlushPipe(SafeHandle InterfaceHandle, byte PipeID) { return WinUsb_FlushPipe(InterfaceHandle, PipeID); } + + public override bool GetDescriptor(SafeHandle InterfaceHandle, + byte DescriptorType, + byte Index, + ushort LanguageID, + IntPtr Buffer, + int BufferLength, + out int LengthTransferred) { return WinUsb_GetDescriptor(InterfaceHandle, DescriptorType, Index, LanguageID, Buffer, BufferLength, out LengthTransferred); } + + public override bool GetOverlappedResult(SafeHandle InterfaceHandle, IntPtr pOVERLAPPED, out int numberOfBytesTransferred, bool Wait) { return WinUsb_GetOverlappedResult(InterfaceHandle, pOVERLAPPED, out numberOfBytesTransferred, Wait); } + + //public override bool ReadPipe(UsbEndpointBase endPointBase, + // byte[] Buffer, + // int BufferLength, + // out int LengthTransferred, + // int isoPacketSize, + // IntPtr pOVERLAPPED) { return WinUsb_ReadPipe(endPointBase.Device.Handle, endPointBase.EpNum, Buffer, BufferLength, out LengthTransferred, pOVERLAPPED); } + + public override bool ReadPipe(UsbEndpointBase endPointBase, + IntPtr pBuffer, + int BufferLength, + out int LengthTransferred, + int isoPacketSize, + IntPtr pOVERLAPPED) { return WinUsb_ReadPipe(endPointBase.Device.Handle, endPointBase.EpNum, pBuffer, BufferLength, out LengthTransferred, pOVERLAPPED); } + + public override bool ResetPipe(SafeHandle InterfaceHandle, byte PipeID) { return WinUsb_ResetPipe(InterfaceHandle, PipeID); } + + //public override bool WritePipe(UsbEndpointBase endPointBase, + // byte[] Buffer, + // int BufferLength, + // out int LengthTransferred, + // int isoPacketSize, + // IntPtr pOVERLAPPED) { return WinUsb_WritePipe(endPointBase.Device.Handle, endPointBase.EpNum, Buffer, BufferLength, out LengthTransferred, pOVERLAPPED); } + + public override bool WritePipe(UsbEndpointBase endPointBase, + IntPtr pBuffer, + int BufferLength, + out int LengthTransferred, + int isoPacketSize, + IntPtr pOVERLAPPED) { return WinUsb_WritePipe(endPointBase.Device.Handle, endPointBase.EpNum, pBuffer, BufferLength, out LengthTransferred, pOVERLAPPED); } + + internal static bool OpenDevice(out SafeFileHandle sfhDevice, string DevicePath) + { + sfhDevice = + Kernel32.CreateFile(DevicePath, + 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); + + return (!sfhDevice.IsInvalid && !sfhDevice.IsClosed); + } + } +} \ No newline at end of file diff --git a/LibWinUsb/WinUsb/PipeInformation.cs b/LibWinUsb/WinUsb/PipeInformation.cs new file mode 100644 index 0000000..793c28c --- /dev/null +++ b/LibWinUsb/WinUsb/PipeInformation.cs @@ -0,0 +1,57 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System.Runtime.InteropServices; +using LibUsbDotNet.Main; + +namespace LibUsbDotNet.WinUsb +{ + /// WinUsb Pipe information. + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public class PipeInformation + { + /// + /// Size of the structure in bytes. + /// + public static readonly int Size = Marshal.SizeOf(typeof (PipeInformation)); + + /// + /// Specifies the pipe type. + /// + public EndpointType PipeType; + + /// + /// The pipe identifier (ID). + /// + public byte PipeId; + + /// + /// The maximum size, in bytes, of the packets that are transmitted on the pipe. + /// + public short MaximumPacketSize; + + /// + /// The pipe interval. + /// + public byte Interval; + } +} \ No newline at end of file diff --git a/LibWinUsb/WinUsb/PipePolicies.cs b/LibWinUsb/WinUsb/PipePolicies.cs new file mode 100644 index 0000000..52bd2fe --- /dev/null +++ b/LibWinUsb/WinUsb/PipePolicies.cs @@ -0,0 +1,288 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; +using LibUsbDotNet.Main; +using LibUsbDotNet.WinUsb.Internal; + +namespace LibUsbDotNet.WinUsb +{ + /// Endpoint specific policies. . + /// + public class PipePolicies + { + private const int MAX_SIZE = 4; + private readonly byte mEpNum; + private readonly SafeHandle mUsbHandle; + + private IntPtr mBufferPtr = IntPtr.Zero; + + internal PipePolicies(SafeHandle usbHandle, byte epNum) + { + mBufferPtr = Marshal.AllocCoTaskMem(MAX_SIZE); + mEpNum = epNum; + mUsbHandle = usbHandle; + } + + /// + /// If the allow partial reads policy parameter is FALSE (that is, zero), the read request fails whenever the device returns more data than the client requested. + /// If the allow partial reads policy parameter is TRUE, the WinUSB driver saves the extra data and sends the extra data to the client during the client's next read. + /// The default value of the allow partial reads policy parameter is TRUE. + /// + public bool AllowPartialReads + { + get + { + int iValueLength = 1; + Marshal.WriteByte(mBufferPtr, 0); + bool bSuccess = GetPipePolicy(PipePolicyType.AllowPartialReads, ref iValueLength, mBufferPtr); + if (bSuccess) + return Marshal.ReadByte(mBufferPtr) == 0 ? false : true; + return false; + } + set + { + int iValueLength = 1; + byte bPipePolicyValue = (value) ? (byte) 1 : (byte) 0; + Marshal.WriteByte(mBufferPtr, bPipePolicyValue); + SetPipePolicy(PipePolicyType.AllowPartialReads, iValueLength, mBufferPtr); + } + } + + /// + /// If the short packet terminate policy parameter is TRUE (that is, nonzero), every write request that is a multiple of the maximum packet size for the endpoint is terminated with a zero-length packet. + /// The default value of the short packet terminate policy parameter is FALSE. + /// + public bool ShortPacketTerminate + { + get + { + int iValueLength = 1; + Marshal.WriteByte(mBufferPtr, 0); + bool bSuccess = GetPipePolicy(PipePolicyType.ShortPacketTerminate, ref iValueLength, mBufferPtr); + if (bSuccess) + return Marshal.ReadByte(mBufferPtr) == 0 ? false : true; + return false; + } + set + { + int iValueLength = 1; + byte bPipePolicyValue = (value) ? (byte) 1 : (byte) 0; + Marshal.WriteByte(mBufferPtr, bPipePolicyValue); + SetPipePolicy(PipePolicyType.ShortPacketTerminate, iValueLength, mBufferPtr); + } + } + + /// + /// If the auto clear stall policy parameter is TRUE (that is, nonzero), the driver fails stalled data transfers, but the driver clears the stall condition automatically, and data continues to flow on the pipe. This policy parameter does not affect control pipes. + /// The default value for the auto clear stall policy parameter is FALSE. + /// + public bool AutoClearStall + { + get + { + int iValueLength = 1; + Marshal.WriteByte(mBufferPtr, 0); + bool bSuccess = GetPipePolicy(PipePolicyType.AutoClearStall, ref iValueLength, mBufferPtr); + if (bSuccess) + return Marshal.ReadByte(mBufferPtr) == 0 ? false : true; + return false; + } + set + { + int iValueLength = 1; + byte bPipePolicyValue = (value) ? (byte) 1 : (byte) 0; + Marshal.WriteByte(mBufferPtr, bPipePolicyValue); + SetPipePolicy(PipePolicyType.AutoClearStall, iValueLength, mBufferPtr); + } + } + + + /// + /// The auto flush policy parameter works with allow partial reads. If allow partial reads is FALSE, the WinUSB driver ignores the value of auto flush. If allow partial reads is TRUE, the value of auto flush determines what the WinUSB driver does when the device returns more data than the client requested. + /// If both allow partial reads and auto flush policy parameters are TRUE (that is, nonzero) and the device returns more data than the client requested, the remaining data is discarded. If allow partial reads is TRUE, but auto flush is FALSE, the WinUSB driver caches the extra data and sends it to the client in the next read operation. + /// The default value of the auto flush policy parameter is FALSE. + /// + public bool AutoFlush + { + get + { + int iValueLength = 1; + Marshal.WriteByte(mBufferPtr, 0); + bool bSuccess = GetPipePolicy(PipePolicyType.AutoFlush, ref iValueLength, mBufferPtr); + if (bSuccess) + return Marshal.ReadByte(mBufferPtr) == 0 ? false : true; + return false; + } + set + { + int iValueLength = 1; + byte bPipePolicyValue = (value) ? (byte) 1 : (byte) 0; + Marshal.WriteByte(mBufferPtr, bPipePolicyValue); + SetPipePolicy(PipePolicyType.AutoFlush, iValueLength, mBufferPtr); + } + } + + /// + /// If the ignore short packets policy parameter is TRUE (that is, nonzero), the host does not complete a read operation after it receives a short packet. Instead, the the host completes the operation only after the host has read the specified number of bytes. + /// If the ignore short packets policy parameter is FALSE, the host completes a read operation when either the host has read the specified number of bytes or the host has received a short packet. + /// The default value of the ignore short packets policy parameter is FALSE. + /// + public bool IgnoreShortPackets + { + get + { + int iValueLength = 1; + Marshal.WriteByte(mBufferPtr, 0); + bool bSuccess = GetPipePolicy(PipePolicyType.IgnoreShortPackets, ref iValueLength, mBufferPtr); + if (bSuccess) + return Marshal.ReadByte(mBufferPtr) == 0 ? false : true; + return false; + } + set + { + int iValueLength = 1; + byte bPipePolicyValue = (value) ? (byte) 1 : (byte) 0; + Marshal.WriteByte(mBufferPtr, bPipePolicyValue); + SetPipePolicy(PipePolicyType.IgnoreShortPackets, iValueLength, mBufferPtr); + } + } + + /// + /// If the raw i/o policy parameter is TRUE (that is, nonzero), calls to WinUsb_ReadPipe and WinUsb_WritePipe for the specified endpoint must satisfy the following conditions: + /// The buffer length must be a multiple of the maximum endpoint packet size. + /// The length must be less than what the host controller supports. + /// If the preceding conditions are met, WinUSB sends data directly to the USB driver stack, bypassing WinUSB's queuing and error handling. + /// If the raw i/o policy parameter is FALSE, no restrictions are imposed on the buffers that are passed to WinUsb_ReadPipe and WinUsb_WritePipe. + /// The default value of the raw i/o policy parameter is FALSE. + /// + public bool RawIo + { + get + { + int iValueLength = 1; + Marshal.WriteByte(mBufferPtr, 0); + bool bSuccess = GetPipePolicy(PipePolicyType.RawIo, ref iValueLength, mBufferPtr); + if (bSuccess) + return Marshal.ReadByte(mBufferPtr) == 0 ? false : true; + return false; + } + set + { + int iValueLength = 1; + byte bPipePolicyValue = (value) ? (byte) 1 : (byte) 0; + Marshal.WriteByte(mBufferPtr, bPipePolicyValue); + SetPipePolicy(PipePolicyType.RawIo, iValueLength, mBufferPtr); + } + } + + /// + /// The pipe transfer timeout policy parameter specifies the time-out interval, in milliseconds. The host cancels transfers that do not complete within the time-out interval. A value of zero means that transfers do not time out. + /// By default, the time-out value is zero, and the host never cancels a transfer because of a time-out. + /// + public int PipeTransferTimeout + { + get + { + int iValueLength = 4; + Marshal.WriteInt32(mBufferPtr, 0); + bool bSuccess = GetPipePolicy(PipePolicyType.PipeTransferTimeout, ref iValueLength, mBufferPtr); + if (bSuccess) + return Marshal.ReadInt32(mBufferPtr); + return -1; + } + set + { + int iValueLength = 4; + Marshal.WriteInt32(mBufferPtr, value); + SetPipePolicy(PipePolicyType.PipeTransferTimeout, iValueLength, mBufferPtr); + } + } + + /// + /// The maximum number of bytes that can be transferred at once. + /// + public int MaxTransferSize + { + get + { + int iValueLength = 4; + Marshal.WriteInt32(mBufferPtr, 0); + bool bSuccess = GetPipePolicy(PipePolicyType.MaximumTransferSize, ref iValueLength, mBufferPtr); + if (bSuccess) + return Marshal.ReadInt32(mBufferPtr); + return -1; + } + } + + + /// + ///Returns a that represents the current . + /// + /// + /// + ///A that represents the current . + /// + public override string ToString() + { + object[] o = new object[] + { + AllowPartialReads, ShortPacketTerminate, AutoClearStall, AutoFlush, IgnoreShortPackets, RawIo, PipeTransferTimeout, + MaxTransferSize + }; + return + string.Format( + "AllowPartialReads:{0}\r\nShortPacketTerminate:{1}\r\nAutoClearStall:{2}\r\nAutoFlush:{3}\r\nIgnoreShortPackets:{4}\r\nRawIO:{5}\r\nPipeTransferTimeout:{6}\r\nMaxTransferSize:{7}\r\n", + o); + } + + + internal bool GetPipePolicy(PipePolicyType policyType, ref int valueLength, IntPtr pBuffer) + { + bool bSuccess = WinUsbAPI.WinUsb_GetPipePolicy(mUsbHandle, mEpNum, policyType, ref valueLength, pBuffer); + + if (!bSuccess) UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "GetPipePolicy", this); + + return bSuccess; + } + + internal bool SetPipePolicy(PipePolicyType policyType, int valueLength, IntPtr pBuffer) + { + bool bSuccess = WinUsbAPI.WinUsb_SetPipePolicy(mUsbHandle, mEpNum, policyType, valueLength, pBuffer); + + if (!bSuccess) UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "SetPipePolicy", this); + + return bSuccess; + } + + /// + /// Frees instance resources. + /// + ~PipePolicies() + { + if (mBufferPtr != IntPtr.Zero) + Marshal.FreeCoTaskMem(mBufferPtr); + + mBufferPtr = IntPtr.Zero; + } + } +} \ No newline at end of file diff --git a/LibWinUsb/WinUsb/PipePolicyType.cs b/LibWinUsb/WinUsb/PipePolicyType.cs new file mode 100644 index 0000000..eb74a8e --- /dev/null +++ b/LibWinUsb/WinUsb/PipePolicyType.cs @@ -0,0 +1,35 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +namespace LibUsbDotNet.WinUsb +{ + internal enum PipePolicyType : byte + { + ShortPacketTerminate = 0x01, + AutoClearStall = 0x02, + PipeTransferTimeout = 0x03, + IgnoreShortPackets = 0x04, + AllowPartialReads = 0x05, + AutoFlush = 0x06, + RawIo = 0x07, + MaximumTransferSize = 0x08, + } +} \ No newline at end of file diff --git a/LibWinUsb/WinUsb/PowerPolicies.cs b/LibWinUsb/WinUsb/PowerPolicies.cs new file mode 100644 index 0000000..2b59c5c --- /dev/null +++ b/LibWinUsb/WinUsb/PowerPolicies.cs @@ -0,0 +1,98 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Runtime.InteropServices; + +namespace LibUsbDotNet.WinUsb +{ + /// + /// power policy for a . + /// + public class PowerPolicies + { + private const int MAX_SIZE = 4; + private readonly WinUsbDevice mUsbDevice; + private IntPtr mBufferPtr = IntPtr.Zero; + + internal PowerPolicies(WinUsbDevice usbDevice) + { + mBufferPtr = Marshal.AllocCoTaskMem(MAX_SIZE); + mUsbDevice = usbDevice; + } + + /// + /// If the auto suspend policy parameter is TRUE (that is, nonzero), the USB stack suspends the device when no transfers are pending. The default value for the AutoSuspend policy parameter is TRUE. + /// + public bool AutoSuspend + { + get + { + int iValueLength = 1; + Marshal.WriteByte(mBufferPtr, 0); + bool bSuccess = mUsbDevice.GetPowerPolicy(PowerPolicyType.AutoSuspend, ref iValueLength, mBufferPtr); + if (bSuccess) + return Marshal.ReadByte(mBufferPtr) == 0 ? false : true; + return false; + } + set + { + int iValueLength = 1; + byte bPowerPolicyValue = (value) ? (byte) 1 : (byte) 0; + Marshal.WriteByte(mBufferPtr, bPowerPolicyValue); + mUsbDevice.SetPowerPolicy(PowerPolicyType.AutoSuspend, iValueLength, mBufferPtr); + } + } + + /// + /// The suspend delay policy parameter specifies the minimum amount of time, in milliseconds, that the WinUSB driver must wait after any transfer before it can suspend the device. + /// + public int SuspendDelay + { + get + { + int iValueLength = Marshal.SizeOf(typeof (int)); + Marshal.WriteInt32(mBufferPtr, 0); + bool bSuccess = mUsbDevice.GetPowerPolicy(PowerPolicyType.SuspendDelay, ref iValueLength, mBufferPtr); + if (bSuccess) + return Marshal.ReadInt32(mBufferPtr); + return -1; + } + set + { + int iValueLength = Marshal.SizeOf(typeof (int)); + Marshal.WriteInt32(mBufferPtr, value); + mUsbDevice.SetPowerPolicy(PowerPolicyType.SuspendDelay, iValueLength, mBufferPtr); + } + } + + /// + /// Frees instance resources. + /// + ~PowerPolicies() + { + if (mBufferPtr != IntPtr.Zero) + Marshal.FreeCoTaskMem(mBufferPtr); + + mBufferPtr = IntPtr.Zero; + } + } +} \ No newline at end of file diff --git a/LibWinUsb/WinUsb/PowerPolicyType.cs b/LibWinUsb/WinUsb/PowerPolicyType.cs new file mode 100644 index 0000000..18dff20 --- /dev/null +++ b/LibWinUsb/WinUsb/PowerPolicyType.cs @@ -0,0 +1,30 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +namespace LibUsbDotNet.WinUsb +{ + internal enum PowerPolicyType : byte + { + AutoSuspend = 0x81, + EnableWake = 0x82, + SuspendDelay = 0x83, + } +} \ No newline at end of file diff --git a/LibWinUsb/WinUsb/WinUsbDevice.cs b/LibWinUsb/WinUsb/WinUsbDevice.cs new file mode 100644 index 0000000..55ac2cd --- /dev/null +++ b/LibWinUsb/WinUsb/WinUsbDevice.cs @@ -0,0 +1,317 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using LibUsbDotNet.Descriptors; +using LibUsbDotNet.Internal; +using LibUsbDotNet.Internal.WinUsb; +using LibUsbDotNet.Main; +using LibUsbDotNet.WinUsb.Internal; +using Microsoft.Win32.SafeHandles; + +namespace LibUsbDotNet.WinUsb +{ + /// + /// Contains members specific to Microsofts WinUSB driver. + /// + /// + /// A should be thought of as a part of, or an interface of a USB device. + /// The class does not have members for selecting configurations and + /// intefaces. This is done at a lower level by the winusb driver depending on which interface the + /// belongs to. + /// + public class WinUsbDevice : UsbDevice, IUsbInterface + { + private readonly string mDevicePath; + private PowerPolicies mPowerPolicies; + private SafeFileHandle mSafeDevHandle; + + internal WinUsbDevice(UsbApiBase usbApi, + SafeFileHandle usbHandle, + SafeHandle handle, + string devicePath) + : base(usbApi, handle) + { + mDevicePath = devicePath; + mSafeDevHandle = usbHandle; + mPowerPolicies = new PowerPolicies(this); + } + + /// + /// Gets the power policies for this . + /// + public PowerPolicies PowerPolicy + { + get { return mPowerPolicies; } + } + + /// + /// Gets the device path used to open this . + /// + public string DevicePath + { + get { return mDevicePath; } + } + + #region IUsbInterface Members + + /// + /// Returns the DriverMode this USB device is using. + /// + public override DriverModeType DriverMode + { + get { return DriverModeType.WinUsb; } + } + + /// + /// Closes the and disposes any . + /// + /// True on success. + public override bool Close() + { + if (IsOpen) + { + ActiveEndpoints.Clear(); + mUsbHandle.Close(); + + if (mSafeDevHandle != null) + if (!mSafeDevHandle.IsClosed) + mSafeDevHandle.Close(); + } + return true; + } + + /// + /// Opens the USB device handle. + /// + /// + ///True if the device is already opened or was opened successfully. + ///False if the device does not exists or is no longer valid. + /// + public override bool Open() + { + if (IsOpen) return true; + + SafeFileHandle sfhDev; + + bool bSuccess = WinUsbAPI.OpenDevice(out sfhDev, mDevicePath); + if (bSuccess) + { + SafeWinUsbInterfaceHandle handle = new SafeWinUsbInterfaceHandle(); + if ((bSuccess = WinUsbAPI.WinUsb_Initialize(sfhDev, ref handle))) + { + mSafeDevHandle = sfhDev; + mUsbHandle = handle; + mPowerPolicies = new PowerPolicies(this); + } + else + UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "Open:Initialize", typeof (UsbDevice)); + } + else + UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "Open", typeof(UsbDevice)); + + + return bSuccess; + } + + #endregion + + /// + /// Opens a WinUsb directly from the user supplied device path. + /// + /// Device path (symbolic link) of the WinUsb device to open. + /// Returns an opened WinUsb device on success, null on failure. + /// True on success. + public static bool Open(string devicePath, out WinUsbDevice usbDevice) + { + usbDevice = null; + + SafeFileHandle sfhDev; + + bool bSuccess = WinUsbAPI.OpenDevice(out sfhDev, devicePath); + if (bSuccess) + { + SafeWinUsbInterfaceHandle handle = new SafeWinUsbInterfaceHandle(); + bSuccess = WinUsbAPI.WinUsb_Initialize(sfhDev, ref handle); + if (bSuccess) + { + usbDevice = new WinUsbDevice(WinUsbApi, sfhDev, handle, devicePath); + } + else + UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "Open:Initialize", typeof(UsbDevice)); + } + else + UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "Open", typeof(UsbDevice)); + + + return bSuccess; + } + + /// + /// Gets endpoint policies for the specified endpoint id. + /// + /// The endpoint ID to retrieve for. + /// A class. + public PipePolicies EndpointPolicies(ReadEndpointID epNum) { return new PipePolicies(mUsbHandle, (byte) epNum); } + + /// + /// Gets endpoint policies for the specified endpoint id. + /// + /// The endpoint ID to retrieve for. + /// A class. + public PipePolicies EndpointPolicies(WriteEndpointID epNum) { return new PipePolicies(mUsbHandle, (byte) epNum); } + + /// + /// Gets an interface associated with this . + /// + /// The index to retrieve. (0 = next interface, 1= interface after next, etc.). + /// A new class for the specified AssociatedInterfaceIndex. + /// True on success. + public bool GetAssociatedInterface(byte associatedInterfaceIndex, out WinUsbDevice usbDevice) + { + usbDevice = null; + IntPtr pHandle = IntPtr.Zero; + bool bSuccess = WinUsbAPI.WinUsb_GetAssociatedInterface(mUsbHandle, associatedInterfaceIndex, ref pHandle); + if (bSuccess) + { + SafeWinUsbInterfaceHandle tempHandle = new SafeWinUsbInterfaceHandle(pHandle); + + usbDevice = new WinUsbDevice(mUsbApi, null, tempHandle, mDevicePath); + } + if (!bSuccess) + UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "GetAssociatedInterface", this); + + return bSuccess; + } + + /// + /// Gets the currently selected alternate settings number for the selected inteface. + /// + /// The selected AlternateSetting number. + /// True on success. + public bool GetCurrentAlternateSetting(out byte settingNumber) + { + bool bSuccess; + //settingNumber = 0; + //if (LockDevice() != ErrorCode.None) return false; + + //try + //{ + bSuccess = WinUsbAPI.WinUsb_GetCurrentAlternateSetting(mUsbHandle, out settingNumber); + + if (!bSuccess) + UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "GetCurrentAlternateSetting", this); + //} + //finally + //{ + // UnlockDevice(); + //} + + + return bSuccess; + } + + /// + /// Gets the device speed. + /// + /// The device speed. + /// True on success. + public bool QueryDeviceSpeed(out DeviceSpeedTypes deviceSpeed) + { + deviceSpeed = DeviceSpeedTypes.Undefined; + byte[] buf = new byte[1]; + int uTransferLength = 1; + bool bSuccess = WinUsbAPI.WinUsb_QueryDeviceInformation(mUsbHandle, DeviceInformationTypes.DeviceSpeed, ref uTransferLength, buf); + + if (bSuccess) + { + deviceSpeed = (DeviceSpeedTypes) buf[0]; + } + else + UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "QueryDeviceInformation:QueryDeviceSpeed", this); + + return bSuccess; + } + + /// + /// Gets a for the specified AlternateInterfaceNumber, + /// + /// The alternate interface index for the to retrieve. + /// The for the specified AlternateInterfaceNumber. + /// True on success. + public bool QueryInterfaceSettings(byte alternateInterfaceNumber, ref UsbInterfaceDescriptor usbAltInterfaceDescriptor) + { + bool bSuccess; + //if (mSemDeviceLock != null) + //{ + // if (LockDevice() != ErrorCode.None) return false; + //} + + //try + //{ + bSuccess = WinUsbAPI.WinUsb_QueryInterfaceSettings(Handle, alternateInterfaceNumber, usbAltInterfaceDescriptor); + if (!bSuccess) + UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "QueryInterfaceSettings", this); + //} + //finally + //{ + // if (mSemDeviceLock != null) UnlockDevice(); + //} + + return bSuccess; + } + + internal bool GetPowerPolicy(PowerPolicyType policyType, ref int valueLength, IntPtr pBuffer) + { + bool bSuccess = WinUsbAPI.WinUsb_GetPowerPolicy(mUsbHandle, policyType, ref valueLength, pBuffer); + + if (!bSuccess) + UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "GetPowerPolicy", this); + + return bSuccess; + } + + /// + /// Gets a list a valid, connected WinUSB device inteface paths for the a given WinUSB device interface guid. + /// + /// A WinUSB DeviceInterfaceGUID. This is set in the usb devices inf file when the drivers for it are installed. + /// A list of connected WinUSB device inteface paths. + /// True if one or more device paths were found. False if no devices are found or an error occured. + public static bool GetDevicePathList(Guid interfaceGuid, out List devicePathList) { return WinUsbRegistry.GetDevicePathList(interfaceGuid, out devicePathList); } + + internal bool SetPowerPolicy(PowerPolicyType policyType, int valueLength, IntPtr pBuffer) + { + bool bSuccess = WinUsbAPI.WinUsb_SetPowerPolicy(mUsbHandle, policyType, valueLength, pBuffer); + + if (!bSuccess) + UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "SetPowerPolicy", this); + + return bSuccess; + } + + /// + /// Closes the device. . + /// + ~WinUsbDevice() { Close(); } + } +} \ No newline at end of file diff --git a/LibWinUsb/WinUsb/WinUsbRegistry.cs b/LibWinUsb/WinUsb/WinUsbRegistry.cs new file mode 100644 index 0000000..d7ef561 --- /dev/null +++ b/LibWinUsb/WinUsb/WinUsbRegistry.cs @@ -0,0 +1,518 @@ +// Copyright © 2006-2010 Travis Robinson. All rights reserved. +// +// website: http://sourceforge.net/projects/libusbdotnet +// e-mail: libusbdotnet@gmail.com +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or +// visit www.gnu.org. +// +// +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Runtime.InteropServices; +using System.Text; +using System.Text.RegularExpressions; +using LibUsbDotNet.Internal; +using LibUsbDotNet.Internal.UsbRegex; +using LibUsbDotNet.Main; +using Microsoft.Win32; + +namespace LibUsbDotNet.WinUsb +{ + /// WinUsb specific members for device registry settings. + /// + public class WinUsbRegistry : UsbRegistry + { + private bool mIsDeviceIDParsed; + + private string mDeviceID; + + // Parsed out of the device ID + private byte mInterfaceID; + private ushort mVid; + private ushort mPid; + + /// + /// Gets a list of WinUSB device paths for the specified interface guid. + /// + /// The DeviceInterfaceGUID to search for. + /// A list of device paths associated with the . + /// True of one or more device paths was found. + /// + /// Each device path string in the represents a seperate WinUSB device (interface). + /// + /// + public static bool GetDevicePathList(Guid deviceInterfaceGuid, out List devicePathList) + { + devicePathList = new List(); + int devicePathIndex = 0; + SetupApi.SP_DEVICE_INTERFACE_DATA interfaceData = SetupApi.SP_DEVICE_INTERFACE_DATA.Empty; + SetupApi.DeviceInterfaceDetailHelper detailHelper; + + IntPtr deviceInfo = SetupApi.SetupDiGetClassDevs(ref deviceInterfaceGuid, null, IntPtr.Zero, SetupApi.DICFG.PRESENT | SetupApi.DICFG.DEVICEINTERFACE); + if (deviceInfo != IntPtr.Zero) + { + while ((SetupApi.SetupDiEnumDeviceInterfaces(deviceInfo, null, ref deviceInterfaceGuid, devicePathIndex, ref interfaceData))) + { + int length = 1024; + detailHelper = new SetupApi.DeviceInterfaceDetailHelper(length); + bool bResult = SetupApi.SetupDiGetDeviceInterfaceDetail(deviceInfo, ref interfaceData, detailHelper.Handle, length, out length, null); + if (bResult) devicePathList.Add(detailHelper.DevicePath); + + devicePathIndex++; + } + } + if (devicePathIndex == 0) + UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "GetDevicePathList", typeof(SetupApi)); + + if (deviceInfo != IntPtr.Zero) + SetupApi.SetupDiDestroyDeviceInfoList(deviceInfo); + + return (devicePathIndex > 0); + } + + /// + /// Gets a list of classes for the specified interface guid. + /// + /// The DeviceInterfaceGUID to search for. + /// A list of device paths associated with the . + /// True of one or more device paths was found. + /// + /// Each in the represents a seperate WinUSB device (interface). + /// + public static bool GetWinUsbRegistryList(Guid deviceInterfaceGuid, out List deviceRegistryList) + { + deviceRegistryList = new List(); + + int devicePathIndex = 0; + SetupApi.SP_DEVICE_INTERFACE_DATA interfaceData = SetupApi.SP_DEVICE_INTERFACE_DATA.Empty; + SetupApi.DeviceInterfaceDetailHelper detailHelper; + + SetupApi.SP_DEVINFO_DATA devInfoData = SetupApi.SP_DEVINFO_DATA.Empty; + + // [1] + IntPtr deviceInfo = SetupApi.SetupDiGetClassDevs(ref deviceInterfaceGuid, null, IntPtr.Zero, SetupApi.DICFG.PRESENT | SetupApi.DICFG.DEVICEINTERFACE); + if (deviceInfo != IntPtr.Zero) + { + while ((SetupApi.SetupDiEnumDeviceInterfaces(deviceInfo, null, ref deviceInterfaceGuid, devicePathIndex, ref interfaceData))) + { + int length = 1024; + detailHelper = new SetupApi.DeviceInterfaceDetailHelper(length); + bool bResult = SetupApi.SetupDiGetDeviceInterfaceDetail(deviceInfo, ref interfaceData, detailHelper.Handle, length, out length, ref devInfoData); + if (bResult) + { + WinUsbRegistry regInfo = new WinUsbRegistry(); + + SetupApi.getSPDRPProperties(deviceInfo, ref devInfoData, regInfo.mDeviceProperties); + + // Use the actual winusb device path for SYMBOLIC_NAME_KEY. This will be used to open the device. + regInfo.mDeviceProperties.Add(SYMBOLIC_NAME_KEY, detailHelper.DevicePath); + + //Debug.WriteLine(detailHelper.DevicePath); + + regInfo.mDeviceInterfaceGuids = new Guid[] { deviceInterfaceGuid }; + + StringBuilder sbDeviceID=new StringBuilder(1024); + if (SetupApi.CM_Get_Device_ID(devInfoData.DevInst,sbDeviceID,sbDeviceID.Capacity,0)==SetupApi.CR.SUCCESS) + { + regInfo.mDeviceProperties[DEVICE_ID_KEY] = sbDeviceID.ToString(); + } + deviceRegistryList.Add(regInfo); + } + + devicePathIndex++; + } + } + if (devicePathIndex == 0) + UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "GetDevicePathList", typeof(SetupApi)); + + if (deviceInfo != IntPtr.Zero) + SetupApi.SetupDiDestroyDeviceInfoList(deviceInfo); + + return (devicePathIndex > 0); + } + + internal WinUsbRegistry() { } + + /// + /// Gets a list of available LibUsb devices. + /// + public static List DeviceList + { + get + { + List deviceList = new List(); + SetupApi.EnumClassDevs(null, SetupApi.DICFG.ALLCLASSES | SetupApi.DICFG.PRESENT, WinUsbRegistryCallBack, deviceList); + return deviceList; + } + } + + /// + /// Gets a collection of DeviceInterfaceGuids that are associated with this WinUSB device. + /// + public override Guid[] DeviceInterfaceGuids + { + get + { + return mDeviceInterfaceGuids; + } + } + + /// + /// Check this value to determine if the usb device is still connected to the bus and ready to open. + /// + /// + /// Uses the symbolic name as a unique id to determine if this device instance is still attached. + /// + /// An exception is thrown if the property is null or empty. + public override bool IsAlive + { + get + { + if (String.IsNullOrEmpty(SymbolicName)) throw new UsbException(this, "A symbolic name is required for this property."); + + List deviceList = DeviceList; + foreach (WinUsbRegistry registry in deviceList) + { + if (String.IsNullOrEmpty(registry.SymbolicName)) continue; + + if (registry.SymbolicName == SymbolicName) + return true; + } + return false; + } + } + + /// + /// Opens the USB device for communucation. + /// + /// Return a new instance of the class. + /// If the device fails to open a null refrence is return. For extended error + /// information use the . + /// + public override UsbDevice Device + { + get + { + WinUsbDevice winUsbDevice; + Open(out winUsbDevice); + return winUsbDevice; + } + } + + + private void parseDeviceID() + { + if (mIsDeviceIDParsed) return; + + mIsDeviceIDParsed = true; + + byte bTemp; + ushort uTemp; + + MatchCollection matches = RegHardwareID.GlobalInstance.Matches(DeviceID); + foreach (Match match in matches) + { + foreach (NamedGroup namedGroup in RegHardwareID.NAMED_GROUPS) + { + Group g = match.Groups[namedGroup.GroupNumber]; + if (g.Success) + { + switch ((RegHardwareID.ENamedGroups)namedGroup.GroupNumber) + { + case RegHardwareID.ENamedGroups.Vid: + if (ushort.TryParse(g.Value, NumberStyles.HexNumber, null, out uTemp)) + { + mVid = uTemp; + break; + } + break; + case RegHardwareID.ENamedGroups.Pid: + if (ushort.TryParse(g.Value, NumberStyles.HexNumber, null, out uTemp)) + { + mPid = uTemp; + break; + } + break; + case RegHardwareID.ENamedGroups.Rev: + break; + case RegHardwareID.ENamedGroups.MI: + if (Byte.TryParse(g.Value, NumberStyles.HexNumber, null, out bTemp)) + { + mInterfaceID = bTemp; + break; + } + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + } + + } + } + + /// + /// Gets the device instance id. + /// + /// + /// For more information on device instance ids, see the CM_Get_Device_ID Function at MSDN. + /// + public string DeviceID + { + get + { + if (ReferenceEquals(mDeviceID,null)) + { + object oDeviceID; + if (mDeviceProperties.TryGetValue(DEVICE_ID_KEY, out oDeviceID)) + { + mDeviceID = oDeviceID.ToString(); + } + else + { + mDeviceID = string.Empty; + } + } + return mDeviceID; + } + } + + /// + /// VendorID + /// + /// This value is parsed out of the field. + public override int Vid + { + get + { + parseDeviceID(); + return mVid; + } + } + + /// + /// ProductID + /// + /// This value is parsed out of the field. + public override int Pid + { + get + { + parseDeviceID(); + return mPid; + } + } + + + /// + /// Gets the interface ID this WinUSB device (interface) is associated with. + /// + /// This value is parsed out of the field. + public byte InterfaceID + { + get + { + parseDeviceID(); + return (byte) mInterfaceID; + } + } + + /// + /// Opens the USB device for communucation. + /// + /// The newly created UsbDevice. + /// True on success. + public override bool Open(out UsbDevice usbDevice) + { + usbDevice = null; + WinUsbDevice winUsbDevice; + bool bSuccess = Open(out winUsbDevice); + if (bSuccess) + usbDevice = winUsbDevice; + return bSuccess; + } + + /// + /// Opens the USB device for communucation. + /// + /// Returns an opened WinUsb device on success, null on failure. + /// True on success. + public bool Open(out WinUsbDevice usbDevice) + { + usbDevice = null; + + if (String.IsNullOrEmpty(SymbolicName)) return false; + if (WinUsbDevice.Open(SymbolicName, out usbDevice)) + { + usbDevice.mUsbRegistry = this; + return true; + } + return false; + } + + /* + private static bool WinUsbRegistryCallBack(IntPtr deviceInfoSet, + int deviceIndex, + ref SetupApi.SP_DEVINFO_DATA deviceInfoData, + object classEnumeratorCallbackParam1) + { + + List deviceList = (List) classEnumeratorCallbackParam1; + + RegistryValueKind propertyType; + byte[] propBuffer = new byte[256]; + int requiredSize; + bool isNew = true; + bool bSuccess; + + bSuccess = SetupApi.SetupDiGetCustomDeviceProperty(deviceInfoSet, + ref deviceInfoData, + DEVICE_INTERFACE_GUIDS, + SetupApi.DICUSTOMDEVPROP.NONE, + out propertyType, + propBuffer, + propBuffer.Length, + out requiredSize); + if (bSuccess) + { + string[] devInterfaceGuids = GetAsStringArray(propBuffer, requiredSize); + + foreach (String devInterfaceGuid in devInterfaceGuids) + { + Guid g = new Guid(devInterfaceGuid); + List devicePaths; + if (SetupApi.GetDevicePathList(g, out devicePaths)) + { + foreach (string devicePath in devicePaths) + { + WinUsbRegistry regInfo = new WinUsbRegistry(); + + SetupApi.getSPDRPProperties(deviceInfoSet, ref deviceInfoData, regInfo.mDeviceProperties); + + // Use the actual winusb device path for SYMBOLIC_NAME_KEY. This will be used to open the device. + regInfo.mDeviceProperties.Add(SYMBOLIC_NAME_KEY, devicePath); + + regInfo.mDeviceInterfaceGuids = new Guid[] { g }; + + // Don't add duplicate devices (with the same device path) + WinUsbRegistry foundRegistry=null; + foreach (WinUsbRegistry usbRegistry in deviceList) + { + if (usbRegistry.SymbolicName == regInfo.SymbolicName) + { + foundRegistry = usbRegistry; + break; + } + } + if (foundRegistry == null) + deviceList.Add(regInfo); + else + { + if (isNew) + { + deviceList.Remove(foundRegistry); + deviceList.Add(regInfo); + } + else + { + + // If the device path already exists, add this compatible guid + // to the foundRegstry guid list. + List newGuidList = new List(foundRegistry.mDeviceInterfaceGuids); + if (!newGuidList.Contains(g)) + { + newGuidList.Add(g); + foundRegistry.mDeviceInterfaceGuids = newGuidList.ToArray(); + } + } + } + isNew = false; + } + } + } + } + + return false; + } + */ + private static bool WinUsbRegistryCallBack(IntPtr deviceInfoSet, + int deviceIndex, + ref SetupApi.SP_DEVINFO_DATA deviceInfoData, + object classEnumeratorCallbackParam1) + { + + List deviceList = (List)classEnumeratorCallbackParam1; + + RegistryValueKind propertyType; + byte[] propBuffer = new byte[256]; + int requiredSize; + bool bSuccess; + + bSuccess = SetupApi.SetupDiGetCustomDeviceProperty(deviceInfoSet, + ref deviceInfoData, + DEVICE_INTERFACE_GUIDS, + SetupApi.DICUSTOMDEVPROP.NONE, + out propertyType, + propBuffer, + propBuffer.Length, + out requiredSize); + if (bSuccess) + { + string[] devInterfaceGuids = GetAsStringArray(propBuffer, requiredSize); + + foreach (String devInterfaceGuid in devInterfaceGuids) + { + Guid g = new Guid(devInterfaceGuid); + List tempList; + if (GetWinUsbRegistryList(g, out tempList)) + { + foreach (WinUsbRegistry regInfo in tempList) + { + // Don't add duplicate devices (with the same device path) + WinUsbRegistry foundRegistry = null; + foreach (WinUsbRegistry usbRegistry in deviceList) + { + if (usbRegistry.SymbolicName == regInfo.SymbolicName) + { + foundRegistry = usbRegistry; + break; + } + } + if (foundRegistry == null) + deviceList.Add(regInfo); + else + { + // If the device path already exists, add this compatible guid + // to the foundRegstry guid list. + List newGuidList = new List(foundRegistry.mDeviceInterfaceGuids); + if (!newGuidList.Contains(g)) + { + newGuidList.Add(g); + foundRegistry.mDeviceInterfaceGuids = newGuidList.ToArray(); + } + } + } + } + } + } + + return false; + } + + } +} \ No newline at end of file diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..8b3f96f --- /dev/null +++ b/Program.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net; +using System.Threading; +using System.Net.Sockets; +using System.Diagnostics; +using com.clusterrr.cloverhack; +using System.IO; +using System.Reflection; + +namespace UsbTest +{ + class Program + { + static void Main(string[] args) + { + int result = -1; +//#if DEBUG + Debug.Listeners.Add(new TextWriterTraceListener(System.Console.Error)); +//#endif + using (var nes = new ClovershellConnection()) + { + try + { + if (args.Length == 0) + { + ShowHelp(); + Environment.Exit(-1); + } + var command = args[0].ToLower(); + nes.Enabled = true; + int t = 300; + while (!nes.Online) + { + Thread.Sleep(10); + t--; + if (t == 0) throw new Exception("no clovershell connection"); + } + var ping = nes.Ping(); + if (ping < 0) throw new Exception("connected to NES mini but clovershell is not responding"); + switch (command) + { + case "shell": + nes.ShellEnabled = true; + nes.Autoreconnect = true; + Console.WriteLine("Started shell server on port {0}.", nes.ShellPort); + Console.WriteLine("Connect to it using terminal client (raw mode, no local echo)."); + Console.WriteLine("Press ENTER to stop."); + Console.ReadLine(); + result = 0; + break; + case "exec": + if (args.Length < 2) + { + ShowHelp(); + Environment.Exit(-1); + } + Stream stdin = null; + if (args.Length >= 3) + { + if (args[2] == "null") + stdin = null; + else if (args[2] == "-") + stdin = Console.OpenStandardInput(); + else + stdin = new FileStream(args[2], FileMode.Open); + } + Stream stdout; + if (args.Length >= 4) + { + if (args[3] == "-") + stdout = Console.OpenStandardOutput(); + else if (args[3] == "null") + stdout = null; + else + stdout = new FileStream(args[3], FileMode.Create); + } + else stdout = Console.OpenStandardOutput(); + Stream stderr; + if (args.Length >= 5) + { + if (args[4] == "-") + stderr = Console.OpenStandardError(); + else if (args[4] == "null") + stderr = null; + else + stderr = new FileStream(args[4], FileMode.Create); + } + else stderr = Console.OpenStandardError(); + var s = DateTime.Now; + result = nes.Execute(args[1], stdin, stdout, stderr); + Console.Error.WriteLine("Done in {0}ms. Exit code: {1}", (int)(DateTime.Now - s).TotalMilliseconds, result); + break; + default: + ShowHelp(); + Environment.Exit(-1); + break; + } + } + catch (Exception ex) + { + Console.Error.WriteLine("Error: " + ex.Message); + } +#if DEBUG + //Debug.WriteLine("Done."); + //Console.ReadLine(); +#endif + } + Environment.Exit(result); + } + + static void ShowHelp() + { + Console.WriteLine("clovershell client (c) cluster, 2017"); + Console.WriteLine("Usage: {0} shell\r\nUsage: {0} exec [stdin [stdout [stderr]]]", Path.GetFileName(Assembly.GetExecutingAssembly().CodeBase)); + } + } +} diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..904fb01 --- /dev/null +++ b/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CloverShell")] +[assembly: AssemblyDescription("Client for hakchi mod which allows to access NES Mini's shell, execute commands and transfer files directly via USB, without UART and FEL.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Alexey 'Cluster' Avdyukhin")] +[assembly: AssemblyProduct("CloverShell")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("666f3811-b995-47bf-b9c0-6cff33a06a43")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("0.0.0.1")] +[assembly: AssemblyFileVersion("0.0.0.1")] -- cgit v1.2.3