NativeMethods.cs 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. #region License
  2. /* Copyright 2012-2013 James F. Bellinger <http://www.zer7.com/software/hidsharp>
  3. Permission to use, copy, modify, and/or distribute this software for any
  4. purpose with or without fee is hereby granted, provided that the above
  5. copyright notice and this permission notice appear in all copies.
  6. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  7. WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  8. MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  9. ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  10. WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  11. ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  12. OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
  13. #endregion
  14. using System;
  15. using System.Globalization;
  16. using System.Linq;
  17. using System.Reflection;
  18. using System.Runtime.InteropServices;
  19. namespace HidSharp.Platform.Linux
  20. {
  21. static class NativeMethods
  22. {
  23. const string libc = "libc";
  24. const string libudev = "libudev.so.0";
  25. public enum error
  26. {
  27. OK = 0,
  28. EPERM = 1,
  29. EINTR = 4,
  30. EIO = 5,
  31. ENXIO = 6,
  32. EBADF = 9,
  33. EAGAIN = 11,
  34. EACCES = 13,
  35. EBUSY = 16,
  36. ENODEV = 19,
  37. EINVAL = 22
  38. }
  39. [Flags]
  40. public enum oflag
  41. {
  42. RDONLY = 0x000,
  43. WRONLY = 0x001,
  44. RDWR = 0x002,
  45. CREAT = 0x040,
  46. EXCL = 0x080,
  47. TRUNC = 0x200,
  48. APPEND = 0x400,
  49. NONBLOCK = 0x800
  50. }
  51. [Flags]
  52. public enum pollev : short
  53. {
  54. IN = 0x01,
  55. PRI = 0x02,
  56. OUT = 0x04,
  57. ERR = 0x08,
  58. HUP = 0x10,
  59. NVAL = 0x20
  60. }
  61. public struct pollfd
  62. {
  63. public int fd;
  64. public pollev events;
  65. public pollev revents;
  66. }
  67. public static int retry(Func<int> sysfunc)
  68. {
  69. while (true)
  70. {
  71. int ret = sysfunc(); var error = (error)Marshal.GetLastWin32Error();
  72. if (ret >= 0 || error != error.EINTR) { return ret; }
  73. }
  74. }
  75. public static IntPtr retry(Func<IntPtr> sysfunc)
  76. {
  77. while (true)
  78. {
  79. IntPtr ret = sysfunc(); var error = (error)Marshal.GetLastWin32Error();
  80. if ((long)ret >= 0 || error != error.EINTR) { return ret; }
  81. }
  82. }
  83. public static bool uname(out string sysname, out Version release, out string machine)
  84. {
  85. string releaseStr; release = null;
  86. if (!uname(out sysname, out releaseStr, out machine)) { return false; }
  87. releaseStr = new string(releaseStr.Trim().TakeWhile(ch => (ch >= '0' && ch <= '9') || ch == '.').ToArray());
  88. release = new Version(releaseStr);
  89. return true;
  90. }
  91. public static bool uname(out string sysname, out string release, out string machine)
  92. {
  93. sysname = null; release = null; machine = null;
  94. string syscallPath = "Mono.Unix.Native.Syscall, Mono.Posix, PublicKeyToken=0738eb9f132ed756";
  95. var syscall = Type.GetType(syscallPath);
  96. if (syscall == null) { return false; }
  97. var unameArgs = new object[1];
  98. int unameRet = (int)syscall.InvokeMember("uname",
  99. BindingFlags.InvokeMethod | BindingFlags.Static, null, null, unameArgs,
  100. CultureInfo.InvariantCulture);
  101. if (unameRet < 0) { return false; }
  102. var uname = unameArgs[0];
  103. Func<string, string> getMember = s => (string)uname.GetType().InvokeMember(s,
  104. BindingFlags.GetField, null, uname, new object[0],
  105. CultureInfo.InvariantCulture);
  106. sysname = getMember("sysname"); release = getMember("release"); machine = getMember("machine");
  107. return true;
  108. }
  109. [DllImport(libc, SetLastError = true)]
  110. public static extern int open(
  111. [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string filename,
  112. oflag oflag);
  113. [DllImport(libc, SetLastError = true)]
  114. public static extern int close(int filedes);
  115. [DllImport(libc, SetLastError = true)]
  116. public static extern IntPtr read(int filedes, IntPtr buffer, IntPtr size);
  117. [DllImport(libc, SetLastError = true)]
  118. public static extern IntPtr write(int filedes, IntPtr buffer, IntPtr size);
  119. [DllImport(libc, SetLastError = true)]
  120. public static extern int poll(pollfd[] fds, IntPtr nfds, int timeout);
  121. [DllImport(libudev)]
  122. public static extern IntPtr udev_new();
  123. [DllImport(libudev)]
  124. public static extern IntPtr udev_ref(IntPtr udev);
  125. [DllImport(libudev)]
  126. public static extern void udev_unref(IntPtr udev);
  127. [DllImport(libudev)]
  128. public static extern IntPtr udev_enumerate_new(IntPtr udev);
  129. [DllImport(libudev)]
  130. public static extern IntPtr udev_enumerate_ref(IntPtr enumerate);
  131. [DllImport(libudev)]
  132. public static extern void udev_enumerate_unref(IntPtr enumerate);
  133. [DllImport(libudev)]
  134. public static extern int udev_enumerate_add_match_subsystem(IntPtr enumerate,
  135. [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string subsystem);
  136. [DllImport(libudev)]
  137. public static extern int udev_enumerate_scan_devices(IntPtr enumerate);
  138. [DllImport(libudev)]
  139. public static extern IntPtr udev_enumerate_get_list_entry(IntPtr enumerate);
  140. [DllImport(libudev)]
  141. public static extern IntPtr udev_list_entry_get_next(IntPtr entry);
  142. [DllImport(libudev)]
  143. [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]
  144. public static extern string udev_list_entry_get_name(IntPtr entry);
  145. [DllImport(libudev)]
  146. public static extern IntPtr udev_device_new_from_syspath(IntPtr udev,
  147. [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string syspath);
  148. [DllImport(libudev)]
  149. public static extern IntPtr udev_device_ref(IntPtr device);
  150. [DllImport(libudev)]
  151. public static extern void udev_device_unref(IntPtr device);
  152. [DllImport(libudev)]
  153. [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]
  154. public static extern string udev_device_get_devnode(IntPtr device);
  155. [DllImport(libudev)]
  156. public static extern IntPtr udev_device_get_parent_with_subsystem_devtype(IntPtr device,
  157. [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string subsystem,
  158. [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string devtype);
  159. [DllImport(libudev)]
  160. [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]
  161. public static extern string udev_device_get_sysattr_value(IntPtr device,
  162. [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string sysattr);
  163. public static bool TryParseHex(string hex, out int result)
  164. {
  165. return int.TryParse(hex, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out result);
  166. }
  167. public static bool TryParseVersion(string version, out int major, out int minor)
  168. {
  169. major = 0; minor = 0; if (version == null) { return false; }
  170. string[] parts = version.Split(new[] { '.' }, 2); if (parts.Length != 2) { return false; }
  171. return int.TryParse(parts[0], out major) && int.TryParse(parts[1], out minor);
  172. }
  173. #region ioctl
  174. // TODO: Linux changes these up depending on platform. Eventually we'll handle it.
  175. // For now, x86 and ARM are safe with this definition.
  176. public const int IOC_NONE = 0;
  177. public const int IOC_WRITE = 1;
  178. public const int IOC_READ = 2;
  179. public const int IOC_NRBITS = 8;
  180. public const int IOC_TYPEBITS = 8;
  181. public const int IOC_SIZEBITS = 14;
  182. public const int IOC_DIRBITS = 2;
  183. public const int IOC_NRSHIFT = 0;
  184. public const int IOC_TYPESHIFT = IOC_NRSHIFT + IOC_NRBITS;
  185. public const int IOC_SIZESHIFT = IOC_TYPESHIFT + IOC_TYPEBITS;
  186. public const int IOC_DIRSHIFT = IOC_SIZESHIFT + IOC_SIZEBITS;
  187. public static int IOC(int dir, int type, int nr, int size)
  188. {
  189. return dir << IOC_DIRSHIFT | type << IOC_TYPESHIFT | nr << IOC_NRSHIFT | size << IOC_SIZESHIFT;
  190. }
  191. #region hidraw
  192. public const int HID_MAX_DESCRIPTOR_SIZE = 4096;
  193. public static readonly int HIDIOCGRDESCSIZE = IOC(IOC_READ, (byte)'H', 1, 4);
  194. public static readonly int HIDIOCGRDESC = IOC(IOC_READ, (byte)'H', 2, Marshal.SizeOf(typeof(hidraw_report_descriptor)));
  195. public struct hidraw_report_descriptor
  196. {
  197. public uint size;
  198. [MarshalAs(UnmanagedType.ByValArray, SizeConst = HID_MAX_DESCRIPTOR_SIZE)]
  199. public byte[] value;
  200. }
  201. [DllImport(libc, SetLastError = true)]
  202. public static extern int ioctl(int filedes, int command, out uint value);
  203. [DllImport(libc, SetLastError = true)]
  204. public static extern int ioctl(int filedes, int command, ref hidraw_report_descriptor value);
  205. #endregion
  206. #endregion
  207. }
  208. }