MODULE UsbHidDriver;
IMPORT
SYSTEM, Machine, KernelLog, Modules, Inputs, Usbdi, UsbHid,
HidParser := UsbHidParser, UsbHidReport, UsagePage := UsbHidUP, UsbKeyboard,
Joystick := Joysticks;
CONST
Name = "UsbHid";
Description = "USB HID driver";
Debug = HidParser.Debug;
Trace = HidParser.Trace;
ShowNoReport = 0;
ShowVeryShortReport = 1;
ShowShortReport = 2;
ShowFullReport = 3;
LoggingMode = ShowNoReport;
MouseSpeed = 50;
MouseWheelSpeed = 3;
MouseAcceleration = 0;
TYPE
MouseState = POINTER TO RECORD
buttons: ARRAY 32 OF UsbHidReport.UsageTuple;
buttonCount: LONGINT;
buttonReport: UsbHidReport.HidReport;
x: UsbHidReport.UsageTuple;
y: UsbHidReport.UsageTuple;
axisReport: UsbHidReport.HidReport;
wheel: UsbHidReport.UsageTuple;
wheelReport: UsbHidReport.HidReport;
lastDx, lastDy: LONGINT;
END;
KeyboardState = OBJECT(UsbKeyboard.KeyboardBase);
VAR
modifierUsages: UsbHidReport.PtrToUsageTupleArr;
keycodeUsages: UsbHidReport.PtrToUsageTupleArr;
pressed* : POINTER TO ARRAY OF UsbKeyboard.Key;
tempPressed : POINTER TO ARRAY OF UsbKeyboard.Key;
ledStateChanged : BOOLEAN;
PROCEDURE Init;
VAR i : SYSTEM.ADDRESS; k : ARRAY 32 OF CHAR;
BEGIN
Machine.GetConfig("Keyboard", k);
i := -1;
IF k # "" THEN i := TableFromFile(k); END;
IF i = -1 THEN i := UsbKeyboard.TableUS(); END;
SYSTEM.PUT(SYSTEM.ADR(keytable), i);
Machine.GetConfig("NumLock", k);
IF k[0] = "1" THEN INCL(leds, UsbKeyboard.NumLock) END;
keyDeadTime := UsbKeyboard.KeyDeadTime DIV 10;
keyDeadTimeRepeat := UsbKeyboard.KeyDeadTimeRepeat DIV 10;
NEW(ledBuffer, 1);
END Init;
PROCEDURE SetMaxKeycodes(nofKeys: LONGINT);
BEGIN
ASSERT(pressed=NIL);
ASSERT(tempPressed=NIL);
NEW(pressed,nofKeys);
NEW(tempPressed, nofKeys);
END SetMaxKeycodes;
PROCEDURE HandleKeyboardEvent;
VAR
i, j : LONGINT;
c : CHAR;
flags : SET;
found, kill : BOOLEAN;
BEGIN
msg.flags := {};
IF (modifierUsages[0].usageValue=1) THEN INCL(msg.flags, Inputs.LeftCtrl) END;
IF (modifierUsages[1].usageValue=1) THEN INCL(msg.flags, Inputs.LeftShift) END;
IF (modifierUsages[2].usageValue=1) THEN INCL(msg.flags, Inputs.LeftAlt) END;
IF (modifierUsages[3].usageValue=1) THEN INCL(msg.flags, Inputs.LeftMeta) END;
IF (modifierUsages[4].usageValue=1) THEN INCL(msg.flags, Inputs.RightCtrl) END;
IF (modifierUsages[5].usageValue=1) THEN INCL(msg.flags, Inputs.RightShift) END;
IF (modifierUsages[6].usageValue=1) THEN INCL(msg.flags, Inputs.RightAlt) END;
IF (modifierUsages[7].usageValue=1) THEN INCL(msg.flags, Inputs.RightMeta) END;
flags := msg.flags;
FOR i := 2 TO 7 DO
c := SYSTEM.VAL(CHAR, keycodeUsages[i-2].usageValue);
IF c # CHR(0) THEN
FOR j := 0 TO 5 DO
IF pressed[j].ch = c THEN
found := TRUE;
pressed[j].updated := TRUE;
tempPressed[i-2].counter := pressed[j].counter + 1;
tempPressed[i-2].ch := pressed[j].ch;
tempPressed[i-2].keysym := pressed[j].keysym;
tempPressed[i-2].updated := FALSE;
tempPressed[i-2].repeat := pressed[j].repeat;
IF pressed[j].repeat THEN
IF (keyDeadTimeRepeat # 0) & (tempPressed[i-2].counter MOD keyDeadTimeRepeat # 0) THEN kill := TRUE; END;
ELSE
IF tempPressed[i-2].counter MOD keyDeadTime # 0 THEN
kill := TRUE;
ELSE
tempPressed[i-2].repeat := TRUE;
END;
END;
END;
END;
END;
IF ~found THEN
tempPressed[i-2].ch := c;
tempPressed[i-2].repeat := FALSE;
tempPressed[i-2].updated := FALSE;
tempPressed[i-2].counter := 1;
END;
IF (c # CHR(0)) & ~kill THEN
HandleKey(c);
tempPressed[i-2].keysym := msg.keysym;
END;
END;
FOR i := 0 TO 5 DO
IF (pressed[i].updated = FALSE) & (pressed[i].ch # CHR(0)) THEN
msg.flags := {};
INCL(msg.flags, Inputs.Release);
msg.ch := pressed[i].ch;
msg.keysym := pressed[i].keysym;
dkHack := deadKey;
HandleKey(c);
deadKey := dkHack;
END;
pressed[i].counter := tempPressed[i].counter;
pressed[i].ch := tempPressed[i].ch;
pressed[i].keysym := tempPressed[i].keysym;
pressed[i].repeat := tempPressed[i].repeat;
pressed[i].updated := FALSE;
END;
HandleModifiers(flags);
IF lastLeds # leds THEN
ledBuffer[0] := SYSTEM.VAL(CHAR, leds); lastLeds := leds;
ledStateChanged := TRUE;
END;
END HandleKeyboardEvent;
END KeyboardState;
ConsumerKey = POINTER TO RECORD
key: LONGINT;
usagePage: LONGINT;
alive: BOOLEAN;
next: ConsumerKey;
END;
ConsumerState= OBJECT
VAR
consumerReport : UsbHidReport.HidReport;
first: ConsumerKey;
PROCEDURE IsSet(usageID, usagePage: LONGINT): BOOLEAN;
VAR cursor: ConsumerKey;
BEGIN
cursor := first;
WHILE(cursor#NIL) DO
IF ((cursor.key=usageID) & (cursor.usagePage=usagePage)) THEN
cursor.alive := TRUE;
RETURN TRUE;
END;
cursor := cursor.next;
END;
RETURN FALSE;
END IsSet;
PROCEDURE AddKey(tuple:UsbHidReport.UsageTuple);
VAR cursor: ConsumerKey;
BEGIN
IF first=NIL THEN
NEW(first);
ELSE
NEW(cursor);
cursor.next := first;
first := cursor;
END;
first.key := tuple.usageID;
first.usagePage := tuple.usagePage;
first.alive := TRUE;
END AddKey;
PROCEDURE CleanUp;
VAR cursor, previous: ConsumerKey;
BEGIN
cursor := first;
WHILE(cursor#NIL) DO
IF cursor.alive = FALSE THEN
SendKeySym(cursor.key,cursor.usagePage,FALSE);
IF(cursor = first) THEN
first := first.next;
ELSE
previous.next := cursor.next;
END;
ELSE
cursor.alive := FALSE;
previous := cursor;
END;
cursor := cursor.next;
END;
END CleanUp;
PROCEDURE SendKeySym(usage, usagePage:LONGINT; pressed:BOOLEAN);
VAR keyMsg : Inputs.KeyboardMsg;
BEGIN
IF Debug THEN
KernelLog.String("Handling key");
END;
IF (usagePage=0) THEN
CASE usage OF
0B5H: keyMsg.keysym := Inputs.KsScanNextTrack;
|0B6H: keyMsg.keysym := Inputs.KsScanPreviousTrack;
|0B7H: keyMsg.keysym := Inputs.KsStopOSC;
|0CDH: keyMsg.keysym := Inputs.KsPlayPause;
|0E2H: keyMsg.keysym := Inputs.KsMute;
|0E9H: keyMsg.keysym := Inputs.KsVolumeIncrement;
|0EAH: keyMsg.keysym := Inputs.KsVolumeDecrement;
|183H: keyMsg.keysym := Inputs.KsALConsumerControl;
|18AH: keyMsg.keysym := Inputs.KsALEmailReader;
|221H: keyMsg.keysym := Inputs.KsACSearch;
|223H: keyMsg.keysym := Inputs.KsACHome;
|224H: keyMsg.keysym := Inputs.KsACBack;
|225H: keyMsg.keysym := Inputs.KsACForward;
|22AH: keyMsg.keysym := Inputs.KsACBookmarks;
ELSE
IF Trace THEN
KernelLog.String("Key Sym "); KernelLog.Hex(usage,0 ); KernelLog.String("H not found"); KernelLog.Ln;
END;
END;
ELSE
IF (usagePage=9H) THEN
keyMsg.keysym := Inputs.KsConsumerButtons+usage;
END;
END;
IF (keyMsg.keysym#0) THEN
IF ~pressed THEN
keyMsg.flags:= {};
keyMsg.keysym := Inputs.KsNil;
INCL(keyMsg.flags, Inputs.Release);
END;
IF Debug THEN
IF usagePage=0 THEN
CASE usage OF
0B5H: KernelLog.String("KsScanNextTrack");
|0B6H: KernelLog.String("KsScanPreviousTrack");
|0B7H: KernelLog.String("KsStopOSC");
|0CDH: KernelLog.String("KsPlayPause");
|0E2H: KernelLog.String("KsMute");
|0E9H: KernelLog.String("KsVolumeIncrement");
|0EAH: KernelLog.String("KsVolumeDecrement");
|183H: KernelLog.String("KsALConsumerControl");
|18AH: KernelLog.String("KsALEmailReader");
|192H: KernelLog.String("KsALCalculator");
|221H: KernelLog.String("KsACSearch");
|223H: KernelLog.String("KsACHome");
|224H: KernelLog.String("KsACBack");
|225H: KernelLog.String("KsACForward");
|22AH: KernelLog.String("KsACBookmarks");
ELSE
KernelLog.String("Key Sym not found"); KernelLog.Ln;
END;
ELSE
IF usagePage=9 THEN
KernelLog.String("KsConsumerButtons(");KernelLog.Int(usage,0); KernelLog.String(")");
END;
END;
IF pressed THEN
KernelLog.String(" pressed");
ELSE
KernelLog.String(" released");
END;
KernelLog.Ln;
END;
Inputs.keyboard.Handle(keyMsg);
END;
END SendKeySym;
END ConsumerState;
JoystickState = POINTER TO RECORD
buttons: ARRAY 32 OF UsbHidReport.UsageTuple;
buttonCount: LONGINT;
buttonReport: UsbHidReport.HidReport;
x: UsbHidReport.UsageTuple;
y: UsbHidReport.UsageTuple;
z: UsbHidReport.UsageTuple;
rx: UsbHidReport.UsageTuple;
ry: UsbHidReport.UsageTuple;
rz: UsbHidReport.UsageTuple;
slider: UsbHidReport.UsageTuple;
hatSwitch: UsbHidReport.UsageTuple;
xReport: UsbHidReport.HidReport;
yReport: UsbHidReport.HidReport;
zReport: UsbHidReport.HidReport;
rxReport: UsbHidReport.HidReport;
ryReport: UsbHidReport.HidReport;
rzReport: UsbHidReport.HidReport;
sliderReport: UsbHidReport.HidReport;
hatSwitchReport: UsbHidReport.HidReport;
joystick: Joystick.Joystick;
END;
HidDriver= OBJECT (UsbHid.HidDriver);
VAR
itemParser : HidParser.ItemParser;
endpoint : LONGINT;
pipe : Usbdi.Pipe;
reportBuffer : Usbdi.BufferPtr;
reportManager : UsbHidReport.HidReportManager;
hidReportItemQueue : UsbHidReport.ReportItemQueue;
mouseState : MouseState;
keyboardState : KeyboardState;
consumerState : ConsumerState;
joystickState : JoystickState;
useReportIDMechanism : BOOLEAN;
PROCEDURE Connect() : BOOLEAN;
VAR
hidDescriptor : UsbHid.HidDescriptor;
i : LONGINT;
reportDescBuffer : Usbdi.BufferPtr;
status : Usbdi.Status;
canManage : BOOLEAN;
BEGIN
NEW(itemParser);
hidDescriptor := GetHidDescriptor();
IF (hidDescriptor = NIL) THEN
RETURN FALSE;
END;
IF Debug THEN UsbHid.ShowHidDescriptor(hidDescriptor); END;
NEW(reportDescBuffer, hidDescriptor.wDescriptorLength);
IF ~GetDescriptor(hidDescriptor.bClassDescriptorType, 0, interface.bInterfaceNumber , hidDescriptor.wDescriptorLength, reportDescBuffer^) THEN
KernelLog.String(" Could not get reportDescriptor"); KernelLog.Ln;
RETURN FALSE;
ELSE
IF Debug THEN
LayoutBuffer(reportDescBuffer^, hidDescriptor.wDescriptorLength);
END;
END;
IF(~itemParser.ParseReportDescriptor(hidDescriptor, reportDescBuffer)) THEN
IF Debug THEN KernelLog.String(" Could not parse Report Descriptor correctly"); KernelLog.Ln; END;
END;
IF Trace THEN
itemParser.errorList.PrintAll;
END;
reportManager := itemParser.GetReportManager();
hidReportItemQueue := reportManager.GetReportItemQueue();
LOOP
IF i >= LEN(interface.endpoints) THEN EXIT; END;
IF (interface.endpoints[i].type = Usbdi.InterruptIn) THEN
endpoint := SHORT(SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, interface.endpoints[0].bEndpointAddress) * {0,1,2,3,7}));
EXIT;
END;
INC(i);
END;
IF endpoint = 0 THEN
IF Debug THEN KernelLog.String("UsbMouse: No interrupt IN endpoint found."); KernelLog.Ln; END;
RETURN FALSE;
END;
pipe := device.GetPipe(endpoint);
IF pipe = NIL THEN RETURN FALSE END;
IF InitializeMouseDriver() = TRUE THEN
canManage := TRUE;
END;
IF InitializeKeyboardDriver()=TRUE THEN
canManage := TRUE;
END;
IF InitializeConsumerDriver() = TRUE THEN
canManage := TRUE;
END;
IF InitializeJoystickDriver()=TRUE THEN
canManage := TRUE;
END;
IF (canManage) THEN
useReportIDMechanism := reportManager.UsesReportIDMechanism();
NEW(reportBuffer, pipe.maxPacketSize);
pipe.SetTimeout(0);
pipe.SetCompletionHandler(HandleHidEvent);
status := pipe.Transfer(pipe.maxPacketSize, 0, reportBuffer^);
IF Debug THEN
KernelLog.String("UsbHidDriver.HidDriver.Connect: Connect successfully finished"); KernelLog.Ln;
END;
END;
RETURN TRUE;
END Connect;
PROCEDURE Disconnect;
BEGIN
itemParser.Disconnect();
itemParser:=NIL;
IF (joystickState#NIL) THEN
IF joystickState.joystick#NIL THEN
Joystick.registry.Remove(joystickState.joystick);
END;
END;
IF Debug OR Trace THEN KernelLog.String("USB HID Device disconnected."); KernelLog.Ln; END;
END Disconnect;
PROCEDURE HandleHidEvent(status : Usbdi.Status; actLen : LONGINT);
VAR
ri : UsbHidReport.ReportItem;
i, bitIndex : LONGINT;
reportID : LONGINT;
res : BOOLEAN;
usageTuple : UsbHidReport.UsageTuple;
PROCEDURE HandleReportItem;
BEGIN
FOR i:=0 TO (ri.reportItemCount-1) DO
IF(ri.values=NIL) THEN
ELSE
IF Debug THEN
KernelLog.String("HandleHidEvent: Reading..."); KernelLog.Ln;
END;
usageTuple := ri.values[i];
usageTuple.usageValue := ReadBits(bitIndex,ri.reportItemSize);
IF (LoggingMode=ShowShortReport) OR (LoggingMode=ShowVeryShortReport) THEN
IF((LoggingMode=ShowShortReport)OR(ri.values[i].usageValue#0)) THEN
KernelLog.String("usageValue for usageID ");
KernelLog.Int(ri.values[i].usageID,0);
KernelLog.String(" is: ");
KernelLog.Int(ri.values[i].usageValue,0);
KernelLog.Ln;
END;
END;
END;
bitIndex := bitIndex + ri.reportItemSize;
END;
END HandleReportItem;
BEGIN
IF Debug THEN
IF((hidReportItemQueue=NIL) OR (reportManager=NIL)) THEN
KernelLog.String("UsbHidDriver:HidDriver.HandleHidEvent: Internal Error,hidReportItemQueue or reportManager not found"); KernelLog.Ln;
END;
LayoutBuffer(reportBuffer^,actLen);
END;
ri := hidReportItemQueue.first;
IF(ri=NIL) THEN
KernelLog.String("ri=NIL"); KernelLog.Ln;
RETURN;
END;
bitIndex := 0;
IF (useReportIDMechanism) THEN
reportID := ReadBits(0, 8);
bitIndex := bitIndex + 8;
WHILE(ri#NIL) DO
IF(ri.reportID=reportID) THEN
HandleReportItem;
END;
ri := ri.next;
END;
ELSE
WHILE(ri#NIL) DO
HandleReportItem;
ri := ri.next;
END;
END;
IF LoggingMode=ShowFullReport THEN reportManager.PrintReportState END;
IF ( (status = Usbdi.Ok) OR (status=Usbdi.ShortPacket)) THEN
IF(mouseState#NIL) THEN
IF Debug THEN KernelLog.String("handle mouse driver"); KernelLog.Ln; END;
HandleMouseDriver;
END;
IF(keyboardState#NIL) THEN
IF Debug THEN KernelLog.String("handle keyboard driver"); KernelLog.Ln; END;
HandleKeyboardDriver;
IF keyboardState.lastLeds # keyboardState.leds THEN
keyboardState.ledBuffer[0] := SYSTEM.VAL(CHAR, keyboardState.leds); keyboardState.lastLeds := keyboardState.leds;
res := SetReport(UsbHid.ReportOutput, 0, keyboardState.ledBuffer^, 1);
END;
END;
IF(consumerState#NIL) THEN
IF Debug THEN KernelLog.String("handle consumer driver"); KernelLog.Ln; END;
HandleConsumerDriver;
END;
IF(joystickState#NIL) THEN
IF Debug THEN KernelLog.String("handle custom driver"); KernelLog.Ln; END;
HandleJoystickDriver;
END;
status := pipe.Transfer(pipe.maxPacketSize, 0, reportBuffer^);
ELSE
IF Debug THEN
KernelLog.String("UsbHidDriver: "); KernelLog.String(name); KernelLog.String("("); KernelLog.String(desc); KernelLog.String(")");
KernelLog.String(" has been disabled."); KernelLog.Ln;
END;
IF (status = Usbdi.Stalled) THEN
IF pipe.ClearHalt() THEN
IF Debug THEN KernelLog.String("UsbHidDriver: Stall on Interrupt Pipe cleared."); KernelLog.Ln; END;
status := pipe.Transfer(pipe.maxPacketSize, 0, reportBuffer^);
ELSE
IF Debug THEN KernelLog.String("UsbHidDriver: Couldn't clear stall on interrupt pipe. Abort."); KernelLog.Ln; END;
device.FreePipe(pipe);
END;
END;
END;
END HandleHidEvent;
PROCEDURE HandleMouseDriver;
VAR
mm : Inputs.MouseMsg;
dx, dy,i : LONGINT;
accelX, accelY : REAL;
BEGIN
dx := TwosComplement(mouseState.x.usageValue, mouseState.axisReport.reportSize);
dy := TwosComplement(mouseState.y.usageValue, mouseState.axisReport.reportSize);
IF Debug THEN KernelLog.String("x and y are: ");KernelLog.Int(dx,0); KernelLog.String(" and ");KernelLog.Int(dy,0); KernelLog.Ln; END;
accelX := 1.0 + ABS(dx - mouseState.lastDx) / 128 * MouseAcceleration;
accelY := 1.0 + ABS(dy - mouseState.lastDy) / 128 * MouseAcceleration;
mouseState.lastDx := dx;
mouseState.lastDy := dy;
mm.dx := ENTIER(MouseSpeed / 50.0 * dx * accelX);
mm.dy := ENTIER(MouseSpeed / 50.0 * dy * accelY);
IF (mouseState.wheel#NIL) THEN
mm.dz := - TwosComplement(mouseState.wheel.usageValue, mouseState.wheelReport.reportSize);
IF mm.dz < 0 THEN mm.dz := - MouseWheelSpeed;
ELSIF mm.dz>0 THEN mm.dz := + MouseWheelSpeed;
END;
END;
IF (mouseState.buttons[0].usageValue#0) THEN mm.keys := mm.keys + {0}; END;
IF (mouseState.buttons[1].usageValue#0) THEN mm.keys := mm.keys + {2}; END;
IF (mouseState.buttons[2].usageValue#0) THEN mm.keys := mm.keys + {1}; END;
FOR i:=3 TO 31 DO
IF (mouseState.buttons[i]#NIL) THEN
IF (mouseState.buttons[i].usageValue#0) THEN mm.keys := mm.keys + {i}; END;
END;
END;
Inputs.mouse.Handle(mm);
END HandleMouseDriver;
PROCEDURE HandleKeyboardDriver;
VAR res : BOOLEAN;
BEGIN
keyboardState.HandleKeyboardEvent();
IF keyboardState.ledStateChanged THEN
res := SetReport(UsbHid.ReportOutput, 0, keyboardState.ledBuffer^, 1);
keyboardState.ledStateChanged := FALSE;
END;
END HandleKeyboardDriver;
PROCEDURE HandleConsumerDriver;
VAR
temp: UsbHidReport.HidReport;
usageTuple: UsbHidReport.UsageTuple;
i: LONGINT;
dictUsage: LONGINT;
BEGIN
temp := consumerState.consumerReport;
WHILE(temp#NIL) DO
IF temp.usages # NIL THEN
FOR i:=0 TO temp.reportCount-1 DO
IF(temp.usages[i].usageValue#0)THEN
IF HidParser.IDMainIsVariable IN SYSTEM.VAL(SET,temp.mainState) THEN
IF Debug THEN
KernelLog.Int(temp.usages[i].usageID,0);
KernelLog.String(" ("); UsagePage.PrintUsagePage(UsagePage.ConsumerPage, temp.usages[i].usageID);
END;
IF(consumerState.IsSet(temp.usages[i].usageID,temp.usages[i].usagePage)=FALSE) THEN
consumerState.AddKey(temp.usages[i]);
consumerState.SendKeySym(temp.usages[i].usageID, temp.usages[i].usagePage, TRUE);
END;
ELSE
IF UsbHidReport.UseUsageDictionaryExt THEN
IF Debug THEN
KernelLog.String("-> usage dictionary index: "); KernelLog.Int(temp.usages[i].usageValue,0); KernelLog.String("; ");
END;
usageTuple := reportManager.GetDictKey(temp.usages[i].usageValue-temp.logicalMinimum, temp.supportedUsages);
IF (consumerState.IsSet(usageTuple.usageID,usageTuple.usagePage)=FALSE) THEN
consumerState.AddKey(usageTuple);
consumerState.SendKeySym(usageTuple.usageID, usageTuple.usagePage, TRUE);
END;
IF Debug THEN
KernelLog.Int(dictUsage,0);
KernelLog.String(" (");
IF usageTuple.usagePage # 0 THEN
UsagePage.PrintUsagePage(usageTuple.usagePage, dictUsage);
ELSE
UsagePage.PrintUsagePage(UsagePage.ConsumerPage, dictUsage);
END;
END;
ELSE
IF Debug THEN
KernelLog.Int(temp.usages[i].usageValue,0);
KernelLog.String(" ("); UsagePage.PrintUsagePage(UsagePage.ConsumerPage, temp.usages[i].usageValue);
END;
IF (consumerState.IsSet(temp.usages[i].usageValue,temp.usages[i].usagePage)=FALSE) THEN
consumerState.AddKey(temp.usages[i]);
consumerState.SendKeySym(temp.usages[i].usageValue,temp.usages[i].usagePage, TRUE);
END;
END;
END;
IF Debug THEN KernelLog.String(") pressed."); KernelLog.Ln; END;
END;
END;
END;
temp := temp.next;
END;
consumerState.CleanUp;
END HandleConsumerDriver;
PROCEDURE HandleJoystickDriver;
VAR
msg : Joystick.JoystickDataMessage;
i: LONGINT;
BEGIN
FOR i:=0 TO joystickState.buttonCount-1 DO
IF (joystickState.buttons[i].usageValue#0) THEN
msg.buttons := msg.buttons + {joystickState.buttons[i].usageID-1};
END;
END;
IF joystickState.x # NIL THEN
IF joystickState.xReport.logicalMinimum<0 THEN
msg.axis[Joystick.AxisX] := TwosComplement(joystickState.x.usageValue,joystickState.xReport.reportSize);
ELSE
msg.axis[Joystick.AxisX] := joystickState.x.usageValue;
END;
END;
IF joystickState.y # NIL THEN
IF joystickState.yReport.logicalMinimum<0 THEN
msg.axis[Joystick.AxisY] := TwosComplement(joystickState.y.usageValue,joystickState.yReport.reportSize);
ELSE
msg.axis[Joystick.AxisY] := joystickState.y.usageValue;
END;
END;
IF joystickState.z # NIL THEN
IF joystickState.zReport.logicalMinimum<0 THEN
msg.axis[Joystick.AxisZ] := TwosComplement(joystickState.z.usageValue,joystickState.zReport.reportSize);
ELSE
msg.axis[Joystick.AxisZ] := joystickState.z.usageValue;
END;
END;
IF joystickState.rx # NIL THEN
IF joystickState.rxReport.logicalMinimum<0 THEN
msg.axis[Joystick.AxisRx] := TwosComplement(joystickState.rx.usageValue,joystickState.rxReport.reportSize);
ELSE
msg.axis[Joystick.AxisRx] := joystickState.rx.usageValue;
END;
END;
IF joystickState.ry # NIL THEN
IF joystickState.ryReport.logicalMinimum<0 THEN
msg.axis[Joystick.AxisRy] := TwosComplement(joystickState.ry.usageValue,joystickState.ryReport.reportSize);
ELSE
msg.axis[Joystick.AxisRy] := joystickState.ry.usageValue;
END;
END;
IF joystickState.rz # NIL THEN
IF joystickState.rzReport.logicalMinimum<0 THEN
msg.axis[Joystick.AxisRz] := TwosComplement(joystickState.rz.usageValue,joystickState.rzReport.reportSize);
ELSE
msg.axis[Joystick.AxisRz] := joystickState.rz.usageValue;
END;
END;
IF joystickState.slider # NIL THEN
IF joystickState.sliderReport.logicalMinimum<0 THEN
msg.axis[Joystick.Slider1] := TwosComplement(joystickState.slider.usageValue,joystickState.sliderReport.reportSize);
ELSE
msg.axis[Joystick.Slider1] := joystickState.slider.usageValue;
END;
END;
IF joystickState.hatSwitch # NIL THEN
CASE (joystickState.hatSwitch.usageValue-joystickState.hatSwitchReport.logicalMinimum+1) OF
1: msg.coolieHat[0]:= {Joystick.HatUp};
|2: msg.coolieHat[0]:= {Joystick.HatUp}+{Joystick.HatLeft};
|3: msg.coolieHat[0]:= {Joystick.HatLeft};
|4: msg.coolieHat[0]:= {Joystick.HatLeft}+{Joystick.HatDown};
|5: msg.coolieHat[0]:= {Joystick.HatDown};
|6: msg.coolieHat[0]:= {Joystick.HatDown}+{Joystick.HatRight};
|7: msg.coolieHat[0]:= {Joystick.HatRight};
|8: msg.coolieHat[0]:= {Joystick.HatRight}+{Joystick.HatUp};
ELSE
END;
END;
joystickState.joystick.Handle(msg);
END HandleJoystickDriver;
PROCEDURE InitializeMouseDriver():BOOLEAN;
VAR
mouseCollection : UsbHidReport.HidCollection;
temp : UsbHidReport.HidReport;
i : LONGINT;
isReportProtocol: BOOLEAN;
BEGIN
mouseCollection := reportManager.GetCollection(1,2);
IF (mouseCollection#NIL) THEN
NEW(mouseState);
mouseState.buttonCount := 0;
FOR i:=0 TO 31 DO
IF( mouseState.buttonReport = NIL) THEN
mouseState.buttons[i] := reportManager.GetUsage(UsagePage.ButtonPage, i+1, mouseCollection,mouseState.buttonReport);
ELSE
mouseState.buttons[i] := reportManager.GetUsage(UsagePage.ButtonPage, i+1, mouseCollection,temp);
END;
IF(mouseState.buttons[i]#NIL) THEN
mouseState.buttonCount := i;
END;
END;
mouseState.x := reportManager.GetUsage(UsagePage.GenericDesktopPage, 30H, mouseCollection,mouseState.axisReport);
IF(mouseState.x=NIL) THEN
KernelLog.String("Initialize mouse driver: error did not find x axis"); KernelLog.Ln;
END;
IF(mouseState.axisReport=NIL) THEN
KernelLog.String("InitializeMouseDriver: Error: Did not find axis report"); KernelLog.Ln;
END;
mouseState.y := reportManager.GetUsage(UsagePage.GenericDesktopPage, 31H, mouseCollection,temp);
IF(mouseState.y=NIL) THEN
KernelLog.String("Initialize mouse driver: error did not find y axis"); KernelLog.Ln;
END;
mouseState.wheel := reportManager.GetUsage(UsagePage.GenericDesktopPage, 38H, mouseCollection,mouseState.wheelReport);
IF(mouseState.wheel=NIL) THEN
KernelLog.String("Initialize mouse driver: warning did not find wheel"); KernelLog.Ln;
END;
IF Trace THEN
KernelLog.String("Found Mouse Configuration"); KernelLog.Ln;
KernelLog.String("Mouse Driver initialized");KernelLog.Ln;
END;
isReportProtocol := SetReportProtocol();
RETURN TRUE;
ELSE
RETURN FALSE;
END;
END InitializeMouseDriver;
PROCEDURE InitializeKeyboardDriver():BOOLEAN;
VAR
keyboardColl: UsbHidReport.HidCollection;
aUsageTuple : UsbHidReport.UsageTuple;
modifierReport: UsbHidReport.HidReport;
keycodeReport: UsbHidReport.HidReport;
BEGIN
keyboardColl:= reportManager.GetCollection(UsagePage.GenericDesktopPage,UsagePage.KeyboardPage);
IF(keyboardColl#NIL) THEN
IF ~SetIdle(0,10) THEN
IF Debug THEN KernelLog.String("UsbKeyboard: Error: Cannot set idle the keyboard."); KernelLog.Ln; END;
END;
NEW(keyboardState);
keyboardState.Init;
aUsageTuple:= reportManager.GetUsage(UsagePage.KeypadPage, 224,
keyboardColl, modifierReport);
IF (modifierReport=NIL) THEN
IF Debug THEN KernelLog.String("Error did not find modifier"); KernelLog.Ln; END;
keyboardState := NIL;
RETURN FALSE;
ELSE
IF (modifierReport.usages=NIL) THEN
IF Debug THEN KernelLog.String("Error did not find modifiers usages"); KernelLog.Ln; END;
keyboardState := NIL;
RETURN FALSE;
ELSE
IF (LEN(modifierReport.usages)<8) THEN
keyboardState := NIL;
RETURN FALSE;
END;
END;
keyboardState.modifierUsages := modifierReport.usages;
END;
aUsageTuple:= reportManager.GetUsage(UsagePage.KeypadPage, 0,
keyboardColl, keycodeReport);
IF(keycodeReport=NIL) THEN
IF Debug THEN KernelLog.String("Error did not find keycodeReport"); KernelLog.Ln; END;
keyboardState := NIL;
RETURN FALSE;
ELSE
IF(keycodeReport.usages=NIL) THEN
keyboardState := NIL;
IF Debug THEN KernelLog.String("Error did not find keycodeReports usages"); KernelLog.Ln; END;
RETURN FALSE;
END;
END;
keyboardState.keycodeUsages := keycodeReport.usages;
keyboardState.SetMaxKeycodes(LEN(keycodeReport.usages));
RETURN SetReportProtocol();
ELSE
RETURN FALSE;
END;
END InitializeKeyboardDriver;
PROCEDURE InitializeConsumerDriver():BOOLEAN;
VAR
consumerColl : UsbHidReport.HidCollection;
temp : UsbHidReport.HidReport;
usageCounter : LONGINT;
BEGIN
consumerColl := reportManager.GetCollection(UsagePage.ConsumerPage, 1H);
IF consumerColl # NIL THEN
NEW(consumerState);
consumerState.consumerReport := consumerColl.firstReport;
IF consumerState.consumerReport # NIL THEN
temp := consumerState.consumerReport;
WHILE (temp # NIL) DO
usageCounter := usageCounter + temp.reportCount;
temp := temp.next;
END;
temp := consumerState.consumerReport;
RETURN TRUE;
ELSE
consumerState := NIL;
END;
END;
RETURN FALSE;
END InitializeConsumerDriver;
PROCEDURE InitializeJoystickDriver():BOOLEAN;
VAR
joystickColl : UsbHidReport.HidCollection;
temp : UsbHidReport.HidReport;
res,i : LONGINT;
BEGIN
joystickColl := reportManager.GetCollection(UsagePage.GenericDesktopPage,4);
IF (joystickColl#NIL) THEN
NEW(joystickState);
joystickState.buttonCount := 0;
FOR i:=0 TO 31 DO
IF( joystickState.buttonReport = NIL) THEN
joystickState.buttons[i] := reportManager.GetUsage(UsagePage.ButtonPage, i+1, joystickColl,joystickState.buttonReport);
ELSE
joystickState.buttons[i] := reportManager.GetUsage(UsagePage.ButtonPage, i+1, joystickColl,temp);
END;
IF(joystickState.buttons[i]#NIL) THEN
joystickState.buttonCount := joystickState.buttonCount +1;
END;
END;
IF Debug THEN
KernelLog.String("Found Joystick Configuration"); KernelLog.Ln;
END;
NEW(joystickState.joystick,joystickState.buttonCount);
joystickState.joystick.desc := "USBHIDJoystick";
joystickState.x := reportManager.GetUsage(UsagePage.GenericDesktopPage, 30H, joystickColl,joystickState.xReport);
IF(joystickState.x#NIL) THEN
joystickState.joystick.AddAxis(Joystick.AxisX, joystickState.xReport.logicalMinimum, joystickState.xReport.logicalMaximum);
END;
joystickState.y := reportManager.GetUsage(UsagePage.GenericDesktopPage, 31H, joystickColl,joystickState.yReport);
IF(joystickState.y#NIL) THEN
joystickState.joystick.AddAxis(Joystick.AxisY, joystickState.yReport.logicalMinimum, joystickState.yReport.logicalMaximum);
END;
joystickState.z := reportManager.GetUsage(UsagePage.GenericDesktopPage, 32H, joystickColl,joystickState.zReport);
IF(joystickState.z#NIL) THEN
joystickState.joystick.AddAxis(Joystick.AxisZ, joystickState.zReport.logicalMinimum, joystickState.zReport.logicalMaximum);
END;
joystickState.rx := reportManager.GetUsage(UsagePage.GenericDesktopPage, 33H, joystickColl,joystickState.rxReport);
IF(joystickState.rx#NIL) THEN
joystickState.joystick.AddAxis(Joystick.AxisRx, joystickState.rxReport.logicalMinimum, joystickState.rxReport.logicalMaximum);
END;
joystickState.ry := reportManager.GetUsage(UsagePage.GenericDesktopPage, 34H, joystickColl,joystickState.ryReport);
IF(joystickState.ry#NIL) THEN
joystickState.joystick.AddAxis(Joystick.AxisRy, joystickState.ryReport.logicalMinimum, joystickState.ryReport.logicalMaximum);
END;
joystickState.rz := reportManager.GetUsage(UsagePage.GenericDesktopPage, 35H, joystickColl,joystickState.rzReport);
IF(joystickState.rz#NIL) THEN
joystickState.joystick.AddAxis(Joystick.AxisRz, joystickState.rzReport.logicalMinimum, joystickState.rzReport.logicalMaximum);
END;
joystickState.slider := reportManager.GetUsage(UsagePage.GenericDesktopPage, 36H, joystickColl,joystickState.sliderReport);
IF(joystickState.slider#NIL) THEN
joystickState.joystick.AddAxis(Joystick.Slider1, joystickState.sliderReport.logicalMinimum, joystickState.sliderReport.logicalMaximum);
END;
joystickState.hatSwitch:= reportManager.GetUsage(UsagePage.GenericDesktopPage, 39H, joystickColl,joystickState.hatSwitchReport);
IF(joystickState.hatSwitch#NIL) THEN
IF (joystickState.hatSwitchReport.logicalMaximum-joystickState.hatSwitchReport.logicalMinimum=7) THEN
joystickState.joystick.AddCoolieHat();
ELSE
KernelLog.String("HatSwitch found, but not compatible. HatSwitch events are not sent to Joysticks.."); KernelLog.Ln;
END;
END;
Joystick.registry.Add(joystickState.joystick,res);
RETURN TRUE;
ELSE
RETURN FALSE;
END;
END InitializeJoystickDriver;
PROCEDURE ReadBits(index, bitLen: LONGINT):LONGINT;
VAR rv : LONGINT;
BEGIN
rv := ReadBitsBuffer(index,bitLen,reportBuffer);
RETURN rv;
END ReadBits;
PROCEDURE ReadBitsBuffer(index, bitLen: LONGINT; localBuf: Usbdi.BufferPtr):LONGINT;
VAR
endIndex : LONGINT;
rv : LONGINT;
temp : LONGINT;
indexEightAligned : LONGINT;
bitsToShift : LONGINT;
set : SET;
BEGIN
endIndex := index + bitLen-1;
IF bitLen<=0 THEN RETURN 0 END;
IF Debug THEN KernelLog.String("read bits from "); KernelLog.Int(index,0); KernelLog.String(" to "); KernelLog.Int(endIndex,0); KernelLog.Ln; END;
IF(endIndex>=(8*LEN(localBuf))) THEN
IF Debug THEN KernelLog.String("ReadBits: Buffer overflow, endindex is out of localBuf"); KernelLog.Ln; END;
RETURN 0;
END;
IF (bitLen=1) THEN
set := SYSTEM.VAL(SET, localBuf[index DIV 8]);
IF (index MOD 8) IN set THEN
rv := 1;
ELSE
rv := 0;
END;
RETURN rv;
END;
IF ((index DIV 8) = (endIndex DIV 8)) THEN
temp := SYSTEM.VAL(LONGINT, ORD(localBuf[index DIV 8]));
IF (bitLen=8) THEN
rv:= temp;
IF Debug THEN
KernelLog.String("the byte value is: "); KernelLog.Int(rv,0); KernelLog.Ln;
END;
RETURN rv;
ELSE
IF Debug THEN
KernelLog.Ln;
KernelLog.String(" the value of the byte is: "); KernelLog.Int(temp,0); KernelLog.Ln;
KernelLog.String(" (");KernelLog.Bits(SYSTEM.VAL(SET, temp),0,8); KernelLog.String(")"); KernelLog.Ln;
KernelLog.String(" read in the byte from "); KernelLog.Int(index MOD 8,0); KernelLog.String(" to ");
KernelLog.Int(endIndex MOD 8,0); KernelLog.String(")"); KernelLog.Ln;
END;
temp := SYSTEM.VAL(LONGINT,(SYSTEM.VAL(SET, temp) * {(index MOD 8)..(endIndex MOD 8)}));
IF Debug THEN
KernelLog.String(" the value of the byte after masking: "); KernelLog.Bits(SYSTEM.VAL(SET, temp),0,8); KernelLog.Ln;
END;
bitsToShift := index MOD 8;
IF Debug THEN
KernelLog.String(" bits to shift: "); KernelLog.Int(bitsToShift,0); KernelLog.Ln;
END;
rv := SYSTEM.VAL(LONGINT,SYSTEM.LSH(SYSTEM.VAL(CHAR,temp),-bitsToShift));
IF Debug THEN
KernelLog.String(" the value of the byte after shifting: "); KernelLog.Bits(SYSTEM.VAL(SET, rv),0,8); KernelLog.Ln;
END;
END;
ELSE
indexEightAligned := SYSTEM.VAL(LONGINT,SYSTEM.VAL(SET,index)+{0..2});
IF Debug THEN
KernelLog.String("index, indexEightAligned, endIndex");
KernelLog.Int(index,6);KernelLog.Int(indexEightAligned,6);KernelLog.Int(endIndex,6); KernelLog.Ln;
END;
temp := ReadBitsBuffer(indexEightAligned+1,endIndex-indexEightAligned, localBuf);
temp := SYSTEM.LSH(temp,indexEightAligned-index+1);
rv := temp + ReadBitsBuffer(index, indexEightAligned-index+1,localBuf);
END;
RETURN rv;
END ReadBitsBuffer;
PROCEDURE TwosComplement(value: LONGINT; bitLen: LONGINT) : LONGINT;
VAR toMuch : LONGINT;
BEGIN
IF(bitLen<32) & (bitLen>0) THEN
IF ((bitLen-1) IN SYSTEM.VAL(SET,value)) THEN
toMuch:= SYSTEM.VAL(LONGINT,{bitLen});
value := value - toMuch;
END;
END;
RETURN value;
END TwosComplement;
PROCEDURE SetReportProtocol():BOOLEAN;
VAR
bootFlag: LONGINT;
BEGIN
IF (GetProtocol(bootFlag)) THEN
IF(bootFlag=0) THEN
IF Debug THEN
KernelLog.String("UsbHidDriver:HidDriver.Connect: GetProtocol returned boot protocol, set to report protocol"); KernelLog.Ln;
END;
IF(SetProtocol(1)=FALSE) THEN
KernelLog.String("UsbHidDriver:HidDriver.Connect: SetProtocol to report failed"); KernelLog.Ln;
RETURN FALSE;
END;
ELSE
IF Debug THEN
KernelLog.String("UsbHidDriver:HidDriver.Connect: GetProtocol returned report protocol"); KernelLog.Ln;
END;
END;
END;
RETURN TRUE;
END SetReportProtocol;
END HidDriver;
PROCEDURE LayoutBuffer*(CONST buf : Usbdi.Buffer; len : LONGINT);
VAR temp : LONGINT;
BEGIN
KernelLog.String("Buffer Outline:"); KernelLog.Ln;
FOR temp := 0 TO len-1 DO
IF (temp MOD 2 = 0) THEN
KernelLog.Ln();
KernelLog.Int(temp, 4);
KernelLog.String(" ");
KernelLog.Hex(ORD(buf[temp]), -2);
ELSE
KernelLog.String(" ");
KernelLog.Hex(ORD(buf[temp]), -2);
END;
END;
KernelLog.Ln(); KernelLog.Ln();
END LayoutBuffer;
PROCEDURE Probe(dev : Usbdi.UsbDevice; if : Usbdi.InterfaceDescriptor) : Usbdi.Driver;
VAR hidDriver : HidDriver;
BEGIN
IF if.bInterfaceClass # 3 THEN RETURN NIL END;
NEW(hidDriver);
RETURN hidDriver;
END Probe;
PROCEDURE Cleanup;
BEGIN
Usbdi.drivers.Remove(Name);
END Cleanup;
PROCEDURE Install*;
END Install;
BEGIN
Modules.InstallTermHandler(Cleanup);
Usbdi.drivers.Add(Probe, Name, Description, 10);
END UsbHidDriver.
UsbHidDriver.Install ~ SystemTools.Free UsbHidDriver UsbHidParser UsbHidErrors UsbHidParserExt UsbHidReport UsbHidUP~