--- acerhk-0.5.35/acerhk.c 2007-02-10 16:46:23.000000000 +0100 +++ acerhk/acerhk.c 2009-07-02 23:48:23.000000000 +0200 @@ -2,14 +2,14 @@ * Filename: acerhk.c * Version: 0.5 * - * Copyright (C) 2002-2006, Olaf Tauber (olaf-tauber@versanet.de) + * Copyright (C) 2002-2007, Olaf Tauber (olaf-tauber@versanet.de) * * Description: kernel driver for Acer Travelmate and similar * laptops special keys * Author: Olaf Tauber * Created at: Mon Apr 29 22:16:42 2002 - * Modified at: Mon Oct 16 21:36:44 2006 - * Modified by: Olaf Tauber + * Modified at: Mon Nov 12 20:53:56 2007 + * Modified by: Olaf Tauber * Modified at: Thu Nov 24 13:03:01 2005 * Modified by: Antonio Cuni * Modified at: Wed Oct 27 19:47:11 CEST 2004 @@ -63,6 +63,7 @@ #include #include #include +#include #include #include #include @@ -550,6 +551,7 @@ */ static asmlinkage void call_bios_6xx(struct register_buffer *buf) { +#ifndef __x86_64__ if (bios_routine) { local_irq_disable(); __asm__ __volatile__( @@ -578,10 +580,12 @@ ); local_irq_enable(); } +#endif } static asmlinkage void call_bios_52x(struct register_buffer *buf) { +#ifndef __x86_64__ if (bios_routine) { local_irq_disable(); __asm__ __volatile__( @@ -611,6 +615,7 @@ ); local_irq_enable(); } +#endif } #define PRINT_BUFFER(x) \ @@ -783,7 +788,8 @@ unsigned char c = 0; spin_lock_irqsave (&rtc_lock, flags); -#ifndef DUMMYHW +/* #ifndef DUMMYHW */ +#if !(defined(DUMMYHW) || defined(__x86_64__)) if (cmos_index) c = CMOS_READ(cmos_index); else if (verbose > 3) @@ -867,9 +873,9 @@ static struct proc_dir_entry *proc_acer_dir; -static unsigned int __init find_hk_area(void) +static unsigned long __init find_hk_area(void) { - int offset, sig; + long offset, sig; unsigned int fkt; fkt = 0; sig = -1; /* offset to signature in io area */ @@ -887,9 +893,9 @@ fkt = readl(reg1 + sig + 5); /* adjust fkt to address of mapped IO area */ if (fkt >= 0xf0000) - fkt = (unsigned int)reg1 + fkt - 0xf0000; + fkt = (unsigned long)reg1 + fkt - 0xf0000; else if (fkt >= 0xe0000) - fkt = (unsigned int)reg1 + fkt - 0xe0000; + fkt = (unsigned long)reg1 + fkt - 0xe0000; else fkt = 0; } @@ -1144,6 +1150,7 @@ case 2000: case 2010: case 2020: + case 5100: /* Aspire 13xx series laptops use dritek hardware, no acerhk-mapping needed VolUp and VolDown are managed as normal keys @@ -1231,6 +1238,17 @@ acerhk_key2name[5] = k_display; /* FN+F3 (Display switch) */ acerhk_key2name[6] = k_res; /* FN+F4 (Display ein/ausschalten) */ break; + case 97600: + /* Medion MD97600, 7 keys, no setup */ + acerhk_key2name[1] = k_help; /* FN+F1 (Help) */ + acerhk_key2name[2] = k_none; + acerhk_key2name[5] = k_display; /* FN+F3 (Display switch) */ + acerhk_key2name[6] = k_res; /* FN+F4 (Display ein/ausschalten) */ + acerhk_key2name[17] = k_p1; + acerhk_key2name[18] = k_p2; + acerhk_key2name[19] = k_p3; + acerhk_key2name[48] = k_wireless; + break; case 42200: /* Medion MD42200, 7 keys, no setup */ acerhk_key2name[2] = k_none; @@ -1288,6 +1306,22 @@ acerhk_key2name[19] = k_p3; acerhk_key2name[8] = k_mute; break; + case 6805: /* Added by damagedspline@aim.com */ + /* Amilo A1xxx does not have Setup key nor a mail key */ + acerhk_key2name[2] = k_none; + acerhk_key2name[54] = k_www; + acerhk_key2name[5] = k_display; + acerhk_key2name[110] = k_setup; //This is the Fancy Fan (cool-n'-quiet) key on A1650g + acerhk_key2name[48] = k_wireless; + break; + case 98200: + /* Medion MD98200, 4 keys, no setup */ + acerhk_key2name[2] = k_none; + acerhk_key2name[48] = k_wireless; + acerhk_key2name[0x79] = k_play; + acerhk_key2name[17] = k_p1; + acerhk_key2name[18] = k_p2; + break; } } @@ -1313,11 +1347,24 @@ acerhk_model_features = 0x00f00000; acerhk_type = TM_new; break; + case 97600: + /* has WLAN button */ + /* The MD97600 seems to require TM_F_CONNECT at least + once after cold boot, otherwise enabling the WLAN + radio does not work */ + acerhk_model_features = TM_F_WBUTTON | TM_F_CONNECT; + acerhk_type = TM_new; + break; case 42200: /* Medion MD42200 */ /* has WLAN button, should call connect() */ acerhk_model_features = TM_F_WBUTTON | TM_F_CONNECT; acerhk_type = TM_old; break; + case 98200: /* Medion MD98200 */ + /* has WLAN button, should call connect() */ + acerhk_model_features = TM_F_WBUTTON; + acerhk_type = TM_old; + break; case 9783: /* Medion MD9783 */ /* only email led */ acerhk_model_features = TM_F_MAIL_LED; @@ -1363,6 +1410,11 @@ acerhk_model_features = TM_F_MAIL_LED | 0x00f00000; acerhk_type = TM_new; break; + case 6805: /* Added by damagedspline@aim.com */ + /* Amilo A1xxx does not have a mail led */ + acerhk_model_features = 0x00f00000; + acerhk_type = TM_new; + break; case 2350: case 4050: acerhk_wlan_state = 1; // Default state is on @@ -1458,6 +1510,7 @@ case 1800: case 2010: case 2020: + case 5100: /* Dritek EC, bluetooth, wifi, mail */ acerhk_type = TM_dritek; acerhk_model_features = TM_F_MAIL_LED_EC2 | TM_F_WLAN_EC2 | TM_F_BLUE_EC2; @@ -1792,6 +1845,8 @@ break; case '2': series = 5020; break; } + } else if (str[8] == '1' && str[9] == '0') { + series = 5100; } else { if (verbose > 1) printk(KERN_INFO"acerhk: model string indicates unknown Aspire 5xxx series\n"); @@ -1854,6 +1909,15 @@ printk(KERN_INFO"acerhk: model string indicates FS AMILO Pro (V2000) series\n"); series = 7400; break; + case 'A': /* AMILO Axxxx - added by damagedspline@aim.com */ + switch (str[7]) { + case '1': /* AMILO A1xxx */ + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates FS AMILO A1xxx series\n"); + series = 6805; + break; + }; + break; default: if (verbose > 1) printk(KERN_INFO"acerhk: model string indicates unknown FS AMILO XX series\n"); @@ -1862,7 +1926,11 @@ } else if (strncmp(str, "MEDIONPC", 8) == 0) { uint medionmodel; - if ((medionmodel = COLUSSI("WIM 2040", 4, reg1, AREA_SIZE)) >= 0) { + if ((medionmodel = COLUSSI("WIM 2090", 8, reg1, AREA_SIZE)) >= 0) { + printk(KERN_INFO"acerhk: found Medion model string:'%s'\n", (char*)reg1+medionmodel); + series = 97600; + } + else if ((medionmodel = COLUSSI("WIM 2040", 4, reg1, AREA_SIZE)) >= 0) { printk(KERN_INFO"acerhk: found Medion model string:'%s'\n", (char*)reg1+medionmodel); series = 96500; } else { @@ -1893,6 +1961,12 @@ printk(KERN_INFO"acerhk: model string indicates a medion MD40100\n"); series = 40100; } + } else if (strncmp(str, "MEDION", 6) == 0) { + if (COLUSSI("WIM2120", 7, reg1, AREA_SIZE) >= 0) { + if (verbose>1) + printk(KERN_INFO"acerhk: model string indicates a Medion MD 98200\n"); + series = 98200; + } } else if (strncmp(str, "AOpen", 5) == 0) { if (strncmp(str, "AOpen*EzRestore", 15) == 0) { if (verbose > 1) @@ -2117,7 +2191,8 @@ /* polling timer handler */ static void acerhk_poll_event(unsigned long save_size) { -#ifndef DUMMYHW +/* #ifndef DUMMYHW */ +#if !(defined(DUMMYHW) || defined(__x86_64__)) unsigned int max = MAX_POLLING_LOOPS; /* make sure not to loop more then 32 times */ if (!max || max > 32) @@ -2139,7 +2214,8 @@ { if (acerhk_blueled_blinking != -1) { acerhk_blueled_blinking = !acerhk_blueled_blinking; -#ifndef DUMMYHW +/* #ifndef DUMMYHW */ +#if !(defined(DUMMYHW) || defined(__x86_64__)) wbutton_fct_1(acerhk_blueled_blinking); #endif acerhk_timer_blinking.expires = jiffies + acerhk_blueled_blinking_delay; @@ -2626,7 +2702,9 @@ printk(KERN_INFO"acerhk: could not create /proc/driver/acerhk\n"); } else { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) proc_acer_dir->owner = THIS_MODULE; +#endif /* now create several files, first general info ... */ entry = create_proc_read_entry("info", 0444, proc_acer_dir, acerhk_proc_info, NULL); @@ -2635,7 +2713,9 @@ remove_proc_entry("driver/acerhk", NULL); retval = 0; } else { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) entry->owner = THIS_MODULE; +#endif /* ... last pressed key ... */ entry = create_proc_read_entry("key", 0444, proc_acer_dir, acerhk_proc_key, NULL); @@ -2645,7 +2725,9 @@ remove_proc_entry("driver/acerhk", NULL); retval = 0; } else { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) entry->owner = THIS_MODULE; +#endif /* ... and led control file */ entry = create_proc_entry("led", 0222, proc_acer_dir); if (entry == NULL) { @@ -2657,7 +2739,9 @@ } else { entry->write_proc = acerhk_proc_led; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) entry->owner = THIS_MODULE; +#endif /* ... and wireless led controll file */ entry = create_proc_entry("wirelessled", 0222, proc_acer_dir); if (entry == NULL) { @@ -2670,7 +2754,9 @@ } else { entry->write_proc = acerhk_proc_wirelessled; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) entry->owner = THIS_MODULE; +#endif /* ... and bluetooth led controll file */ entry = create_proc_entry("blueled", 0222, proc_acer_dir); if (entry == NULL) { @@ -2683,7 +2769,9 @@ retval = 0; } else { entry->write_proc = acerhk_proc_blueled; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) entry->owner = THIS_MODULE; +#endif retval = 1; #ifdef ACERDEBUG /* add extra file for debugging purposes */ @@ -2700,7 +2788,9 @@ } else { entry->write_proc = acerhk_proc_debug; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) entry->owner = THIS_MODULE; +#endif retval = 1; } #endif @@ -2832,6 +2922,20 @@ return 0; } +#ifdef CONFIG_PM +static int acerhk_resume(struct platform_device *dev) +{ + printk(KERN_INFO"acerhk: Resuming. Setting wlan_state to: %d\n", acerhk_wlan_state); + + if (acerhk_wlan_state) + wbutton_fct_2(1); + else + wbutton_fct_2(0); + + return 0; +} +#endif + static struct file_operations acerhk_fops = { owner: THIS_MODULE, ioctl: acerhk_ioctl, @@ -2842,15 +2946,15 @@ release: acerhk_release, }; -static struct miscdevice acerhk_dev = { - MISC_DYNAMIC_MINOR, - "acerhk", - &acerhk_fops +static struct miscdevice acerhk_misc_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "acerhk", + .fops = &acerhk_fops, }; /* }}} */ -static void __init model_init(void) +static void __devinit model_init(void) { /* set callroutine, features and keymap for model */ setup_model_features(acerhk_series); @@ -2875,12 +2979,13 @@ } -static void __exit acerhk_cleanup_module (void); -static int __init acerhk_init(void) +static int __devexit acerhk_remove(struct platform_device *dev); + +static int __devinit acerhk_probe(struct platform_device *dev) { int ret; - ret = misc_register( &acerhk_dev ); + ret = misc_register(&acerhk_misc_dev); if (ret) { printk(KERN_ERR "acerhk: can't misc_register on minor=%d\n", ACERHK_MINOR); ret = -EAGAIN; @@ -2888,7 +2993,7 @@ else if (!acerhk_proc_init()) { printk(KERN_ERR "acerhk: can't create procfs entries\n"); ret = -ENOMEM; - misc_deregister( &acerhk_dev ); + misc_deregister( &acerhk_misc_dev ); } else { reg1 = ioremap(0xf0000, 0xffff); @@ -2904,7 +3009,8 @@ /* attach to input system */ init_input(); memset(acerhk_model_string, 0x00, ACERHK_MODEL_STRLEN); -#ifdef DUMMYHW +/* #ifdef DUMMYHW */ +#if (defined(DUMMYHW) || defined(__x86_64__)) acerhk_model_addr = (void*)0x12345678; /* copy the string, but not more than 15 characters */ strncpy(acerhk_model_string, "TravelmateDummy", ACERHK_MODEL_STRLEN-1); @@ -2950,14 +3056,14 @@ } else { printk(KERN_ERR "acerhk: can't find bios routine, cannot do anything for you, sorry!\n"); ret = -ENOMEM; - acerhk_cleanup_module(); + return acerhk_remove(dev); } #endif } return ret; } -static void __exit acerhk_cleanup_module (void) +static int __devexit acerhk_remove(struct platform_device *dev) { acerhk_proc_cleanup(); stop_blinking(); @@ -2968,16 +3074,68 @@ if (preg400) iounmap(preg400); release_input(); - misc_deregister( &acerhk_dev ); + misc_deregister(&acerhk_misc_dev); if ( acerhk_type == TM_dritek ) { disable_dritek_keyboard(); } if (verbose > 2) printk(KERN_INFO "acerhk: unloaded\n"); + + return 0; +} + +static struct platform_driver acerhk_driver = { + .driver = { + .name = "acerhk", + .owner = THIS_MODULE, + }, + .probe = acerhk_probe, + .remove = __devexit_p(acerhk_remove), +#ifdef CONFIG_PM + .resume = acerhk_resume, +#endif +}; + +static struct platform_device *acerhk_platform_device; + +static int __init acerhk_init(void) +{ + int error; + + error = platform_driver_register(&acerhk_driver); + if (error) + return error; + + acerhk_platform_device = platform_device_alloc("acerhk", -1); + if (!acerhk_platform_device) { + error = -ENOMEM; + goto err_driver_unregister; + } + + error = platform_device_add(acerhk_platform_device); + if (error) + goto err_free_device; + + + return 0; + + err_free_device: + platform_device_put(acerhk_platform_device); + err_driver_unregister: + platform_driver_unregister(&acerhk_driver); + return error; } +static void __exit acerhk_exit(void) +{ + platform_device_unregister(acerhk_platform_device); + platform_driver_unregister(&acerhk_driver); + printk(KERN_INFO "acerhk: removed.\n"); +} + + module_init(acerhk_init); -module_exit(acerhk_cleanup_module); +module_exit(acerhk_exit); MODULE_AUTHOR("Olaf Tauber"); MODULE_DESCRIPTION("AcerHotkeys extra buttons keyboard driver"); --- acerhk-0.5.35/doc/FAQ 2005-11-10 18:45:33.000000000 +0100 +++ acerhk/doc/FAQ 2007-09-21 21:58:40.000000000 +0200 @@ -1,5 +1,15 @@ ****************************************************************************** +Q: The driver works perfectly when using force_series, what is needed to add +autodetection? + +A: I need the model name of the laptop, if you do not see a usable name in +/proc/driver/acerhk/info please try the tools dmidecode/biosdecode/vpddecode +to find this name. You can also load the driver and then look into the bios +directly by scanning the memory which is mapped by the driver. + +****************************************************************************** + Q: I have a (non Acer) notebook which is not recognized by your driver but I think it should. What information do you need?