2005-11-20 08:50:06 +03:00
/*
* Wistron laptop button driver
* Copyright ( C ) 2005 Miloslav Trmac < mitr @ volny . cz >
2005-11-20 08:50:37 +03:00
* Copyright ( C ) 2005 Bernhard Rosenkraenzer < bero @ arklinux . org >
2005-11-20 08:50:58 +03:00
* Copyright ( C ) 2005 Dmitry Torokhov < dtor @ mail . ru >
2005-11-20 08:50:06 +03:00
*
* You can redistribute and / or modify this program under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU General
* Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 59 Temple Place Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
2006-10-11 12:22:01 +04:00
# include <linux/io.h>
2005-11-20 08:50:06 +03:00
# include <linux/dmi.h>
# include <linux/init.h>
2007-05-23 07:48:39 +04:00
# include <linux/input-polldev.h>
2005-11-20 08:50:06 +03:00
# include <linux/interrupt.h>
2007-05-21 08:46:22 +04:00
# include <linux/jiffies.h>
2005-11-20 08:50:06 +03:00
# include <linux/kernel.h>
# include <linux/mc146818rtc.h>
# include <linux/module.h>
# include <linux/preempt.h>
# include <linux/string.h>
# include <linux/types.h>
2005-11-20 08:50:58 +03:00
# include <linux/platform_device.h>
2007-05-21 08:46:31 +04:00
# include <linux/leds.h>
2005-11-20 08:50:06 +03:00
2007-05-23 07:48:39 +04:00
/* How often we poll keys - msecs */
# define POLL_INTERVAL_DEFAULT 500 /* when idle */
# define POLL_INTERVAL_BURST 100 /* when a key was recently pressed */
2005-11-20 08:50:06 +03:00
2005-11-20 08:50:37 +03:00
/* BIOS subsystem IDs */
# define WIFI 0x35
# define BLUETOOTH 0x34
2007-05-21 08:46:31 +04:00
# define MAIL_LED 0x31
2005-11-20 08:50:37 +03:00
2005-11-20 08:50:06 +03:00
MODULE_AUTHOR ( " Miloslav Trmac <mitr@volny.cz> " ) ;
MODULE_DESCRIPTION ( " Wistron laptop button driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
2007-05-21 08:46:31 +04:00
MODULE_VERSION ( " 0.3 " ) ;
2005-11-20 08:50:06 +03:00
static int force ; /* = 0; */
module_param ( force , bool , 0 ) ;
MODULE_PARM_DESC ( force , " Load even if computer is not in database " ) ;
static char * keymap_name ; /* = NULL; */
module_param_named ( keymap , keymap_name , charp , 0 ) ;
2007-04-12 09:32:41 +04:00
MODULE_PARM_DESC ( keymap , " Keymap name, if it can't be autodetected [generic, 1557/MS2141] " ) ;
2005-11-20 08:50:06 +03:00
2005-11-20 08:50:58 +03:00
static struct platform_device * wistron_device ;
2005-11-20 08:50:06 +03:00
/* BIOS interface implementation */
static void __iomem * bios_entry_point ; /* BIOS routine entry point */
static void __iomem * bios_code_map_base ;
static void __iomem * bios_data_map_base ;
static u8 cmos_address ;
struct regs {
u32 eax , ebx , ecx ;
} ;
static void call_bios ( struct regs * regs )
{
unsigned long flags ;
preempt_disable ( ) ;
local_irq_save ( flags ) ;
asm volatile ( " pushl %%ebp; "
" movl %7, %%ebp; "
" call *%6; "
" popl %%ebp "
: " =a " ( regs - > eax ) , " =b " ( regs - > ebx ) , " =c " ( regs - > ecx )
: " 0 " ( regs - > eax ) , " 1 " ( regs - > ebx ) , " 2 " ( regs - > ecx ) ,
" m " ( bios_entry_point ) , " m " ( bios_data_map_base )
: " edx " , " edi " , " esi " , " memory " ) ;
local_irq_restore ( flags ) ;
preempt_enable ( ) ;
}
2006-01-10 09:59:07 +03:00
static ssize_t __init locate_wistron_bios ( void __iomem * base )
2005-11-20 08:50:06 +03:00
{
2006-07-06 08:23:38 +04:00
static unsigned char __initdata signature [ ] =
2005-11-20 08:50:06 +03:00
{ 0x42 , 0x21 , 0x55 , 0x30 } ;
2006-01-10 09:59:07 +03:00
ssize_t offset ;
2005-11-20 08:50:06 +03:00
for ( offset = 0 ; offset < 0x10000 ; offset + = 0x10 ) {
if ( check_signature ( base + offset , signature ,
sizeof ( signature ) ) ! = 0 )
return offset ;
}
return - 1 ;
}
static int __init map_bios ( void )
{
void __iomem * base ;
2006-01-10 09:59:07 +03:00
ssize_t offset ;
2005-11-20 08:50:06 +03:00
u32 entry_point ;
base = ioremap ( 0xF0000 , 0x10000 ) ; /* Can't fail */
offset = locate_wistron_bios ( base ) ;
if ( offset < 0 ) {
printk ( KERN_ERR " wistron_btns: BIOS entry point not found \n " ) ;
iounmap ( base ) ;
return - ENODEV ;
}
entry_point = readl ( base + offset + 5 ) ;
printk ( KERN_DEBUG
" wistron_btns: BIOS signature found at %p, entry point %08X \n " ,
base + offset , entry_point ) ;
if ( entry_point > = 0xF0000 ) {
bios_code_map_base = base ;
bios_entry_point = bios_code_map_base + ( entry_point & 0xFFFF ) ;
} else {
iounmap ( base ) ;
bios_code_map_base = ioremap ( entry_point & ~ 0x3FFF , 0x4000 ) ;
if ( bios_code_map_base = = NULL ) {
printk ( KERN_ERR
" wistron_btns: Can't map BIOS code at %08X \n " ,
entry_point & ~ 0x3FFF ) ;
goto err ;
}
bios_entry_point = bios_code_map_base + ( entry_point & 0x3FFF ) ;
}
/* The Windows driver maps 0x10000 bytes, we keep only one page... */
bios_data_map_base = ioremap ( 0x400 , 0xc00 ) ;
if ( bios_data_map_base = = NULL ) {
printk ( KERN_ERR " wistron_btns: Can't map BIOS data \n " ) ;
goto err_code ;
}
return 0 ;
err_code :
iounmap ( bios_code_map_base ) ;
err :
return - ENOMEM ;
}
2005-11-20 08:50:46 +03:00
static inline void unmap_bios ( void )
2005-11-20 08:50:06 +03:00
{
iounmap ( bios_code_map_base ) ;
iounmap ( bios_data_map_base ) ;
}
/* BIOS calls */
static u16 bios_pop_queue ( void )
{
struct regs regs ;
memset ( & regs , 0 , sizeof ( regs ) ) ;
regs . eax = 0x9610 ;
regs . ebx = 0x061C ;
regs . ecx = 0x0000 ;
call_bios ( & regs ) ;
return regs . eax ;
}
2005-12-28 09:26:24 +03:00
static void __devinit bios_attach ( void )
2005-11-20 08:50:06 +03:00
{
struct regs regs ;
memset ( & regs , 0 , sizeof ( regs ) ) ;
regs . eax = 0x9610 ;
regs . ebx = 0x012E ;
call_bios ( & regs ) ;
}
2005-11-20 08:50:46 +03:00
static void bios_detach ( void )
2005-11-20 08:50:06 +03:00
{
struct regs regs ;
memset ( & regs , 0 , sizeof ( regs ) ) ;
regs . eax = 0x9610 ;
regs . ebx = 0x002E ;
call_bios ( & regs ) ;
}
2005-12-28 09:26:24 +03:00
static u8 __devinit bios_get_cmos_address ( void )
2005-11-20 08:50:06 +03:00
{
struct regs regs ;
memset ( & regs , 0 , sizeof ( regs ) ) ;
regs . eax = 0x9610 ;
regs . ebx = 0x051C ;
call_bios ( & regs ) ;
return regs . ecx ;
}
2005-12-28 09:26:24 +03:00
static u16 __devinit bios_get_default_setting ( u8 subsys )
2005-11-20 08:50:06 +03:00
{
struct regs regs ;
memset ( & regs , 0 , sizeof ( regs ) ) ;
regs . eax = 0x9610 ;
2005-11-20 08:50:37 +03:00
regs . ebx = 0x0200 | subsys ;
2005-11-20 08:50:06 +03:00
call_bios ( & regs ) ;
return regs . eax ;
}
2005-11-20 08:50:37 +03:00
static void bios_set_state ( u8 subsys , int enable )
2005-11-20 08:50:06 +03:00
{
struct regs regs ;
memset ( & regs , 0 , sizeof ( regs ) ) ;
regs . eax = 0x9610 ;
2005-11-20 08:50:37 +03:00
regs . ebx = ( enable ? 0x0100 : 0x0000 ) | subsys ;
2005-11-20 08:50:06 +03:00
call_bios ( & regs ) ;
}
2005-11-20 08:50:37 +03:00
/* Hardware database */
2005-11-20 08:50:06 +03:00
struct key_entry {
char type ; /* See KE_* below */
u8 code ;
2007-04-12 09:32:34 +04:00
union {
u16 keycode ; /* For KE_KEY */
struct { /* For KE_SW */
u8 code ;
u8 value ;
} sw ;
} ;
2005-11-20 08:50:06 +03:00
} ;
2007-04-12 09:32:34 +04:00
enum { KE_END , KE_KEY , KE_SW , KE_WIFI , KE_BLUETOOTH } ;
# define FE_MAIL_LED 0x01
# define FE_WIFI_LED 0x02
# define FE_UNTESTED 0x80
2005-11-20 08:50:06 +03:00
2007-06-15 07:31:45 +04:00
static struct key_entry * keymap ; /* = NULL; Current key map */
2009-08-08 10:17:39 +04:00
static bool have_wifi ;
static bool have_bluetooth ;
static int leds_present ; /* bitmask of leds present */
2005-11-20 08:50:06 +03:00
2007-10-03 23:15:40 +04:00
static int __init dmi_matched ( const struct dmi_system_id * dmi )
2005-11-20 08:50:06 +03:00
{
const struct key_entry * key ;
keymap = dmi - > driver_data ;
for ( key = keymap ; key - > type ! = KE_END ; key + + ) {
2006-10-02 05:58:51 +04:00
if ( key - > type = = KE_WIFI )
2009-08-08 10:17:39 +04:00
have_wifi = true ;
2006-10-02 05:58:51 +04:00
else if ( key - > type = = KE_BLUETOOTH )
2009-08-08 10:17:39 +04:00
have_bluetooth = true ;
2005-11-20 08:50:06 +03:00
}
2009-08-08 10:17:39 +04:00
leds_present = key - > code & ( FE_MAIL_LED | FE_WIFI_LED ) ;
2007-05-21 08:46:31 +04:00
2005-11-20 08:50:06 +03:00
return 1 ;
}
2007-04-12 09:32:49 +04:00
static struct key_entry keymap_empty [ ] __initdata = {
2005-11-20 08:50:06 +03:00
{ KE_END , 0 }
} ;
2007-04-12 09:32:49 +04:00
static struct key_entry keymap_fs_amilo_pro_v2000 [ ] __initdata = {
2007-04-12 09:32:34 +04:00
{ KE_KEY , 0x01 , { KEY_HELP } } ,
{ KE_KEY , 0x11 , { KEY_PROG1 } } ,
{ KE_KEY , 0x12 , { KEY_PROG2 } } ,
{ KE_WIFI , 0x30 } ,
{ KE_KEY , 0x31 , { KEY_MAIL } } ,
{ KE_KEY , 0x36 , { KEY_WWW } } ,
2005-11-20 08:50:06 +03:00
{ KE_END , 0 }
} ;
2008-08-08 20:13:13 +04:00
static struct key_entry keymap_fs_amilo_pro_v3505 [ ] __initdata = {
{ KE_KEY , 0x01 , { KEY_HELP } } , /* Fn+F1 */
{ KE_KEY , 0x06 , { KEY_DISPLAYTOGGLE } } , /* Fn+F4 */
{ KE_BLUETOOTH , 0x30 } , /* Fn+F10 */
{ KE_KEY , 0x31 , { KEY_MAIL } } , /* mail button */
{ KE_KEY , 0x36 , { KEY_WWW } } , /* www button */
{ KE_WIFI , 0x78 } , /* satelite dish button */
{ KE_END , 0 }
} ;
2007-04-12 09:32:49 +04:00
static struct key_entry keymap_fujitsu_n3510 [ ] __initdata = {
2007-04-12 09:32:34 +04:00
{ KE_KEY , 0x11 , { KEY_PROG1 } } ,
{ KE_KEY , 0x12 , { KEY_PROG2 } } ,
{ KE_KEY , 0x36 , { KEY_WWW } } ,
{ KE_KEY , 0x31 , { KEY_MAIL } } ,
{ KE_KEY , 0x71 , { KEY_STOPCD } } ,
{ KE_KEY , 0x72 , { KEY_PLAYPAUSE } } ,
{ KE_KEY , 0x74 , { KEY_REWIND } } ,
{ KE_KEY , 0x78 , { KEY_FORWARD } } ,
2006-04-05 08:40:01 +04:00
{ KE_END , 0 }
} ;
2007-04-12 09:32:49 +04:00
static struct key_entry keymap_wistron_ms2111 [ ] __initdata = {
2007-04-12 09:32:34 +04:00
{ KE_KEY , 0x11 , { KEY_PROG1 } } ,
{ KE_KEY , 0x12 , { KEY_PROG2 } } ,
{ KE_KEY , 0x13 , { KEY_PROG3 } } ,
{ KE_KEY , 0x31 , { KEY_MAIL } } ,
{ KE_KEY , 0x36 , { KEY_WWW } } ,
{ KE_END , FE_MAIL_LED }
} ;
2007-04-12 09:32:49 +04:00
static struct key_entry keymap_wistron_md40100 [ ] __initdata = {
2007-04-12 09:32:34 +04:00
{ KE_KEY , 0x01 , { KEY_HELP } } ,
{ KE_KEY , 0x02 , { KEY_CONFIG } } ,
{ KE_KEY , 0x31 , { KEY_MAIL } } ,
{ KE_KEY , 0x36 , { KEY_WWW } } ,
{ KE_KEY , 0x37 , { KEY_DISPLAYTOGGLE } } , /* Display on/off */
{ KE_END , FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED }
2006-06-27 09:48:24 +04:00
} ;
2007-04-12 09:32:49 +04:00
static struct key_entry keymap_wistron_ms2141 [ ] __initdata = {
2007-04-12 09:32:34 +04:00
{ KE_KEY , 0x11 , { KEY_PROG1 } } ,
{ KE_KEY , 0x12 , { KEY_PROG2 } } ,
{ KE_WIFI , 0x30 } ,
{ KE_KEY , 0x22 , { KEY_REWIND } } ,
{ KE_KEY , 0x23 , { KEY_FORWARD } } ,
{ KE_KEY , 0x24 , { KEY_PLAYPAUSE } } ,
{ KE_KEY , 0x25 , { KEY_STOPCD } } ,
{ KE_KEY , 0x31 , { KEY_MAIL } } ,
{ KE_KEY , 0x36 , { KEY_WWW } } ,
2005-11-20 08:50:06 +03:00
{ KE_END , 0 }
} ;
2007-04-12 09:32:49 +04:00
static struct key_entry keymap_acer_aspire_1500 [ ] __initdata = {
2007-04-12 09:32:34 +04:00
{ KE_KEY , 0x01 , { KEY_HELP } } ,
{ KE_KEY , 0x03 , { KEY_POWER } } ,
{ KE_KEY , 0x11 , { KEY_PROG1 } } ,
{ KE_KEY , 0x12 , { KEY_PROG2 } } ,
{ KE_WIFI , 0x30 } ,
{ KE_KEY , 0x31 , { KEY_MAIL } } ,
{ KE_KEY , 0x36 , { KEY_WWW } } ,
{ KE_KEY , 0x49 , { KEY_CONFIG } } ,
{ KE_BLUETOOTH , 0x44 } ,
{ KE_END , FE_UNTESTED }
} ;
2007-04-12 09:32:49 +04:00
static struct key_entry keymap_acer_aspire_1600 [ ] __initdata = {
2007-04-12 09:32:34 +04:00
{ KE_KEY , 0x01 , { KEY_HELP } } ,
{ KE_KEY , 0x03 , { KEY_POWER } } ,
{ KE_KEY , 0x08 , { KEY_MUTE } } ,
{ KE_KEY , 0x11 , { KEY_PROG1 } } ,
{ KE_KEY , 0x12 , { KEY_PROG2 } } ,
{ KE_KEY , 0x13 , { KEY_PROG3 } } ,
{ KE_KEY , 0x31 , { KEY_MAIL } } ,
{ KE_KEY , 0x36 , { KEY_WWW } } ,
{ KE_KEY , 0x49 , { KEY_CONFIG } } ,
{ KE_WIFI , 0x30 } ,
{ KE_BLUETOOTH , 0x44 } ,
{ KE_END , FE_MAIL_LED | FE_UNTESTED }
} ;
/* 3020 has been tested */
2007-04-12 09:32:49 +04:00
static struct key_entry keymap_acer_aspire_5020 [ ] __initdata = {
2007-04-12 09:32:34 +04:00
{ KE_KEY , 0x01 , { KEY_HELP } } ,
{ KE_KEY , 0x03 , { KEY_POWER } } ,
{ KE_KEY , 0x05 , { KEY_SWITCHVIDEOMODE } } , /* Display selection */
{ KE_KEY , 0x11 , { KEY_PROG1 } } ,
{ KE_KEY , 0x12 , { KEY_PROG2 } } ,
{ KE_KEY , 0x31 , { KEY_MAIL } } ,
{ KE_KEY , 0x36 , { KEY_WWW } } ,
{ KE_KEY , 0x6a , { KEY_CONFIG } } ,
{ KE_WIFI , 0x30 } ,
{ KE_BLUETOOTH , 0x44 } ,
{ KE_END , FE_MAIL_LED | FE_UNTESTED }
} ;
2007-04-12 09:32:49 +04:00
static struct key_entry keymap_acer_travelmate_2410 [ ] __initdata = {
2007-04-12 09:32:34 +04:00
{ KE_KEY , 0x01 , { KEY_HELP } } ,
{ KE_KEY , 0x6d , { KEY_POWER } } ,
{ KE_KEY , 0x11 , { KEY_PROG1 } } ,
{ KE_KEY , 0x12 , { KEY_PROG2 } } ,
{ KE_KEY , 0x31 , { KEY_MAIL } } ,
{ KE_KEY , 0x36 , { KEY_WWW } } ,
{ KE_KEY , 0x6a , { KEY_CONFIG } } ,
{ KE_WIFI , 0x30 } ,
{ KE_BLUETOOTH , 0x44 } ,
{ KE_END , FE_MAIL_LED | FE_UNTESTED }
} ;
2007-04-12 09:32:49 +04:00
static struct key_entry keymap_acer_travelmate_110 [ ] __initdata = {
2007-04-12 09:32:34 +04:00
{ KE_KEY , 0x01 , { KEY_HELP } } ,
{ KE_KEY , 0x02 , { KEY_CONFIG } } ,
{ KE_KEY , 0x03 , { KEY_POWER } } ,
{ KE_KEY , 0x08 , { KEY_MUTE } } ,
{ KE_KEY , 0x11 , { KEY_PROG1 } } ,
{ KE_KEY , 0x12 , { KEY_PROG2 } } ,
{ KE_KEY , 0x20 , { KEY_VOLUMEUP } } ,
{ KE_KEY , 0x21 , { KEY_VOLUMEDOWN } } ,
{ KE_KEY , 0x31 , { KEY_MAIL } } ,
{ KE_KEY , 0x36 , { KEY_WWW } } ,
{ KE_SW , 0x4a , { . sw = { SW_LID , 1 } } } , /* lid close */
{ KE_SW , 0x4b , { . sw = { SW_LID , 0 } } } , /* lid open */
{ KE_WIFI , 0x30 } ,
{ KE_END , FE_MAIL_LED | FE_UNTESTED }
} ;
2007-04-12 09:32:49 +04:00
static struct key_entry keymap_acer_travelmate_300 [ ] __initdata = {
2007-04-12 09:32:34 +04:00
{ KE_KEY , 0x01 , { KEY_HELP } } ,
{ KE_KEY , 0x02 , { KEY_CONFIG } } ,
{ KE_KEY , 0x03 , { KEY_POWER } } ,
{ KE_KEY , 0x08 , { KEY_MUTE } } ,
{ KE_KEY , 0x11 , { KEY_PROG1 } } ,
{ KE_KEY , 0x12 , { KEY_PROG2 } } ,
{ KE_KEY , 0x20 , { KEY_VOLUMEUP } } ,
{ KE_KEY , 0x21 , { KEY_VOLUMEDOWN } } ,
{ KE_KEY , 0x31 , { KEY_MAIL } } ,
{ KE_KEY , 0x36 , { KEY_WWW } } ,
{ KE_WIFI , 0x30 } ,
{ KE_BLUETOOTH , 0x44 } ,
{ KE_END , FE_MAIL_LED | FE_UNTESTED }
} ;
2007-04-12 09:32:49 +04:00
static struct key_entry keymap_acer_travelmate_380 [ ] __initdata = {
2007-04-12 09:32:34 +04:00
{ KE_KEY , 0x01 , { KEY_HELP } } ,
{ KE_KEY , 0x02 , { KEY_CONFIG } } ,
{ KE_KEY , 0x03 , { KEY_POWER } } , /* not 370 */
{ KE_KEY , 0x11 , { KEY_PROG1 } } ,
{ KE_KEY , 0x12 , { KEY_PROG2 } } ,
{ KE_KEY , 0x13 , { KEY_PROG3 } } ,
{ KE_KEY , 0x31 , { KEY_MAIL } } ,
{ KE_KEY , 0x36 , { KEY_WWW } } ,
{ KE_WIFI , 0x30 } ,
{ KE_END , FE_MAIL_LED | FE_UNTESTED }
} ;
/* unusual map */
2007-04-12 09:32:49 +04:00
static struct key_entry keymap_acer_travelmate_220 [ ] __initdata = {
2007-04-12 09:32:34 +04:00
{ KE_KEY , 0x01 , { KEY_HELP } } ,
{ KE_KEY , 0x02 , { KEY_CONFIG } } ,
{ KE_KEY , 0x11 , { KEY_MAIL } } ,
{ KE_KEY , 0x12 , { KEY_WWW } } ,
{ KE_KEY , 0x13 , { KEY_PROG2 } } ,
{ KE_KEY , 0x31 , { KEY_PROG1 } } ,
{ KE_END , FE_WIFI_LED | FE_UNTESTED }
} ;
2007-04-12 09:32:49 +04:00
static struct key_entry keymap_acer_travelmate_230 [ ] __initdata = {
2007-04-12 09:32:34 +04:00
{ KE_KEY , 0x01 , { KEY_HELP } } ,
{ KE_KEY , 0x02 , { KEY_CONFIG } } ,
{ KE_KEY , 0x11 , { KEY_PROG1 } } ,
{ KE_KEY , 0x12 , { KEY_PROG2 } } ,
{ KE_KEY , 0x31 , { KEY_MAIL } } ,
{ KE_KEY , 0x36 , { KEY_WWW } } ,
{ KE_END , FE_WIFI_LED | FE_UNTESTED }
2005-11-20 08:50:37 +03:00
} ;
2007-04-12 09:32:49 +04:00
static struct key_entry keymap_acer_travelmate_240 [ ] __initdata = {
2007-04-12 09:32:34 +04:00
{ KE_KEY , 0x01 , { KEY_HELP } } ,
{ KE_KEY , 0x02 , { KEY_CONFIG } } ,
{ KE_KEY , 0x03 , { KEY_POWER } } ,
{ KE_KEY , 0x08 , { KEY_MUTE } } ,
{ KE_KEY , 0x31 , { KEY_MAIL } } ,
{ KE_KEY , 0x36 , { KEY_WWW } } ,
{ KE_KEY , 0x11 , { KEY_PROG1 } } ,
{ KE_KEY , 0x12 , { KEY_PROG2 } } ,
{ KE_BLUETOOTH , 0x44 } ,
{ KE_WIFI , 0x30 } ,
{ KE_END , FE_UNTESTED }
} ;
2007-04-12 09:32:49 +04:00
static struct key_entry keymap_acer_travelmate_350 [ ] __initdata = {
2007-04-12 09:32:34 +04:00
{ KE_KEY , 0x01 , { KEY_HELP } } ,
{ KE_KEY , 0x02 , { KEY_CONFIG } } ,
{ KE_KEY , 0x11 , { KEY_PROG1 } } ,
{ KE_KEY , 0x12 , { KEY_PROG2 } } ,
{ KE_KEY , 0x13 , { KEY_MAIL } } ,
{ KE_KEY , 0x14 , { KEY_PROG3 } } ,
{ KE_KEY , 0x15 , { KEY_WWW } } ,
{ KE_END , FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED }
} ;
2007-04-12 09:32:49 +04:00
static struct key_entry keymap_acer_travelmate_360 [ ] __initdata = {
2007-04-12 09:32:34 +04:00
{ KE_KEY , 0x01 , { KEY_HELP } } ,
{ KE_KEY , 0x02 , { KEY_CONFIG } } ,
{ KE_KEY , 0x11 , { KEY_PROG1 } } ,
{ KE_KEY , 0x12 , { KEY_PROG2 } } ,
{ KE_KEY , 0x13 , { KEY_MAIL } } ,
{ KE_KEY , 0x14 , { KEY_PROG3 } } ,
{ KE_KEY , 0x15 , { KEY_WWW } } ,
{ KE_KEY , 0x40 , { KEY_WLAN } } ,
{ KE_END , FE_WIFI_LED | FE_UNTESTED } /* no mail led */
2005-12-11 20:41:32 +03:00
} ;
2007-03-07 09:45:16 +03:00
/* Wifi subsystem only activates the led. Therefore we need to pass
* wifi event as a normal key , then userspace can really change the wifi state .
* TODO we need to export led state to userspace ( wifi and mail ) */
2007-04-12 09:32:49 +04:00
static struct key_entry keymap_acer_travelmate_610 [ ] __initdata = {
2007-04-12 09:32:34 +04:00
{ KE_KEY , 0x01 , { KEY_HELP } } ,
{ KE_KEY , 0x02 , { KEY_CONFIG } } ,
{ KE_KEY , 0x11 , { KEY_PROG1 } } ,
2007-04-30 07:41:53 +04:00
{ KE_KEY , 0x12 , { KEY_PROG2 } } ,
2007-04-12 09:32:34 +04:00
{ KE_KEY , 0x13 , { KEY_PROG3 } } ,
{ KE_KEY , 0x14 , { KEY_MAIL } } ,
{ KE_KEY , 0x15 , { KEY_WWW } } ,
{ KE_KEY , 0x40 , { KEY_WLAN } } ,
{ KE_END , FE_MAIL_LED | FE_WIFI_LED }
} ;
2007-04-12 09:32:49 +04:00
static struct key_entry keymap_acer_travelmate_630 [ ] __initdata = {
2007-04-12 09:32:34 +04:00
{ KE_KEY , 0x01 , { KEY_HELP } } ,
{ KE_KEY , 0x02 , { KEY_CONFIG } } ,
{ KE_KEY , 0x03 , { KEY_POWER } } ,
{ KE_KEY , 0x08 , { KEY_MUTE } } , /* not 620 */
{ KE_KEY , 0x11 , { KEY_PROG1 } } ,
{ KE_KEY , 0x12 , { KEY_PROG2 } } ,
{ KE_KEY , 0x13 , { KEY_PROG3 } } ,
{ KE_KEY , 0x20 , { KEY_VOLUMEUP } } ,
{ KE_KEY , 0x21 , { KEY_VOLUMEDOWN } } ,
{ KE_KEY , 0x31 , { KEY_MAIL } } ,
{ KE_KEY , 0x36 , { KEY_WWW } } ,
{ KE_WIFI , 0x30 } ,
{ KE_END , FE_MAIL_LED | FE_UNTESTED }
2007-03-07 09:45:16 +03:00
} ;
2007-04-12 09:32:49 +04:00
static struct key_entry keymap_aopen_1559as [ ] __initdata = {
2007-04-12 09:32:34 +04:00
{ KE_KEY , 0x01 , { KEY_HELP } } ,
{ KE_KEY , 0x06 , { KEY_PROG3 } } ,
{ KE_KEY , 0x11 , { KEY_PROG1 } } ,
{ KE_KEY , 0x12 , { KEY_PROG2 } } ,
{ KE_WIFI , 0x30 } ,
{ KE_KEY , 0x31 , { KEY_MAIL } } ,
{ KE_KEY , 0x36 , { KEY_WWW } } ,
2006-06-27 09:48:24 +04:00
{ KE_END , 0 } ,
2006-05-30 07:29:36 +04:00
} ;
2007-04-12 09:32:49 +04:00
static struct key_entry keymap_fs_amilo_d88x0 [ ] __initdata = {
2007-04-12 09:32:34 +04:00
{ KE_KEY , 0x01 , { KEY_HELP } } ,
{ KE_KEY , 0x08 , { KEY_MUTE } } ,
{ KE_KEY , 0x31 , { KEY_MAIL } } ,
{ KE_KEY , 0x36 , { KEY_WWW } } ,
{ KE_KEY , 0x11 , { KEY_PROG1 } } ,
{ KE_KEY , 0x12 , { KEY_PROG2 } } ,
{ KE_KEY , 0x13 , { KEY_PROG3 } } ,
{ KE_END , FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED }
} ;
2007-04-12 09:32:49 +04:00
static struct key_entry keymap_wistron_md2900 [ ] __initdata = {
2007-04-12 09:32:34 +04:00
{ KE_KEY , 0x01 , { KEY_HELP } } ,
{ KE_KEY , 0x02 , { KEY_CONFIG } } ,
{ KE_KEY , 0x11 , { KEY_PROG1 } } ,
{ KE_KEY , 0x12 , { KEY_PROG2 } } ,
{ KE_KEY , 0x31 , { KEY_MAIL } } ,
{ KE_KEY , 0x36 , { KEY_WWW } } ,
{ KE_WIFI , 0x30 } ,
{ KE_END , FE_MAIL_LED | FE_UNTESTED }
} ;
2007-04-12 09:32:49 +04:00
static struct key_entry keymap_wistron_md96500 [ ] __initdata = {
2007-04-12 09:32:34 +04:00
{ KE_KEY , 0x01 , { KEY_HELP } } ,
{ KE_KEY , 0x02 , { KEY_CONFIG } } ,
{ KE_KEY , 0x05 , { KEY_SWITCHVIDEOMODE } } , /* Display selection */
{ KE_KEY , 0x06 , { KEY_DISPLAYTOGGLE } } , /* Display on/off */
{ KE_KEY , 0x08 , { KEY_MUTE } } ,
{ KE_KEY , 0x11 , { KEY_PROG1 } } ,
{ KE_KEY , 0x12 , { KEY_PROG2 } } ,
{ KE_KEY , 0x20 , { KEY_VOLUMEUP } } ,
{ KE_KEY , 0x21 , { KEY_VOLUMEDOWN } } ,
{ KE_KEY , 0x22 , { KEY_REWIND } } ,
{ KE_KEY , 0x23 , { KEY_FORWARD } } ,
{ KE_KEY , 0x24 , { KEY_PLAYPAUSE } } ,
{ KE_KEY , 0x25 , { KEY_STOPCD } } ,
{ KE_KEY , 0x31 , { KEY_MAIL } } ,
{ KE_KEY , 0x36 , { KEY_WWW } } ,
{ KE_WIFI , 0x30 } ,
{ KE_BLUETOOTH , 0x44 } ,
{ KE_END , FE_UNTESTED }
2007-02-10 09:29:42 +03:00
} ;
2007-04-12 09:32:49 +04:00
static struct key_entry keymap_wistron_generic [ ] __initdata = {
2007-04-12 09:32:41 +04:00
{ KE_KEY , 0x01 , { KEY_HELP } } ,
{ KE_KEY , 0x02 , { KEY_CONFIG } } ,
{ KE_KEY , 0x03 , { KEY_POWER } } ,
{ KE_KEY , 0x05 , { KEY_SWITCHVIDEOMODE } } , /* Display selection */
{ KE_KEY , 0x06 , { KEY_DISPLAYTOGGLE } } , /* Display on/off */
{ KE_KEY , 0x08 , { KEY_MUTE } } ,
{ KE_KEY , 0x11 , { KEY_PROG1 } } ,
{ KE_KEY , 0x12 , { KEY_PROG2 } } ,
{ KE_KEY , 0x13 , { KEY_PROG3 } } ,
{ KE_KEY , 0x14 , { KEY_MAIL } } ,
{ KE_KEY , 0x15 , { KEY_WWW } } ,
{ KE_KEY , 0x20 , { KEY_VOLUMEUP } } ,
{ KE_KEY , 0x21 , { KEY_VOLUMEDOWN } } ,
{ KE_KEY , 0x22 , { KEY_REWIND } } ,
{ KE_KEY , 0x23 , { KEY_FORWARD } } ,
{ KE_KEY , 0x24 , { KEY_PLAYPAUSE } } ,
{ KE_KEY , 0x25 , { KEY_STOPCD } } ,
{ KE_KEY , 0x31 , { KEY_MAIL } } ,
{ KE_KEY , 0x36 , { KEY_WWW } } ,
{ KE_KEY , 0x37 , { KEY_DISPLAYTOGGLE } } , /* Display on/off */
{ KE_KEY , 0x40 , { KEY_WLAN } } ,
{ KE_KEY , 0x49 , { KEY_CONFIG } } ,
{ KE_SW , 0x4a , { . sw = { SW_LID , 1 } } } , /* lid close */
{ KE_SW , 0x4b , { . sw = { SW_LID , 0 } } } , /* lid open */
{ KE_KEY , 0x6a , { KEY_CONFIG } } ,
{ KE_KEY , 0x6d , { KEY_POWER } } ,
{ KE_KEY , 0x71 , { KEY_STOPCD } } ,
{ KE_KEY , 0x72 , { KEY_PLAYPAUSE } } ,
{ KE_KEY , 0x74 , { KEY_REWIND } } ,
{ KE_KEY , 0x78 , { KEY_FORWARD } } ,
{ KE_WIFI , 0x30 } ,
{ KE_BLUETOOTH , 0x44 } ,
{ KE_END , 0 }
} ;
2009-09-10 06:17:24 +04:00
static struct key_entry keymap_aopen_1557 [ ] __initdata = {
{ KE_KEY , 0x01 , { KEY_HELP } } ,
{ KE_KEY , 0x11 , { KEY_PROG1 } } ,
{ KE_KEY , 0x12 , { KEY_PROG2 } } ,
{ KE_WIFI , 0x30 } ,
{ KE_KEY , 0x22 , { KEY_REWIND } } ,
{ KE_KEY , 0x23 , { KEY_FORWARD } } ,
{ KE_KEY , 0x24 , { KEY_PLAYPAUSE } } ,
{ KE_KEY , 0x25 , { KEY_STOPCD } } ,
{ KE_KEY , 0x31 , { KEY_MAIL } } ,
{ KE_KEY , 0x36 , { KEY_WWW } } ,
{ KE_END , 0 }
} ;
2009-08-04 00:39:09 +04:00
static struct key_entry keymap_prestigio [ ] __initdata = {
{ KE_KEY , 0x11 , { KEY_PROG1 } } ,
{ KE_KEY , 0x12 , { KEY_PROG2 } } ,
2009-09-10 06:17:24 +04:00
{ KE_WIFI , 0x30 } ,
2009-08-04 00:39:09 +04:00
{ KE_KEY , 0x22 , { KEY_REWIND } } ,
{ KE_KEY , 0x23 , { KEY_FORWARD } } ,
{ KE_KEY , 0x24 , { KEY_PLAYPAUSE } } ,
{ KE_KEY , 0x25 , { KEY_STOPCD } } ,
{ KE_KEY , 0x31 , { KEY_MAIL } } ,
{ KE_KEY , 0x36 , { KEY_WWW } } ,
{ KE_END , 0 }
} ;
2005-11-20 08:50:06 +03:00
/*
* If your machine is not here ( which is currently rather likely ) , please send
* a list of buttons and their key codes ( reported when loading this module
* with force = 1 ) and the output of dmidecode to $ MODULE_AUTHOR .
*/
2006-07-06 08:23:38 +04:00
static struct dmi_system_id dmi_ids [ ] __initdata = {
2005-11-20 08:50:06 +03:00
{
. callback = dmi_matched ,
. ident = " Fujitsu-Siemens Amilo Pro V2000 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " FUJITSU SIEMENS " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " AMILO Pro V2000 " ) ,
} ,
. driver_data = keymap_fs_amilo_pro_v2000
} ,
2008-08-08 20:13:13 +04:00
{
. callback = dmi_matched ,
. ident = " Fujitsu-Siemens Amilo Pro Edition V3505 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " FUJITSU SIEMENS " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " AMILO Pro Edition V3505 " ) ,
} ,
. driver_data = keymap_fs_amilo_pro_v3505
} ,
2006-04-05 08:39:20 +04:00
{
. callback = dmi_matched ,
. ident = " Fujitsu-Siemens Amilo M7400 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " FUJITSU SIEMENS " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " AMILO M " ) ,
} ,
. driver_data = keymap_fs_amilo_pro_v2000
} ,
2009-07-13 08:02:27 +04:00
{
. callback = dmi_matched ,
. ident = " Maxdata Pro 7000 DX " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " MAXDATA " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " Pro 7000 " ) ,
} ,
. driver_data = keymap_fs_amilo_pro_v2000
} ,
2006-04-05 08:40:01 +04:00
{
. callback = dmi_matched ,
. ident = " Fujitsu N3510 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " FUJITSU " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " N3510 " ) ,
} ,
. driver_data = keymap_fujitsu_n3510
} ,
2005-11-20 08:50:37 +03:00
{
. callback = dmi_matched ,
. ident = " Acer Aspire 1500 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Acer " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " Aspire 1500 " ) ,
} ,
. driver_data = keymap_acer_aspire_1500
} ,
2007-04-12 09:32:34 +04:00
{
. callback = dmi_matched ,
. ident = " Acer Aspire 1600 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Acer " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " Aspire 1600 " ) ,
} ,
. driver_data = keymap_acer_aspire_1600
} ,
{
. callback = dmi_matched ,
. ident = " Acer Aspire 3020 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Acer " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " Aspire 3020 " ) ,
} ,
. driver_data = keymap_acer_aspire_5020
} ,
{
. callback = dmi_matched ,
. ident = " Acer Aspire 5020 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Acer " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " Aspire 5020 " ) ,
} ,
. driver_data = keymap_acer_aspire_5020
} ,
{
. callback = dmi_matched ,
. ident = " Acer TravelMate 2100 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Acer " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " TravelMate 2100 " ) ,
} ,
. driver_data = keymap_acer_aspire_5020
} ,
{
. callback = dmi_matched ,
. ident = " Acer TravelMate 2410 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Acer " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " TravelMate 2410 " ) ,
} ,
. driver_data = keymap_acer_travelmate_2410
} ,
{
. callback = dmi_matched ,
. ident = " Acer TravelMate C300 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Acer " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " TravelMate C300 " ) ,
} ,
. driver_data = keymap_acer_travelmate_300
} ,
{
. callback = dmi_matched ,
. ident = " Acer TravelMate C100 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Acer " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " TravelMate C100 " ) ,
} ,
. driver_data = keymap_acer_travelmate_300
} ,
{
. callback = dmi_matched ,
. ident = " Acer TravelMate C110 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Acer " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " TravelMate C110 " ) ,
} ,
. driver_data = keymap_acer_travelmate_110
} ,
{
. callback = dmi_matched ,
. ident = " Acer TravelMate 380 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Acer " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " TravelMate 380 " ) ,
} ,
. driver_data = keymap_acer_travelmate_380
} ,
{
. callback = dmi_matched ,
. ident = " Acer TravelMate 370 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Acer " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " TravelMate 370 " ) ,
} ,
. driver_data = keymap_acer_travelmate_380 /* keyboard minus 1 key */
} ,
{
. callback = dmi_matched ,
. ident = " Acer TravelMate 220 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Acer " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " TravelMate 220 " ) ,
} ,
. driver_data = keymap_acer_travelmate_220
} ,
{
. callback = dmi_matched ,
. ident = " Acer TravelMate 260 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Acer " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " TravelMate 260 " ) ,
} ,
. driver_data = keymap_acer_travelmate_220
} ,
{
. callback = dmi_matched ,
. ident = " Acer TravelMate 230 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Acer " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " TravelMate 230 " ) ,
/* acerhk looks for "TravelMate F4..." ?! */
} ,
. driver_data = keymap_acer_travelmate_230
} ,
{
. callback = dmi_matched ,
. ident = " Acer TravelMate 280 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Acer " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " TravelMate 280 " ) ,
} ,
. driver_data = keymap_acer_travelmate_230
} ,
2005-12-11 20:41:32 +03:00
{
. callback = dmi_matched ,
. ident = " Acer TravelMate 240 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Acer " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " TravelMate 240 " ) ,
} ,
. driver_data = keymap_acer_travelmate_240
} ,
2007-04-12 09:32:34 +04:00
{
. callback = dmi_matched ,
. ident = " Acer TravelMate 250 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Acer " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " TravelMate 250 " ) ,
} ,
. driver_data = keymap_acer_travelmate_240
} ,
2006-10-02 06:07:14 +04:00
{
. callback = dmi_matched ,
. ident = " Acer TravelMate 2424NWXCi " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Acer " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " TravelMate 2420 " ) ,
} ,
. driver_data = keymap_acer_travelmate_240
} ,
2007-04-12 09:32:34 +04:00
{
. callback = dmi_matched ,
. ident = " Acer TravelMate 350 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Acer " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " TravelMate 350 " ) ,
} ,
. driver_data = keymap_acer_travelmate_350
} ,
{
. callback = dmi_matched ,
. ident = " Acer TravelMate 360 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Acer " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " TravelMate 360 " ) ,
} ,
. driver_data = keymap_acer_travelmate_360
} ,
2007-03-07 09:45:16 +03:00
{
. callback = dmi_matched ,
. ident = " Acer TravelMate 610 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " ACER " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " TravelMate 610 " ) ,
} ,
. driver_data = keymap_acer_travelmate_610
} ,
2007-04-12 09:32:34 +04:00
{
. callback = dmi_matched ,
. ident = " Acer TravelMate 620 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Acer " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " TravelMate 620 " ) ,
} ,
. driver_data = keymap_acer_travelmate_630
} ,
{
. callback = dmi_matched ,
. ident = " Acer TravelMate 630 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Acer " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " TravelMate 630 " ) ,
} ,
. driver_data = keymap_acer_travelmate_630
} ,
2006-10-02 06:07:14 +04:00
{
2006-05-30 07:29:36 +04:00
. callback = dmi_matched ,
. ident = " AOpen 1559AS " ,
. matches = {
DMI_MATCH ( DMI_PRODUCT_NAME , " E2U " ) ,
DMI_MATCH ( DMI_BOARD_NAME , " E2U " ) ,
} ,
. driver_data = keymap_aopen_1559as
} ,
2006-06-27 09:48:24 +04:00
{
. callback = dmi_matched ,
. ident = " Medion MD 9783 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " MEDIONNB " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " MD 9783 " ) ,
} ,
. driver_data = keymap_wistron_ms2111
} ,
2007-04-12 09:32:34 +04:00
{
. callback = dmi_matched ,
. ident = " Medion MD 40100 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " MEDIONNB " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " WID2000 " ) ,
} ,
. driver_data = keymap_wistron_md40100
} ,
{
. callback = dmi_matched ,
. ident = " Medion MD 2900 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " MEDIONNB " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " WIM 2000 " ) ,
} ,
. driver_data = keymap_wistron_md2900
} ,
2009-10-06 08:43:39 +04:00
{
. callback = dmi_matched ,
. ident = " Medion MD 42200 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Medion " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " WIM 2030 " ) ,
} ,
. driver_data = keymap_fs_amilo_pro_v2000
} ,
2007-04-12 09:32:34 +04:00
{
. callback = dmi_matched ,
. ident = " Medion MD 96500 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " MEDIONPC " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " WIM 2040 " ) ,
} ,
. driver_data = keymap_wistron_md96500
} ,
{
. callback = dmi_matched ,
. ident = " Medion MD 95400 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " MEDIONPC " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " WIM 2050 " ) ,
} ,
. driver_data = keymap_wistron_md96500
} ,
{
. callback = dmi_matched ,
. ident = " Fujitsu Siemens Amilo D7820 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " FUJITSU SIEMENS " ) , /* not sure */
DMI_MATCH ( DMI_PRODUCT_NAME , " Amilo D " ) ,
} ,
. driver_data = keymap_fs_amilo_d88x0
} ,
2007-02-10 09:29:42 +03:00
{
. callback = dmi_matched ,
. ident = " Fujitsu Siemens Amilo D88x0 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " FUJITSU SIEMENS " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " AMILO D " ) ,
} ,
. driver_data = keymap_fs_amilo_d88x0
} ,
2005-12-15 12:19:05 +03:00
{ NULL , }
2005-11-20 08:50:06 +03:00
} ;
2007-04-12 09:32:49 +04:00
/* Copy the good keymap, as the original ones are free'd */
static int __init copy_keymap ( void )
{
const struct key_entry * key ;
struct key_entry * new_keymap ;
unsigned int length = 1 ;
for ( key = keymap ; key - > type ! = KE_END ; key + + )
length + + ;
new_keymap = kmalloc ( length * sizeof ( struct key_entry ) , GFP_KERNEL ) ;
if ( ! new_keymap )
return - ENOMEM ;
memcpy ( new_keymap , keymap , length * sizeof ( struct key_entry ) ) ;
keymap = new_keymap ;
return 0 ;
}
2005-11-20 08:50:06 +03:00
static int __init select_keymap ( void )
{
2007-04-12 09:32:41 +04:00
dmi_check_system ( dmi_ids ) ;
2005-11-20 08:50:06 +03:00
if ( keymap_name ! = NULL ) {
if ( strcmp ( keymap_name , " 1557/MS2141 " ) = = 0 )
keymap = keymap_wistron_ms2141 ;
2009-09-10 06:17:24 +04:00
else if ( strcmp ( keymap_name , " aopen1557 " ) = = 0 )
keymap = keymap_aopen_1557 ;
2009-08-04 00:39:09 +04:00
else if ( strcmp ( keymap_name , " prestigio " ) = = 0 )
keymap = keymap_prestigio ;
2007-04-12 09:32:41 +04:00
else if ( strcmp ( keymap_name , " generic " ) = = 0 )
keymap = keymap_wistron_generic ;
2005-11-20 08:50:06 +03:00
else {
printk ( KERN_ERR " wistron_btns: Keymap unknown \n " ) ;
return - EINVAL ;
}
}
if ( keymap = = NULL ) {
if ( ! force ) {
printk ( KERN_ERR " wistron_btns: System unknown \n " ) ;
return - ENODEV ;
}
keymap = keymap_empty ;
}
2007-04-12 09:32:49 +04:00
return copy_keymap ( ) ;
2005-11-20 08:50:06 +03:00
}
/* Input layer interface */
2007-05-23 07:48:39 +04:00
static struct input_polled_dev * wistron_idev ;
static unsigned long jiffies_last_press ;
2009-08-08 10:17:39 +04:00
static bool wifi_enabled ;
static bool bluetooth_enabled ;
2005-11-20 08:50:06 +03:00
2007-05-23 07:48:39 +04:00
static void report_key ( struct input_dev * dev , unsigned int keycode )
2005-11-20 08:50:06 +03:00
{
2007-05-23 07:48:39 +04:00
input_report_key ( dev , keycode , 1 ) ;
input_sync ( dev ) ;
input_report_key ( dev , keycode , 0 ) ;
input_sync ( dev ) ;
2005-11-20 08:50:06 +03:00
}
2007-05-23 07:48:39 +04:00
static void report_switch ( struct input_dev * dev , unsigned int code , int value )
2007-04-12 09:32:34 +04:00
{
2007-05-23 07:48:39 +04:00
input_report_switch ( dev , code , value ) ;
input_sync ( dev ) ;
2007-04-12 09:32:34 +04:00
}
2007-05-21 08:46:31 +04:00
/* led management */
static void wistron_mail_led_set ( struct led_classdev * led_cdev ,
enum led_brightness value )
{
bios_set_state ( MAIL_LED , ( value ! = LED_OFF ) ? 1 : 0 ) ;
}
/* same as setting up wifi card, but for laptops on which the led is managed */
static void wistron_wifi_led_set ( struct led_classdev * led_cdev ,
enum led_brightness value )
{
bios_set_state ( WIFI , ( value ! = LED_OFF ) ? 1 : 0 ) ;
}
static struct led_classdev wistron_mail_led = {
2007-10-31 17:00:07 +03:00
. name = " wistron:green:mail " ,
2007-05-21 08:46:31 +04:00
. brightness_set = wistron_mail_led_set ,
} ;
static struct led_classdev wistron_wifi_led = {
2007-10-31 17:00:07 +03:00
. name = " wistron:red:wifi " ,
2007-05-21 08:46:31 +04:00
. brightness_set = wistron_wifi_led_set ,
} ;
static void __devinit wistron_led_init ( struct device * parent )
{
2009-08-08 10:17:39 +04:00
if ( leds_present & FE_WIFI_LED ) {
2007-05-21 08:46:31 +04:00
u16 wifi = bios_get_default_setting ( WIFI ) ;
if ( wifi & 1 ) {
wistron_wifi_led . brightness = ( wifi & 2 ) ? LED_FULL : LED_OFF ;
if ( led_classdev_register ( parent , & wistron_wifi_led ) )
2009-08-08 10:17:39 +04:00
leds_present & = ~ FE_WIFI_LED ;
2007-05-21 08:46:31 +04:00
else
bios_set_state ( WIFI , wistron_wifi_led . brightness ) ;
} else
2009-08-08 10:17:39 +04:00
leds_present & = ~ FE_WIFI_LED ;
2007-05-21 08:46:31 +04:00
}
2009-08-08 10:17:39 +04:00
if ( leds_present & FE_MAIL_LED ) {
2007-05-21 08:46:31 +04:00
/* bios_get_default_setting(MAIL) always retuns 0, so just turn the led off */
wistron_mail_led . brightness = LED_OFF ;
if ( led_classdev_register ( parent , & wistron_mail_led ) )
2009-08-08 10:17:39 +04:00
leds_present & = ~ FE_MAIL_LED ;
2007-05-21 08:46:31 +04:00
else
bios_set_state ( MAIL_LED , wistron_mail_led . brightness ) ;
}
}
static void __devexit wistron_led_remove ( void )
{
2009-08-08 10:17:39 +04:00
if ( leds_present & FE_MAIL_LED )
2007-05-21 08:46:31 +04:00
led_classdev_unregister ( & wistron_mail_led ) ;
2009-08-08 10:17:39 +04:00
if ( leds_present & FE_WIFI_LED )
2007-05-21 08:46:31 +04:00
led_classdev_unregister ( & wistron_wifi_led ) ;
}
static inline void wistron_led_suspend ( void )
{
2009-08-08 10:17:39 +04:00
if ( leds_present & FE_MAIL_LED )
2007-05-21 08:46:31 +04:00
led_classdev_suspend ( & wistron_mail_led ) ;
2009-08-08 10:17:39 +04:00
if ( leds_present & FE_WIFI_LED )
2007-05-21 08:46:31 +04:00
led_classdev_suspend ( & wistron_wifi_led ) ;
}
static inline void wistron_led_resume ( void )
{
2009-08-08 10:17:39 +04:00
if ( leds_present & FE_MAIL_LED )
2007-05-21 08:46:31 +04:00
led_classdev_resume ( & wistron_mail_led ) ;
2009-08-08 10:17:39 +04:00
if ( leds_present & FE_WIFI_LED )
2007-05-21 08:46:31 +04:00
led_classdev_resume ( & wistron_wifi_led ) ;
}
2007-06-15 07:31:45 +04:00
static struct key_entry * wistron_get_entry_by_scancode ( int code )
{
struct key_entry * key ;
for ( key = keymap ; key - > type ! = KE_END ; key + + )
if ( code = = key - > code )
return key ;
return NULL ;
}
static struct key_entry * wistron_get_entry_by_keycode ( int keycode )
{
struct key_entry * key ;
for ( key = keymap ; key - > type ! = KE_END ; key + + )
if ( key - > type = = KE_KEY & & keycode = = key - > keycode )
return key ;
return NULL ;
}
2005-11-20 08:50:06 +03:00
static void handle_key ( u8 code )
{
2007-06-15 07:31:45 +04:00
const struct key_entry * key = wistron_get_entry_by_scancode ( code ) ;
2005-11-20 08:50:06 +03:00
2007-06-15 07:31:45 +04:00
if ( key ) {
switch ( key - > type ) {
case KE_KEY :
report_key ( wistron_idev - > input , key - > keycode ) ;
break ;
case KE_SW :
report_switch ( wistron_idev - > input ,
key - > sw . code , key - > sw . value ) ;
break ;
case KE_WIFI :
if ( have_wifi ) {
wifi_enabled = ! wifi_enabled ;
bios_set_state ( WIFI , wifi_enabled ) ;
2005-11-20 08:50:06 +03:00
}
2007-06-15 07:31:45 +04:00
break ;
case KE_BLUETOOTH :
if ( have_bluetooth ) {
bluetooth_enabled = ! bluetooth_enabled ;
bios_set_state ( BLUETOOTH , bluetooth_enabled ) ;
}
break ;
default :
BUG ( ) ;
2005-11-20 08:50:06 +03:00
}
2007-06-15 07:31:45 +04:00
jiffies_last_press = jiffies ;
} else
printk ( KERN_NOTICE
" wistron_btns: Unknown key code %02X \n " , code ) ;
2005-11-20 08:50:06 +03:00
}
2007-05-23 07:48:39 +04:00
static void poll_bios ( bool discard )
2005-11-20 08:50:06 +03:00
{
u8 qlen ;
u16 val ;
for ( ; ; ) {
qlen = CMOS_READ ( cmos_address ) ;
if ( qlen = = 0 )
break ;
val = bios_pop_queue ( ) ;
2007-05-23 07:48:39 +04:00
if ( val ! = 0 & & ! discard )
2005-11-20 08:50:06 +03:00
handle_key ( ( u8 ) val ) ;
}
2007-05-23 07:48:39 +04:00
}
static void wistron_flush ( struct input_polled_dev * dev )
{
/* Flush stale event queue */
poll_bios ( true ) ;
}
static void wistron_poll ( struct input_polled_dev * dev )
{
poll_bios ( false ) ;
2005-11-20 08:50:06 +03:00
2007-05-23 07:48:39 +04:00
/* Increase poll frequency if user is currently pressing keys (< 2s ago) */
if ( time_before ( jiffies , jiffies_last_press + 2 * HZ ) )
dev - > poll_interval = POLL_INTERVAL_BURST ;
2007-05-21 08:46:22 +04:00
else
2007-05-23 07:48:39 +04:00
dev - > poll_interval = POLL_INTERVAL_DEFAULT ;
2005-11-20 08:50:06 +03:00
}
2007-06-15 07:31:45 +04:00
static int wistron_getkeycode ( struct input_dev * dev , int scancode , int * keycode )
{
const struct key_entry * key = wistron_get_entry_by_scancode ( scancode ) ;
if ( key & & key - > type = = KE_KEY ) {
* keycode = key - > keycode ;
return 0 ;
}
return - EINVAL ;
}
static int wistron_setkeycode ( struct input_dev * dev , int scancode , int keycode )
{
struct key_entry * key ;
int old_keycode ;
if ( keycode < 0 | | keycode > KEY_MAX )
return - EINVAL ;
key = wistron_get_entry_by_scancode ( scancode ) ;
if ( key & & key - > type = = KE_KEY ) {
old_keycode = key - > keycode ;
key - > keycode = keycode ;
set_bit ( keycode , dev - > keybit ) ;
if ( ! wistron_get_entry_by_keycode ( old_keycode ) )
clear_bit ( old_keycode , dev - > keybit ) ;
return 0 ;
}
return - EINVAL ;
}
2007-05-23 07:48:39 +04:00
static int __devinit setup_input_dev ( void )
{
2008-06-26 19:05:01 +04:00
struct key_entry * key ;
2007-05-23 07:48:39 +04:00
struct input_dev * input_dev ;
int error ;
wistron_idev = input_allocate_polled_device ( ) ;
if ( ! wistron_idev )
return - ENOMEM ;
2009-10-18 11:38:57 +04:00
wistron_idev - > open = wistron_flush ;
2007-05-23 07:48:39 +04:00
wistron_idev - > poll = wistron_poll ;
wistron_idev - > poll_interval = POLL_INTERVAL_DEFAULT ;
input_dev = wistron_idev - > input ;
input_dev - > name = " Wistron laptop buttons " ;
input_dev - > phys = " wistron/input0 " ;
input_dev - > id . bustype = BUS_HOST ;
2007-06-15 07:31:45 +04:00
input_dev - > dev . parent = & wistron_device - > dev ;
input_dev - > getkeycode = wistron_getkeycode ;
input_dev - > setkeycode = wistron_setkeycode ;
2007-05-23 07:48:39 +04:00
for ( key = keymap ; key - > type ! = KE_END ; key + + ) {
switch ( key - > type ) {
case KE_KEY :
set_bit ( EV_KEY , input_dev - > evbit ) ;
set_bit ( key - > keycode , input_dev - > keybit ) ;
break ;
case KE_SW :
set_bit ( EV_SW , input_dev - > evbit ) ;
set_bit ( key - > sw . code , input_dev - > swbit ) ;
break ;
2008-06-26 19:05:01 +04:00
/* if wifi or bluetooth are not available, create normal keys */
case KE_WIFI :
if ( ! have_wifi ) {
key - > type = KE_KEY ;
key - > keycode = KEY_WLAN ;
key - - ;
}
break ;
case KE_BLUETOOTH :
if ( ! have_bluetooth ) {
key - > type = KE_KEY ;
key - > keycode = KEY_BLUETOOTH ;
key - - ;
}
break ;
2007-05-23 07:48:39 +04:00
default :
break ;
}
}
/* reads information flags on KE_END */
if ( key - > code & FE_UNTESTED )
printk ( KERN_WARNING " Untested laptop multimedia keys, "
" please report success or failure to eric.piel "
" @tremplin-utc.net \n " ) ;
error = input_register_polled_device ( wistron_idev ) ;
if ( error ) {
input_free_polled_device ( wistron_idev ) ;
return error ;
}
return 0 ;
}
/* Driver core */
2005-12-28 09:26:24 +03:00
static int __devinit wistron_probe ( struct platform_device * dev )
{
2007-05-23 07:48:39 +04:00
int err ;
2005-12-28 09:26:24 +03:00
bios_attach ( ) ;
cmos_address = bios_get_cmos_address ( ) ;
if ( have_wifi ) {
u16 wifi = bios_get_default_setting ( WIFI ) ;
if ( wifi & 1 )
2009-08-08 10:17:39 +04:00
wifi_enabled = wifi & 2 ;
2005-12-28 09:26:24 +03:00
else
have_wifi = 0 ;
if ( have_wifi )
bios_set_state ( WIFI , wifi_enabled ) ;
}
if ( have_bluetooth ) {
u16 bt = bios_get_default_setting ( BLUETOOTH ) ;
if ( bt & 1 )
2009-08-08 10:17:39 +04:00
bluetooth_enabled = bt & 2 ;
2005-12-28 09:26:24 +03:00
else
2009-08-08 10:17:39 +04:00
have_bluetooth = false ;
2005-12-28 09:26:24 +03:00
if ( have_bluetooth )
bios_set_state ( BLUETOOTH , bluetooth_enabled ) ;
}
2007-05-21 08:46:31 +04:00
wistron_led_init ( & dev - > dev ) ;
2009-08-08 10:17:39 +04:00
2007-05-23 07:48:39 +04:00
err = setup_input_dev ( ) ;
if ( err ) {
bios_detach ( ) ;
return err ;
}
2005-12-28 09:26:24 +03:00
return 0 ;
}
static int __devexit wistron_remove ( struct platform_device * dev )
{
2007-05-21 08:46:31 +04:00
wistron_led_remove ( ) ;
2007-05-23 07:48:39 +04:00
input_unregister_polled_device ( wistron_idev ) ;
input_free_polled_device ( wistron_idev ) ;
2005-12-28 09:26:24 +03:00
bios_detach ( ) ;
return 0 ;
}
# ifdef CONFIG_PM
2009-08-08 10:17:39 +04:00
static int wistron_suspend ( struct device * dev )
2005-11-20 08:50:58 +03:00
{
2005-11-20 08:51:05 +03:00
if ( have_wifi )
bios_set_state ( WIFI , 0 ) ;
if ( have_bluetooth )
bios_set_state ( BLUETOOTH , 0 ) ;
2007-05-21 08:46:31 +04:00
wistron_led_suspend ( ) ;
2009-08-08 10:17:39 +04:00
2005-11-20 08:50:58 +03:00
return 0 ;
}
2009-08-08 10:17:39 +04:00
static int wistron_resume ( struct device * dev )
2005-11-20 08:50:58 +03:00
{
if ( have_wifi )
bios_set_state ( WIFI , wifi_enabled ) ;
if ( have_bluetooth )
bios_set_state ( BLUETOOTH , bluetooth_enabled ) ;
2007-05-21 08:46:31 +04:00
wistron_led_resume ( ) ;
2009-08-08 10:17:39 +04:00
2007-05-23 07:48:39 +04:00
poll_bios ( true ) ;
2005-11-20 08:50:58 +03:00
return 0 ;
}
2009-08-08 10:17:39 +04:00
static const struct dev_pm_ops wistron_pm_ops = {
. suspend = wistron_suspend ,
. resume = wistron_resume ,
. poweroff = wistron_suspend ,
. restore = wistron_resume ,
} ;
2005-12-28 09:26:24 +03:00
# endif
2005-11-20 08:50:58 +03:00
static struct platform_driver wistron_driver = {
. driver = {
. name = " wistron-bios " ,
2005-12-28 09:26:24 +03:00
. owner = THIS_MODULE ,
2009-08-08 10:17:39 +04:00
# if CONFIG_PM
. pm = & wistron_pm_ops ,
# endif
2005-11-20 08:50:58 +03:00
} ,
2005-12-28 09:26:24 +03:00
. probe = wistron_probe ,
. remove = __devexit_p ( wistron_remove ) ,
2005-11-20 08:50:58 +03:00
} ;
2005-11-20 08:50:06 +03:00
static int __init wb_module_init ( void )
{
int err ;
err = select_keymap ( ) ;
if ( err )
return err ;
2005-11-20 08:50:46 +03:00
2005-11-20 08:50:06 +03:00
err = map_bios ( ) ;
if ( err )
return err ;
2005-11-20 08:50:46 +03:00
2005-11-20 08:50:58 +03:00
err = platform_driver_register ( & wistron_driver ) ;
if ( err )
2005-12-28 09:26:24 +03:00
goto err_unmap_bios ;
2005-11-20 08:50:58 +03:00
2005-12-28 09:26:24 +03:00
wistron_device = platform_device_alloc ( " wistron-bios " , - 1 ) ;
if ( ! wistron_device ) {
err = - ENOMEM ;
2005-11-20 08:50:58 +03:00
goto err_unregister_driver ;
}
2005-12-28 09:26:24 +03:00
err = platform_device_add ( wistron_device ) ;
2005-11-20 08:50:58 +03:00
if ( err )
2005-12-28 09:26:24 +03:00
goto err_free_device ;
2005-11-20 08:50:06 +03:00
return 0 ;
2005-11-20 08:50:58 +03:00
2005-12-28 09:26:24 +03:00
err_free_device :
platform_device_put ( wistron_device ) ;
2005-11-20 08:50:58 +03:00
err_unregister_driver :
platform_driver_unregister ( & wistron_driver ) ;
2005-12-28 09:26:24 +03:00
err_unmap_bios :
2005-11-20 08:50:58 +03:00
unmap_bios ( ) ;
return err ;
2005-11-20 08:50:06 +03:00
}
static void __exit wb_module_exit ( void )
{
2005-11-20 08:50:58 +03:00
platform_device_unregister ( wistron_device ) ;
platform_driver_unregister ( & wistron_driver ) ;
2005-11-20 08:50:06 +03:00
unmap_bios ( ) ;
2007-04-12 09:32:49 +04:00
kfree ( keymap ) ;
2005-11-20 08:50:06 +03:00
}
module_init ( wb_module_init ) ;
module_exit ( wb_module_exit ) ;