internal void CommonWrite(byte[] buffer, int offset, int count, Queue <CommonOutputReport> queue, bool feature, int maxOutputReportLength) { Throw.If.OutOfRange(buffer, offset, count); count = Math.Min(count, maxOutputReportLength); if (count == 0) { return; } int writeTimeout = WriteTimeout; int startTime = Environment.TickCount; int timeout; HandleAcquireIfOpenOrFail(); try { lock (queue) { while (true) { if (queue.Count == 0) { byte[] packet = new byte[count]; Array.Copy(buffer, offset, packet, 0, count); var outputReport = new CommonOutputReport { Bytes = packet, Feature = feature }; queue.Enqueue(outputReport); Monitor.PulseAll(queue); while (true) { if (outputReport.Done) { if (!outputReport.DoneOK) { throw new IOException(); } return; } timeout = GetTimeout(startTime, writeTimeout); if (!Monitor.Wait(queue, timeout)) { throw new TimeoutException(); } } } timeout = GetTimeout(startTime, writeTimeout); if (!Monitor.Wait(queue, timeout)) { throw new TimeoutException(); } } } } finally { HandleRelease(); } }
unsafe void WriteThread() { if (!HandleAcquire()) { return; } try { lock (_outputQueue) { while (true) { while (!_shutdown && _outputQueue.Count == 0) { Monitor.Wait(_outputQueue); } if (_shutdown) { break; } NativeMethods.IOReturn ret; CommonOutputReport outputReport = _outputQueue.Peek(); try { fixed(byte *outputReportBytes = outputReport.Bytes) { Monitor.Exit(_outputQueue); try { ret = NativeMethods.IOHIDDeviceSetReport(_handle, outputReport.Feature ? NativeMethods.IOHIDReportType.Feature : NativeMethods.IOHIDReportType.Output, (IntPtr)outputReport.Bytes[0], (IntPtr)outputReportBytes, (IntPtr)outputReport.Bytes.Length); if (ret == NativeMethods.IOReturn.Success) { outputReport.DoneOK = true; } } finally { Monitor.Enter(_outputQueue); } } } finally { _outputQueue.Dequeue(); outputReport.Done = true; Monitor.PulseAll(_outputQueue); } } } } finally { HandleRelease(); } }
unsafe void WriteThread() { if (!HandleAcquire()) { return; } try { lock (_outputQueue) { while (true) { while (!_shutdown && _outputQueue.Count == 0) { Monitor.Wait(_outputQueue); } if (_shutdown) { break; } CommonOutputReport outputReport = _outputQueue.Peek(); byte[] outputBytesRaw = outputReport.Bytes; // Linux doesn't expect a Report ID if the device doesn't use one. //if (!((LinuxHidDevice)Device).ReportsUseID && outputBytesRaw.Length > 0) { outputBytesRaw = outputBytesRaw.Skip(1).ToArray(); } // BUGFIX: Yes, it does. But only on write(). (HIDSharp 2.0.2) try { fixed(byte *outputBytes = outputBytesRaw) { // hidraw is apparently blocking for output, even when O_NONBLOCK is used. // See for yourself at drivers/hid/hidraw.c... IntPtr length; Monitor.Exit(_outputQueue); try { var outputBytesPtr = (IntPtr)outputBytes; length = NativeMethods.retry(() => NativeMethods.write (_handle, outputBytesPtr, (UIntPtr)outputBytesRaw.Length)); if ((long)length == outputBytesRaw.Length) { outputReport.DoneOK = true; } } finally { Monitor.Enter(_outputQueue); } } } finally { _outputQueue.Dequeue(); outputReport.Done = true; Monitor.PulseAll(_outputQueue); } } } } finally { HandleRelease(); } }
unsafe void WriteThread() { if (!HandleAcquire()) { return; } try { lock (_outputQueue) { while (true) { while (!_shutdown && _outputQueue.Count == 0) { Monitor.Wait(_outputQueue); } if (_shutdown) { break; } NativeMethods.IOReturn ret; CommonOutputReport outputReport = _outputQueue.Peek(); try { fixed(byte *outputReportBytes = outputReport.Bytes) { Monitor.Exit(_outputQueue); try { int reportID = outputReport.Bytes[0]; var hasReportID = ((MacHidDevice)Device).ReportsUseID; int reportOffset = hasReportID ? 0 : 1; var reportPtr = (IntPtr)(outputReportBytes + reportOffset); int reportLength = outputReport.Bytes.Length - reportOffset; if (reportLength > 0) { ret = NativeMethods.IOHIDDeviceSetReport(_handle, outputReport.Feature ? NativeMethods.IOHIDReportType.Feature : NativeMethods.IOHIDReportType.Output, (IntPtr)reportID, reportPtr, (IntPtr)reportLength); if (ret == NativeMethods.IOReturn.Success) { outputReport.DoneOK = true; } } } finally { Monitor.Enter(_outputQueue); } } } finally { _outputQueue.Dequeue(); outputReport.Done = true; Monitor.PulseAll(_outputQueue); } } } } finally { HandleRelease(); } }
internal void CommonWrite(byte[] buffer, int offset, int count, Queue<CommonOutputReport> queue, bool feature, int maxOutputReportLength) { Throw.If.OutOfRange(buffer, offset, count); count = Math.Min(count, maxOutputReportLength); if (count == 0) { return; } int writeTimeout = WriteTimeout; int startTime = Environment.TickCount; int timeout; HandleAcquireIfOpenOrFail(); try { lock (queue) { while (true) { if (queue.Count == 0) { byte[] packet = new byte[count]; Array.Copy(buffer, offset, packet, 0, count); var outputReport = new CommonOutputReport() { Bytes = packet, Feature = feature }; queue.Enqueue(outputReport); Monitor.PulseAll(queue); while (true) { if (outputReport.Done) { if (!outputReport.DoneOK) { throw new IOException(); } return; } timeout = GetTimeout(startTime, writeTimeout); if (!Monitor.Wait(queue, timeout)) { throw new TimeoutException(); } } } timeout = GetTimeout(startTime, writeTimeout); if (!Monitor.Wait(queue, timeout)) { throw new TimeoutException(); } } } } finally { HandleRelease(); } }