WIP FPC-III support
[linux/fpc-iii.git] / drivers / input / keyboard / fpckbd.c
blob515b2ccdc6fe25f3c49ec3c7362a43ed0dedd767
1 /*
2 * fpckbd.c
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>
21 #include <linux/io.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,
57 0, KEY_COMPOSE
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 ) {
67 int i, j;
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++ )
78 if( last_rep[ i ] ) {
79 for( j = 2; j < 8; j++ )
80 if( new_rep[ j ] == last_rep[ i ] )
81 goto ignore_old;
83 if( last_rep[ i ] < 0x66 && code_trans[ last_rep[ i ] ] )
84 input_report_key( fpc_dev, code_trans[ last_rep[ i ] ], 0 );
85 ignore_old:
89 for( i = 2; i < 8; i++ )
90 if( new_rep[ i ] ) {
91 for( j = 2; j < 8; j++ )
92 if( last_rep[ j ] == new_rep[ i ] )
93 goto ignore_new;
95 if( new_rep[ i ] < 0x66 && code_trans[ new_rep[ i ] ] )
96 input_report_key( fpc_dev, code_trans[ new_rep[ i ] ], 1 );
97 ignore_new:
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 ) {
110 int i, err;
112 if( !( fpc_dev = input_allocate_device() ) )
113 return -ENOMEM;
115 // FIXME use platform device to get address
116 if( !( report = ioremap( FPCKBD_BASE, 0x10000 ) ) )
117 return -ENOMEM;
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 ) ) )
125 return err;
127 timer_setup( &timer, fpckbd_timer, 0 );
128 mod_timer( &timer, jiffies + HZ / 100 + 1 );
130 return 0;
133 static void __exit fpckbd_exit( void ) {
135 del_timer_sync( &timer );
137 input_unregister_device( fpc_dev );
139 // FIXME iounmap
142 module_init( fpckbd_init );
143 module_exit( fpckbd_exit );