linux/drivers/input/misc/wistron_btns.c
<<
>>
Prefs
   1/*
   2 * Wistron laptop button driver
   3 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
   4 * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
   5 * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
   6 *
   7 * You can redistribute and/or modify this program under the terms of the
   8 * GNU General Public License version 2 as published by the Free Software
   9 * Foundation.
  10 *
  11 * This program is distributed in the hope that it will be useful, but
  12 * WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
  14 * Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License along
  17 * with this program; if not, write to the Free Software Foundation, Inc.,
  18 * 59 Temple Place Suite 330, Boston, MA 02111-1307, USA.
  19 */
  20#include <linux/io.h>
  21#include <linux/dmi.h>
  22#include <linux/init.h>
  23#include <linux/input-polldev.h>
  24#include <linux/interrupt.h>
  25#include <linux/jiffies.h>
  26#include <linux/kernel.h>
  27#include <linux/mc146818rtc.h>
  28#include <linux/module.h>
  29#include <linux/preempt.h>
  30#include <linux/string.h>
  31#include <linux/types.h>
  32#include <linux/platform_device.h>
  33#include <linux/leds.h>
  34
  35/* How often we poll keys - msecs */
  36#define POLL_INTERVAL_DEFAULT   500 /* when idle */
  37#define POLL_INTERVAL_BURST     100 /* when a key was recently pressed */
  38
  39/* BIOS subsystem IDs */
  40#define WIFI            0x35
  41#define BLUETOOTH       0x34
  42#define MAIL_LED        0x31
  43
  44MODULE_AUTHOR("Miloslav Trmac <mitr@volny.cz>");
  45MODULE_DESCRIPTION("Wistron laptop button driver");
  46MODULE_LICENSE("GPL v2");
  47MODULE_VERSION("0.3");
  48
  49static int force; /* = 0; */
  50module_param(force, bool, 0);
  51MODULE_PARM_DESC(force, "Load even if computer is not in database");
  52
  53static char *keymap_name; /* = NULL; */
  54module_param_named(keymap, keymap_name, charp, 0);
  55MODULE_PARM_DESC(keymap, "Keymap name, if it can't be autodetected [generic, 1557/MS2141]");
  56
  57static struct platform_device *wistron_device;
  58
  59 /* BIOS interface implementation */
  60
  61static void __iomem *bios_entry_point; /* BIOS routine entry point */
  62static void __iomem *bios_code_map_base;
  63static void __iomem *bios_data_map_base;
  64
  65static u8 cmos_address;
  66
  67struct regs {
  68        u32 eax, ebx, ecx;
  69};
  70
  71static void call_bios(struct regs *regs)
  72{
  73        unsigned long flags;
  74
  75        preempt_disable();
  76        local_irq_save(flags);
  77        asm volatile ("pushl %%ebp;"
  78                      "movl %7, %%ebp;"
  79                      "call *%6;"
  80                      "popl %%ebp"
  81                      : "=a" (regs->eax), "=b" (regs->ebx), "=c" (regs->ecx)
  82                      : "0" (regs->eax), "1" (regs->ebx), "2" (regs->ecx),
  83                        "m" (bios_entry_point), "m" (bios_data_map_base)
  84                      : "edx", "edi", "esi", "memory");
  85        local_irq_restore(flags);
  86        preempt_enable();
  87}
  88
  89static ssize_t __init locate_wistron_bios(void __iomem *base)
  90{
  91        static unsigned char __initdata signature[] =
  92                { 0x42, 0x21, 0x55, 0x30 };
  93        ssize_t offset;
  94
  95        for (offset = 0; offset < 0x10000; offset += 0x10) {
  96                if (check_signature(base + offset, signature,
  97                                    sizeof(signature)) != 0)
  98                        return offset;
  99        }
 100        return -1;
 101}
 102
 103static int __init map_bios(void)
 104{
 105        void __iomem *base;
 106        ssize_t offset;
 107        u32 entry_point;
 108
 109        base = ioremap(0xF0000, 0x10000); /* Can't fail */
 110        offset = locate_wistron_bios(base);
 111        if (offset < 0) {
 112                printk(KERN_ERR "wistron_btns: BIOS entry point not found\n");
 113                iounmap(base);
 114                return -ENODEV;
 115        }
 116
 117        entry_point = readl(base + offset + 5);
 118        printk(KERN_DEBUG
 119                "wistron_btns: BIOS signature found at %p, entry point %08X\n",
 120                base + offset, entry_point);
 121
 122        if (entry_point >= 0xF0000) {
 123                bios_code_map_base = base;
 124                bios_entry_point = bios_code_map_base + (entry_point & 0xFFFF);
 125        } else {
 126                iounmap(base);
 127                bios_code_map_base = ioremap(entry_point & ~0x3FFF, 0x4000);
 128                if (bios_code_map_base == NULL) {
 129                        printk(KERN_ERR
 130                                "wistron_btns: Can't map BIOS code at %08X\n",
 131                                entry_point & ~0x3FFF);
 132                        goto err;
 133                }
 134                bios_entry_point = bios_code_map_base + (entry_point & 0x3FFF);
 135        }
 136        /* The Windows driver maps 0x10000 bytes, we keep only one page... */
 137        bios_data_map_base = ioremap(0x400, 0xc00);
 138        if (bios_data_map_base == NULL) {
 139                printk(KERN_ERR "wistron_btns: Can't map BIOS data\n");
 140                goto err_code;
 141        }
 142        return 0;
 143
 144err_code:
 145        iounmap(bios_code_map_base);
 146err:
 147        return -ENOMEM;
 148}
 149
 150static inline void unmap_bios(void)
 151{
 152        iounmap(bios_code_map_base);
 153        iounmap(bios_data_map_base);
 154}
 155
 156 /* BIOS calls */
 157
 158static u16 bios_pop_queue(void)
 159{
 160        struct regs regs;
 161
 162        memset(&regs, 0, sizeof (regs));
 163        regs.eax = 0x9610;
 164        regs.ebx = 0x061C;
 165        regs.ecx = 0x0000;
 166        call_bios(&regs);
 167
 168        return regs.eax;
 169}
 170
 171static void __devinit bios_attach(void)
 172{
 173        struct regs regs;
 174
 175        memset(&regs, 0, sizeof (regs));
 176        regs.eax = 0x9610;
 177        regs.ebx = 0x012E;
 178        call_bios(&regs);
 179}
 180
 181static void bios_detach(void)
 182{
 183        struct regs regs;
 184
 185        memset(&regs, 0, sizeof (regs));
 186        regs.eax = 0x9610;
 187        regs.ebx = 0x002E;
 188        call_bios(&regs);
 189}
 190
 191static u8 __devinit bios_get_cmos_address(void)
 192{
 193        struct regs regs;
 194
 195        memset(&regs, 0, sizeof (regs));
 196        regs.eax = 0x9610;
 197        regs.ebx = 0x051C;
 198        call_bios(&regs);
 199
 200        return regs.ecx;
 201}
 202
 203static u16 __devinit bios_get_default_setting(u8 subsys)
 204{
 205        struct regs regs;
 206
 207        memset(&regs, 0, sizeof (regs));
 208        regs.eax = 0x9610;
 209        regs.ebx = 0x0200 | subsys;
 210        call_bios(&regs);
 211
 212        return regs.eax;
 213}
 214
 215static void bios_set_state(u8 subsys, int enable)
 216{
 217        struct regs regs;
 218
 219        memset(&regs, 0, sizeof (regs));
 220        regs.eax = 0x9610;
 221        regs.ebx = (enable ? 0x0100 : 0x0000) | subsys;
 222        call_bios(&regs);
 223}
 224
 225/* Hardware database */
 226
 227struct key_entry {
 228        char type;              /* See KE_* below */
 229        u8 code;
 230        union {
 231                u16 keycode;            /* For KE_KEY */
 232                struct {                /* For KE_SW */
 233                        u8 code;
 234                        u8 value;
 235                } sw;
 236        };
 237};
 238
 239enum { KE_END, KE_KEY, KE_SW, KE_WIFI, KE_BLUETOOTH };
 240
 241#define FE_MAIL_LED 0x01
 242#define FE_WIFI_LED 0x02
 243#define FE_UNTESTED 0x80
 244
 245static struct key_entry *keymap; /* = NULL; Current key map */
 246static int have_wifi;
 247static int have_bluetooth;
 248static int have_leds;
 249
 250static int __init dmi_matched(const struct dmi_system_id *dmi)
 251{
 252        const struct key_entry *key;
 253
 254        keymap = dmi->driver_data;
 255        for (key = keymap; key->type != KE_END; key++) {
 256                if (key->type == KE_WIFI)
 257                        have_wifi = 1;
 258                else if (key->type == KE_BLUETOOTH)
 259                        have_bluetooth = 1;
 260        }
 261        have_leds = key->code & (FE_MAIL_LED | FE_WIFI_LED);
 262
 263        return 1;
 264}
 265
 266static struct key_entry keymap_empty[] __initdata = {
 267        { KE_END, 0 }
 268};
 269
 270static struct key_entry keymap_fs_amilo_pro_v2000[] __initdata = {
 271        { KE_KEY,  0x01, {KEY_HELP} },
 272        { KE_KEY,  0x11, {KEY_PROG1} },
 273        { KE_KEY,  0x12, {KEY_PROG2} },
 274        { KE_WIFI, 0x30 },
 275        { KE_KEY,  0x31, {KEY_MAIL} },
 276        { KE_KEY,  0x36, {KEY_WWW} },
 277        { KE_END,  0 }
 278};
 279
 280static struct key_entry keymap_fs_amilo_pro_v3505[] __initdata = {
 281        { KE_KEY,       0x01, {KEY_HELP} },          /* Fn+F1 */
 282        { KE_KEY,       0x06, {KEY_DISPLAYTOGGLE} }, /* Fn+F4 */
 283        { KE_BLUETOOTH, 0x30 },                      /* Fn+F10 */
 284        { KE_KEY,       0x31, {KEY_MAIL} },          /* mail button */
 285        { KE_KEY,       0x36, {KEY_WWW} },           /* www button */
 286        { KE_WIFI,      0x78 },                      /* satelite dish button */
 287        { KE_END,       0 }
 288};
 289
 290static struct key_entry keymap_fujitsu_n3510[] __initdata = {
 291        { KE_KEY, 0x11, {KEY_PROG1} },
 292        { KE_KEY, 0x12, {KEY_PROG2} },
 293        { KE_KEY, 0x36, {KEY_WWW} },
 294        { KE_KEY, 0x31, {KEY_MAIL} },
 295        { KE_KEY, 0x71, {KEY_STOPCD} },
 296        { KE_KEY, 0x72, {KEY_PLAYPAUSE} },
 297        { KE_KEY, 0x74, {KEY_REWIND} },
 298        { KE_KEY, 0x78, {KEY_FORWARD} },
 299        { KE_END, 0 }
 300};
 301
 302static struct key_entry keymap_wistron_ms2111[] __initdata = {
 303        { KE_KEY,  0x11, {KEY_PROG1} },
 304        { KE_KEY,  0x12, {KEY_PROG2} },
 305        { KE_KEY,  0x13, {KEY_PROG3} },
 306        { KE_KEY,  0x31, {KEY_MAIL} },
 307        { KE_KEY,  0x36, {KEY_WWW} },
 308        { KE_END, FE_MAIL_LED }
 309};
 310
 311static struct key_entry keymap_wistron_md40100[] __initdata = {
 312        { KE_KEY, 0x01, {KEY_HELP} },
 313        { KE_KEY, 0x02, {KEY_CONFIG} },
 314        { KE_KEY, 0x31, {KEY_MAIL} },
 315        { KE_KEY, 0x36, {KEY_WWW} },
 316        { KE_KEY, 0x37, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
 317        { KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED }
 318};
 319
 320static struct key_entry keymap_wistron_ms2141[] __initdata = {
 321        { KE_KEY,  0x11, {KEY_PROG1} },
 322        { KE_KEY,  0x12, {KEY_PROG2} },
 323        { KE_WIFI, 0x30 },
 324        { KE_KEY,  0x22, {KEY_REWIND} },
 325        { KE_KEY,  0x23, {KEY_FORWARD} },
 326        { KE_KEY,  0x24, {KEY_PLAYPAUSE} },
 327        { KE_KEY,  0x25, {KEY_STOPCD} },
 328        { KE_KEY,  0x31, {KEY_MAIL} },
 329        { KE_KEY,  0x36, {KEY_WWW} },
 330        { KE_END,  0 }
 331};
 332
 333static struct key_entry keymap_acer_aspire_1500[] __initdata = {
 334        { KE_KEY, 0x01, {KEY_HELP} },
 335        { KE_KEY, 0x03, {KEY_POWER} },
 336        { KE_KEY, 0x11, {KEY_PROG1} },
 337        { KE_KEY, 0x12, {KEY_PROG2} },
 338        { KE_WIFI, 0x30 },
 339        { KE_KEY, 0x31, {KEY_MAIL} },
 340        { KE_KEY, 0x36, {KEY_WWW} },
 341        { KE_KEY, 0x49, {KEY_CONFIG} },
 342        { KE_BLUETOOTH, 0x44 },
 343        { KE_END, FE_UNTESTED }
 344};
 345
 346static struct key_entry keymap_acer_aspire_1600[] __initdata = {
 347        { KE_KEY, 0x01, {KEY_HELP} },
 348        { KE_KEY, 0x03, {KEY_POWER} },
 349        { KE_KEY, 0x08, {KEY_MUTE} },
 350        { KE_KEY, 0x11, {KEY_PROG1} },
 351        { KE_KEY, 0x12, {KEY_PROG2} },
 352        { KE_KEY, 0x13, {KEY_PROG3} },
 353        { KE_KEY, 0x31, {KEY_MAIL} },
 354        { KE_KEY, 0x36, {KEY_WWW} },
 355        { KE_KEY, 0x49, {KEY_CONFIG} },
 356        { KE_WIFI, 0x30 },
 357        { KE_BLUETOOTH, 0x44 },
 358        { KE_END, FE_MAIL_LED | FE_UNTESTED }
 359};
 360
 361/* 3020 has been tested */
 362static struct key_entry keymap_acer_aspire_5020[] __initdata = {
 363        { KE_KEY, 0x01, {KEY_HELP} },
 364        { KE_KEY, 0x03, {KEY_POWER} },
 365        { KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */
 366        { KE_KEY, 0x11, {KEY_PROG1} },
 367        { KE_KEY, 0x12, {KEY_PROG2} },
 368        { KE_KEY, 0x31, {KEY_MAIL} },
 369        { KE_KEY, 0x36, {KEY_WWW} },
 370        { KE_KEY, 0x6a, {KEY_CONFIG} },
 371        { KE_WIFI, 0x30 },
 372        { KE_BLUETOOTH, 0x44 },
 373        { KE_END, FE_MAIL_LED | FE_UNTESTED }
 374};
 375
 376static struct key_entry keymap_acer_travelmate_2410[] __initdata = {
 377        { KE_KEY, 0x01, {KEY_HELP} },
 378        { KE_KEY, 0x6d, {KEY_POWER} },
 379        { KE_KEY, 0x11, {KEY_PROG1} },
 380        { KE_KEY, 0x12, {KEY_PROG2} },
 381        { KE_KEY, 0x31, {KEY_MAIL} },
 382        { KE_KEY, 0x36, {KEY_WWW} },
 383        { KE_KEY, 0x6a, {KEY_CONFIG} },
 384        { KE_WIFI, 0x30 },
 385        { KE_BLUETOOTH, 0x44 },
 386        { KE_END, FE_MAIL_LED | FE_UNTESTED }
 387};
 388
 389static struct key_entry keymap_acer_travelmate_110[] __initdata = {
 390        { KE_KEY, 0x01, {KEY_HELP} },
 391        { KE_KEY, 0x02, {KEY_CONFIG} },
 392        { KE_KEY, 0x03, {KEY_POWER} },
 393        { KE_KEY, 0x08, {KEY_MUTE} },
 394        { KE_KEY, 0x11, {KEY_PROG1} },
 395        { KE_KEY, 0x12, {KEY_PROG2} },
 396        { KE_KEY, 0x20, {KEY_VOLUMEUP} },
 397        { KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
 398        { KE_KEY, 0x31, {KEY_MAIL} },
 399        { KE_KEY, 0x36, {KEY_WWW} },
 400        { KE_SW, 0x4a, {.sw = {SW_LID, 1}} }, /* lid close */
 401        { KE_SW, 0x4b, {.sw = {SW_LID, 0}} }, /* lid open */
 402        { KE_WIFI, 0x30 },
 403        { KE_END, FE_MAIL_LED | FE_UNTESTED }
 404};
 405
 406static struct key_entry keymap_acer_travelmate_300[] __initdata = {
 407        { KE_KEY, 0x01, {KEY_HELP} },
 408        { KE_KEY, 0x02, {KEY_CONFIG} },
 409        { KE_KEY, 0x03, {KEY_POWER} },
 410        { KE_KEY, 0x08, {KEY_MUTE} },
 411        { KE_KEY, 0x11, {KEY_PROG1} },
 412        { KE_KEY, 0x12, {KEY_PROG2} },
 413        { KE_KEY, 0x20, {KEY_VOLUMEUP} },
 414        { KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
 415        { KE_KEY, 0x31, {KEY_MAIL} },
 416        { KE_KEY, 0x36, {KEY_WWW} },
 417        { KE_WIFI, 0x30 },
 418        { KE_BLUETOOTH, 0x44 },
 419        { KE_END, FE_MAIL_LED | FE_UNTESTED }
 420};
 421
 422static struct key_entry keymap_acer_travelmate_380[] __initdata = {
 423        { KE_KEY, 0x01, {KEY_HELP} },
 424        { KE_KEY, 0x02, {KEY_CONFIG} },
 425        { KE_KEY, 0x03, {KEY_POWER} }, /* not 370 */
 426        { KE_KEY, 0x11, {KEY_PROG1} },
 427        { KE_KEY, 0x12, {KEY_PROG2} },
 428        { KE_KEY, 0x13, {KEY_PROG3} },
 429        { KE_KEY, 0x31, {KEY_MAIL} },
 430        { KE_KEY, 0x36, {KEY_WWW} },
 431        { KE_WIFI, 0x30 },
 432        { KE_END, FE_MAIL_LED | FE_UNTESTED }
 433};
 434
 435/* unusual map */
 436static struct key_entry keymap_acer_travelmate_220[] __initdata = {
 437        { KE_KEY, 0x01, {KEY_HELP} },
 438        { KE_KEY, 0x02, {KEY_CONFIG} },
 439        { KE_KEY, 0x11, {KEY_MAIL} },
 440        { KE_KEY, 0x12, {KEY_WWW} },
 441        { KE_KEY, 0x13, {KEY_PROG2} },
 442        { KE_KEY, 0x31, {KEY_PROG1} },
 443        { KE_END, FE_WIFI_LED | FE_UNTESTED }
 444};
 445
 446static struct key_entry keymap_acer_travelmate_230[] __initdata = {
 447        { KE_KEY, 0x01, {KEY_HELP} },
 448        { KE_KEY, 0x02, {KEY_CONFIG} },
 449        { KE_KEY, 0x11, {KEY_PROG1} },
 450        { KE_KEY, 0x12, {KEY_PROG2} },
 451        { KE_KEY, 0x31, {KEY_MAIL} },
 452        { KE_KEY, 0x36, {KEY_WWW} },
 453        { KE_END, FE_WIFI_LED | FE_UNTESTED }
 454};
 455
 456static struct key_entry keymap_acer_travelmate_240[] __initdata = {
 457        { KE_KEY, 0x01, {KEY_HELP} },
 458        { KE_KEY, 0x02, {KEY_CONFIG} },
 459        { KE_KEY, 0x03, {KEY_POWER} },
 460        { KE_KEY, 0x08, {KEY_MUTE} },
 461        { KE_KEY, 0x31, {KEY_MAIL} },
 462        { KE_KEY, 0x36, {KEY_WWW} },
 463        { KE_KEY, 0x11, {KEY_PROG1} },
 464        { KE_KEY, 0x12, {KEY_PROG2} },
 465        { KE_BLUETOOTH, 0x44 },
 466        { KE_WIFI, 0x30 },
 467        { KE_END, FE_UNTESTED }
 468};
 469
 470static struct key_entry keymap_acer_travelmate_350[] __initdata = {
 471        { KE_KEY, 0x01, {KEY_HELP} },
 472        { KE_KEY, 0x02, {KEY_CONFIG} },
 473        { KE_KEY, 0x11, {KEY_PROG1} },
 474        { KE_KEY, 0x12, {KEY_PROG2} },
 475        { KE_KEY, 0x13, {KEY_MAIL} },
 476        { KE_KEY, 0x14, {KEY_PROG3} },
 477        { KE_KEY, 0x15, {KEY_WWW} },
 478        { KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED }
 479};
 480
 481static struct key_entry keymap_acer_travelmate_360[] __initdata = {
 482        { KE_KEY, 0x01, {KEY_HELP} },
 483        { KE_KEY, 0x02, {KEY_CONFIG} },
 484        { KE_KEY, 0x11, {KEY_PROG1} },
 485        { KE_KEY, 0x12, {KEY_PROG2} },
 486        { KE_KEY, 0x13, {KEY_MAIL} },
 487        { KE_KEY, 0x14, {KEY_PROG3} },
 488        { KE_KEY, 0x15, {KEY_WWW} },
 489        { KE_KEY, 0x40, {KEY_WLAN} },
 490        { KE_END, FE_WIFI_LED | FE_UNTESTED } /* no mail led */
 491};
 492
 493/* Wifi subsystem only activates the led. Therefore we need to pass
 494 * wifi event as a normal key, then userspace can really change the wifi state.
 495 * TODO we need to export led state to userspace (wifi and mail) */
 496static struct key_entry keymap_acer_travelmate_610[] __initdata = {
 497        { KE_KEY, 0x01, {KEY_HELP} },
 498        { KE_KEY, 0x02, {KEY_CONFIG} },
 499        { KE_KEY, 0x11, {KEY_PROG1} },
 500        { KE_KEY, 0x12, {KEY_PROG2} },
 501        { KE_KEY, 0x13, {KEY_PROG3} },
 502        { KE_KEY, 0x14, {KEY_MAIL} },
 503        { KE_KEY, 0x15, {KEY_WWW} },
 504        { KE_KEY, 0x40, {KEY_WLAN} },
 505        { KE_END, FE_MAIL_LED | FE_WIFI_LED }
 506};
 507
 508static struct key_entry keymap_acer_travelmate_630[] __initdata = {
 509        { KE_KEY, 0x01, {KEY_HELP} },
 510        { KE_KEY, 0x02, {KEY_CONFIG} },
 511        { KE_KEY, 0x03, {KEY_POWER} },
 512        { KE_KEY, 0x08, {KEY_MUTE} }, /* not 620 */
 513        { KE_KEY, 0x11, {KEY_PROG1} },
 514        { KE_KEY, 0x12, {KEY_PROG2} },
 515        { KE_KEY, 0x13, {KEY_PROG3} },
 516        { KE_KEY, 0x20, {KEY_VOLUMEUP} },
 517        { KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
 518        { KE_KEY, 0x31, {KEY_MAIL} },
 519        { KE_KEY, 0x36, {KEY_WWW} },
 520        { KE_WIFI, 0x30 },
 521        { KE_END, FE_MAIL_LED | FE_UNTESTED }
 522};
 523
 524static struct key_entry keymap_aopen_1559as[] __initdata = {
 525        { KE_KEY,  0x01, {KEY_HELP} },
 526        { KE_KEY,  0x06, {KEY_PROG3} },
 527        { KE_KEY,  0x11, {KEY_PROG1} },
 528        { KE_KEY,  0x12, {KEY_PROG2} },
 529        { KE_WIFI, 0x30 },
 530        { KE_KEY,  0x31, {KEY_MAIL} },
 531        { KE_KEY,  0x36, {KEY_WWW} },
 532        { KE_END,  0 },
 533};
 534
 535static struct key_entry keymap_fs_amilo_d88x0[] __initdata = {
 536        { KE_KEY, 0x01, {KEY_HELP} },
 537        { KE_KEY, 0x08, {KEY_MUTE} },
 538        { KE_KEY, 0x31, {KEY_MAIL} },
 539        { KE_KEY, 0x36, {KEY_WWW} },
 540        { KE_KEY, 0x11, {KEY_PROG1} },
 541        { KE_KEY, 0x12, {KEY_PROG2} },
 542        { KE_KEY, 0x13, {KEY_PROG3} },
 543        { KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED }
 544};
 545
 546static struct key_entry keymap_wistron_md2900[] __initdata = {
 547        { KE_KEY, 0x01, {KEY_HELP} },
 548        { KE_KEY, 0x02, {KEY_CONFIG} },
 549        { KE_KEY, 0x11, {KEY_PROG1} },
 550        { KE_KEY, 0x12, {KEY_PROG2} },
 551        { KE_KEY, 0x31, {KEY_MAIL} },
 552        { KE_KEY, 0x36, {KEY_WWW} },
 553        { KE_WIFI, 0x30 },
 554        { KE_END, FE_MAIL_LED | FE_UNTESTED }
 555};
 556
 557static struct key_entry keymap_wistron_md96500[] __initdata = {
 558        { KE_KEY, 0x01, {KEY_HELP} },
 559        { KE_KEY, 0x02, {KEY_CONFIG} },
 560        { KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */
 561        { KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
 562        { KE_KEY, 0x08, {KEY_MUTE} },
 563        { KE_KEY, 0x11, {KEY_PROG1} },
 564        { KE_KEY, 0x12, {KEY_PROG2} },
 565        { KE_KEY, 0x20, {KEY_VOLUMEUP} },
 566        { KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
 567        { KE_KEY, 0x22, {KEY_REWIND} },
 568        { KE_KEY, 0x23, {KEY_FORWARD} },
 569        { KE_KEY, 0x24, {KEY_PLAYPAUSE} },
 570        { KE_KEY, 0x25, {KEY_STOPCD} },
 571        { KE_KEY, 0x31, {KEY_MAIL} },
 572        { KE_KEY, 0x36, {KEY_WWW} },
 573        { KE_WIFI, 0x30 },
 574        { KE_BLUETOOTH, 0x44 },
 575        { KE_END, FE_UNTESTED }
 576};
 577
 578static struct key_entry keymap_wistron_generic[] __initdata = {
 579        { KE_KEY, 0x01, {KEY_HELP} },
 580        { KE_KEY, 0x02, {KEY_CONFIG} },
 581        { KE_KEY, 0x03, {KEY_POWER} },
 582        { KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */
 583        { KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
 584        { KE_KEY, 0x08, {KEY_MUTE} },
 585        { KE_KEY, 0x11, {KEY_PROG1} },
 586        { KE_KEY, 0x12, {KEY_PROG2} },
 587        { KE_KEY, 0x13, {KEY_PROG3} },
 588        { KE_KEY, 0x14, {KEY_MAIL} },
 589        { KE_KEY, 0x15, {KEY_WWW} },
 590        { KE_KEY, 0x20, {KEY_VOLUMEUP} },
 591        { KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
 592        { KE_KEY, 0x22, {KEY_REWIND} },
 593        { KE_KEY, 0x23, {KEY_FORWARD} },
 594        { KE_KEY, 0x24, {KEY_PLAYPAUSE} },
 595        { KE_KEY, 0x25, {KEY_STOPCD} },
 596        { KE_KEY, 0x31, {KEY_MAIL} },
 597        { KE_KEY, 0x36, {KEY_WWW} },
 598        { KE_KEY, 0x37, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
 599        { KE_KEY, 0x40, {KEY_WLAN} },
 600        { KE_KEY, 0x49, {KEY_CONFIG} },
 601        { KE_SW, 0x4a, {.sw = {SW_LID, 1}} }, /* lid close */
 602        { KE_SW, 0x4b, {.sw = {SW_LID, 0}} }, /* lid open */
 603        { KE_KEY, 0x6a, {KEY_CONFIG} },
 604        { KE_KEY, 0x6d, {KEY_POWER} },
 605        { KE_KEY, 0x71, {KEY_STOPCD} },
 606        { KE_KEY, 0x72, {KEY_PLAYPAUSE} },
 607        { KE_KEY, 0x74, {KEY_REWIND} },
 608        { KE_KEY, 0x78, {KEY_FORWARD} },
 609        { KE_WIFI, 0x30 },
 610        { KE_BLUETOOTH, 0x44 },
 611        { KE_END, 0 }
 612};
 613
 614/*
 615 * If your machine is not here (which is currently rather likely), please send
 616 * a list of buttons and their key codes (reported when loading this module
 617 * with force=1) and the output of dmidecode to $MODULE_AUTHOR.
 618 */
 619static struct dmi_system_id dmi_ids[] __initdata = {
 620        {
 621                .callback = dmi_matched,
 622                .ident = "Fujitsu-Siemens Amilo Pro V2000",
 623                .matches = {
 624                        DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
 625                        DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro V2000"),
 626                },
 627                .driver_data = keymap_fs_amilo_pro_v2000
 628        },
 629        {
 630                .callback = dmi_matched,
 631                .ident = "Fujitsu-Siemens Amilo Pro Edition V3505",
 632                .matches = {
 633                        DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
 634                        DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro Edition V3505"),
 635                },
 636                .driver_data = keymap_fs_amilo_pro_v3505
 637        },
 638        {
 639                .callback = dmi_matched,
 640                .ident = "Fujitsu-Siemens Amilo M7400",
 641                .matches = {
 642                        DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
 643                        DMI_MATCH(DMI_PRODUCT_NAME, "AMILO M        "),
 644                },
 645                .driver_data = keymap_fs_amilo_pro_v2000
 646        },
 647        {
 648                .callback = dmi_matched,
 649                .ident = "Fujitsu N3510",
 650                .matches = {
 651                        DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
 652                        DMI_MATCH(DMI_PRODUCT_NAME, "N3510"),
 653                },
 654                .driver_data = keymap_fujitsu_n3510
 655        },
 656        {
 657                .callback = dmi_matched,
 658                .ident = "Acer Aspire 1500",
 659                .matches = {
 660                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 661                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1500"),
 662                },
 663                .driver_data = keymap_acer_aspire_1500
 664        },
 665        {
 666                .callback = dmi_matched,
 667                .ident = "Acer Aspire 1600",
 668                .matches = {
 669                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 670                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1600"),
 671                },
 672                .driver_data = keymap_acer_aspire_1600
 673        },
 674        {
 675                .callback = dmi_matched,
 676                .ident = "Acer Aspire 3020",
 677                .matches = {
 678                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 679                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3020"),
 680                },
 681                .driver_data = keymap_acer_aspire_5020
 682        },
 683        {
 684                .callback = dmi_matched,
 685                .ident = "Acer Aspire 5020",
 686                .matches = {
 687                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 688                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5020"),
 689                },
 690                .driver_data = keymap_acer_aspire_5020
 691        },
 692        {
 693                .callback = dmi_matched,
 694                .ident = "Acer TravelMate 2100",
 695                .matches = {
 696                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 697                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2100"),
 698                },
 699                .driver_data = keymap_acer_aspire_5020
 700        },
 701        {
 702                .callback = dmi_matched,
 703                .ident = "Acer TravelMate 2410",
 704                .matches = {
 705                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 706                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2410"),
 707                },
 708                .driver_data = keymap_acer_travelmate_2410
 709        },
 710        {
 711                .callback = dmi_matched,
 712                .ident = "Acer TravelMate C300",
 713                .matches = {
 714                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 715                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C300"),
 716                },
 717                .driver_data = keymap_acer_travelmate_300
 718        },
 719        {
 720                .callback = dmi_matched,
 721                .ident = "Acer TravelMate C100",
 722                .matches = {
 723                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 724                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C100"),
 725                },
 726                .driver_data = keymap_acer_travelmate_300
 727        },
 728        {
 729                .callback = dmi_matched,
 730                .ident = "Acer TravelMate C110",
 731                .matches = {
 732                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 733                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C110"),
 734                },
 735                .driver_data = keymap_acer_travelmate_110
 736        },
 737        {
 738                .callback = dmi_matched,
 739                .ident = "Acer TravelMate 380",
 740                .matches = {
 741                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 742                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 380"),
 743                },
 744                .driver_data = keymap_acer_travelmate_380
 745        },
 746        {
 747                .callback = dmi_matched,
 748                .ident = "Acer TravelMate 370",
 749                .matches = {
 750                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 751                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 370"),
 752                },
 753                .driver_data = keymap_acer_travelmate_380 /* keyboard minus 1 key */
 754        },
 755        {
 756                .callback = dmi_matched,
 757                .ident = "Acer TravelMate 220",
 758                .matches = {
 759                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 760                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 220"),
 761                },
 762                .driver_data = keymap_acer_travelmate_220
 763        },
 764        {
 765                .callback = dmi_matched,
 766                .ident = "Acer TravelMate 260",
 767                .matches = {
 768                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 769                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 260"),
 770                },
 771                .driver_data = keymap_acer_travelmate_220
 772        },
 773        {
 774                .callback = dmi_matched,
 775                .ident = "Acer TravelMate 230",
 776                .matches = {
 777                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 778                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 230"),
 779                        /* acerhk looks for "TravelMate F4..." ?! */
 780                },
 781                .driver_data = keymap_acer_travelmate_230
 782        },
 783        {
 784                .callback = dmi_matched,
 785                .ident = "Acer TravelMate 280",
 786                .matches = {
 787                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 788                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 280"),
 789                },
 790                .driver_data = keymap_acer_travelmate_230
 791        },
 792        {
 793                .callback = dmi_matched,
 794                .ident = "Acer TravelMate 240",
 795                .matches = {
 796                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 797                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 240"),
 798                },
 799                .driver_data = keymap_acer_travelmate_240
 800        },
 801        {
 802                .callback = dmi_matched,
 803                .ident = "Acer TravelMate 250",
 804                .matches = {
 805                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 806                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 250"),
 807                },
 808                .driver_data = keymap_acer_travelmate_240
 809        },
 810        {
 811                .callback = dmi_matched,
 812                .ident = "Acer TravelMate 2424NWXCi",
 813                .matches = {
 814                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 815                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2420"),
 816                },
 817                .driver_data = keymap_acer_travelmate_240
 818        },
 819        {
 820                .callback = dmi_matched,
 821                .ident = "Acer TravelMate 350",
 822                .matches = {
 823                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 824                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 350"),
 825                },
 826                .driver_data = keymap_acer_travelmate_350
 827        },
 828        {
 829                .callback = dmi_matched,
 830                .ident = "Acer TravelMate 360",
 831                .matches = {
 832                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 833                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
 834                },
 835                .driver_data = keymap_acer_travelmate_360
 836        },
 837        {
 838                .callback = dmi_matched,
 839                .ident = "Acer TravelMate 610",
 840                .matches = {
 841                        DMI_MATCH(DMI_SYS_VENDOR, "ACER"),
 842                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 610"),
 843                },
 844                .driver_data = keymap_acer_travelmate_610
 845        },
 846        {
 847                .callback = dmi_matched,
 848                .ident = "Acer TravelMate 620",
 849                .matches = {
 850                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 851                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 620"),
 852                },
 853                .driver_data = keymap_acer_travelmate_630
 854        },
 855        {
 856                .callback = dmi_matched,
 857                .ident = "Acer TravelMate 630",
 858                .matches = {
 859                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 860                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 630"),
 861                },
 862                .driver_data = keymap_acer_travelmate_630
 863        },
 864        {
 865                .callback = dmi_matched,
 866                .ident = "AOpen 1559AS",
 867                .matches = {
 868                        DMI_MATCH(DMI_PRODUCT_NAME, "E2U"),
 869                        DMI_MATCH(DMI_BOARD_NAME, "E2U"),
 870                },
 871                .driver_data = keymap_aopen_1559as
 872        },
 873        {
 874                .callback = dmi_matched,
 875                .ident = "Medion MD 9783",
 876                .matches = {
 877                        DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
 878                        DMI_MATCH(DMI_PRODUCT_NAME, "MD 9783"),
 879                },
 880                .driver_data = keymap_wistron_ms2111
 881        },
 882        {
 883                .callback = dmi_matched,
 884                .ident = "Medion MD 40100",
 885                .matches = {
 886                        DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
 887                        DMI_MATCH(DMI_PRODUCT_NAME, "WID2000"),
 888                },
 889                .driver_data = keymap_wistron_md40100
 890        },
 891        {
 892                .callback = dmi_matched,
 893                .ident = "Medion MD 2900",
 894                .matches = {
 895                        DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
 896                        DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2000"),
 897                },
 898                .driver_data = keymap_wistron_md2900
 899        },
 900        {
 901                .callback = dmi_matched,
 902                .ident = "Medion MD 96500",
 903                .matches = {
 904                        DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"),
 905                        DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2040"),
 906                },
 907                .driver_data = keymap_wistron_md96500
 908        },
 909        {
 910                .callback = dmi_matched,
 911                .ident = "Medion MD 95400",
 912                .matches = {
 913                        DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"),
 914                        DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2050"),
 915                },
 916                .driver_data = keymap_wistron_md96500
 917        },
 918        {
 919                .callback = dmi_matched,
 920                .ident = "Fujitsu Siemens Amilo D7820",
 921                .matches = {
 922                        DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), /* not sure */
 923                        DMI_MATCH(DMI_PRODUCT_NAME, "Amilo D"),
 924                },
 925                .driver_data = keymap_fs_amilo_d88x0
 926        },
 927        {
 928                .callback = dmi_matched,
 929                .ident = "Fujitsu Siemens Amilo D88x0",
 930                .matches = {
 931                        DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
 932                        DMI_MATCH(DMI_PRODUCT_NAME, "AMILO D"),
 933                },
 934                .driver_data = keymap_fs_amilo_d88x0
 935        },
 936        { NULL, }
 937};
 938
 939/* Copy the good keymap, as the original ones are free'd */
 940static int __init copy_keymap(void)
 941{
 942        const struct key_entry *key;
 943        struct key_entry *new_keymap;
 944        unsigned int length = 1;
 945
 946        for (key = keymap; key->type != KE_END; key++)
 947                length++;
 948
 949        new_keymap = kmalloc(length * sizeof(struct key_entry), GFP_KERNEL);
 950        if (!new_keymap)
 951                return -ENOMEM;
 952
 953        memcpy(new_keymap, keymap, length * sizeof(struct key_entry));
 954        keymap = new_keymap;
 955
 956        return 0;
 957}
 958
 959static int __init select_keymap(void)
 960{
 961        dmi_check_system(dmi_ids);
 962        if (keymap_name != NULL) {
 963                if (strcmp (keymap_name, "1557/MS2141") == 0)
 964                        keymap = keymap_wistron_ms2141;
 965                else if (strcmp (keymap_name, "generic") == 0)
 966                        keymap = keymap_wistron_generic;
 967                else {
 968                        printk(KERN_ERR "wistron_btns: Keymap unknown\n");
 969                        return -EINVAL;
 970                }
 971        }
 972        if (keymap == NULL) {
 973                if (!force) {
 974                        printk(KERN_ERR "wistron_btns: System unknown\n");
 975                        return -ENODEV;
 976                }
 977                keymap = keymap_empty;
 978        }
 979
 980        return copy_keymap();
 981}
 982
 983 /* Input layer interface */
 984
 985static struct input_polled_dev *wistron_idev;
 986static unsigned long jiffies_last_press;
 987static int wifi_enabled;
 988static int bluetooth_enabled;
 989
 990static void report_key(struct input_dev *dev, unsigned int keycode)
 991{
 992        input_report_key(dev, keycode, 1);
 993        input_sync(dev);
 994        input_report_key(dev, keycode, 0);
 995        input_sync(dev);
 996}
 997
 998static void report_switch(struct input_dev *dev, unsigned int code, int value)
 999{
1000        input_report_switch(dev, code, value);
1001        input_sync(dev);
1002}
1003
1004
1005 /* led management */
1006static void wistron_mail_led_set(struct led_classdev *led_cdev,
1007                                enum led_brightness value)
1008{
1009        bios_set_state(MAIL_LED, (value != LED_OFF) ? 1 : 0);
1010}
1011
1012/* same as setting up wifi card, but for laptops on which the led is managed */
1013static void wistron_wifi_led_set(struct led_classdev *led_cdev,
1014                                enum led_brightness value)
1015{
1016        bios_set_state(WIFI, (value != LED_OFF) ? 1 : 0);
1017}
1018
1019static struct led_classdev wistron_mail_led = {
1020        .name                   = "wistron:green:mail",
1021        .brightness_set         = wistron_mail_led_set,
1022};
1023
1024static struct led_classdev wistron_wifi_led = {
1025        .name                   = "wistron:red:wifi",
1026        .brightness_set         = wistron_wifi_led_set,
1027};
1028
1029static void __devinit wistron_led_init(struct device *parent)
1030{
1031        if (have_leds & FE_WIFI_LED) {
1032                u16 wifi = bios_get_default_setting(WIFI);
1033                if (wifi & 1) {
1034                        wistron_wifi_led.brightness = (wifi & 2) ? LED_FULL : LED_OFF;
1035                        if (led_classdev_register(parent, &wistron_wifi_led))
1036                                have_leds &= ~FE_WIFI_LED;
1037                        else
1038                                bios_set_state(WIFI, wistron_wifi_led.brightness);
1039
1040                } else
1041                        have_leds &= ~FE_WIFI_LED;
1042        }
1043
1044        if (have_leds & FE_MAIL_LED) {
1045                /* bios_get_default_setting(MAIL) always retuns 0, so just turn the led off */
1046                wistron_mail_led.brightness = LED_OFF;
1047                if (led_classdev_register(parent, &wistron_mail_led))
1048                        have_leds &= ~FE_MAIL_LED;
1049                else
1050                        bios_set_state(MAIL_LED, wistron_mail_led.brightness);
1051        }
1052}
1053
1054static void __devexit wistron_led_remove(void)
1055{
1056        if (have_leds & FE_MAIL_LED)
1057                led_classdev_unregister(&wistron_mail_led);
1058
1059        if (have_leds & FE_WIFI_LED)
1060                led_classdev_unregister(&wistron_wifi_led);
1061}
1062
1063static inline void wistron_led_suspend(void)
1064{
1065        if (have_leds & FE_MAIL_LED)
1066                led_classdev_suspend(&wistron_mail_led);
1067
1068        if (have_leds & FE_WIFI_LED)
1069                led_classdev_suspend(&wistron_wifi_led);
1070}
1071
1072static inline void wistron_led_resume(void)
1073{
1074        if (have_leds & FE_MAIL_LED)
1075                led_classdev_resume(&wistron_mail_led);
1076
1077        if (have_leds & FE_WIFI_LED)
1078                led_classdev_resume(&wistron_wifi_led);
1079}
1080
1081static struct key_entry *wistron_get_entry_by_scancode(int code)
1082{
1083        struct key_entry *key;
1084
1085        for (key = keymap; key->type != KE_END; key++)
1086                if (code == key->code)
1087                        return key;
1088
1089        return NULL;
1090}
1091
1092static struct key_entry *wistron_get_entry_by_keycode(int keycode)
1093{
1094        struct key_entry *key;
1095
1096        for (key = keymap; key->type != KE_END; key++)
1097                if (key->type == KE_KEY && keycode == key->keycode)
1098                        return key;
1099
1100        return NULL;
1101}
1102
1103static void handle_key(u8 code)
1104{
1105        const struct key_entry *key = wistron_get_entry_by_scancode(code);
1106
1107        if (key) {
1108                switch (key->type) {
1109                case KE_KEY:
1110                        report_key(wistron_idev->input, key->keycode);
1111                        break;
1112
1113                case KE_SW:
1114                        report_switch(wistron_idev->input,
1115                                      key->sw.code, key->sw.value);
1116                        break;
1117
1118                case KE_WIFI:
1119                        if (have_wifi) {
1120                                wifi_enabled = !wifi_enabled;
1121                                bios_set_state(WIFI, wifi_enabled);
1122                        }
1123                        break;
1124
1125                case KE_BLUETOOTH:
1126                        if (have_bluetooth) {
1127                                bluetooth_enabled = !bluetooth_enabled;
1128                                bios_set_state(BLUETOOTH, bluetooth_enabled);
1129                        }
1130                        break;
1131
1132                default:
1133                        BUG();
1134                }
1135                jiffies_last_press = jiffies;
1136        } else
1137                printk(KERN_NOTICE
1138                        "wistron_btns: Unknown key code %02X\n", code);
1139}
1140
1141static void poll_bios(bool discard)
1142{
1143        u8 qlen;
1144        u16 val;
1145
1146        for (;;) {
1147                qlen = CMOS_READ(cmos_address);
1148                if (qlen == 0)
1149                        break;
1150                val = bios_pop_queue();
1151                if (val != 0 && !discard)
1152                        handle_key((u8)val);
1153        }
1154}
1155
1156static void wistron_flush(struct input_polled_dev *dev)
1157{
1158        /* Flush stale event queue */
1159        poll_bios(true);
1160}
1161
1162static void wistron_poll(struct input_polled_dev *dev)
1163{
1164        poll_bios(false);
1165
1166        /* Increase poll frequency if user is currently pressing keys (< 2s ago) */
1167        if (time_before(jiffies, jiffies_last_press + 2 * HZ))
1168                dev->poll_interval = POLL_INTERVAL_BURST;
1169        else
1170                dev->poll_interval = POLL_INTERVAL_DEFAULT;
1171}
1172
1173static int wistron_getkeycode(struct input_dev *dev, int scancode, int *keycode)
1174{
1175        const struct key_entry *key = wistron_get_entry_by_scancode(scancode);
1176
1177        if (key && key->type == KE_KEY) {
1178                *keycode = key->keycode;
1179                return 0;
1180        }
1181
1182        return -EINVAL;
1183}
1184
1185static int wistron_setkeycode(struct input_dev *dev, int scancode, int keycode)
1186{
1187        struct key_entry *key;
1188        int old_keycode;
1189
1190        if (keycode < 0 || keycode > KEY_MAX)
1191                return -EINVAL;
1192
1193        key = wistron_get_entry_by_scancode(scancode);
1194        if (key && key->type == KE_KEY) {
1195                old_keycode = key->keycode;
1196                key->keycode = keycode;
1197                set_bit(keycode, dev->keybit);
1198                if (!wistron_get_entry_by_keycode(old_keycode))
1199                        clear_bit(old_keycode, dev->keybit);
1200                return 0;
1201        }
1202
1203        return -EINVAL;
1204}
1205
1206static int __devinit setup_input_dev(void)
1207{
1208        struct key_entry *key;
1209        struct input_dev *input_dev;
1210        int error;
1211
1212        wistron_idev = input_allocate_polled_device();
1213        if (!wistron_idev)
1214                return -ENOMEM;
1215
1216        wistron_idev->flush = wistron_flush;
1217        wistron_idev->poll = wistron_poll;
1218        wistron_idev->poll_interval = POLL_INTERVAL_DEFAULT;
1219
1220        input_dev = wistron_idev->input;
1221        input_dev->name = "Wistron laptop buttons";
1222        input_dev->phys = "wistron/input0";
1223        input_dev->id.bustype = BUS_HOST;
1224        input_dev->dev.parent = &wistron_device->dev;
1225
1226        input_dev->getkeycode = wistron_getkeycode;
1227        input_dev->setkeycode = wistron_setkeycode;
1228
1229        for (key = keymap; key->type != KE_END; key++) {
1230                switch (key->type) {
1231                        case KE_KEY:
1232                                set_bit(EV_KEY, input_dev->evbit);
1233                                set_bit(key->keycode, input_dev->keybit);
1234                                break;
1235
1236                        case KE_SW:
1237                                set_bit(EV_SW, input_dev->evbit);
1238                                set_bit(key->sw.code, input_dev->swbit);
1239                                break;
1240
1241                        /* if wifi or bluetooth are not available, create normal keys */
1242                        case KE_WIFI:
1243                                if (!have_wifi) {
1244                                        key->type = KE_KEY;
1245                                        key->keycode = KEY_WLAN;
1246                                        key--;
1247                                }
1248                                break;
1249
1250                        case KE_BLUETOOTH:
1251                                if (!have_bluetooth) {
1252                                        key->type = KE_KEY;
1253                                        key->keycode = KEY_BLUETOOTH;
1254                                        key--;
1255                                }
1256                                break;
1257
1258                        default:
1259                                break;
1260                }
1261        }
1262
1263        /* reads information flags on KE_END */
1264        if (key->code & FE_UNTESTED)
1265                printk(KERN_WARNING "Untested laptop multimedia keys, "
1266                        "please report success or failure to eric.piel"
1267                        "@tremplin-utc.net\n");
1268
1269        error = input_register_polled_device(wistron_idev);
1270        if (error) {
1271                input_free_polled_device(wistron_idev);
1272                return error;
1273        }
1274
1275        return 0;
1276}
1277
1278/* Driver core */
1279
1280static int __devinit wistron_probe(struct platform_device *dev)
1281{
1282        int err;
1283
1284        bios_attach();
1285        cmos_address = bios_get_cmos_address();
1286
1287        if (have_wifi) {
1288                u16 wifi = bios_get_default_setting(WIFI);
1289                if (wifi & 1)
1290                        wifi_enabled = (wifi & 2) ? 1 : 0;
1291                else
1292                        have_wifi = 0;
1293
1294                if (have_wifi)
1295                        bios_set_state(WIFI, wifi_enabled);
1296        }
1297
1298        if (have_bluetooth) {
1299                u16 bt = bios_get_default_setting(BLUETOOTH);
1300                if (bt & 1)
1301                        bluetooth_enabled = (bt & 2) ? 1 : 0;
1302                else
1303                        have_bluetooth = 0;
1304
1305                if (have_bluetooth)
1306                        bios_set_state(BLUETOOTH, bluetooth_enabled);
1307        }
1308
1309        wistron_led_init(&dev->dev);
1310        err = setup_input_dev();
1311        if (err) {
1312                bios_detach();
1313                return err;
1314        }
1315
1316        return 0;
1317}
1318
1319static int __devexit wistron_remove(struct platform_device *dev)
1320{
1321        wistron_led_remove();
1322        input_unregister_polled_device(wistron_idev);
1323        input_free_polled_device(wistron_idev);
1324        bios_detach();
1325
1326        return 0;
1327}
1328
1329#ifdef CONFIG_PM
1330static int wistron_suspend(struct platform_device *dev, pm_message_t state)
1331{
1332        if (have_wifi)
1333                bios_set_state(WIFI, 0);
1334
1335        if (have_bluetooth)
1336                bios_set_state(BLUETOOTH, 0);
1337
1338        wistron_led_suspend();
1339        return 0;
1340}
1341
1342static int wistron_resume(struct platform_device *dev)
1343{
1344        if (have_wifi)
1345                bios_set_state(WIFI, wifi_enabled);
1346
1347        if (have_bluetooth)
1348                bios_set_state(BLUETOOTH, bluetooth_enabled);
1349
1350        wistron_led_resume();
1351        poll_bios(true);
1352
1353        return 0;
1354}
1355#else
1356#define wistron_suspend         NULL
1357#define wistron_resume          NULL
1358#endif
1359
1360static struct platform_driver wistron_driver = {
1361        .driver         = {
1362                .name   = "wistron-bios",
1363                .owner  = THIS_MODULE,
1364        },
1365        .probe          = wistron_probe,
1366        .remove         = __devexit_p(wistron_remove),
1367        .suspend        = wistron_suspend,
1368        .resume         = wistron_resume,
1369};
1370
1371static int __init wb_module_init(void)
1372{
1373        int err;
1374
1375        err = select_keymap();
1376        if (err)
1377                return err;
1378
1379        err = map_bios();
1380        if (err)
1381                return err;
1382
1383        err = platform_driver_register(&wistron_driver);
1384        if (err)
1385                goto err_unmap_bios;
1386
1387        wistron_device = platform_device_alloc("wistron-bios", -1);
1388        if (!wistron_device) {
1389                err = -ENOMEM;
1390                goto err_unregister_driver;
1391        }
1392
1393        err = platform_device_add(wistron_device);
1394        if (err)
1395                goto err_free_device;
1396
1397        return 0;
1398
1399 err_free_device:
1400        platform_device_put(wistron_device);
1401 err_unregister_driver:
1402        platform_driver_unregister(&wistron_driver);
1403 err_unmap_bios:
1404        unmap_bios();
1405
1406        return err;
1407}
1408
1409static void __exit wb_module_exit(void)
1410{
1411        platform_device_unregister(wistron_device);
1412        platform_driver_unregister(&wistron_driver);
1413        unmap_bios();
1414        kfree(keymap);
1415}
1416
1417module_init(wb_module_init);
1418module_exit(wb_module_exit);
1419
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.