Mercurial > hg > ucis.core
diff USBLib/Communication/LibUsb0/LibUsbDevice.cs @ 21:dcfec2be27c9
Added USBLib
author | Ivo Smits <Ivo@UCIS.nl> |
---|---|
date | Mon, 15 Apr 2013 01:04:59 +0200 |
parents | |
children | 053cc617af54 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBLib/Communication/LibUsb0/LibUsbDevice.cs Mon Apr 15 01:04:59 2013 +0200 @@ -0,0 +1,264 @@ +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Threading; +using Microsoft.Win32.SafeHandles; +using UCIS.USBLib.Internal.Windows; + +namespace UCIS.USBLib.Communication.LibUsb { + public class LibUsb0Device : UsbInterface, IUsbDevice { + //private readonly List<int> mClaimedInterfaces = new List<int>(); + public string DeviceFilename { get; private set; } + public IUsbDeviceRegistry Registry { get; private set; } + private SafeFileHandle DeviceHandle; + + public LibUsb0Device(String path, LibUsb0Registry registry) { + DeviceFilename = path; + this.Registry = registry; + DeviceHandle = Kernel32.CreateFile(DeviceFilename, + NativeFileAccess.SPECIAL, + NativeFileShare.NONE, + IntPtr.Zero, + NativeFileMode.OPEN_EXISTING, + NativeFileFlag.FILE_FLAG_OVERLAPPED, + IntPtr.Zero); + if (DeviceHandle.IsInvalid || DeviceHandle.IsClosed) throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not open device"); + } + public override void Close() { + if (DeviceHandle != null) DeviceHandle.Close(); + } + + public override Byte Configuration { + get { return base.Configuration; } + set { + ControlWrite( + UsbControlRequestType.EndpointOut | UsbControlRequestType.TypeStandard | UsbControlRequestType.RecipDevice, + (byte)UsbStandardRequest.SetConfiguration, + value, + 0, null, 0, 0); + } + } + + public void ClaimInterface(int interfaceID) { + LibUsbRequest req = new LibUsbRequest(); + req.Iface.ID = interfaceID; + req.Timeout = UsbConstants.DEFAULT_TIMEOUT; + int ret; + DeviceIoControl(DeviceHandle, LibUsbIoCtl.CLAIM_INTERFACE, ref req, LibUsbRequest.Size, null, 0, out ret); + } + public void ReleaseInterface(int interfaceID) { + LibUsbRequest req = new LibUsbRequest(); + req.Iface.ID = interfaceID; + req.Timeout = UsbConstants.DEFAULT_TIMEOUT; + int ret; + DeviceIoControl(DeviceHandle, LibUsbIoCtl.RELEASE_INTERFACE, ref req, LibUsbRequest.Size, null, 0, out ret); + } + public void SetAltInterface(int interfaceID, int alternateID) { + LibUsbRequest req = new LibUsbRequest(); + req.Iface.ID = interfaceID; + req.Iface.AlternateID = alternateID; + req.Timeout = UsbConstants.DEFAULT_TIMEOUT; + int ret; + DeviceIoControl(DeviceHandle, LibUsbIoCtl.SET_INTERFACE, ref req, LibUsbRequest.Size, null, 0, out ret); + } + public void ResetDevice() { + LibUsbRequest req = new LibUsbRequest(); + req.Timeout = UsbConstants.DEFAULT_TIMEOUT; + int ret; + DeviceIoControl(DeviceHandle, LibUsbIoCtl.RESET_DEVICE, ref req, LibUsbRequest.Size, null, 0, out ret); + } + public unsafe override int GetDescriptor(byte descriptorType, byte index, short langId, byte[] buffer, int offset, int length) { + if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer length"); + LibUsbRequest req = new LibUsbRequest(); + req.Descriptor.Index = index; + req.Descriptor.LangID = langId; + req.Descriptor.Recipient = (byte)UsbEndpointDirection.EndpointIn & 0x1F; + req.Descriptor.Type = descriptorType; + req.Timeout = UsbConstants.DEFAULT_TIMEOUT; + int ret; + fixed (Byte* b = buffer) { + DeviceIoControl(DeviceHandle, LibUsbIoCtl.GET_DESCRIPTOR, ref req, LibUsbRequest.Size, (IntPtr)(b + offset), length, out ret); + } + return ret; + } + public override int BulkRead(byte endpoint, byte[] buffer, int offset, int length) { + return PipeTransfer(endpoint, false, false, buffer, offset, length, 0); + } + public override int BulkWrite(byte endpoint, byte[] buffer, int offset, int length) { + return PipeTransfer(endpoint, true, false, buffer, offset, length, 0); + } + public override int InterruptRead(byte endpoint, byte[] buffer, int offset, int length) { + return PipeTransfer(endpoint, false, false, buffer, offset, length, 0); + } + public override int InterruptWrite(byte endpoint, byte[] buffer, int offset, int length) { + return PipeTransfer(endpoint, true, false, buffer, offset, length, 0); + } + public unsafe override int ControlRead(UsbControlRequestType requestType, byte request, short value, short index, byte[] buffer, int offset, int length) { + if (buffer == null) buffer = new Byte[0]; + if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer length"); + int code; + LibUsbRequest req = new LibUsbRequest(); + PrepareControlTransfer(requestType, request, value, index, length, ref req, out code); + int ret; + fixed (Byte* b = buffer) { + DeviceIoControl(DeviceHandle, code, ref req, LibUsbRequest.Size, (IntPtr)(b + offset), length, out ret); + } + return ret; + } + public unsafe override int ControlWrite(UsbControlRequestType requestType, byte request, short value, short index, byte[] buffer, int offset, int length) { + Byte[] inbuffer = new Byte[length + LibUsbRequest.Size]; + if (length > 0) Buffer.BlockCopy(buffer, offset, inbuffer, LibUsbRequest.Size, length); + int code; + fixed (Byte* inbufferp = inbuffer) + PrepareControlTransfer(requestType, request, value, index, length, ref *((LibUsbRequest*)inbufferp), out code); + int ret; + DeviceIoControl(DeviceHandle, code, inbuffer, length + LibUsbRequest.Size, null, 0, out ret); + return length; + //ret -= LibUsbRequest.Size; + //if (ret <= 0) return 0; + //return ret; + } + void PrepareControlTransfer(UsbControlRequestType requestType, byte request, short value, short index, int length, ref LibUsbRequest req, out int code) { + code = LibUsbIoCtl.CONTROL_TRANSFER; + req.Timeout = UsbConstants.DEFAULT_TIMEOUT; + req.Control.RequestType = (Byte)requestType; + req.Control.Request = request; + req.Control.Value = (ushort)value; + req.Control.Index = (ushort)index; + req.Control.Length = (ushort)length; + switch ((UsbControlRequestType)((int)requestType & (0x03 << 5))) { + case UsbControlRequestType.TypeStandard: + switch ((UsbStandardRequest)request) { + case UsbStandardRequest.GetStatus: + req.Status.Recipient = (int)requestType & 0x1F; + req.Status.Index = index; + code = LibUsbIoCtl.GET_STATUS; + break; + case UsbStandardRequest.ClearFeature: + req.Feature.Recipient = (int)requestType & 0x1F; + req.Feature.ID = value; + req.Feature.Index = index; + code = LibUsbIoCtl.CLEAR_FEATURE; + break; + case UsbStandardRequest.SetFeature: + req.Feature.Recipient = (int)requestType & 0x1F; + req.Feature.ID = value; + req.Feature.Index = index; + code = LibUsbIoCtl.SET_FEATURE; + break; + case UsbStandardRequest.GetDescriptor: + req.Descriptor.Recipient = (int)requestType & 0x1F; + req.Descriptor.Type = (value >> 8) & 0xFF; + req.Descriptor.Index = value & 0xFF; + req.Descriptor.LangID = index; + code = LibUsbIoCtl.GET_DESCRIPTOR; + break; + case UsbStandardRequest.SetDescriptor: + req.Descriptor.Recipient = (int)requestType & 0x1F; + req.Descriptor.Type = (value >> 8) & 0xFF; + req.Descriptor.Index = value & 0xFF; + req.Descriptor.LangID = index; + code = LibUsbIoCtl.SET_DESCRIPTOR; + break; + case UsbStandardRequest.GetConfiguration: + code = LibUsbIoCtl.GET_CONFIGURATION; + break; + case UsbStandardRequest.SetConfiguration: + req.Config.ID = value; + code = LibUsbIoCtl.SET_CONFIGURATION; + break; + case UsbStandardRequest.GetInterface: + req.Iface.ID = index; + code = LibUsbIoCtl.GET_INTERFACE; + break; + case UsbStandardRequest.SetInterface: + req.Iface.ID = index; + req.Iface.AlternateID = value; + code = LibUsbIoCtl.SET_INTERFACE; + break; + default: + throw new ArgumentException(String.Format("Invalid request: 0x{0:X8}", request)); + } + break; + case UsbControlRequestType.TypeVendor: + case UsbControlRequestType.TypeClass: + req.Vendor.Type = ((byte)requestType >> 5) & 0x03; + req.Vendor.Recipient = (int)requestType & 0x1F; + req.Vendor.Request = (int)request; + req.Vendor.ID = value; + req.Vendor.Index = index; + code = ((byte)requestType & 0x80) != 0 ? LibUsbIoCtl.VENDOR_READ : LibUsbIoCtl.VENDOR_WRITE; + break; + case UsbControlRequestType.TypeReserved: + default: + throw new ArgumentException(String.Format("Invalid or unsupported request type: 0x{0:X8}", requestType)); + } + } + + unsafe int PipeTransfer(Byte epnum, Boolean write, Boolean isochronous, Byte[] buffer, int offset, int length, int packetsize) { + if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer length"); + LibUsbRequest req = new LibUsbRequest(); + req.Endpoint.ID = epnum; + req.Endpoint.PacketSize = packetsize; + req.Timeout = UsbConstants.DEFAULT_TIMEOUT; + fixed (Byte* b = buffer) { + if (write) { + int cltCode = isochronous ? LibUsbIoCtl.ISOCHRONOUS_WRITE : LibUsbIoCtl.INTERRUPT_OR_BULK_WRITE; + int transfered = 0; + while (length > 0) { + int ret; + DeviceIoControl(DeviceHandle, cltCode, ref req, LibUsbRequest.Size, (IntPtr)(b + offset), Math.Min(Int16.MaxValue, length), out ret); + if (ret <= 0) throw new System.IO.EndOfStreamException(); + length -= ret; + offset += ret; + transfered += ret; + } + return transfered; + } else { + int cltCode = isochronous ? LibUsbIoCtl.ISOCHRONOUS_READ : LibUsbIoCtl.INTERRUPT_OR_BULK_READ; + int ret; + DeviceIoControl(DeviceHandle, cltCode, ref req, LibUsbRequest.Size, (IntPtr)(b + offset), Math.Min(UInt16.MaxValue, length), out ret); + return ret; + } + } + } + public void PipeReset(byte pipeID) { + LibUsbRequest req = new LibUsbRequest(); + req.Endpoint.ID = pipeID; + req.Timeout = UsbConstants.DEFAULT_TIMEOUT; + int ret; + DeviceIoControl(DeviceHandle, LibUsbIoCtl.RESET_ENDPOINT, ref req, LibUsbRequest.Size, null, 0, out ret); + } + + private unsafe void DeviceIoControl(SafeHandle hDevice, int IoControlCode, [In] ref LibUsbRequest InBuffer, int nInBufferSize, Byte[] OutBuffer, int nOutBufferSize, out int pBytesReturned) { + fixed (LibUsbRequest* InBufferPtr = &InBuffer) { + fixed (Byte* OutBufferPtr = OutBuffer) { + DeviceIoControl(hDevice, IoControlCode, (IntPtr)InBufferPtr, nInBufferSize, (IntPtr)OutBufferPtr, nOutBufferSize, out pBytesReturned); + } + } + } + private unsafe void DeviceIoControl(SafeHandle hDevice, int IoControlCode, Byte[] InBuffer, int nInBufferSize, Byte[] OutBuffer, int nOutBufferSize, out int pBytesReturned) { + fixed (Byte* InBufferPtr = InBuffer, OutBufferPtr = OutBuffer) { + DeviceIoControl(hDevice, IoControlCode, (IntPtr)InBufferPtr, nInBufferSize, (IntPtr)OutBufferPtr, nOutBufferSize, out pBytesReturned); + } + } + private unsafe void DeviceIoControl(SafeHandle hDevice, int IoControlCode, [In] ref LibUsbRequest InBuffer, int nInBufferSize, IntPtr OutBuffer, int nOutBufferSize, out int pBytesReturned) { + fixed (LibUsbRequest* InBufferPtr = &InBuffer) { + DeviceIoControl(hDevice, IoControlCode, (IntPtr)InBufferPtr, nInBufferSize, OutBuffer, nOutBufferSize, out pBytesReturned); + } + } + private unsafe void DeviceIoControl(SafeHandle hDevice, int IoControlCode, IntPtr InBuffer, int nInBufferSize, IntPtr OutBuffer, int nOutBufferSize, out int pBytesReturned) { + using (ManualResetEvent evt = new ManualResetEvent(false)) { + NativeOverlapped overlapped = new NativeOverlapped(); + overlapped.EventHandle = evt.SafeWaitHandle.DangerousGetHandle(); + if (Kernel32.DeviceIoControl(hDevice, IoControlCode, InBuffer, nInBufferSize, OutBuffer, nOutBufferSize, out pBytesReturned, &overlapped)) + return; + int err = Marshal.GetLastWin32Error(); + if (err != 997) throw new Win32Exception(err); + evt.WaitOne(); + if (!Kernel32.GetOverlappedResult(hDevice, &overlapped, out pBytesReturned, false)) + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + } + } +} \ No newline at end of file