2005-04-16 15:20:36 -07:00
/*
* AT and PS / 2 keyboard driver
*
* Copyright ( c ) 1999 - 2002 Vojtech Pavlik
*/
/*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation .
*/
/*
* This driver can handle standard AT keyboards and PS / 2 keyboards in
* Translated and Raw Set 2 and Set 3 , as well as AT keyboards on dumb
* input - only controllers and AT keyboards connected over a one way RS232
* converter .
*/
# include <linux/delay.h>
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/slab.h>
# include <linux/interrupt.h>
# include <linux/init.h>
# include <linux/input.h>
# include <linux/serio.h>
# include <linux/workqueue.h>
# include <linux/libps2.h>
2006-02-19 00:22:18 -05:00
# include <linux/mutex.h>
2005-04-16 15:20:36 -07:00
# define DRIVER_DESC "AT and PS / 2 keyboard driver"
MODULE_AUTHOR ( " Vojtech Pavlik <vojtech@suse.cz> " ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_LICENSE ( " GPL " ) ;
static int atkbd_set = 2 ;
module_param_named ( set , atkbd_set , int , 0 ) ;
MODULE_PARM_DESC ( set , " Select keyboard code set (2 = default, 3 = PS/2 native) " ) ;
# if defined(__i386__) || defined(__x86_64__) || defined(__hppa__)
static int atkbd_reset ;
# else
static int atkbd_reset = 1 ;
# endif
module_param_named ( reset , atkbd_reset , bool , 0 ) ;
MODULE_PARM_DESC ( reset , " Reset keyboard during initialization " ) ;
static int atkbd_softrepeat ;
module_param_named ( softrepeat , atkbd_softrepeat , bool , 0 ) ;
MODULE_PARM_DESC ( softrepeat , " Use software keyboard repeat " ) ;
static int atkbd_softraw = 1 ;
module_param_named ( softraw , atkbd_softraw , bool , 0 ) ;
MODULE_PARM_DESC ( softraw , " Use software generated rawmode " ) ;
2005-06-07 13:22:14 -07:00
static int atkbd_scroll = 0 ;
2005-04-16 15:20:36 -07:00
module_param_named ( scroll , atkbd_scroll , bool , 0 ) ;
MODULE_PARM_DESC ( scroll , " Enable scroll-wheel on MS Office and similar keyboards " ) ;
static int atkbd_extra ;
module_param_named ( extra , atkbd_extra , bool , 0 ) ;
MODULE_PARM_DESC ( extra , " Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards " ) ;
__obsolete_setup ( " atkbd_set= " ) ;
__obsolete_setup ( " atkbd_reset " ) ;
__obsolete_setup ( " atkbd_softrepeat= " ) ;
/*
* Scancode to keycode tables . These are just the default setting , and
* are loadable via an userland utility .
*/
static unsigned char atkbd_set2_keycode [ 512 ] = {
# ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES
/* XXX: need a more general approach */
# include "hpps2atkbd.h" /* include the keyboard scancodes */
# else
0 , 67 , 65 , 63 , 61 , 59 , 60 , 88 , 0 , 68 , 66 , 64 , 62 , 15 , 41 , 117 ,
0 , 56 , 42 , 93 , 29 , 16 , 2 , 0 , 0 , 0 , 44 , 31 , 30 , 17 , 3 , 0 ,
0 , 46 , 45 , 32 , 18 , 5 , 4 , 95 , 0 , 57 , 47 , 33 , 20 , 19 , 6 , 183 ,
0 , 49 , 48 , 35 , 34 , 21 , 7 , 184 , 0 , 0 , 50 , 36 , 22 , 8 , 9 , 185 ,
0 , 51 , 37 , 23 , 24 , 11 , 10 , 0 , 0 , 52 , 53 , 38 , 39 , 25 , 12 , 0 ,
0 , 89 , 40 , 0 , 26 , 13 , 0 , 0 , 58 , 54 , 28 , 27 , 0 , 43 , 0 , 85 ,
0 , 86 , 91 , 90 , 92 , 0 , 14 , 94 , 0 , 79 , 124 , 75 , 71 , 121 , 0 , 0 ,
82 , 83 , 80 , 76 , 77 , 72 , 1 , 69 , 87 , 78 , 81 , 74 , 55 , 73 , 70 , 99 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
217 , 100 , 255 , 0 , 97 , 165 , 0 , 0 , 156 , 0 , 0 , 0 , 0 , 0 , 0 , 125 ,
173 , 114 , 0 , 113 , 0 , 0 , 0 , 126 , 128 , 0 , 0 , 140 , 0 , 0 , 0 , 127 ,
159 , 0 , 115 , 0 , 164 , 0 , 0 , 116 , 158 , 0 , 150 , 166 , 0 , 0 , 0 , 142 ,
157 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 155 , 0 , 98 , 0 , 0 , 163 , 0 , 0 ,
226 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 255 , 96 , 0 , 0 , 0 , 143 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 107 , 0 , 105 , 102 , 0 , 0 , 112 ,
110 , 111 , 108 , 112 , 106 , 103 , 0 , 119 , 0 , 118 , 109 , 0 , 99 , 104 , 119 , 0 ,
0 , 0 , 0 , 65 , 99 ,
# endif
} ;
static unsigned char atkbd_set3_keycode [ 512 ] = {
0 , 0 , 0 , 0 , 0 , 0 , 0 , 59 , 1 , 138 , 128 , 129 , 130 , 15 , 41 , 60 ,
131 , 29 , 42 , 86 , 58 , 16 , 2 , 61 , 133 , 56 , 44 , 31 , 30 , 17 , 3 , 62 ,
134 , 46 , 45 , 32 , 18 , 5 , 4 , 63 , 135 , 57 , 47 , 33 , 20 , 19 , 6 , 64 ,
136 , 49 , 48 , 35 , 34 , 21 , 7 , 65 , 137 , 100 , 50 , 36 , 22 , 8 , 9 , 66 ,
125 , 51 , 37 , 23 , 24 , 11 , 10 , 67 , 126 , 52 , 53 , 38 , 39 , 25 , 12 , 68 ,
113 , 114 , 40 , 43 , 26 , 13 , 87 , 99 , 97 , 54 , 28 , 27 , 43 , 43 , 88 , 70 ,
108 , 105 , 119 , 103 , 111 , 107 , 14 , 110 , 0 , 79 , 106 , 75 , 71 , 109 , 102 , 104 ,
82 , 83 , 80 , 76 , 77 , 72 , 69 , 98 , 0 , 96 , 81 , 0 , 78 , 73 , 55 , 183 ,
184 , 185 , 186 , 187 , 74 , 94 , 92 , 93 , 0 , 0 , 0 , 125 , 126 , 127 , 112 , 0 ,
0 , 139 , 150 , 163 , 165 , 115 , 152 , 150 , 166 , 140 , 160 , 154 , 113 , 114 , 167 , 168 ,
148 , 149 , 147 , 140
} ;
static unsigned char atkbd_unxlate_table [ 128 ] = {
0 , 118 , 22 , 30 , 38 , 37 , 46 , 54 , 61 , 62 , 70 , 69 , 78 , 85 , 102 , 13 ,
21 , 29 , 36 , 45 , 44 , 53 , 60 , 67 , 68 , 77 , 84 , 91 , 90 , 20 , 28 , 27 ,
35 , 43 , 52 , 51 , 59 , 66 , 75 , 76 , 82 , 14 , 18 , 93 , 26 , 34 , 33 , 42 ,
50 , 49 , 58 , 65 , 73 , 74 , 89 , 124 , 17 , 41 , 88 , 5 , 6 , 4 , 12 , 3 ,
11 , 2 , 10 , 1 , 9 , 119 , 126 , 108 , 117 , 125 , 123 , 107 , 115 , 116 , 121 , 105 ,
114 , 122 , 112 , 113 , 127 , 96 , 97 , 120 , 7 , 15 , 23 , 31 , 39 , 47 , 55 , 63 ,
71 , 79 , 86 , 94 , 8 , 16 , 24 , 32 , 40 , 48 , 56 , 64 , 72 , 80 , 87 , 111 ,
19 , 25 , 57 , 81 , 83 , 92 , 95 , 98 , 99 , 100 , 101 , 103 , 104 , 106 , 109 , 110
} ;
# define ATKBD_CMD_SETLEDS 0x10ed
# define ATKBD_CMD_GSCANSET 0x11f0
# define ATKBD_CMD_SSCANSET 0x10f0
# define ATKBD_CMD_GETID 0x02f2
# define ATKBD_CMD_SETREP 0x10f3
# define ATKBD_CMD_ENABLE 0x00f4
# define ATKBD_CMD_RESET_DIS 0x00f5
# define ATKBD_CMD_SETALL_MBR 0x00fa
# define ATKBD_CMD_RESET_BAT 0x02ff
# define ATKBD_CMD_RESEND 0x00fe
# define ATKBD_CMD_EX_ENABLE 0x10ea
# define ATKBD_CMD_EX_SETLEDS 0x20eb
# define ATKBD_CMD_OK_GETID 0x02e8
# define ATKBD_RET_ACK 0xfa
# define ATKBD_RET_NAK 0xfe
# define ATKBD_RET_BAT 0xaa
# define ATKBD_RET_EMUL0 0xe0
# define ATKBD_RET_EMUL1 0xe1
# define ATKBD_RET_RELEASE 0xf0
2006-06-26 01:51:23 -04:00
# define ATKBD_RET_HANGEUL 0xf1
2005-04-16 15:20:36 -07:00
# define ATKBD_RET_HANJA 0xf2
# define ATKBD_RET_ERR 0xff
# define ATKBD_KEY_UNKNOWN 0
# define ATKBD_KEY_NULL 255
# define ATKBD_SCR_1 254
# define ATKBD_SCR_2 253
# define ATKBD_SCR_4 252
# define ATKBD_SCR_8 251
# define ATKBD_SCR_CLICK 250
# define ATKBD_SCR_LEFT 249
# define ATKBD_SCR_RIGHT 248
# define ATKBD_SPECIAL 248
2005-11-20 00:49:42 -05:00
# define ATKBD_LED_EVENT_BIT 0
# define ATKBD_REP_EVENT_BIT 1
2005-04-16 15:20:36 -07:00
static struct {
unsigned char keycode ;
unsigned char set2 ;
} atkbd_scroll_keys [ ] = {
{ ATKBD_SCR_1 , 0xc5 } ,
2005-05-28 15:51:47 -07:00
{ ATKBD_SCR_2 , 0x9d } ,
{ ATKBD_SCR_4 , 0xa4 } ,
{ ATKBD_SCR_8 , 0x9b } ,
2005-04-16 15:20:36 -07:00
{ ATKBD_SCR_CLICK , 0xe0 } ,
{ ATKBD_SCR_LEFT , 0xcb } ,
{ ATKBD_SCR_RIGHT , 0xd2 } ,
} ;
/*
* The atkbd control structure
*/
struct atkbd {
2005-09-15 02:01:45 -05:00
struct ps2dev ps2dev ;
struct input_dev * dev ;
2005-04-16 15:20:36 -07:00
/* Written only during init */
char name [ 64 ] ;
char phys [ 32 ] ;
unsigned short id ;
unsigned char keycode [ 512 ] ;
unsigned char set ;
unsigned char translated ;
unsigned char extra ;
unsigned char write ;
unsigned char softrepeat ;
unsigned char softraw ;
unsigned char scroll ;
unsigned char enabled ;
/* Accessed only from interrupt */
unsigned char emul ;
unsigned char resend ;
unsigned char release ;
unsigned char bat_xl ;
2005-09-05 00:11:41 -05:00
unsigned char err_xl ;
2005-04-16 15:20:36 -07:00
unsigned int last ;
unsigned long time ;
2005-11-20 00:49:42 -05:00
struct work_struct event_work ;
2006-02-19 00:22:18 -05:00
struct mutex event_mutex ;
2005-11-20 00:49:42 -05:00
unsigned long event_mask ;
2005-04-16 15:20:36 -07:00
} ;
static ssize_t atkbd_attr_show_helper ( struct device * dev , char * buf ,
ssize_t ( * handler ) ( struct atkbd * , char * ) ) ;
static ssize_t atkbd_attr_set_helper ( struct device * dev , const char * buf , size_t count ,
ssize_t ( * handler ) ( struct atkbd * , const char * , size_t ) ) ;
# define ATKBD_DEFINE_ATTR(_name) \
static ssize_t atkbd_show_ # # _name ( struct atkbd * , char * ) ; \
static ssize_t atkbd_set_ # # _name ( struct atkbd * , const char * , size_t ) ; \
2005-05-17 06:42:58 -04:00
static ssize_t atkbd_do_show_ # # _name ( struct device * d , struct device_attribute * attr , char * b ) \
2005-04-16 15:20:36 -07:00
{ \
return atkbd_attr_show_helper ( d , b , atkbd_show_ # # _name ) ; \
} \
2005-05-17 06:42:58 -04:00
static ssize_t atkbd_do_set_ # # _name ( struct device * d , struct device_attribute * attr , const char * b , size_t s ) \
2005-04-16 15:20:36 -07:00
{ \
return atkbd_attr_set_helper ( d , b , s , atkbd_set_ # # _name ) ; \
} \
2005-05-29 02:28:42 -05:00
static struct device_attribute atkbd_attr_ # # _name = \
2005-04-16 15:20:36 -07:00
__ATTR ( _name , S_IWUSR | S_IRUGO , atkbd_do_show_ # # _name , atkbd_do_set_ # # _name ) ;
ATKBD_DEFINE_ATTR ( extra ) ;
ATKBD_DEFINE_ATTR ( scroll ) ;
ATKBD_DEFINE_ATTR ( set ) ;
ATKBD_DEFINE_ATTR ( softrepeat ) ;
ATKBD_DEFINE_ATTR ( softraw ) ;
static void atkbd_report_key ( struct input_dev * dev , struct pt_regs * regs , int code , int value )
{
input_regs ( dev , regs ) ;
if ( value = = 3 ) {
input_report_key ( dev , code , 1 ) ;
input_sync ( dev ) ;
input_report_key ( dev , code , 0 ) ;
} else
input_event ( dev , EV_KEY , code , value ) ;
input_sync ( dev ) ;
}
/*
* atkbd_interrupt ( ) . Here takes place processing of data received from
* the keyboard into events .
*/
static irqreturn_t atkbd_interrupt ( struct serio * serio , unsigned char data ,
unsigned int flags , struct pt_regs * regs )
{
struct atkbd * atkbd = serio_get_drvdata ( serio ) ;
unsigned int code = data ;
int scroll = 0 , hscroll = 0 , click = - 1 ;
int value ;
# ifdef ATKBD_DEBUG
printk ( KERN_DEBUG " atkbd.c: Received %02x flags %02x \n " , data , flags ) ;
# endif
# if !defined(__i386__) && !defined (__x86_64__)
if ( ( flags & ( SERIO_FRAME | SERIO_PARITY ) ) & & ( ~ flags & SERIO_TIMEOUT ) & & ! atkbd - > resend & & atkbd - > write ) {
printk ( KERN_WARNING " atkbd.c: frame/parity error: %02x \n " , flags ) ;
serio_write ( serio , ATKBD_CMD_RESEND ) ;
atkbd - > resend = 1 ;
goto out ;
}
if ( ! flags & & data = = ATKBD_RET_ACK )
atkbd - > resend = 0 ;
# endif
if ( unlikely ( atkbd - > ps2dev . flags & PS2_FLAG_ACK ) )
if ( ps2_handle_ack ( & atkbd - > ps2dev , data ) )
goto out ;
if ( unlikely ( atkbd - > ps2dev . flags & PS2_FLAG_CMD ) )
if ( ps2_handle_response ( & atkbd - > ps2dev , data ) )
goto out ;
if ( ! atkbd - > enabled )
goto out ;
2005-09-15 02:01:45 -05:00
input_event ( atkbd - > dev , EV_MSC , MSC_RAW , code ) ;
2005-04-16 15:20:36 -07:00
if ( atkbd - > translated ) {
if ( atkbd - > emul | |
2006-03-14 00:09:52 -05:00
( code ! = ATKBD_RET_EMUL0 & & code ! = ATKBD_RET_EMUL1 & &
2006-06-26 01:51:23 -04:00
code ! = ATKBD_RET_HANGEUL & & code ! = ATKBD_RET_HANJA & &
2006-03-14 00:09:52 -05:00
( code ! = ATKBD_RET_ERR | | atkbd - > err_xl ) & &
( code ! = ATKBD_RET_BAT | | atkbd - > bat_xl ) ) ) {
2005-04-16 15:20:36 -07:00
atkbd - > release = code > > 7 ;
code & = 0x7f ;
}
2005-09-05 00:11:41 -05:00
if ( ! atkbd - > emul ) {
if ( ( code & 0x7f ) = = ( ATKBD_RET_BAT & 0x7f ) )
2006-03-14 00:09:52 -05:00
atkbd - > bat_xl = ! ( data > > 7 ) ;
2005-09-05 00:11:41 -05:00
if ( ( code & 0x7f ) = = ( ATKBD_RET_ERR & 0x7f ) )
2006-03-14 00:09:52 -05:00
atkbd - > err_xl = ! ( data > > 7 ) ;
2005-09-05 00:11:41 -05:00
}
2005-04-16 15:20:36 -07:00
}
switch ( code ) {
case ATKBD_RET_BAT :
atkbd - > enabled = 0 ;
2006-01-05 23:00:13 -05:00
serio_reconnect ( atkbd - > ps2dev . serio ) ;
2005-04-16 15:20:36 -07:00
goto out ;
case ATKBD_RET_EMUL0 :
atkbd - > emul = 1 ;
goto out ;
case ATKBD_RET_EMUL1 :
atkbd - > emul = 2 ;
goto out ;
case ATKBD_RET_RELEASE :
atkbd - > release = 1 ;
goto out ;
2006-06-26 01:51:23 -04:00
case ATKBD_RET_HANGEUL :
atkbd_report_key ( atkbd - > dev , regs , KEY_HANGEUL , 3 ) ;
2005-04-16 15:20:36 -07:00
goto out ;
case ATKBD_RET_HANJA :
2005-09-15 02:01:45 -05:00
atkbd_report_key ( atkbd - > dev , regs , KEY_HANJA , 3 ) ;
2005-04-16 15:20:36 -07:00
goto out ;
case ATKBD_RET_ERR :
printk ( KERN_DEBUG " atkbd.c: Keyboard on %s reports too many keys pressed. \n " , serio - > phys ) ;
goto out ;
}
if ( atkbd - > set ! = 3 )
code = ( code & 0x7f ) | ( ( code & 0x80 ) < < 1 ) ;
if ( atkbd - > emul ) {
if ( - - atkbd - > emul )
goto out ;
code | = ( atkbd - > set ! = 3 ) ? 0x80 : 0x100 ;
}
if ( atkbd - > keycode [ code ] ! = ATKBD_KEY_NULL )
2005-09-15 02:01:45 -05:00
input_event ( atkbd - > dev , EV_MSC , MSC_SCAN , code ) ;
2005-04-16 15:20:36 -07:00
switch ( atkbd - > keycode [ code ] ) {
case ATKBD_KEY_NULL :
break ;
case ATKBD_KEY_UNKNOWN :
if ( data = = ATKBD_RET_ACK | | data = = ATKBD_RET_NAK ) {
printk ( KERN_WARNING " atkbd.c: Spurious %s on %s. Some program, "
" like XFree86, might be trying access hardware directly. \n " ,
data = = ATKBD_RET_ACK ? " ACK " : " NAK " , serio - > phys ) ;
} else {
printk ( KERN_WARNING " atkbd.c: Unknown key %s "
" (%s set %d, code %#x on %s). \n " ,
atkbd - > release ? " released " : " pressed " ,
atkbd - > translated ? " translated " : " raw " ,
atkbd - > set , code , serio - > phys ) ;
printk ( KERN_WARNING " atkbd.c: Use 'setkeycodes %s%02x <keycode>' "
" to make it known. \n " ,
code & 0x80 ? " e0 " : " " , code & 0x7f ) ;
}
2005-09-15 02:01:45 -05:00
input_sync ( atkbd - > dev ) ;
2005-04-16 15:20:36 -07:00
break ;
case ATKBD_SCR_1 :
scroll = 1 - atkbd - > release * 2 ;
break ;
case ATKBD_SCR_2 :
scroll = 2 - atkbd - > release * 4 ;
break ;
case ATKBD_SCR_4 :
scroll = 4 - atkbd - > release * 8 ;
break ;
case ATKBD_SCR_8 :
scroll = 8 - atkbd - > release * 16 ;
break ;
case ATKBD_SCR_CLICK :
click = ! atkbd - > release ;
break ;
case ATKBD_SCR_LEFT :
hscroll = - 1 ;
break ;
case ATKBD_SCR_RIGHT :
hscroll = 1 ;
break ;
default :
value = atkbd - > release ? 0 :
2005-09-15 02:01:45 -05:00
( 1 + ( ! atkbd - > softrepeat & & test_bit ( atkbd - > keycode [ code ] , atkbd - > dev - > key ) ) ) ;
2005-04-16 15:20:36 -07:00
2005-05-29 02:28:42 -05:00
switch ( value ) { /* Workaround Toshiba laptop multiple keypress */
2005-04-16 15:20:36 -07:00
case 0 :
atkbd - > last = 0 ;
break ;
case 1 :
atkbd - > last = code ;
2005-09-15 02:01:45 -05:00
atkbd - > time = jiffies + msecs_to_jiffies ( atkbd - > dev - > rep [ REP_DELAY ] ) / 2 ;
2005-04-16 15:20:36 -07:00
break ;
case 2 :
if ( ! time_after ( jiffies , atkbd - > time ) & & atkbd - > last = = code )
value = 1 ;
break ;
}
2005-09-15 02:01:45 -05:00
atkbd_report_key ( atkbd - > dev , regs , atkbd - > keycode [ code ] , value ) ;
2005-04-16 15:20:36 -07:00
}
if ( atkbd - > scroll ) {
2005-09-15 02:01:45 -05:00
input_regs ( atkbd - > dev , regs ) ;
2005-04-16 15:20:36 -07:00
if ( click ! = - 1 )
2005-09-15 02:01:45 -05:00
input_report_key ( atkbd - > dev , BTN_MIDDLE , click ) ;
input_report_rel ( atkbd - > dev , REL_WHEEL , scroll ) ;
input_report_rel ( atkbd - > dev , REL_HWHEEL , hscroll ) ;
input_sync ( atkbd - > dev ) ;
2005-04-16 15:20:36 -07:00
}
atkbd - > release = 0 ;
out :
return IRQ_HANDLED ;
}
/*
2005-11-20 00:49:42 -05:00
* atkbd_event_work ( ) is used to complete processing of events that
* can not be processed by input_event ( ) which is often called from
* interrupt context .
2005-04-16 15:20:36 -07:00
*/
2005-11-20 00:49:42 -05:00
static void atkbd_event_work ( void * data )
2005-04-16 15:20:36 -07:00
{
const short period [ 32 ] =
{ 33 , 37 , 42 , 46 , 50 , 54 , 58 , 63 , 67 , 75 , 83 , 92 , 100 , 109 , 116 , 125 ,
133 , 149 , 167 , 182 , 200 , 217 , 232 , 250 , 270 , 303 , 333 , 370 , 400 , 435 , 470 , 500 } ;
const short delay [ 4 ] =
{ 250 , 500 , 750 , 1000 } ;
2005-11-20 00:49:42 -05:00
struct atkbd * atkbd = data ;
struct input_dev * dev = atkbd - > dev ;
2005-04-16 15:20:36 -07:00
unsigned char param [ 2 ] ;
int i , j ;
2006-02-19 00:22:18 -05:00
mutex_lock ( & atkbd - > event_mutex ) ;
2005-11-20 00:49:42 -05:00
if ( test_and_clear_bit ( ATKBD_LED_EVENT_BIT , & atkbd - > event_mask ) ) {
param [ 0 ] = ( test_bit ( LED_SCROLLL , dev - > led ) ? 1 : 0 )
| ( test_bit ( LED_NUML , dev - > led ) ? 2 : 0 )
| ( test_bit ( LED_CAPSL , dev - > led ) ? 4 : 0 ) ;
ps2_command ( & atkbd - > ps2dev , param , ATKBD_CMD_SETLEDS ) ;
if ( atkbd - > extra ) {
param [ 0 ] = 0 ;
param [ 1 ] = ( test_bit ( LED_COMPOSE , dev - > led ) ? 0x01 : 0 )
| ( test_bit ( LED_SLEEP , dev - > led ) ? 0x02 : 0 )
| ( test_bit ( LED_SUSPEND , dev - > led ) ? 0x04 : 0 )
| ( test_bit ( LED_MISC , dev - > led ) ? 0x10 : 0 )
| ( test_bit ( LED_MUTE , dev - > led ) ? 0x20 : 0 ) ;
ps2_command ( & atkbd - > ps2dev , param , ATKBD_CMD_EX_SETLEDS ) ;
}
}
if ( test_and_clear_bit ( ATKBD_REP_EVENT_BIT , & atkbd - > event_mask ) ) {
i = j = 0 ;
while ( i < 31 & & period [ i ] < dev - > rep [ REP_PERIOD ] )
i + + ;
while ( j < 3 & & delay [ j ] < dev - > rep [ REP_DELAY ] )
j + + ;
dev - > rep [ REP_PERIOD ] = period [ i ] ;
dev - > rep [ REP_DELAY ] = delay [ j ] ;
param [ 0 ] = i | ( j < < 5 ) ;
ps2_command ( & atkbd - > ps2dev , param , ATKBD_CMD_SETREP ) ;
}
2006-02-19 00:22:18 -05:00
mutex_unlock ( & atkbd - > event_mutex ) ;
2005-11-20 00:49:42 -05:00
}
/*
* Event callback from the input module . Events that change the state of
* the hardware are processed here . If action can not be performed in
* interrupt context it is offloaded to atkbd_event_work .
*/
static int atkbd_event ( struct input_dev * dev , unsigned int type , unsigned int code , int value )
{
struct atkbd * atkbd = dev - > private ;
2005-04-16 15:20:36 -07:00
if ( ! atkbd - > write )
return - 1 ;
switch ( type ) {
case EV_LED :
2005-11-20 00:49:42 -05:00
set_bit ( ATKBD_LED_EVENT_BIT , & atkbd - > event_mask ) ;
wmb ( ) ;
schedule_work ( & atkbd - > event_work ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
case EV_REP :
2005-11-20 00:49:42 -05:00
if ( ! atkbd - > softrepeat ) {
set_bit ( ATKBD_REP_EVENT_BIT , & atkbd - > event_mask ) ;
wmb ( ) ;
schedule_work ( & atkbd - > event_work ) ;
}
2005-04-16 15:20:36 -07:00
return 0 ;
}
return - 1 ;
}
/*
* atkbd_enable ( ) signals that interrupt handler is allowed to
* generate input events .
*/
static inline void atkbd_enable ( struct atkbd * atkbd )
{
serio_pause_rx ( atkbd - > ps2dev . serio ) ;
atkbd - > enabled = 1 ;
serio_continue_rx ( atkbd - > ps2dev . serio ) ;
}
/*
* atkbd_disable ( ) tells input handler that all incoming data except
* for ACKs and command response should be dropped .
*/
static inline void atkbd_disable ( struct atkbd * atkbd )
{
serio_pause_rx ( atkbd - > ps2dev . serio ) ;
atkbd - > enabled = 0 ;
serio_continue_rx ( atkbd - > ps2dev . serio ) ;
}
/*
* atkbd_probe ( ) probes for an AT keyboard on a serio port .
*/
static int atkbd_probe ( struct atkbd * atkbd )
{
struct ps2dev * ps2dev = & atkbd - > ps2dev ;
unsigned char param [ 2 ] ;
/*
* Some systems , where the bit - twiddling when testing the io - lines of the
* controller may confuse the keyboard need a full reset of the keyboard . On
* these systems the BIOS also usually doesn ' t do it for us .
*/
if ( atkbd_reset )
if ( ps2_command ( ps2dev , NULL , ATKBD_CMD_RESET_BAT ) )
printk ( KERN_WARNING " atkbd.c: keyboard reset failed on %s \n " , ps2dev - > serio - > phys ) ;
/*
* Then we check the keyboard ID . We should get 0xab83 under normal conditions .
* Some keyboards report different values , but the first byte is always 0xab or
* 0xac . Some old AT keyboards don ' t report anything . If a mouse is connected , this
* should make sure we don ' t try to set the LEDs on it .
*/
param [ 0 ] = param [ 1 ] = 0xa5 ; /* initialize with invalid values */
if ( ps2_command ( ps2dev , param , ATKBD_CMD_GETID ) ) {
/*
* If the get ID command failed , we check if we can at least set the LEDs on
* the keyboard . This should work on every keyboard out there . It also turns
* the LEDs off , which we want anyway .
*/
param [ 0 ] = 0 ;
if ( ps2_command ( ps2dev , param , ATKBD_CMD_SETLEDS ) )
return - 1 ;
atkbd - > id = 0xabba ;
return 0 ;
}
if ( param [ 0 ] ! = 0xab & & param [ 0 ] ! = 0xac & & /* Regular and NCD Sun keyboards */
param [ 0 ] ! = 0x2b & & param [ 0 ] ! = 0x5d & & /* Trust keyboard, raw and translated */
param [ 0 ] ! = 0x60 & & param [ 0 ] ! = 0x47 ) /* NMB SGI keyboard, raw and translated */
return - 1 ;
atkbd - > id = ( param [ 0 ] < < 8 ) | param [ 1 ] ;
if ( atkbd - > id = = 0xaca1 & & atkbd - > translated ) {
printk ( KERN_ERR " atkbd.c: NCD terminal keyboards are only supported on non-translating \n " ) ;
printk ( KERN_ERR " atkbd.c: controllers. Use i8042.direct=1 to disable translation. \n " ) ;
return - 1 ;
}
return 0 ;
}
/*
* atkbd_select_set checks if a keyboard has a working Set 3 support , and
* sets it into that . Unfortunately there are keyboards that can be switched
* to Set 3 , but don ' t work well in that ( BTC Multimedia . . . )
*/
static int atkbd_select_set ( struct atkbd * atkbd , int target_set , int allow_extra )
{
struct ps2dev * ps2dev = & atkbd - > ps2dev ;
unsigned char param [ 2 ] ;
atkbd - > extra = 0 ;
/*
* For known special keyboards we can go ahead and set the correct set .
* We check for NCD PS / 2 Sun , NorthGate OmniKey 101 and
* IBM RapidAccess / IBM EzButton / Chicony KBP - 8993 keyboards .
*/
if ( atkbd - > translated )
return 2 ;
if ( atkbd - > id = = 0xaca1 ) {
param [ 0 ] = 3 ;
ps2_command ( ps2dev , param , ATKBD_CMD_SSCANSET ) ;
return 3 ;
}
if ( allow_extra ) {
param [ 0 ] = 0x71 ;
if ( ! ps2_command ( ps2dev , param , ATKBD_CMD_EX_ENABLE ) ) {
atkbd - > extra = 1 ;
return 2 ;
}
}
if ( target_set ! = 3 )
return 2 ;
if ( ! ps2_command ( ps2dev , param , ATKBD_CMD_OK_GETID ) ) {
atkbd - > id = param [ 0 ] < < 8 | param [ 1 ] ;
return 2 ;
}
param [ 0 ] = 3 ;
if ( ps2_command ( ps2dev , param , ATKBD_CMD_SSCANSET ) )
return 2 ;
param [ 0 ] = 0 ;
if ( ps2_command ( ps2dev , param , ATKBD_CMD_GSCANSET ) )
return 2 ;
if ( param [ 0 ] ! = 3 ) {
param [ 0 ] = 2 ;
if ( ps2_command ( ps2dev , param , ATKBD_CMD_SSCANSET ) )
return 2 ;
}
ps2_command ( ps2dev , param , ATKBD_CMD_SETALL_MBR ) ;
return 3 ;
}
static int atkbd_activate ( struct atkbd * atkbd )
{
struct ps2dev * ps2dev = & atkbd - > ps2dev ;
unsigned char param [ 1 ] ;
/*
* Set the LEDs to a defined state .
*/
param [ 0 ] = 0 ;
if ( ps2_command ( ps2dev , param , ATKBD_CMD_SETLEDS ) )
return - 1 ;
/*
* Set autorepeat to fastest possible .
*/
param [ 0 ] = 0 ;
if ( ps2_command ( ps2dev , param , ATKBD_CMD_SETREP ) )
return - 1 ;
/*
* Enable the keyboard to receive keystrokes .
*/
if ( ps2_command ( ps2dev , NULL , ATKBD_CMD_ENABLE ) ) {
printk ( KERN_ERR " atkbd.c: Failed to enable keyboard on %s \n " ,
ps2dev - > serio - > phys ) ;
return - 1 ;
}
return 0 ;
}
/*
* atkbd_cleanup ( ) restores the keyboard state so that BIOS is happy after a
* reboot .
*/
static void atkbd_cleanup ( struct serio * serio )
{
struct atkbd * atkbd = serio_get_drvdata ( serio ) ;
ps2_command ( & atkbd - > ps2dev , NULL , ATKBD_CMD_RESET_BAT ) ;
}
/*
* atkbd_disconnect ( ) closes and frees .
*/
static void atkbd_disconnect ( struct serio * serio )
{
struct atkbd * atkbd = serio_get_drvdata ( serio ) ;
atkbd_disable ( atkbd ) ;
/* make sure we don't have a command in flight */
2005-05-01 08:59:04 -07:00
synchronize_sched ( ) ; /* Allow atkbd_interrupt()s to complete. */
2005-04-16 15:20:36 -07:00
flush_scheduled_work ( ) ;
device_remove_file ( & serio - > dev , & atkbd_attr_extra ) ;
device_remove_file ( & serio - > dev , & atkbd_attr_scroll ) ;
device_remove_file ( & serio - > dev , & atkbd_attr_set ) ;
device_remove_file ( & serio - > dev , & atkbd_attr_softrepeat ) ;
device_remove_file ( & serio - > dev , & atkbd_attr_softraw ) ;
2005-09-15 02:01:45 -05:00
input_unregister_device ( atkbd - > dev ) ;
2005-04-16 15:20:36 -07:00
serio_close ( serio ) ;
serio_set_drvdata ( serio , NULL ) ;
kfree ( atkbd ) ;
}
/*
2005-09-15 02:01:45 -05:00
* atkbd_set_keycode_table ( ) initializes keyboard ' s keycode table
2005-04-16 15:20:36 -07:00
* according to the selected scancode set
*/
static void atkbd_set_keycode_table ( struct atkbd * atkbd )
{
int i , j ;
memset ( atkbd - > keycode , 0 , sizeof ( atkbd - > keycode ) ) ;
if ( atkbd - > translated ) {
for ( i = 0 ; i < 128 ; i + + ) {
atkbd - > keycode [ i ] = atkbd_set2_keycode [ atkbd_unxlate_table [ i ] ] ;
atkbd - > keycode [ i | 0x80 ] = atkbd_set2_keycode [ atkbd_unxlate_table [ i ] | 0x80 ] ;
if ( atkbd - > scroll )
for ( j = 0 ; j < ARRAY_SIZE ( atkbd_scroll_keys ) ; j + + )
if ( ( atkbd_unxlate_table [ i ] | 0x80 ) = = atkbd_scroll_keys [ j ] . set2 )
atkbd - > keycode [ i | 0x80 ] = atkbd_scroll_keys [ j ] . keycode ;
}
} else if ( atkbd - > set = = 3 ) {
memcpy ( atkbd - > keycode , atkbd_set3_keycode , sizeof ( atkbd - > keycode ) ) ;
} else {
memcpy ( atkbd - > keycode , atkbd_set2_keycode , sizeof ( atkbd - > keycode ) ) ;
if ( atkbd - > scroll )
for ( i = 0 ; i < ARRAY_SIZE ( atkbd_scroll_keys ) ; i + + )
atkbd - > keycode [ atkbd_scroll_keys [ i ] . set2 ] = atkbd_scroll_keys [ i ] . keycode ;
}
}
/*
* atkbd_set_device_attrs ( ) sets up keyboard ' s input device structure
*/
static void atkbd_set_device_attrs ( struct atkbd * atkbd )
{
2005-09-15 02:01:45 -05:00
struct input_dev * input_dev = atkbd - > dev ;
2005-04-16 15:20:36 -07:00
int i ;
2005-09-15 02:01:45 -05:00
if ( atkbd - > extra )
2006-06-26 01:46:17 -04:00
snprintf ( atkbd - > name , sizeof ( atkbd - > name ) ,
" AT Set 2 Extra keyboard " ) ;
2005-09-15 02:01:45 -05:00
else
2006-06-26 01:46:17 -04:00
snprintf ( atkbd - > name , sizeof ( atkbd - > name ) ,
" AT %s Set %d keyboard " ,
atkbd - > translated ? " Translated " : " Raw " , atkbd - > set ) ;
2005-04-16 15:20:36 -07:00
2006-06-26 01:46:17 -04:00
snprintf ( atkbd - > phys , sizeof ( atkbd - > phys ) ,
" %s/input0 " , atkbd - > ps2dev . serio - > phys ) ;
2005-04-16 15:20:36 -07:00
2005-09-15 02:01:45 -05:00
input_dev - > name = atkbd - > name ;
input_dev - > phys = atkbd - > phys ;
input_dev - > id . bustype = BUS_I8042 ;
input_dev - > id . vendor = 0x0001 ;
input_dev - > id . product = atkbd - > translated ? 1 : atkbd - > set ;
input_dev - > id . version = atkbd - > id ;
input_dev - > event = atkbd_event ;
input_dev - > private = atkbd ;
input_dev - > cdev . dev = & atkbd - > ps2dev . serio - > dev ;
2005-04-16 15:20:36 -07:00
2005-09-15 02:01:45 -05:00
input_dev - > evbit [ 0 ] = BIT ( EV_KEY ) | BIT ( EV_REP ) | BIT ( EV_MSC ) ;
2005-04-16 15:20:36 -07:00
if ( atkbd - > write ) {
2005-09-15 02:01:45 -05:00
input_dev - > evbit [ 0 ] | = BIT ( EV_LED ) ;
input_dev - > ledbit [ 0 ] = BIT ( LED_NUML ) | BIT ( LED_CAPSL ) | BIT ( LED_SCROLLL ) ;
2005-04-16 15:20:36 -07:00
}
if ( atkbd - > extra )
2005-09-15 02:01:45 -05:00
input_dev - > ledbit [ 0 ] | = BIT ( LED_COMPOSE ) | BIT ( LED_SUSPEND ) |
2005-04-16 15:20:36 -07:00
BIT ( LED_SLEEP ) | BIT ( LED_MUTE ) | BIT ( LED_MISC ) ;
if ( ! atkbd - > softrepeat ) {
2005-09-15 02:01:45 -05:00
input_dev - > rep [ REP_DELAY ] = 250 ;
input_dev - > rep [ REP_PERIOD ] = 33 ;
2005-04-16 15:20:36 -07:00
}
2005-09-15 02:01:45 -05:00
input_dev - > mscbit [ 0 ] = atkbd - > softraw ? BIT ( MSC_SCAN ) : BIT ( MSC_RAW ) | BIT ( MSC_SCAN ) ;
2005-04-16 15:20:36 -07:00
if ( atkbd - > scroll ) {
2005-09-15 02:01:45 -05:00
input_dev - > evbit [ 0 ] | = BIT ( EV_REL ) ;
input_dev - > relbit [ 0 ] = BIT ( REL_WHEEL ) | BIT ( REL_HWHEEL ) ;
set_bit ( BTN_MIDDLE , input_dev - > keybit ) ;
2005-04-16 15:20:36 -07:00
}
2005-09-15 02:01:45 -05:00
input_dev - > keycode = atkbd - > keycode ;
input_dev - > keycodesize = sizeof ( unsigned char ) ;
input_dev - > keycodemax = ARRAY_SIZE ( atkbd_set2_keycode ) ;
2005-04-16 15:20:36 -07:00
for ( i = 0 ; i < 512 ; i + + )
if ( atkbd - > keycode [ i ] & & atkbd - > keycode [ i ] < ATKBD_SPECIAL )
2005-09-15 02:01:45 -05:00
set_bit ( atkbd - > keycode [ i ] , input_dev - > keybit ) ;
2005-04-16 15:20:36 -07:00
}
/*
* atkbd_connect ( ) is called when the serio module finds an interface
* that isn ' t handled yet by an appropriate device driver . We check if
* there is an AT keyboard out there and if yes , we register ourselves
* to the input module .
*/
static int atkbd_connect ( struct serio * serio , struct serio_driver * drv )
{
struct atkbd * atkbd ;
2005-09-15 02:01:45 -05:00
struct input_dev * dev ;
int err = - ENOMEM ;
2005-04-16 15:20:36 -07:00
2005-09-15 02:01:45 -05:00
atkbd = kzalloc ( sizeof ( struct atkbd ) , GFP_KERNEL ) ;
dev = input_allocate_device ( ) ;
if ( ! atkbd | | ! dev )
goto fail ;
2005-04-16 15:20:36 -07:00
2005-09-15 02:01:45 -05:00
atkbd - > dev = dev ;
2005-04-16 15:20:36 -07:00
ps2_init ( & atkbd - > ps2dev , serio ) ;
2005-11-20 00:49:42 -05:00
INIT_WORK ( & atkbd - > event_work , atkbd_event_work , atkbd ) ;
2006-02-19 00:22:18 -05:00
mutex_init ( & atkbd - > event_mutex ) ;
2005-04-16 15:20:36 -07:00
switch ( serio - > id . type ) {
case SERIO_8042_XL :
atkbd - > translated = 1 ;
case SERIO_8042 :
if ( serio - > write )
atkbd - > write = 1 ;
break ;
}
atkbd - > softraw = atkbd_softraw ;
atkbd - > softrepeat = atkbd_softrepeat ;
atkbd - > scroll = atkbd_scroll ;
if ( atkbd - > softrepeat )
atkbd - > softraw = 1 ;
serio_set_drvdata ( serio , atkbd ) ;
err = serio_open ( serio , drv ) ;
2005-09-15 02:01:45 -05:00
if ( err )
goto fail ;
2005-04-16 15:20:36 -07:00
if ( atkbd - > write ) {
if ( atkbd_probe ( atkbd ) ) {
serio_close ( serio ) ;
2005-09-15 02:01:45 -05:00
err = - ENODEV ;
goto fail ;
2005-04-16 15:20:36 -07:00
}
atkbd - > set = atkbd_select_set ( atkbd , atkbd_set , atkbd_extra ) ;
atkbd_activate ( atkbd ) ;
} else {
atkbd - > set = 2 ;
atkbd - > id = 0xab00 ;
}
atkbd_set_keycode_table ( atkbd ) ;
atkbd_set_device_attrs ( atkbd ) ;
device_create_file ( & serio - > dev , & atkbd_attr_extra ) ;
device_create_file ( & serio - > dev , & atkbd_attr_scroll ) ;
device_create_file ( & serio - > dev , & atkbd_attr_set ) ;
device_create_file ( & serio - > dev , & atkbd_attr_softrepeat ) ;
device_create_file ( & serio - > dev , & atkbd_attr_softraw ) ;
atkbd_enable ( atkbd ) ;
2005-09-15 02:01:45 -05:00
input_register_device ( atkbd - > dev ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
2005-09-15 02:01:45 -05:00
fail : serio_set_drvdata ( serio , NULL ) ;
input_free_device ( dev ) ;
kfree ( atkbd ) ;
return err ;
2005-04-16 15:20:36 -07:00
}
/*
* atkbd_reconnect ( ) tries to restore keyboard into a sane state and is
* most likely called on resume .
*/
static int atkbd_reconnect ( struct serio * serio )
{
struct atkbd * atkbd = serio_get_drvdata ( serio ) ;
struct serio_driver * drv = serio - > drv ;
unsigned char param [ 1 ] ;
if ( ! atkbd | | ! drv ) {
printk ( KERN_DEBUG " atkbd: reconnect request, but serio is disconnected, ignoring... \n " ) ;
return - 1 ;
}
atkbd_disable ( atkbd ) ;
if ( atkbd - > write ) {
2005-09-15 02:01:45 -05:00
param [ 0 ] = ( test_bit ( LED_SCROLLL , atkbd - > dev - > led ) ? 1 : 0 )
| ( test_bit ( LED_NUML , atkbd - > dev - > led ) ? 2 : 0 )
| ( test_bit ( LED_CAPSL , atkbd - > dev - > led ) ? 4 : 0 ) ;
2005-04-16 15:20:36 -07:00
if ( atkbd_probe ( atkbd ) )
return - 1 ;
if ( atkbd - > set ! = atkbd_select_set ( atkbd , atkbd - > set , atkbd - > extra ) )
return - 1 ;
atkbd_activate ( atkbd ) ;
if ( ps2_command ( & atkbd - > ps2dev , param , ATKBD_CMD_SETLEDS ) )
return - 1 ;
}
atkbd_enable ( atkbd ) ;
return 0 ;
}
static struct serio_device_id atkbd_serio_ids [ ] = {
{
. type = SERIO_8042 ,
. proto = SERIO_ANY ,
. id = SERIO_ANY ,
. extra = SERIO_ANY ,
} ,
{
. type = SERIO_8042_XL ,
. proto = SERIO_ANY ,
. id = SERIO_ANY ,
. extra = SERIO_ANY ,
} ,
{
. type = SERIO_RS232 ,
. proto = SERIO_PS2SER ,
. id = SERIO_ANY ,
. extra = SERIO_ANY ,
} ,
{ 0 }
} ;
MODULE_DEVICE_TABLE ( serio , atkbd_serio_ids ) ;
static struct serio_driver atkbd_drv = {
. driver = {
. name = " atkbd " ,
} ,
. description = DRIVER_DESC ,
. id_table = atkbd_serio_ids ,
. interrupt = atkbd_interrupt ,
. connect = atkbd_connect ,
. reconnect = atkbd_reconnect ,
. disconnect = atkbd_disconnect ,
. cleanup = atkbd_cleanup ,
} ;
static ssize_t atkbd_attr_show_helper ( struct device * dev , char * buf ,
ssize_t ( * handler ) ( struct atkbd * , char * ) )
{
struct serio * serio = to_serio_port ( dev ) ;
int retval ;
retval = serio_pin_driver ( serio ) ;
if ( retval )
return retval ;
if ( serio - > drv ! = & atkbd_drv ) {
retval = - ENODEV ;
goto out ;
}
retval = handler ( ( struct atkbd * ) serio_get_drvdata ( serio ) , buf ) ;
out :
serio_unpin_driver ( serio ) ;
return retval ;
}
static ssize_t atkbd_attr_set_helper ( struct device * dev , const char * buf , size_t count ,
ssize_t ( * handler ) ( struct atkbd * , const char * , size_t ) )
{
struct serio * serio = to_serio_port ( dev ) ;
struct atkbd * atkbd ;
int retval ;
retval = serio_pin_driver ( serio ) ;
if ( retval )
return retval ;
if ( serio - > drv ! = & atkbd_drv ) {
retval = - ENODEV ;
goto out ;
}
atkbd = serio_get_drvdata ( serio ) ;
atkbd_disable ( atkbd ) ;
retval = handler ( atkbd , buf , count ) ;
atkbd_enable ( atkbd ) ;
out :
serio_unpin_driver ( serio ) ;
return retval ;
}
static ssize_t atkbd_show_extra ( struct atkbd * atkbd , char * buf )
{
return sprintf ( buf , " %d \n " , atkbd - > extra ? 1 : 0 ) ;
}
static ssize_t atkbd_set_extra ( struct atkbd * atkbd , const char * buf , size_t count )
{
2005-09-15 02:01:45 -05:00
struct input_dev * new_dev ;
2005-04-16 15:20:36 -07:00
unsigned long value ;
char * rest ;
if ( ! atkbd - > write )
return - EIO ;
value = simple_strtoul ( buf , & rest , 10 ) ;
if ( * rest | | value > 1 )
return - EINVAL ;
if ( atkbd - > extra ! = value ) {
2005-09-15 02:01:45 -05:00
/*
* Since device ' s properties will change we need to
* unregister old device . But allocate new one first
* to make sure we have it .
*/
if ( ! ( new_dev = input_allocate_device ( ) ) )
return - ENOMEM ;
input_unregister_device ( atkbd - > dev ) ;
atkbd - > dev = new_dev ;
2005-04-16 15:20:36 -07:00
atkbd - > set = atkbd_select_set ( atkbd , atkbd - > set , value ) ;
atkbd_activate ( atkbd ) ;
atkbd_set_device_attrs ( atkbd ) ;
2005-09-15 02:01:45 -05:00
input_register_device ( atkbd - > dev ) ;
2005-04-16 15:20:36 -07:00
}
return count ;
}
static ssize_t atkbd_show_scroll ( struct atkbd * atkbd , char * buf )
{
return sprintf ( buf , " %d \n " , atkbd - > scroll ? 1 : 0 ) ;
}
static ssize_t atkbd_set_scroll ( struct atkbd * atkbd , const char * buf , size_t count )
{
2005-09-15 02:01:45 -05:00
struct input_dev * new_dev ;
2005-04-16 15:20:36 -07:00
unsigned long value ;
char * rest ;
value = simple_strtoul ( buf , & rest , 10 ) ;
if ( * rest | | value > 1 )
return - EINVAL ;
if ( atkbd - > scroll ! = value ) {
2005-09-15 02:01:45 -05:00
if ( ! ( new_dev = input_allocate_device ( ) ) )
return - ENOMEM ;
input_unregister_device ( atkbd - > dev ) ;
atkbd - > dev = new_dev ;
2005-04-16 15:20:36 -07:00
atkbd - > scroll = value ;
atkbd_set_keycode_table ( atkbd ) ;
atkbd_set_device_attrs ( atkbd ) ;
2005-09-15 02:01:45 -05:00
input_register_device ( atkbd - > dev ) ;
2005-04-16 15:20:36 -07:00
}
return count ;
}
static ssize_t atkbd_show_set ( struct atkbd * atkbd , char * buf )
{
return sprintf ( buf , " %d \n " , atkbd - > set ) ;
}
static ssize_t atkbd_set_set ( struct atkbd * atkbd , const char * buf , size_t count )
{
2005-09-15 02:01:45 -05:00
struct input_dev * new_dev ;
2005-04-16 15:20:36 -07:00
unsigned long value ;
char * rest ;
if ( ! atkbd - > write )
return - EIO ;
value = simple_strtoul ( buf , & rest , 10 ) ;
if ( * rest | | ( value ! = 2 & & value ! = 3 ) )
return - EINVAL ;
if ( atkbd - > set ! = value ) {
2005-09-15 02:01:45 -05:00
if ( ! ( new_dev = input_allocate_device ( ) ) )
return - ENOMEM ;
input_unregister_device ( atkbd - > dev ) ;
atkbd - > dev = new_dev ;
2005-04-16 15:20:36 -07:00
atkbd - > set = atkbd_select_set ( atkbd , value , atkbd - > extra ) ;
atkbd_activate ( atkbd ) ;
atkbd_set_keycode_table ( atkbd ) ;
atkbd_set_device_attrs ( atkbd ) ;
2005-09-15 02:01:45 -05:00
input_register_device ( atkbd - > dev ) ;
2005-04-16 15:20:36 -07:00
}
return count ;
}
static ssize_t atkbd_show_softrepeat ( struct atkbd * atkbd , char * buf )
{
return sprintf ( buf , " %d \n " , atkbd - > softrepeat ? 1 : 0 ) ;
}
static ssize_t atkbd_set_softrepeat ( struct atkbd * atkbd , const char * buf , size_t count )
{
2005-09-15 02:01:45 -05:00
struct input_dev * new_dev ;
2005-04-16 15:20:36 -07:00
unsigned long value ;
char * rest ;
if ( ! atkbd - > write )
return - EIO ;
value = simple_strtoul ( buf , & rest , 10 ) ;
if ( * rest | | value > 1 )
return - EINVAL ;
if ( atkbd - > softrepeat ! = value ) {
2005-09-15 02:01:45 -05:00
if ( ! ( new_dev = input_allocate_device ( ) ) )
return - ENOMEM ;
input_unregister_device ( atkbd - > dev ) ;
atkbd - > dev = new_dev ;
2005-04-16 15:20:36 -07:00
atkbd - > softrepeat = value ;
if ( atkbd - > softrepeat )
atkbd - > softraw = 1 ;
atkbd_set_device_attrs ( atkbd ) ;
2005-09-15 02:01:45 -05:00
input_register_device ( atkbd - > dev ) ;
2005-04-16 15:20:36 -07:00
}
return count ;
}
static ssize_t atkbd_show_softraw ( struct atkbd * atkbd , char * buf )
{
return sprintf ( buf , " %d \n " , atkbd - > softraw ? 1 : 0 ) ;
}
static ssize_t atkbd_set_softraw ( struct atkbd * atkbd , const char * buf , size_t count )
{
2005-09-15 02:01:45 -05:00
struct input_dev * new_dev ;
2005-04-16 15:20:36 -07:00
unsigned long value ;
char * rest ;
value = simple_strtoul ( buf , & rest , 10 ) ;
if ( * rest | | value > 1 )
return - EINVAL ;
if ( atkbd - > softraw ! = value ) {
2005-09-15 02:01:45 -05:00
if ( ! ( new_dev = input_allocate_device ( ) ) )
return - ENOMEM ;
input_unregister_device ( atkbd - > dev ) ;
atkbd - > dev = new_dev ;
2005-04-16 15:20:36 -07:00
atkbd - > softraw = value ;
atkbd_set_device_attrs ( atkbd ) ;
2005-09-15 02:01:45 -05:00
input_register_device ( atkbd - > dev ) ;
2005-04-16 15:20:36 -07:00
}
return count ;
}
static int __init atkbd_init ( void )
{
serio_register_driver ( & atkbd_drv ) ;
return 0 ;
}
static void __exit atkbd_exit ( void )
{
serio_unregister_driver ( & atkbd_drv ) ;
}
module_init ( atkbd_init ) ;
module_exit ( atkbd_exit ) ;