123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 |
- MODULE UsbHid; (** AUTHOR "staubesv"; PURPOSE "HID device class specific requests"; *)
- (**
- * Base class for HID class driver.
- * Implements the HID class-specific requests and parsing of the HID descriptor.
- *
- * References:
- * Device Class Definition for Human Interface Devices (HID), version 1.11, 27.06.2001, www.usb.org
- *
- * History:
- *
- * 20.11.2005 First Release (staubesv)
- * 09.01.2006 Adapted to Usb.Mod changes (staubesv)
- * 05.07.2006 Adapted to Usbdi (staubesv)
- * 23.11.2006 Removed interfaceNumber parameter, added GetHidDescriptor, cleanup (staubesv)
- *)
- IMPORT KernelLog, Usbdi;
- CONST
- (** HID Descriptors Types *)
- DescriptorHID* = 21H;
- DescriptorReport* = 22H;
- DescriptorPhysical* = 23H;
- (** HID Report Types *)
- ReportInput* = 01H;
- ReportOutput* = 02H;
- ReportFeature* = 03H;
- (** HID Protocol Types *)
- BootProtocol* = 0;
- ReportProtocol* = 1;
- (* USB HID Class Specific Request Codes, HID p. 51 *)
- HrGetReport = 01H;
- HrGetIdle = 02H;
- HrGetProtocol = 03H;
- HrSetReport = 09H;
- HrSetIdle = 0AH;
- HrSetProtocol = 0BH;
- SrGetDescriptor = 6;
- HidSetRequest = Usbdi.ToDevice + Usbdi.Class + Usbdi.Interface;
- HidGetRequest = Usbdi.ToHost + Usbdi.Class + Usbdi.Interface;
- TYPE
- (* HID descriptor according to the Device Class Definition for HID, p. 22 *)
- HidDescriptor* = POINTER TO RECORD
- bLength- : LONGINT;
- bDescriptorType- : LONGINT;
- bcdHID- : LONGINT;
- bCountryCode- : LONGINT;
- bNumDescriptors- : LONGINT;
- bClassDescriptorType- : LONGINT;
- wDescriptorLength- : LONGINT;
- optionalDescriptors- : POINTER TO ARRAY OF OptionalDescriptor;
- END;
- OptionalDescriptor* = RECORD
- bDescriptorType- : LONGINT;
- wDescriptorLength- : LONGINT;
- END;
- TYPE
- (* Base class of HID device drivers. Provides the HID class specific requests. *)
- HidDriver* = OBJECT(Usbdi.Driver);
- (** HID class specific device requests *)
- (**
- * The SetIdle request silinces a particular report on the Interrupt In pipe until a new event occurs or
- * the specified amount of time passes (HID, p.52)
- * @param interface Related USB device interface
- * @param duration: 0: infinite, 1-255: value * 4ms
- * @reportId 0: idle rate applies to all reports, otherwise it applies only to reports with the corresponding reportId
- * @return TRUE, if requests succeeds, FALSE otherwise
- *)
- PROCEDURE SetIdle*(reportId, duration : LONGINT) : BOOLEAN;
- BEGIN
- ASSERT(interface.bInterfaceClass = 3H);
- RETURN device.Request(HidSetRequest, HrSetIdle, reportId + duration*100H, interface.bInterfaceNumber, 0, Usbdi.NoData) = Usbdi.Ok;
- END SetIdle;
- (**
- * The GetIdle request reads the current idle rate for a particular input report. See HID p. 52
- * @param interface Related USB device interface
- * @param reportId
- * @param idle Idle rate; 0: infinite duration, otherwise: idle rate in milliseconds; Only valid then request succeeded!
- * @return TRUE, if request succeeded, FALSE otherwise
- *)
- PROCEDURE GetIdle*(reportId : LONGINT; VAR idle : LONGINT) : BOOLEAN;
- VAR buffer : Usbdi.BufferPtr;
- BEGIN
- ASSERT(interface.bInterfaceClass = 3H);
- NEW(buffer, 1);
- IF device.Request(HidGetRequest, HrGetIdle, reportId, interface.bInterfaceNumber, 1, buffer) = Usbdi.Ok THEN
- idle := 4*ORD(buffer[0]);
- RETURN TRUE;
- END;
- RETURN FALSE;
- END GetIdle;
- (**
- * The SetProtocol request switches between the boot protocol and the report protocol (HID p. 54).
- * This request is only supported by devices in the boot subclass. Default is the Report Protocol.
- * @param interface the request should be applied to
- * @param protocol 0: Boot Protocol, 1: Report Protocol
- * @return TRUE, if request succeeded, FALSE otherwise
- *)
- PROCEDURE SetProtocol*(protocol : LONGINT) : BOOLEAN;
- BEGIN
- ASSERT(interface.bInterfaceClass = 3H);
- ASSERT(((protocol = BootProtocol) OR (protocol = ReportProtocol)) & (interface.bInterfaceSubClass = 1));
- RETURN device.Request(HidSetRequest, HrSetProtocol, protocol, interface.bInterfaceNumber, 0, Usbdi.NoData) = Usbdi.Ok ;
- END SetProtocol;
- (**
- * The Getprotocol requests reads which protocol is currently active (HID, p. 54).
- * This request is only supported by devices in the boot subclass.
- * @param interface the request should be applied to
- * @param protocol 0: Boot Protocol, 1: Report Protocol (Only valid if request succeeds!)
- * @return TRUE, if request succeeded, FALSE otherwise
- *)
- PROCEDURE GetProtocol*(VAR protocol : LONGINT) : BOOLEAN;
- VAR buffer : Usbdi.BufferPtr;
- BEGIN
- IF (interface.bInterfaceClass # 3H) OR (interface.bInterfaceSubClass # 1) THEN
- TRACE(interface.bInterfaceClass, interface.bInterfaceSubClass); RETURN FALSE
- END;
- ASSERT((interface.bInterfaceClass = 3H) & (interface.bInterfaceSubClass= 1));
- NEW(buffer, 1);
- IF device.Request(HidGetRequest, HrGetProtocol, 0, interface.bInterfaceNumber, 1, buffer) = Usbdi.Ok THEN
- protocol := ORD(buffer[0]);
- RETURN TRUE;
- END;
- RETURN FALSE;
- END GetProtocol;
- (**
- * The SetReport request allows the host to send a report to the device, possibly setting the state of input,
- * output, or feature controls (HID, p. 52).
- * @param interface the request should be applied to
- * @param type of the report the host sends
- * @param id of the report the host sends
- * @param buffer: Buffer containing the report
- * @param len: Lenght of the report
- * @return TRUE, if request succeeded, FALSE otherwise
- *)
- PROCEDURE SetReport*(type, id : LONGINT; VAR buffer: Usbdi.Buffer; len : LONGINT) : BOOLEAN;
- BEGIN
- ASSERT(interface.bInterfaceClass = 3H);
- RETURN device.Request(HidSetRequest, HrSetReport, id + type*100H, interface.bInterfaceNumber, len, buffer) = Usbdi.Ok;
- END SetReport;
- (**
- * The GetReport request allows the host to receive a report via the Control pipe (HID, p.51)
- * @param interface the request should be applied to
- * @param type Type of the report we want
- * @param id of the report we want
- * @param buffer: Buffer to put the report into
- * @param len: Exspected length of the report
- * @return TRUE, if request succeeded, FALSE otherwise
- *)
- PROCEDURE GetReport*(type, id : LONGINT; VAR buffer: Usbdi.Buffer; len : LONGINT) : BOOLEAN;
- BEGIN
- ASSERT(LEN(buffer) >= len);
- ASSERT(interface.bInterfaceClass = 3H);
- RETURN device.Request(HidGetRequest, HrGetReport, id + type*100H, interface.bInterfaceNumber, len, buffer) = Usbdi.Ok;
- END GetReport;
- (** This request returns the specified descriptor if the descriptor exists *)
- PROCEDURE GetDescriptor*(descriptor, index, wIndex, len : LONGINT; VAR buffer : Usbdi.Buffer) : BOOLEAN;
- BEGIN
- ASSERT(LEN(buffer) >= len);
- RETURN device.Request(Usbdi.ToHost + Usbdi.Standard + Usbdi.Interface, SrGetDescriptor, index + descriptor*100H, wIndex, len, buffer) = Usbdi.Ok;
- END GetDescriptor;
- (** Returns the HID descriptor of this interface or NIL if not present *)
- PROCEDURE GetHidDescriptor*() : HidDescriptor;
- VAR ud : Usbdi.UnknownDescriptor; hidDescriptor : HidDescriptor;
- BEGIN
- ASSERT(interface.bInterfaceClass = 3H);
- (* The HID descriptor is part of the configuration descriptor and therefore already pre-parsed by the USB system *)
- ud := interface.unknown;
- WHILE (ud # NIL) & (ud.bDescriptorType # DescriptorHID) DO ud := ud.next; END;
- IF ud # NIL THEN
- hidDescriptor := ParseHidDescriptor(ud.descriptor);
- END;
- RETURN hidDescriptor;
- END GetHidDescriptor;
- END HidDriver;
- (* Load and parse the HID descriptor correspondig to the drivers interface *)
- PROCEDURE ParseHidDescriptor(descriptor : Usbdi.BufferPtr) : HidDescriptor;
- VAR hid : HidDescriptor; i : LONGINT;
- BEGIN
- IF (descriptor # NIL) & (LEN(descriptor) >= 8) THEN
- NEW(hid);
- hid.bLength := ORD(descriptor[0]);
- hid.bDescriptorType := ORD(descriptor[1]);
- hid.bcdHID := ORD(descriptor[2]) + 100H*ORD(descriptor[3]);
- hid.bCountryCode := ORD(descriptor[4]);
- hid.bNumDescriptors := ORD(descriptor[5]);
- hid.bClassDescriptorType := ORD(descriptor[6]);
- hid.wDescriptorLength := ORD(descriptor[7]);
- (* Parse the optional descriptors if there are some *)
- IF hid.bNumDescriptors > 1 THEN
- IF LEN(descriptor) >= (3 * (hid.bNumDescriptors-2)) + 7 THEN
- KernelLog.String("UsbHid: Warning: HID descriptor too short"); KernelLog.Ln;
- RETURN hid;
- END;
- NEW(hid.optionalDescriptors, hid.bNumDescriptors-1);
- FOR i := 0 TO hid.bNumDescriptors-2 DO
- hid.optionalDescriptors[i].bDescriptorType := ORD(descriptor[(3 * i) + 6]);
- hid.optionalDescriptors[i].wDescriptorLength := ORD(descriptor[(3 * i) + 7]);
- END;
- END;
- END;
- RETURN hid;
- END ParseHidDescriptor;
- PROCEDURE ShowHidDescriptor*(hd : HidDescriptor);
- VAR i : LONGINT;
- BEGIN
- KernelLog.String("HID Descriptor: ");
- IF hd = NIL THEN KernelLog.String("NIL"); END; KernelLog.Ln;
- KernelLog.String(" bLength: "); KernelLog.Int(hd.bLength, 0); KernelLog.Ln;
- KernelLog.String(" bDescriptorType: "); KernelLog.Int(hd.bDescriptorType, 0);
- KernelLog.String(" bcdHID: "); KernelLog.Hex(hd.bcdHID, 0); KernelLog.Char("H"); KernelLog.Ln;
- KernelLog.String(" bCountryCode: "); KernelLog.Hex(hd.bCountryCode, 0); KernelLog.Char("H"); KernelLog.Ln;
- KernelLog.String(" bNumDescriptors: "); KernelLog.Int(hd.bNumDescriptors, 0); KernelLog.Ln;
- KernelLog.String(" bClassDescriptorType: "); KernelLog.Int(hd.bClassDescriptorType, 0); KernelLog.Ln;
- KernelLog.String(" wDescriptorLength: "); KernelLog.Int(hd.wDescriptorLength, 0); KernelLog.Ln;
- KernelLog.String(" Optional descriptors: ");
- IF (hd.optionalDescriptors = NIL) THEN
- KernelLog.String("None"); KernelLog.Ln;
- ELSE
- FOR i := 0 TO LEN(hd.optionalDescriptors)-1 DO
- KernelLog.String(" bDescriptorType: "); KernelLog.Int(hd.optionalDescriptors[i].bDescriptorType, 0);
- KernelLog.String(", wDescriptorLength: "); KernelLog.Int(hd.optionalDescriptors[i].wDescriptorLength, 0);
- KernelLog.Ln;
- END;
- END;
- END ShowHidDescriptor;
- END UsbHid.
|