MODULE UsbHid;
IMPORT KernelLog, Usbdi;
CONST
DescriptorHID* = 21H;
DescriptorReport* = 22H;
DescriptorPhysical* = 23H;
ReportInput* = 01H;
ReportOutput* = 02H;
ReportFeature* = 03H;
BootProtocol* = 0;
ReportProtocol* = 1;
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
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
HidDriver* = OBJECT(Usbdi.Driver);
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;
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;
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;
PROCEDURE GetProtocol*(VAR protocol : LONGINT) : BOOLEAN;
VAR buffer : Usbdi.BufferPtr;
BEGIN
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;
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;
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;
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;
PROCEDURE GetHidDescriptor*() : HidDescriptor;
VAR ud : Usbdi.UnknownDescriptor; hidDescriptor : HidDescriptor;
BEGIN
ASSERT(interface.bInterfaceClass = 3H);
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;
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]);
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.