Skip to content

Commit 5c29618

Browse files
committed
Creating our dummy Keypadder input device now works.
1 parent 37def42 commit 5c29618

File tree

4 files changed

+121
-38
lines changed

4 files changed

+121
-38
lines changed

.vscode/launch.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@
99
"type": "gdb",
1010
"request": "launch",
1111
"target": "./bin/keypadder",
12-
"arguments": "--config=examples/keypad.toml",
12+
"arguments": "--config=${workspaceRoot}/examples/keypad.toml",
1313
"cwd": "${workspaceRoot}",
14-
"valuesFormatting": "parseText"
14+
"valuesFormatting": "parseText",
15+
"gdbpath": "/home/steve/bin/sudo_gdb.sh"
1516
}
1617
]
1718
}

src/injector.adb

+68-3
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,99 @@
22
-- SPDX-FileCopyrightText: Copyright 2023 Stephen Merrony
33

44
with Ada.Text_IO;
5+
with Interfaces; use Interfaces;
56

6-
with Uinput; use Uinput;
7+
with Uinput; use Uinput;
78

89
package body Injector is
910

1011
task body Injector_Task is
1112
Uinput_FID : K_File_ID_T;
13+
Usetup : K_Uinput_Setup_T;
1214
IE_Time : K_Timeval_T; -- defaults to zeroes
1315
Key_IE : K_Input_Event_T;
1416
Report_IE : constant K_Input_Event_T := (Time => IE_Time,
1517
IE_Type => EV_SYN,
1618
IE_Code => SYN_REPORT,
1719
IE_Value => 0);
1820
Result : K_Int_T;
21+
Key_Val : K_Int_T := 0;
22+
Request : K_Ioctl_ID_T;
23+
24+
function IOW (Code : Unsigned_32; Len : Integer) return K_Ioctl_ID_T is
25+
Tmp : Unsigned_32 := Code;
26+
begin
27+
Tmp := Tmp + Shift_Left (Unsigned_32 (UINPUT_IOCTL_BASE), 8);
28+
Tmp := Tmp + Shift_Left (Unsigned_32 (Len), 16); -- arg length of 4 (?)
29+
Tmp := Tmp + Shift_Left (Unsigned_32 (1), 30); -- direction (write, out)
30+
return K_Ioctl_ID_T (Tmp);
31+
end IOW;
32+
function IO (Code : Unsigned_32; Len : Integer) return K_Ioctl_ID_T is
33+
Tmp : Unsigned_32 := Code;
34+
begin
35+
Tmp := Tmp + Shift_Left (Unsigned_32 (UINPUT_IOCTL_BASE), 8);
36+
Tmp := Tmp + Shift_Left (Unsigned_32 (Len), 16); -- arg length of 4 (?)
37+
return K_Ioctl_ID_T (Tmp);
38+
end IO;
1939
begin
2040
accept Start do
21-
K_Open (Uinput_FID, Linux_Path, O_WRONLY + O_NONBLOCK);
41+
Uinput_FID := K_Open (Linux_Path, O_WRONLY + O_NONBLOCK);
42+
if Uinput_FID = -1 then
43+
Ada.Text_IO.Put_Line ("ERROR: Could not open " & Linux_Path);
44+
raise Cannot_Open;
45+
end if;
2246
-- populate the unchanging fields in the Key_IE
2347
Key_IE.Time := IE_Time;
2448
Key_IE.IE_Type := EV_KEY;
49+
50+
-- set up for keyboard events
51+
Request := IOW (UI_SET_EVBIT, 4);
52+
Result := K_IOCTL_3_Arg (Uinput_FID, Request, K_Long_T (EV_KEY));
53+
if Result = -1 then
54+
C_Perror ("UI_SET_EVBIT failed...");
55+
raise IOCTL_Error with "UI_SET_EVBIT failed";
56+
end if;
57+
58+
-- enable all possible (0 .. 255) key values
59+
loop
60+
Result := K_IOCTL_3_Arg (Uinput_FID, IOW (UI_SET_KEYBIT, 4), K_Long_T (Key_Val));
61+
if Result = -1 then
62+
Ada.Text_IO.Put_Line ("ERROR: Could not SET_KEYBIT");
63+
raise IOCTL_Error with "Could not SET_KEYBIT";
64+
end if;
65+
Key_Val := Key_Val + 1;
66+
exit when Key_Val = 256;
67+
end loop;
68+
69+
-- configure our dummy USB device...
70+
Usetup.ID.K_Bustype := BUS_USB;
71+
Usetup.ID.K_Vendor := 16#1234#; -- sample vendor
72+
Usetup.ID.K_Product := 16#5678#; -- sample K_Product
73+
Usetup.Name (1 .. 9) := "Keypadder";
74+
Usetup.Name (10 .. Uinput_Max_Name_Size) := (others => Character'Val (0));
75+
Request := IOW (UI_DEV_SETUP, Usetup'Size / 8);
76+
Result := K_IOCTL_Uinput_Setup (Uinput_FID, Request, Usetup);
77+
if Result = -1 then
78+
C_Perror ("UI_DEV_SETUP failed...");
79+
raise IOCTL_Error with "UI_DEV_SETUP failed";
80+
end if;
81+
82+
-- create the dummy device
83+
Request := IO (UI_DEV_CREATE, 0);
84+
Result := K_IOCTL_2_Arg (Uinput_FID, Request);
85+
if Result = -1 then
86+
C_Perror ("UI_DEV_CREATE failed...");
87+
raise IOCTL_Error with "UI_DEV_CREATE failed";
88+
end if;
2589
end Start;
90+
2691
loop
2792
select
2893
accept Send (Keys : String) do
2994
Ada.Text_IO.Put_Line ("Injector got Send request for: " & Keys);
3095
for C in Keys'Range loop
3196
-- Key press, report the event, send key release, and report again
32-
Key_IE.IE_Code := Char_To_K_Int (Keys (C));
97+
Key_IE.IE_Code := Char_To_K_U16 (Keys (C));
3398
Key_IE.IE_Value := 1;
3499
-- IE_IO.Write (Uinput_File, Key_IE);
35100
-- IE_IO.Write (Uinput_File, Report_IE);

src/uinput.adb

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33

44
package body Uinput is
55

6-
procedure Emit (FID : K_File_ID_T; E_Type, E_Code, E_Val : K_Int_T) is
6+
procedure Emit (FID : K_File_ID_T;
7+
E_Type, E_Code : K_U16_T;
8+
E_Val : K_Int_T) is
79
IE : K_Input_Event_T;
810
Dummy_SS : K_SSize_T;
911
IE_Address : constant System.Address := IE'Address;

src/uinput.ads

+47-32
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
with Ada.Unchecked_Conversion;
55
with Interfaces; use Interfaces;
6+
with System;
67
with System.Address_To_Access_Conversions;
78

89
package Uinput is
@@ -18,82 +19,90 @@ package Uinput is
1819
type K_Size_T is new Unsigned_64;
1920
type K_SSize_T is new Integer_64;
2021
type K_File_ID_T is new Integer_32;
21-
type K_Ioctl_ID_T is new Integer_32;
22+
type K_Ioctl_ID_T is new Unsigned_32;
2223
type K_Dummy_T is new Integer_32;
2324

25+
UINPUT_IOCTL_BASE : constant Integer_32 := 85; -- ASCII 'U'
26+
2427
Uinput_Max_Name_Size : constant Integer := 80;
28+
BUS_USB : constant K_U16_T := 3;
2529

2630
type K_Input_ID_T is record
2731
K_Bustype,
2832
K_Vendor,
2933
K_Product,
3034
K_Version : K_U16_T;
3135
end record;
36+
pragma Convention (C, K_Input_ID_T);
3237

3338
type K_Uinput_Setup_T is record
3439
ID : K_Input_ID_T;
3540
Name : String (1 .. Uinput_Max_Name_Size);
36-
FF_Effects_Max : K_U32_T;
41+
FF_Effects_Max : K_U32_T := 0;
3742
end record;
43+
pragma Convention (C, K_Uinput_Setup_T);
44+
45+
UI_SET_EVBIT : constant Unsigned_32 := 100;
46+
UI_SET_KEYBIT : constant Unsigned_32 := 101;
3847

39-
package Uinput_Setup_Pointers is new System.Address_To_Access_Conversions (K_Uinput_Setup_T);
48+
UI_DEV_SETUP : constant Unsigned_32 := 3;
49+
UI_DEV_CREATE : constant Unsigned_32 := 1;
50+
UI_DEV_DESTROY : constant Unsigned_32 := 2;
4051

4152
type K_Timeval_T is record
4253
TV_Sec : K_Int_T := 0;
4354
TV_USec : K_Long_T := 0;
4455
end record;
4556

4657
-- The Event Types we need...
47-
EV_SYN : constant K_Int_T := 0;
48-
EV_KEY : constant K_Int_T := 1;
49-
EV_REL : constant K_Int_T := 2;
58+
EV_SYN : constant K_U16_T := 0;
59+
EV_KEY : constant K_U16_T := 1;
60+
EV_REL : constant K_U16_T := 2;
5061

5162
type K_Input_Event_T is record
5263
Time : K_Timeval_T;
53-
IE_Type : K_Int_T;
54-
IE_Code : K_Int_T;
64+
IE_Type : K_U16_T;
65+
IE_Code : K_U16_T;
5566
IE_Value : K_Int_T;
5667
end record;
68+
pragma Convention (C, K_Input_Event_T);
5769

5870
K_Input_Event_Size : constant K_Size_T := K_Input_Event_T'Size;
5971

6072
package IE_Pointers is new System.Address_To_Access_Conversions (K_Input_Event_T);
6173

6274
-- The short-form 2 arg (i.e. 1 parameter) ioctl call
63-
procedure K_IOCTL_2_Arg (Result : out K_Int_T;
64-
FID : K_File_ID_T;
65-
IOCTL_ID : K_Ioctl_ID_T;
66-
Ignored : K_Dummy_T);
75+
function K_IOCTL_2_Arg (FID : K_File_ID_T;
76+
IOCTL_ID : K_Ioctl_ID_T;
77+
Ignored : K_Dummy_T := 0
78+
) return K_Int_T;
6779
pragma Import (C, K_IOCTL_2_Arg, "ioctl");
68-
pragma Import_Valued_Procedure (K_IOCTL_2_Arg);
6980

7081
-- The long-form 3 arg (i.e. 2 parameters) ioctl call
7182
-- with a simple (int) 3rd argument
72-
procedure K_IOCTL_3_Arg (Result : out K_Int_T;
73-
FID : K_File_ID_T;
74-
IOCTL_ID : K_Ioctl_ID_T;
75-
IOCTL_Arg : K_Int_T);
83+
function K_IOCTL_3_Arg (FID : K_File_ID_T;
84+
IOCTL_ID : K_Ioctl_ID_T;
85+
IOCTL_Arg : K_Long_T
86+
) return K_Int_T;
7687
pragma Import (C, K_IOCTL_3_Arg, "ioctl");
77-
pragma Import_Valued_Procedure (K_IOCTL_3_Arg);
7888

7989
-- The long-form 3 arg (i.e. 2 parameters) ioctl call
8090
-- with an (address of) Uinput_Setup 3rd argument
81-
procedure K_IOCTL_Uinput_Setup (Result : out K_Int_T;
82-
FID : K_File_ID_T;
83-
IOCTL_ID : K_Ioctl_ID_T;
84-
Uinput_Setup_Addr : Uinput_Setup_Pointers.Object_Pointer);
91+
function K_IOCTL_Uinput_Setup (FID : K_File_ID_T;
92+
IOCTL_ID : K_Ioctl_ID_T;
93+
Usetup : K_Uinput_Setup_T
94+
) return K_Int_T;
8595
pragma Import (C, K_IOCTL_Uinput_Setup, "ioctl");
86-
pragma Import_Valued_Procedure (K_IOCTL_Uinput_Setup);
96+
97+
procedure C_Perror (Msg : String);
98+
pragma Import (C, C_Perror, "perror");
8799

88100
O_WRONLY : constant K_Int_T := 1;
89101
O_NONBLOCK : constant K_Int_T := 2048;
90102

91-
-- System file open call
92-
procedure K_Open (FID : out K_File_ID_T;
93-
Path : String;
94-
Flags : K_Int_T);
103+
function K_Open (Path : String;
104+
Flags : K_Int_T) return K_File_ID_T;
95105
pragma Import (C, K_Open, "open");
96-
pragma Import_Valued_Procedure (K_Open);
97106

98107
-- System file write call
99108
procedure K_Write_IE (Written : out K_SSize_T;
@@ -110,12 +119,18 @@ package Uinput is
110119
pragma Import_Valued_Procedure (K_Close);
111120

112121
-- The special Event Code we need...
113-
SYN_REPORT : constant K_Int_T := 0;
122+
SYN_REPORT : constant K_U16_T := 0;
114123

115-
function Char_To_K_Int is new Ada.Unchecked_Conversion (Character, K_Int_T);
124+
pragma Warnings (Off, "types for unchecked conversion have different sizes");
125+
function Char_To_K_U16 is new Ada.Unchecked_Conversion (Character, K_U16_T);
126+
pragma Warnings (On, "types for unchecked conversion have different sizes");
116127

117-
Cannot_Open, Cannot_Write : exception;
128+
Cannot_Open,
129+
Cannot_Write,
130+
IOCTL_Error : exception;
118131

119-
procedure Emit (FID : K_File_ID_T; E_Type, E_Code, E_Val : K_Int_T);
132+
procedure Emit (FID : K_File_ID_T;
133+
E_Type, E_Code : K_U16_T;
134+
E_Val : K_Int_T);
120135

121136
end Uinput;

0 commit comments

Comments
 (0)