4 * Copyright 2020, Gary Wong <gtw@gnu.org>
6 * This file is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
11 * This file is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this file. If not, see <https://www.gnu.org/licenses/>.
20 #include <linux/input.h>
22 #include <linux/module.h>
23 #include <uapi/linux/input-event-codes.h>
25 MODULE_AUTHOR( "Gary Wong <gtw@gnu.org>" );
26 MODULE_DESCRIPTION( "FPC-III keyboard driver" );
27 MODULE_LICENSE( "GPL" );
29 #define FPCKBD_BASE 0xA0000000
31 static struct timer_list timer
;
32 static struct input_dev
*fpc_dev
;
33 static unsigned char __iomem
*report
;
34 static unsigned char last_rep
[ 8 ];
36 static const unsigned char code_trans
[ 0x66 ] = {
37 0, 0, 0, 0, KEY_A
, KEY_B
, KEY_C
, KEY_D
,
38 KEY_E
, KEY_F
, KEY_G
, KEY_H
, KEY_I
, KEY_J
, KEY_K
, KEY_L
,
39 KEY_M
, KEY_N
, KEY_O
, KEY_P
, KEY_Q
, KEY_R
, KEY_S
, KEY_T
,
40 KEY_U
, KEY_V
, KEY_W
, KEY_X
, KEY_Y
, KEY_Z
, KEY_1
, KEY_2
,
41 KEY_3
, KEY_4
, KEY_5
, KEY_6
, KEY_7
, KEY_8
, KEY_9
, KEY_0
,
42 KEY_ENTER
, KEY_ESC
, KEY_BACKSPACE
, KEY_TAB
,
43 KEY_SPACE
, KEY_MINUS
, KEY_EQUAL
, KEY_LEFTBRACE
,
44 KEY_RIGHTBRACE
, KEY_BACKSLASH
, 0, KEY_SEMICOLON
,
45 KEY_APOSTROPHE
, KEY_GRAVE
, KEY_COMMA
, KEY_DOT
,
46 KEY_SLASH
, KEY_CAPSLOCK
, KEY_F1
, KEY_F2
,
47 KEY_F3
, KEY_F4
, KEY_F5
, KEY_F6
,
48 KEY_F7
, KEY_F8
, KEY_F9
, KEY_F10
,
49 KEY_F11
, KEY_F12
, KEY_SYSRQ
, KEY_SCROLLLOCK
,
50 KEY_PAUSE
, KEY_INSERT
, KEY_HOME
, KEY_PAGEUP
,
51 KEY_DELETE
, KEY_END
, KEY_PAGEDOWN
, KEY_RIGHT
,
52 KEY_LEFT
, KEY_DOWN
, KEY_UP
, KEY_NUMLOCK
,
53 KEY_KPSLASH
, KEY_KPASTERISK
, KEY_KPMINUS
, KEY_KPPLUS
,
54 KEY_KPENTER
, KEY_KP1
, KEY_KP2
, KEY_KP3
,
55 KEY_KP4
, KEY_KP5
, KEY_KP6
, KEY_KP7
,
56 KEY_KP8
, KEY_KP9
, KEY_KP0
, KEY_KPDOT
,
60 static const unsigned char mod_trans
[ 8 ] = {
61 KEY_LEFTCTRL
, KEY_LEFTSHIFT
, KEY_LEFTALT
, KEY_LEFTMETA
,
62 KEY_RIGHTCTRL
, KEY_RIGHTSHIFT
, KEY_RIGHTALT
, KEY_RIGHTMETA
65 static void fpckbd_timer( struct timer_list
*t
) {
68 unsigned char new_rep
[ 8 ];
70 memcpy_fromio( new_rep
, report
, 8 );
72 for( i
= 0; i
< 8; i
++ )
73 if( ( new_rep
[ 0 ] ^ last_rep
[ 0 ] ) & ( 1 << i
) )
74 input_report_key( fpc_dev
, mod_trans
[ i
],
75 new_rep
[ 0 ] & ( 1 << i
) );
77 for( i
= 2; i
< 8; i
++ )
79 for( j
= 2; j
< 8; j
++ )
80 if( new_rep
[ j
] == last_rep
[ i
] )
83 if( last_rep
[ i
] < 0x66 && code_trans
[ last_rep
[ i
] ] )
84 input_report_key( fpc_dev
, code_trans
[ last_rep
[ i
] ], 0 );
89 for( i
= 2; i
< 8; i
++ )
91 for( j
= 2; j
< 8; j
++ )
92 if( last_rep
[ j
] == new_rep
[ i
] )
95 if( new_rep
[ i
] < 0x66 && code_trans
[ new_rep
[ i
] ] )
96 input_report_key( fpc_dev
, code_trans
[ new_rep
[ i
] ], 1 );
101 input_sync( fpc_dev
);
103 memcpy( last_rep
, new_rep
, 8 );
105 mod_timer( &timer
, jiffies
+ HZ
/ 100 + 1 );
108 static int __init
fpckbd_init( void ) {
112 if( !( fpc_dev
= input_allocate_device() ) )
115 // FIXME use platform device to get address
116 if( !( report
= ioremap( FPCKBD_BASE
, 0x10000 ) ) )
119 fpc_dev
->evbit
[ 0 ] = BIT_MASK( EV_KEY
) | BIT_MASK( EV_REP
);
121 for( i
= 1; i
< 0x80; i
++ )
122 __set_bit( i
, fpc_dev
->keybit
);
124 if( ( err
= input_register_device( fpc_dev
) ) )
127 timer_setup( &timer
, fpckbd_timer
, 0 );
128 mod_timer( &timer
, jiffies
+ HZ
/ 100 + 1 );
133 static void __exit
fpckbd_exit( void ) {
135 del_timer_sync( &timer
);
137 input_unregister_device( fpc_dev
);
142 module_init( fpckbd_init
);
143 module_exit( fpckbd_exit
);