UsbHid.Mod 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. MODULE UsbHid; (** AUTHOR "staubesv"; PURPOSE "HID device class specific requests"; *)
  2. (**
  3. * Base class for HID class driver.
  4. * Implements the HID class-specific requests and parsing of the HID descriptor.
  5. *
  6. * References:
  7. * Device Class Definition for Human Interface Devices (HID), version 1.11, 27.06.2001, www.usb.org
  8. *
  9. * History:
  10. *
  11. * 20.11.2005 First Release (staubesv)
  12. * 09.01.2006 Adapted to Usb.Mod changes (staubesv)
  13. * 05.07.2006 Adapted to Usbdi (staubesv)
  14. * 23.11.2006 Removed interfaceNumber parameter, added GetHidDescriptor, cleanup (staubesv)
  15. *)
  16. IMPORT KernelLog, Usbdi;
  17. CONST
  18. (** HID Descriptors Types *)
  19. DescriptorHID* = 21H;
  20. DescriptorReport* = 22H;
  21. DescriptorPhysical* = 23H;
  22. (** HID Report Types *)
  23. ReportInput* = 01H;
  24. ReportOutput* = 02H;
  25. ReportFeature* = 03H;
  26. (** HID Protocol Types *)
  27. BootProtocol* = 0;
  28. ReportProtocol* = 1;
  29. (* USB HID Class Specific Request Codes, HID p. 51 *)
  30. HrGetReport = 01H;
  31. HrGetIdle = 02H;
  32. HrGetProtocol = 03H;
  33. HrSetReport = 09H;
  34. HrSetIdle = 0AH;
  35. HrSetProtocol = 0BH;
  36. SrGetDescriptor = 6;
  37. HidSetRequest = Usbdi.ToDevice + Usbdi.Class + Usbdi.Interface;
  38. HidGetRequest = Usbdi.ToHost + Usbdi.Class + Usbdi.Interface;
  39. TYPE
  40. (* HID descriptor according to the Device Class Definition for HID, p. 22 *)
  41. HidDescriptor* = POINTER TO RECORD
  42. bLength- : LONGINT;
  43. bDescriptorType- : LONGINT;
  44. bcdHID- : LONGINT;
  45. bCountryCode- : LONGINT;
  46. bNumDescriptors- : LONGINT;
  47. bClassDescriptorType- : LONGINT;
  48. wDescriptorLength- : LONGINT;
  49. optionalDescriptors- : POINTER TO ARRAY OF OptionalDescriptor;
  50. END;
  51. OptionalDescriptor* = RECORD
  52. bDescriptorType- : LONGINT;
  53. wDescriptorLength- : LONGINT;
  54. END;
  55. TYPE
  56. (* Base class of HID device drivers. Provides the HID class specific requests. *)
  57. HidDriver* = OBJECT(Usbdi.Driver);
  58. (** HID class specific device requests *)
  59. (**
  60. * The SetIdle request silinces a particular report on the Interrupt In pipe until a new event occurs or
  61. * the specified amount of time passes (HID, p.52)
  62. * @param interface Related USB device interface
  63. * @param duration: 0: infinite, 1-255: value * 4ms
  64. * @reportId 0: idle rate applies to all reports, otherwise it applies only to reports with the corresponding reportId
  65. * @return TRUE, if requests succeeds, FALSE otherwise
  66. *)
  67. PROCEDURE SetIdle*(reportId, duration : LONGINT) : BOOLEAN;
  68. BEGIN
  69. ASSERT(interface.bInterfaceClass = 3H);
  70. RETURN device.Request(HidSetRequest, HrSetIdle, reportId + duration*100H, interface.bInterfaceNumber, 0, Usbdi.NoData) = Usbdi.Ok;
  71. END SetIdle;
  72. (**
  73. * The GetIdle request reads the current idle rate for a particular input report. See HID p. 52
  74. * @param interface Related USB device interface
  75. * @param reportId
  76. * @param idle Idle rate; 0: infinite duration, otherwise: idle rate in milliseconds; Only valid then request succeeded!
  77. * @return TRUE, if request succeeded, FALSE otherwise
  78. *)
  79. PROCEDURE GetIdle*(reportId : LONGINT; VAR idle : LONGINT) : BOOLEAN;
  80. VAR buffer : Usbdi.BufferPtr;
  81. BEGIN
  82. ASSERT(interface.bInterfaceClass = 3H);
  83. NEW(buffer, 1);
  84. IF device.Request(HidGetRequest, HrGetIdle, reportId, interface.bInterfaceNumber, 1, buffer) = Usbdi.Ok THEN
  85. idle := 4*ORD(buffer[0]);
  86. RETURN TRUE;
  87. END;
  88. RETURN FALSE;
  89. END GetIdle;
  90. (**
  91. * The SetProtocol request switches between the boot protocol and the report protocol (HID p. 54).
  92. * This request is only supported by devices in the boot subclass. Default is the Report Protocol.
  93. * @param interface the request should be applied to
  94. * @param protocol 0: Boot Protocol, 1: Report Protocol
  95. * @return TRUE, if request succeeded, FALSE otherwise
  96. *)
  97. PROCEDURE SetProtocol*(protocol : LONGINT) : BOOLEAN;
  98. BEGIN
  99. ASSERT(interface.bInterfaceClass = 3H);
  100. ASSERT(((protocol = BootProtocol) OR (protocol = ReportProtocol)) & (interface.bInterfaceSubClass = 1));
  101. RETURN device.Request(HidSetRequest, HrSetProtocol, protocol, interface.bInterfaceNumber, 0, Usbdi.NoData) = Usbdi.Ok ;
  102. END SetProtocol;
  103. (**
  104. * The Getprotocol requests reads which protocol is currently active (HID, p. 54).
  105. * This request is only supported by devices in the boot subclass.
  106. * @param interface the request should be applied to
  107. * @param protocol 0: Boot Protocol, 1: Report Protocol (Only valid if request succeeds!)
  108. * @return TRUE, if request succeeded, FALSE otherwise
  109. *)
  110. PROCEDURE GetProtocol*(VAR protocol : LONGINT) : BOOLEAN;
  111. VAR buffer : Usbdi.BufferPtr;
  112. BEGIN
  113. IF (interface.bInterfaceClass # 3H) OR (interface.bInterfaceSubClass # 1) THEN
  114. TRACE(interface.bInterfaceClass, interface.bInterfaceSubClass); RETURN FALSE
  115. END;
  116. ASSERT((interface.bInterfaceClass = 3H) & (interface.bInterfaceSubClass= 1));
  117. NEW(buffer, 1);
  118. IF device.Request(HidGetRequest, HrGetProtocol, 0, interface.bInterfaceNumber, 1, buffer) = Usbdi.Ok THEN
  119. protocol := ORD(buffer[0]);
  120. RETURN TRUE;
  121. END;
  122. RETURN FALSE;
  123. END GetProtocol;
  124. (**
  125. * The SetReport request allows the host to send a report to the device, possibly setting the state of input,
  126. * output, or feature controls (HID, p. 52).
  127. * @param interface the request should be applied to
  128. * @param type of the report the host sends
  129. * @param id of the report the host sends
  130. * @param buffer: Buffer containing the report
  131. * @param len: Lenght of the report
  132. * @return TRUE, if request succeeded, FALSE otherwise
  133. *)
  134. PROCEDURE SetReport*(type, id : LONGINT; VAR buffer: Usbdi.Buffer; len : LONGINT) : BOOLEAN;
  135. BEGIN
  136. ASSERT(interface.bInterfaceClass = 3H);
  137. RETURN device.Request(HidSetRequest, HrSetReport, id + type*100H, interface.bInterfaceNumber, len, buffer) = Usbdi.Ok;
  138. END SetReport;
  139. (**
  140. * The GetReport request allows the host to receive a report via the Control pipe (HID, p.51)
  141. * @param interface the request should be applied to
  142. * @param type Type of the report we want
  143. * @param id of the report we want
  144. * @param buffer: Buffer to put the report into
  145. * @param len: Exspected length of the report
  146. * @return TRUE, if request succeeded, FALSE otherwise
  147. *)
  148. PROCEDURE GetReport*(type, id : LONGINT; VAR buffer: Usbdi.Buffer; len : LONGINT) : BOOLEAN;
  149. BEGIN
  150. ASSERT(LEN(buffer) >= len);
  151. ASSERT(interface.bInterfaceClass = 3H);
  152. RETURN device.Request(HidGetRequest, HrGetReport, id + type*100H, interface.bInterfaceNumber, len, buffer) = Usbdi.Ok;
  153. END GetReport;
  154. (** This request returns the specified descriptor if the descriptor exists *)
  155. PROCEDURE GetDescriptor*(descriptor, index, wIndex, len : LONGINT; VAR buffer : Usbdi.Buffer) : BOOLEAN;
  156. BEGIN
  157. ASSERT(LEN(buffer) >= len);
  158. RETURN device.Request(Usbdi.ToHost + Usbdi.Standard + Usbdi.Interface, SrGetDescriptor, index + descriptor*100H, wIndex, len, buffer) = Usbdi.Ok;
  159. END GetDescriptor;
  160. (** Returns the HID descriptor of this interface or NIL if not present *)
  161. PROCEDURE GetHidDescriptor*() : HidDescriptor;
  162. VAR ud : Usbdi.UnknownDescriptor; hidDescriptor : HidDescriptor;
  163. BEGIN
  164. ASSERT(interface.bInterfaceClass = 3H);
  165. (* The HID descriptor is part of the configuration descriptor and therefore already pre-parsed by the USB system *)
  166. ud := interface.unknown;
  167. WHILE (ud # NIL) & (ud.bDescriptorType # DescriptorHID) DO ud := ud.next; END;
  168. IF ud # NIL THEN
  169. hidDescriptor := ParseHidDescriptor(ud.descriptor);
  170. END;
  171. RETURN hidDescriptor;
  172. END GetHidDescriptor;
  173. END HidDriver;
  174. (* Load and parse the HID descriptor correspondig to the drivers interface *)
  175. PROCEDURE ParseHidDescriptor(descriptor : Usbdi.BufferPtr) : HidDescriptor;
  176. VAR hid : HidDescriptor; i : LONGINT;
  177. BEGIN
  178. IF (descriptor # NIL) & (LEN(descriptor) >= 8) THEN
  179. NEW(hid);
  180. hid.bLength := ORD(descriptor[0]);
  181. hid.bDescriptorType := ORD(descriptor[1]);
  182. hid.bcdHID := ORD(descriptor[2]) + 100H*ORD(descriptor[3]);
  183. hid.bCountryCode := ORD(descriptor[4]);
  184. hid.bNumDescriptors := ORD(descriptor[5]);
  185. hid.bClassDescriptorType := ORD(descriptor[6]);
  186. hid.wDescriptorLength := ORD(descriptor[7]);
  187. (* Parse the optional descriptors if there are some *)
  188. IF hid.bNumDescriptors > 1 THEN
  189. IF LEN(descriptor) >= (3 * (hid.bNumDescriptors-2)) + 7 THEN
  190. KernelLog.String("UsbHid: Warning: HID descriptor too short"); KernelLog.Ln;
  191. RETURN hid;
  192. END;
  193. NEW(hid.optionalDescriptors, hid.bNumDescriptors-1);
  194. FOR i := 0 TO hid.bNumDescriptors-2 DO
  195. hid.optionalDescriptors[i].bDescriptorType := ORD(descriptor[(3 * i) + 6]);
  196. hid.optionalDescriptors[i].wDescriptorLength := ORD(descriptor[(3 * i) + 7]);
  197. END;
  198. END;
  199. END;
  200. RETURN hid;
  201. END ParseHidDescriptor;
  202. PROCEDURE ShowHidDescriptor*(hd : HidDescriptor);
  203. VAR i : LONGINT;
  204. BEGIN
  205. KernelLog.String("HID Descriptor: ");
  206. IF hd = NIL THEN KernelLog.String("NIL"); END; KernelLog.Ln;
  207. KernelLog.String(" bLength: "); KernelLog.Int(hd.bLength, 0); KernelLog.Ln;
  208. KernelLog.String(" bDescriptorType: "); KernelLog.Int(hd.bDescriptorType, 0);
  209. KernelLog.String(" bcdHID: "); KernelLog.Hex(hd.bcdHID, 0); KernelLog.Char("H"); KernelLog.Ln;
  210. KernelLog.String(" bCountryCode: "); KernelLog.Hex(hd.bCountryCode, 0); KernelLog.Char("H"); KernelLog.Ln;
  211. KernelLog.String(" bNumDescriptors: "); KernelLog.Int(hd.bNumDescriptors, 0); KernelLog.Ln;
  212. KernelLog.String(" bClassDescriptorType: "); KernelLog.Int(hd.bClassDescriptorType, 0); KernelLog.Ln;
  213. KernelLog.String(" wDescriptorLength: "); KernelLog.Int(hd.wDescriptorLength, 0); KernelLog.Ln;
  214. KernelLog.String(" Optional descriptors: ");
  215. IF (hd.optionalDescriptors = NIL) THEN
  216. KernelLog.String("None"); KernelLog.Ln;
  217. ELSE
  218. FOR i := 0 TO LEN(hd.optionalDescriptors)-1 DO
  219. KernelLog.String(" bDescriptorType: "); KernelLog.Int(hd.optionalDescriptors[i].bDescriptorType, 0);
  220. KernelLog.String(", wDescriptorLength: "); KernelLog.Int(hd.optionalDescriptors[i].wDescriptorLength, 0);
  221. KernelLog.Ln;
  222. END;
  223. END;
  224. END ShowHidDescriptor;
  225. END UsbHid.