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