acer-wmi.c revision b3c9092b2fed427d45117d23ceb577ad8dc46a9a
1/* 2 * Acer WMI Laptop Extras 3 * 4 * Copyright (C) 2007-2009 Carlos Corbacho <carlos@strangeworlds.co.uk> 5 * 6 * Based on acer_acpi: 7 * Copyright (C) 2005-2007 E.M. Smith 8 * Copyright (C) 2007-2008 Carlos Corbacho <cathectic@gmail.com> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23 */ 24 25#include <linux/kernel.h> 26#include <linux/module.h> 27#include <linux/init.h> 28#include <linux/types.h> 29#include <linux/dmi.h> 30#include <linux/fb.h> 31#include <linux/backlight.h> 32#include <linux/leds.h> 33#include <linux/platform_device.h> 34#include <linux/acpi.h> 35#include <linux/i8042.h> 36#include <linux/rfkill.h> 37#include <linux/workqueue.h> 38#include <linux/debugfs.h> 39#include <linux/slab.h> 40#include <linux/input.h> 41#include <linux/input/sparse-keymap.h> 42 43#include <acpi/acpi_drivers.h> 44 45MODULE_AUTHOR("Carlos Corbacho"); 46MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver"); 47MODULE_LICENSE("GPL"); 48 49#define ACER_LOGPREFIX "acer-wmi: " 50#define ACER_ERR KERN_ERR ACER_LOGPREFIX 51#define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX 52#define ACER_INFO KERN_INFO ACER_LOGPREFIX 53#define ACER_WARNING KERN_WARNING ACER_LOGPREFIX 54 55/* 56 * Magic Number 57 * Meaning is unknown - this number is required for writing to ACPI for AMW0 58 * (it's also used in acerhk when directly accessing the BIOS) 59 */ 60#define ACER_AMW0_WRITE 0x9610 61 62/* 63 * Bit masks for the AMW0 interface 64 */ 65#define ACER_AMW0_WIRELESS_MASK 0x35 66#define ACER_AMW0_BLUETOOTH_MASK 0x34 67#define ACER_AMW0_MAILLED_MASK 0x31 68 69/* 70 * Method IDs for WMID interface 71 */ 72#define ACER_WMID_GET_WIRELESS_METHODID 1 73#define ACER_WMID_GET_BLUETOOTH_METHODID 2 74#define ACER_WMID_GET_BRIGHTNESS_METHODID 3 75#define ACER_WMID_SET_WIRELESS_METHODID 4 76#define ACER_WMID_SET_BLUETOOTH_METHODID 5 77#define ACER_WMID_SET_BRIGHTNESS_METHODID 6 78#define ACER_WMID_GET_THREEG_METHODID 10 79#define ACER_WMID_SET_THREEG_METHODID 11 80 81/* 82 * Acer ACPI method GUIDs 83 */ 84#define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB" 85#define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C" 86#define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3" 87#define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A" 88#define WMID_GUID3 "61EF69EA-865C-4BC3-A502-A0DEBA0CB531" 89 90/* 91 * Acer ACPI event GUIDs 92 */ 93#define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026" 94 95MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB"); 96MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"); 97MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026"); 98 99enum acer_wmi_event_ids { 100 WMID_HOTKEY_EVENT = 0x1, 101}; 102 103static const struct key_entry acer_wmi_keymap[] = { 104 {KE_KEY, 0x01, {KEY_WLAN} }, /* WiFi */ 105 {KE_KEY, 0x12, {KEY_BLUETOOTH} }, /* BT */ 106 {KE_KEY, 0x21, {KEY_PROG1} }, /* Backup */ 107 {KE_KEY, 0x22, {KEY_PROG2} }, /* Arcade */ 108 {KE_KEY, 0x23, {KEY_PROG3} }, /* P_Key */ 109 {KE_KEY, 0x24, {KEY_PROG4} }, /* Social networking_Key */ 110 {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */ 111 {KE_KEY, 0x82, {KEY_F22} }, /* Touch Pad On/Off */ 112 {KE_END, 0} 113}; 114 115static struct input_dev *acer_wmi_input_dev; 116 117struct event_return_value { 118 u8 function; 119 u8 key_num; 120 u16 device_state; 121 u32 reserved; 122} __attribute__((packed)); 123 124/* 125 * GUID3 Get Device Status device flags 126 */ 127#define ACER_WMID3_GDS_THREEG (1<<6) /* 3G */ 128 129struct wmid3_gds_input_param { /* Get Device Status input parameter */ 130 u8 function_num; /* Function Number */ 131 u8 hotkey_number; /* Hotkey Number */ 132 u16 devices; /* Get Device */ 133} __attribute__((packed)); 134 135struct wmid3_gds_return_value { /* Get Device Status return value*/ 136 u8 error_code; /* Error Code */ 137 u8 ec_return_value; /* EC Return Value */ 138 u16 devices; /* Current Device Status */ 139 u32 reserved; 140} __attribute__((packed)); 141 142/* 143 * Interface capability flags 144 */ 145#define ACER_CAP_MAILLED (1<<0) 146#define ACER_CAP_WIRELESS (1<<1) 147#define ACER_CAP_BLUETOOTH (1<<2) 148#define ACER_CAP_BRIGHTNESS (1<<3) 149#define ACER_CAP_THREEG (1<<4) 150#define ACER_CAP_ANY (0xFFFFFFFF) 151 152/* 153 * Interface type flags 154 */ 155enum interface_flags { 156 ACER_AMW0, 157 ACER_AMW0_V2, 158 ACER_WMID, 159}; 160 161#define ACER_DEFAULT_WIRELESS 0 162#define ACER_DEFAULT_BLUETOOTH 0 163#define ACER_DEFAULT_MAILLED 0 164#define ACER_DEFAULT_THREEG 0 165 166static int max_brightness = 0xF; 167 168static int mailled = -1; 169static int brightness = -1; 170static int threeg = -1; 171static int force_series; 172 173module_param(mailled, int, 0444); 174module_param(brightness, int, 0444); 175module_param(threeg, int, 0444); 176module_param(force_series, int, 0444); 177MODULE_PARM_DESC(mailled, "Set initial state of Mail LED"); 178MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness"); 179MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware"); 180MODULE_PARM_DESC(force_series, "Force a different laptop series"); 181 182struct acer_data { 183 int mailled; 184 int threeg; 185 int brightness; 186}; 187 188struct acer_debug { 189 struct dentry *root; 190 struct dentry *devices; 191 u32 wmid_devices; 192}; 193 194static struct rfkill *wireless_rfkill; 195static struct rfkill *bluetooth_rfkill; 196static struct rfkill *threeg_rfkill; 197 198/* Each low-level interface must define at least some of the following */ 199struct wmi_interface { 200 /* The WMI device type */ 201 u32 type; 202 203 /* The capabilities this interface provides */ 204 u32 capability; 205 206 /* Private data for the current interface */ 207 struct acer_data data; 208 209 /* debugfs entries associated with this interface */ 210 struct acer_debug debug; 211}; 212 213/* The static interface pointer, points to the currently detected interface */ 214static struct wmi_interface *interface; 215 216/* 217 * Embedded Controller quirks 218 * Some laptops require us to directly access the EC to either enable or query 219 * features that are not available through WMI. 220 */ 221 222struct quirk_entry { 223 u8 wireless; 224 u8 mailled; 225 s8 brightness; 226 u8 bluetooth; 227}; 228 229static struct quirk_entry *quirks; 230 231static void set_quirks(void) 232{ 233 if (!interface) 234 return; 235 236 if (quirks->mailled) 237 interface->capability |= ACER_CAP_MAILLED; 238 239 if (quirks->brightness) 240 interface->capability |= ACER_CAP_BRIGHTNESS; 241} 242 243static int dmi_matched(const struct dmi_system_id *dmi) 244{ 245 quirks = dmi->driver_data; 246 return 1; 247} 248 249static struct quirk_entry quirk_unknown = { 250}; 251 252static struct quirk_entry quirk_acer_aspire_1520 = { 253 .brightness = -1, 254}; 255 256static struct quirk_entry quirk_acer_travelmate_2490 = { 257 .mailled = 1, 258}; 259 260/* This AMW0 laptop has no bluetooth */ 261static struct quirk_entry quirk_medion_md_98300 = { 262 .wireless = 1, 263}; 264 265static struct quirk_entry quirk_fujitsu_amilo_li_1718 = { 266 .wireless = 2, 267}; 268 269/* The Aspire One has a dummy ACPI-WMI interface - disable it */ 270static struct dmi_system_id __devinitdata acer_blacklist[] = { 271 { 272 .ident = "Acer Aspire One (SSD)", 273 .matches = { 274 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 275 DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"), 276 }, 277 }, 278 { 279 .ident = "Acer Aspire One (HDD)", 280 .matches = { 281 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 282 DMI_MATCH(DMI_PRODUCT_NAME, "AOA150"), 283 }, 284 }, 285 {} 286}; 287 288static struct dmi_system_id acer_quirks[] = { 289 { 290 .callback = dmi_matched, 291 .ident = "Acer Aspire 1360", 292 .matches = { 293 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 294 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"), 295 }, 296 .driver_data = &quirk_acer_aspire_1520, 297 }, 298 { 299 .callback = dmi_matched, 300 .ident = "Acer Aspire 1520", 301 .matches = { 302 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 303 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1520"), 304 }, 305 .driver_data = &quirk_acer_aspire_1520, 306 }, 307 { 308 .callback = dmi_matched, 309 .ident = "Acer Aspire 3100", 310 .matches = { 311 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 312 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"), 313 }, 314 .driver_data = &quirk_acer_travelmate_2490, 315 }, 316 { 317 .callback = dmi_matched, 318 .ident = "Acer Aspire 3610", 319 .matches = { 320 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 321 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3610"), 322 }, 323 .driver_data = &quirk_acer_travelmate_2490, 324 }, 325 { 326 .callback = dmi_matched, 327 .ident = "Acer Aspire 5100", 328 .matches = { 329 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 330 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"), 331 }, 332 .driver_data = &quirk_acer_travelmate_2490, 333 }, 334 { 335 .callback = dmi_matched, 336 .ident = "Acer Aspire 5610", 337 .matches = { 338 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 339 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"), 340 }, 341 .driver_data = &quirk_acer_travelmate_2490, 342 }, 343 { 344 .callback = dmi_matched, 345 .ident = "Acer Aspire 5630", 346 .matches = { 347 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 348 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"), 349 }, 350 .driver_data = &quirk_acer_travelmate_2490, 351 }, 352 { 353 .callback = dmi_matched, 354 .ident = "Acer Aspire 5650", 355 .matches = { 356 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 357 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"), 358 }, 359 .driver_data = &quirk_acer_travelmate_2490, 360 }, 361 { 362 .callback = dmi_matched, 363 .ident = "Acer Aspire 5680", 364 .matches = { 365 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 366 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"), 367 }, 368 .driver_data = &quirk_acer_travelmate_2490, 369 }, 370 { 371 .callback = dmi_matched, 372 .ident = "Acer Aspire 9110", 373 .matches = { 374 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 375 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"), 376 }, 377 .driver_data = &quirk_acer_travelmate_2490, 378 }, 379 { 380 .callback = dmi_matched, 381 .ident = "Acer TravelMate 2490", 382 .matches = { 383 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 384 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"), 385 }, 386 .driver_data = &quirk_acer_travelmate_2490, 387 }, 388 { 389 .callback = dmi_matched, 390 .ident = "Acer TravelMate 4200", 391 .matches = { 392 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 393 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4200"), 394 }, 395 .driver_data = &quirk_acer_travelmate_2490, 396 }, 397 { 398 .callback = dmi_matched, 399 .ident = "Fujitsu Siemens Amilo Li 1718", 400 .matches = { 401 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 402 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Li 1718"), 403 }, 404 .driver_data = &quirk_fujitsu_amilo_li_1718, 405 }, 406 { 407 .callback = dmi_matched, 408 .ident = "Medion MD 98300", 409 .matches = { 410 DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), 411 DMI_MATCH(DMI_PRODUCT_NAME, "WAM2030"), 412 }, 413 .driver_data = &quirk_medion_md_98300, 414 }, 415 {} 416}; 417 418/* Find which quirks are needed for a particular vendor/ model pair */ 419static void find_quirks(void) 420{ 421 if (!force_series) { 422 dmi_check_system(acer_quirks); 423 } else if (force_series == 2490) { 424 quirks = &quirk_acer_travelmate_2490; 425 } 426 427 if (quirks == NULL) 428 quirks = &quirk_unknown; 429 430 set_quirks(); 431} 432 433/* 434 * General interface convenience methods 435 */ 436 437static bool has_cap(u32 cap) 438{ 439 if ((interface->capability & cap) != 0) 440 return 1; 441 442 return 0; 443} 444 445/* 446 * AMW0 (V1) interface 447 */ 448struct wmab_args { 449 u32 eax; 450 u32 ebx; 451 u32 ecx; 452 u32 edx; 453}; 454 455struct wmab_ret { 456 u32 eax; 457 u32 ebx; 458 u32 ecx; 459 u32 edx; 460 u32 eex; 461}; 462 463static acpi_status wmab_execute(struct wmab_args *regbuf, 464struct acpi_buffer *result) 465{ 466 struct acpi_buffer input; 467 acpi_status status; 468 input.length = sizeof(struct wmab_args); 469 input.pointer = (u8 *)regbuf; 470 471 status = wmi_evaluate_method(AMW0_GUID1, 1, 1, &input, result); 472 473 return status; 474} 475 476static acpi_status AMW0_get_u32(u32 *value, u32 cap, 477struct wmi_interface *iface) 478{ 479 int err; 480 u8 result; 481 482 switch (cap) { 483 case ACER_CAP_MAILLED: 484 switch (quirks->mailled) { 485 default: 486 err = ec_read(0xA, &result); 487 if (err) 488 return AE_ERROR; 489 *value = (result >> 7) & 0x1; 490 return AE_OK; 491 } 492 break; 493 case ACER_CAP_WIRELESS: 494 switch (quirks->wireless) { 495 case 1: 496 err = ec_read(0x7B, &result); 497 if (err) 498 return AE_ERROR; 499 *value = result & 0x1; 500 return AE_OK; 501 case 2: 502 err = ec_read(0x71, &result); 503 if (err) 504 return AE_ERROR; 505 *value = result & 0x1; 506 return AE_OK; 507 default: 508 err = ec_read(0xA, &result); 509 if (err) 510 return AE_ERROR; 511 *value = (result >> 2) & 0x1; 512 return AE_OK; 513 } 514 break; 515 case ACER_CAP_BLUETOOTH: 516 switch (quirks->bluetooth) { 517 default: 518 err = ec_read(0xA, &result); 519 if (err) 520 return AE_ERROR; 521 *value = (result >> 4) & 0x1; 522 return AE_OK; 523 } 524 break; 525 case ACER_CAP_BRIGHTNESS: 526 switch (quirks->brightness) { 527 default: 528 err = ec_read(0x83, &result); 529 if (err) 530 return AE_ERROR; 531 *value = result; 532 return AE_OK; 533 } 534 break; 535 default: 536 return AE_ERROR; 537 } 538 return AE_OK; 539} 540 541static acpi_status AMW0_set_u32(u32 value, u32 cap, struct wmi_interface *iface) 542{ 543 struct wmab_args args; 544 545 args.eax = ACER_AMW0_WRITE; 546 args.ebx = value ? (1<<8) : 0; 547 args.ecx = args.edx = 0; 548 549 switch (cap) { 550 case ACER_CAP_MAILLED: 551 if (value > 1) 552 return AE_BAD_PARAMETER; 553 args.ebx |= ACER_AMW0_MAILLED_MASK; 554 break; 555 case ACER_CAP_WIRELESS: 556 if (value > 1) 557 return AE_BAD_PARAMETER; 558 args.ebx |= ACER_AMW0_WIRELESS_MASK; 559 break; 560 case ACER_CAP_BLUETOOTH: 561 if (value > 1) 562 return AE_BAD_PARAMETER; 563 args.ebx |= ACER_AMW0_BLUETOOTH_MASK; 564 break; 565 case ACER_CAP_BRIGHTNESS: 566 if (value > max_brightness) 567 return AE_BAD_PARAMETER; 568 switch (quirks->brightness) { 569 default: 570 return ec_write(0x83, value); 571 break; 572 } 573 default: 574 return AE_ERROR; 575 } 576 577 /* Actually do the set */ 578 return wmab_execute(&args, NULL); 579} 580 581static acpi_status AMW0_find_mailled(void) 582{ 583 struct wmab_args args; 584 struct wmab_ret ret; 585 acpi_status status = AE_OK; 586 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; 587 union acpi_object *obj; 588 589 args.eax = 0x86; 590 args.ebx = args.ecx = args.edx = 0; 591 592 status = wmab_execute(&args, &out); 593 if (ACPI_FAILURE(status)) 594 return status; 595 596 obj = (union acpi_object *) out.pointer; 597 if (obj && obj->type == ACPI_TYPE_BUFFER && 598 obj->buffer.length == sizeof(struct wmab_ret)) { 599 ret = *((struct wmab_ret *) obj->buffer.pointer); 600 } else { 601 kfree(out.pointer); 602 return AE_ERROR; 603 } 604 605 if (ret.eex & 0x1) 606 interface->capability |= ACER_CAP_MAILLED; 607 608 kfree(out.pointer); 609 610 return AE_OK; 611} 612 613static acpi_status AMW0_set_capabilities(void) 614{ 615 struct wmab_args args; 616 struct wmab_ret ret; 617 acpi_status status; 618 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; 619 union acpi_object *obj; 620 621 /* 622 * On laptops with this strange GUID (non Acer), normal probing doesn't 623 * work. 624 */ 625 if (wmi_has_guid(AMW0_GUID2)) { 626 interface->capability |= ACER_CAP_WIRELESS; 627 return AE_OK; 628 } 629 630 args.eax = ACER_AMW0_WRITE; 631 args.ecx = args.edx = 0; 632 633 args.ebx = 0xa2 << 8; 634 args.ebx |= ACER_AMW0_WIRELESS_MASK; 635 636 status = wmab_execute(&args, &out); 637 if (ACPI_FAILURE(status)) 638 return status; 639 640 obj = out.pointer; 641 if (obj && obj->type == ACPI_TYPE_BUFFER && 642 obj->buffer.length == sizeof(struct wmab_ret)) { 643 ret = *((struct wmab_ret *) obj->buffer.pointer); 644 } else { 645 status = AE_ERROR; 646 goto out; 647 } 648 649 if (ret.eax & 0x1) 650 interface->capability |= ACER_CAP_WIRELESS; 651 652 args.ebx = 2 << 8; 653 args.ebx |= ACER_AMW0_BLUETOOTH_MASK; 654 655 /* 656 * It's ok to use existing buffer for next wmab_execute call. 657 * But we need to kfree(out.pointer) if next wmab_execute fail. 658 */ 659 status = wmab_execute(&args, &out); 660 if (ACPI_FAILURE(status)) 661 goto out; 662 663 obj = (union acpi_object *) out.pointer; 664 if (obj && obj->type == ACPI_TYPE_BUFFER 665 && obj->buffer.length == sizeof(struct wmab_ret)) { 666 ret = *((struct wmab_ret *) obj->buffer.pointer); 667 } else { 668 status = AE_ERROR; 669 goto out; 670 } 671 672 if (ret.eax & 0x1) 673 interface->capability |= ACER_CAP_BLUETOOTH; 674 675 /* 676 * This appears to be safe to enable, since all Wistron based laptops 677 * appear to use the same EC register for brightness, even if they 678 * differ for wireless, etc 679 */ 680 if (quirks->brightness >= 0) 681 interface->capability |= ACER_CAP_BRIGHTNESS; 682 683 status = AE_OK; 684out: 685 kfree(out.pointer); 686 return status; 687} 688 689static struct wmi_interface AMW0_interface = { 690 .type = ACER_AMW0, 691}; 692 693static struct wmi_interface AMW0_V2_interface = { 694 .type = ACER_AMW0_V2, 695}; 696 697/* 698 * New interface (The WMID interface) 699 */ 700static acpi_status 701WMI_execute_u32(u32 method_id, u32 in, u32 *out) 702{ 703 struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) }; 704 struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL }; 705 union acpi_object *obj; 706 u32 tmp; 707 acpi_status status; 708 709 status = wmi_evaluate_method(WMID_GUID1, 1, method_id, &input, &result); 710 711 if (ACPI_FAILURE(status)) 712 return status; 713 714 obj = (union acpi_object *) result.pointer; 715 if (obj && obj->type == ACPI_TYPE_BUFFER && 716 obj->buffer.length == sizeof(u32)) { 717 tmp = *((u32 *) obj->buffer.pointer); 718 } else { 719 tmp = 0; 720 } 721 722 if (out) 723 *out = tmp; 724 725 kfree(result.pointer); 726 727 return status; 728} 729 730static acpi_status WMID_get_u32(u32 *value, u32 cap, 731struct wmi_interface *iface) 732{ 733 acpi_status status; 734 u8 tmp; 735 u32 result, method_id = 0; 736 737 switch (cap) { 738 case ACER_CAP_WIRELESS: 739 method_id = ACER_WMID_GET_WIRELESS_METHODID; 740 break; 741 case ACER_CAP_BLUETOOTH: 742 method_id = ACER_WMID_GET_BLUETOOTH_METHODID; 743 break; 744 case ACER_CAP_BRIGHTNESS: 745 method_id = ACER_WMID_GET_BRIGHTNESS_METHODID; 746 break; 747 case ACER_CAP_THREEG: 748 method_id = ACER_WMID_GET_THREEG_METHODID; 749 break; 750 case ACER_CAP_MAILLED: 751 if (quirks->mailled == 1) { 752 ec_read(0x9f, &tmp); 753 *value = tmp & 0x1; 754 return 0; 755 } 756 default: 757 return AE_ERROR; 758 } 759 status = WMI_execute_u32(method_id, 0, &result); 760 761 if (ACPI_SUCCESS(status)) 762 *value = (u8)result; 763 764 return status; 765} 766 767static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface) 768{ 769 u32 method_id = 0; 770 char param; 771 772 switch (cap) { 773 case ACER_CAP_BRIGHTNESS: 774 if (value > max_brightness) 775 return AE_BAD_PARAMETER; 776 method_id = ACER_WMID_SET_BRIGHTNESS_METHODID; 777 break; 778 case ACER_CAP_WIRELESS: 779 if (value > 1) 780 return AE_BAD_PARAMETER; 781 method_id = ACER_WMID_SET_WIRELESS_METHODID; 782 break; 783 case ACER_CAP_BLUETOOTH: 784 if (value > 1) 785 return AE_BAD_PARAMETER; 786 method_id = ACER_WMID_SET_BLUETOOTH_METHODID; 787 break; 788 case ACER_CAP_THREEG: 789 if (value > 1) 790 return AE_BAD_PARAMETER; 791 method_id = ACER_WMID_SET_THREEG_METHODID; 792 break; 793 case ACER_CAP_MAILLED: 794 if (value > 1) 795 return AE_BAD_PARAMETER; 796 if (quirks->mailled == 1) { 797 param = value ? 0x92 : 0x93; 798 i8042_lock_chip(); 799 i8042_command(¶m, 0x1059); 800 i8042_unlock_chip(); 801 return 0; 802 } 803 break; 804 default: 805 return AE_ERROR; 806 } 807 return WMI_execute_u32(method_id, (u32)value, NULL); 808} 809 810static acpi_status WMID_set_capabilities(void) 811{ 812 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; 813 union acpi_object *obj; 814 acpi_status status; 815 u32 devices; 816 817 status = wmi_query_block(WMID_GUID2, 1, &out); 818 if (ACPI_FAILURE(status)) 819 return status; 820 821 obj = (union acpi_object *) out.pointer; 822 if (obj && obj->type == ACPI_TYPE_BUFFER && 823 obj->buffer.length == sizeof(u32)) { 824 devices = *((u32 *) obj->buffer.pointer); 825 } else { 826 kfree(out.pointer); 827 return AE_ERROR; 828 } 829 830 /* Not sure on the meaning of the relevant bits yet to detect these */ 831 interface->capability |= ACER_CAP_WIRELESS; 832 interface->capability |= ACER_CAP_THREEG; 833 834 /* WMID always provides brightness methods */ 835 interface->capability |= ACER_CAP_BRIGHTNESS; 836 837 if (devices & 0x10) 838 interface->capability |= ACER_CAP_BLUETOOTH; 839 840 if (!(devices & 0x20)) 841 max_brightness = 0x9; 842 843 kfree(out.pointer); 844 return status; 845} 846 847static struct wmi_interface wmid_interface = { 848 .type = ACER_WMID, 849}; 850 851/* 852 * Generic Device (interface-independent) 853 */ 854 855static acpi_status get_u32(u32 *value, u32 cap) 856{ 857 acpi_status status = AE_ERROR; 858 859 switch (interface->type) { 860 case ACER_AMW0: 861 status = AMW0_get_u32(value, cap, interface); 862 break; 863 case ACER_AMW0_V2: 864 if (cap == ACER_CAP_MAILLED) { 865 status = AMW0_get_u32(value, cap, interface); 866 break; 867 } 868 case ACER_WMID: 869 status = WMID_get_u32(value, cap, interface); 870 break; 871 } 872 873 return status; 874} 875 876static acpi_status set_u32(u32 value, u32 cap) 877{ 878 acpi_status status; 879 880 if (interface->capability & cap) { 881 switch (interface->type) { 882 case ACER_AMW0: 883 return AMW0_set_u32(value, cap, interface); 884 case ACER_AMW0_V2: 885 if (cap == ACER_CAP_MAILLED) 886 return AMW0_set_u32(value, cap, interface); 887 888 /* 889 * On some models, some WMID methods don't toggle 890 * properly. For those cases, we want to run the AMW0 891 * method afterwards to be certain we've really toggled 892 * the device state. 893 */ 894 if (cap == ACER_CAP_WIRELESS || 895 cap == ACER_CAP_BLUETOOTH) { 896 status = WMID_set_u32(value, cap, interface); 897 if (ACPI_FAILURE(status)) 898 return status; 899 900 return AMW0_set_u32(value, cap, interface); 901 } 902 case ACER_WMID: 903 return WMID_set_u32(value, cap, interface); 904 default: 905 return AE_BAD_PARAMETER; 906 } 907 } 908 return AE_BAD_PARAMETER; 909} 910 911static void __init acer_commandline_init(void) 912{ 913 /* 914 * These will all fail silently if the value given is invalid, or the 915 * capability isn't available on the given interface 916 */ 917 set_u32(mailled, ACER_CAP_MAILLED); 918 set_u32(threeg, ACER_CAP_THREEG); 919 set_u32(brightness, ACER_CAP_BRIGHTNESS); 920} 921 922/* 923 * LED device (Mail LED only, no other LEDs known yet) 924 */ 925static void mail_led_set(struct led_classdev *led_cdev, 926enum led_brightness value) 927{ 928 set_u32(value, ACER_CAP_MAILLED); 929} 930 931static struct led_classdev mail_led = { 932 .name = "acer-wmi::mail", 933 .brightness_set = mail_led_set, 934}; 935 936static int __devinit acer_led_init(struct device *dev) 937{ 938 return led_classdev_register(dev, &mail_led); 939} 940 941static void acer_led_exit(void) 942{ 943 led_classdev_unregister(&mail_led); 944} 945 946/* 947 * Backlight device 948 */ 949static struct backlight_device *acer_backlight_device; 950 951static int read_brightness(struct backlight_device *bd) 952{ 953 u32 value; 954 get_u32(&value, ACER_CAP_BRIGHTNESS); 955 return value; 956} 957 958static int update_bl_status(struct backlight_device *bd) 959{ 960 int intensity = bd->props.brightness; 961 962 if (bd->props.power != FB_BLANK_UNBLANK) 963 intensity = 0; 964 if (bd->props.fb_blank != FB_BLANK_UNBLANK) 965 intensity = 0; 966 967 set_u32(intensity, ACER_CAP_BRIGHTNESS); 968 969 return 0; 970} 971 972static struct backlight_ops acer_bl_ops = { 973 .get_brightness = read_brightness, 974 .update_status = update_bl_status, 975}; 976 977static int __devinit acer_backlight_init(struct device *dev) 978{ 979 struct backlight_properties props; 980 struct backlight_device *bd; 981 982 memset(&props, 0, sizeof(struct backlight_properties)); 983 props.max_brightness = max_brightness; 984 bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops, 985 &props); 986 if (IS_ERR(bd)) { 987 printk(ACER_ERR "Could not register Acer backlight device\n"); 988 acer_backlight_device = NULL; 989 return PTR_ERR(bd); 990 } 991 992 acer_backlight_device = bd; 993 994 bd->props.power = FB_BLANK_UNBLANK; 995 bd->props.brightness = read_brightness(bd); 996 backlight_update_status(bd); 997 return 0; 998} 999 1000static void acer_backlight_exit(void) 1001{ 1002 backlight_device_unregister(acer_backlight_device); 1003} 1004 1005static acpi_status wmid3_get_device_status(u32 *value, u16 device) 1006{ 1007 struct wmid3_gds_return_value return_value; 1008 acpi_status status; 1009 union acpi_object *obj; 1010 struct wmid3_gds_input_param params = { 1011 .function_num = 0x1, 1012 .hotkey_number = 0x01, 1013 .devices = device, 1014 }; 1015 struct acpi_buffer input = { 1016 sizeof(struct wmid3_gds_input_param), 1017 ¶ms 1018 }; 1019 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 1020 1021 status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output); 1022 if (ACPI_FAILURE(status)) 1023 return status; 1024 1025 obj = output.pointer; 1026 1027 if (!obj) 1028 return AE_ERROR; 1029 else if (obj->type != ACPI_TYPE_BUFFER) { 1030 kfree(obj); 1031 return AE_ERROR; 1032 } 1033 if (obj->buffer.length != 8) { 1034 printk(ACER_WARNING "Unknown buffer length %d\n", 1035 obj->buffer.length); 1036 kfree(obj); 1037 return AE_ERROR; 1038 } 1039 1040 return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer); 1041 kfree(obj); 1042 1043 if (return_value.error_code || return_value.ec_return_value) 1044 printk(ACER_WARNING "Get Device Status failed: " 1045 "0x%x - 0x%x\n", return_value.error_code, 1046 return_value.ec_return_value); 1047 else 1048 *value = !!(return_value.devices & device); 1049 1050 return status; 1051} 1052 1053/* 1054 * Rfkill devices 1055 */ 1056static void acer_rfkill_update(struct work_struct *ignored); 1057static DECLARE_DELAYED_WORK(acer_rfkill_work, acer_rfkill_update); 1058static void acer_rfkill_update(struct work_struct *ignored) 1059{ 1060 u32 state; 1061 acpi_status status; 1062 1063 status = get_u32(&state, ACER_CAP_WIRELESS); 1064 if (ACPI_SUCCESS(status)) 1065 rfkill_set_sw_state(wireless_rfkill, !state); 1066 1067 if (has_cap(ACER_CAP_BLUETOOTH)) { 1068 status = get_u32(&state, ACER_CAP_BLUETOOTH); 1069 if (ACPI_SUCCESS(status)) 1070 rfkill_set_sw_state(bluetooth_rfkill, !state); 1071 } 1072 1073 if (has_cap(ACER_CAP_THREEG) && wmi_has_guid(WMID_GUID3)) { 1074 status = wmid3_get_device_status(&state, 1075 ACER_WMID3_GDS_THREEG); 1076 if (ACPI_SUCCESS(status)) 1077 rfkill_set_sw_state(threeg_rfkill, !state); 1078 } 1079 1080 schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); 1081} 1082 1083static int acer_rfkill_set(void *data, bool blocked) 1084{ 1085 acpi_status status; 1086 u32 cap = (unsigned long)data; 1087 status = set_u32(!blocked, cap); 1088 if (ACPI_FAILURE(status)) 1089 return -ENODEV; 1090 return 0; 1091} 1092 1093static const struct rfkill_ops acer_rfkill_ops = { 1094 .set_block = acer_rfkill_set, 1095}; 1096 1097static struct rfkill *acer_rfkill_register(struct device *dev, 1098 enum rfkill_type type, 1099 char *name, u32 cap) 1100{ 1101 int err; 1102 struct rfkill *rfkill_dev; 1103 1104 rfkill_dev = rfkill_alloc(name, dev, type, 1105 &acer_rfkill_ops, 1106 (void *)(unsigned long)cap); 1107 if (!rfkill_dev) 1108 return ERR_PTR(-ENOMEM); 1109 1110 err = rfkill_register(rfkill_dev); 1111 if (err) { 1112 rfkill_destroy(rfkill_dev); 1113 return ERR_PTR(err); 1114 } 1115 return rfkill_dev; 1116} 1117 1118static int acer_rfkill_init(struct device *dev) 1119{ 1120 wireless_rfkill = acer_rfkill_register(dev, RFKILL_TYPE_WLAN, 1121 "acer-wireless", ACER_CAP_WIRELESS); 1122 if (IS_ERR(wireless_rfkill)) 1123 return PTR_ERR(wireless_rfkill); 1124 1125 if (has_cap(ACER_CAP_BLUETOOTH)) { 1126 bluetooth_rfkill = acer_rfkill_register(dev, 1127 RFKILL_TYPE_BLUETOOTH, "acer-bluetooth", 1128 ACER_CAP_BLUETOOTH); 1129 if (IS_ERR(bluetooth_rfkill)) { 1130 rfkill_unregister(wireless_rfkill); 1131 rfkill_destroy(wireless_rfkill); 1132 return PTR_ERR(bluetooth_rfkill); 1133 } 1134 } 1135 1136 if (has_cap(ACER_CAP_THREEG)) { 1137 threeg_rfkill = acer_rfkill_register(dev, 1138 RFKILL_TYPE_WWAN, "acer-threeg", 1139 ACER_CAP_THREEG); 1140 if (IS_ERR(threeg_rfkill)) { 1141 rfkill_unregister(wireless_rfkill); 1142 rfkill_destroy(wireless_rfkill); 1143 rfkill_unregister(bluetooth_rfkill); 1144 rfkill_destroy(bluetooth_rfkill); 1145 return PTR_ERR(threeg_rfkill); 1146 } 1147 } 1148 1149 schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); 1150 1151 return 0; 1152} 1153 1154static void acer_rfkill_exit(void) 1155{ 1156 cancel_delayed_work_sync(&acer_rfkill_work); 1157 1158 rfkill_unregister(wireless_rfkill); 1159 rfkill_destroy(wireless_rfkill); 1160 1161 if (has_cap(ACER_CAP_BLUETOOTH)) { 1162 rfkill_unregister(bluetooth_rfkill); 1163 rfkill_destroy(bluetooth_rfkill); 1164 } 1165 1166 if (has_cap(ACER_CAP_THREEG)) { 1167 rfkill_unregister(threeg_rfkill); 1168 rfkill_destroy(threeg_rfkill); 1169 } 1170 return; 1171} 1172 1173/* 1174 * sysfs interface 1175 */ 1176static ssize_t show_bool_threeg(struct device *dev, 1177 struct device_attribute *attr, char *buf) 1178{ 1179 u32 result; \ 1180 acpi_status status; 1181 if (wmi_has_guid(WMID_GUID3)) 1182 status = wmid3_get_device_status(&result, 1183 ACER_WMID3_GDS_THREEG); 1184 else 1185 status = get_u32(&result, ACER_CAP_THREEG); 1186 if (ACPI_SUCCESS(status)) 1187 return sprintf(buf, "%u\n", result); 1188 return sprintf(buf, "Read error\n"); 1189} 1190 1191static ssize_t set_bool_threeg(struct device *dev, 1192 struct device_attribute *attr, const char *buf, size_t count) 1193{ 1194 u32 tmp = simple_strtoul(buf, NULL, 10); 1195 acpi_status status = set_u32(tmp, ACER_CAP_THREEG); 1196 if (ACPI_FAILURE(status)) 1197 return -EINVAL; 1198 return count; 1199} 1200static DEVICE_ATTR(threeg, S_IWUGO | S_IRUGO | S_IWUSR, show_bool_threeg, 1201 set_bool_threeg); 1202 1203static ssize_t show_interface(struct device *dev, struct device_attribute *attr, 1204 char *buf) 1205{ 1206 switch (interface->type) { 1207 case ACER_AMW0: 1208 return sprintf(buf, "AMW0\n"); 1209 case ACER_AMW0_V2: 1210 return sprintf(buf, "AMW0 v2\n"); 1211 case ACER_WMID: 1212 return sprintf(buf, "WMID\n"); 1213 default: 1214 return sprintf(buf, "Error!\n"); 1215 } 1216} 1217 1218static DEVICE_ATTR(interface, S_IRUGO, show_interface, NULL); 1219 1220static void acer_wmi_notify(u32 value, void *context) 1221{ 1222 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 1223 union acpi_object *obj; 1224 struct event_return_value return_value; 1225 acpi_status status; 1226 1227 status = wmi_get_event_data(value, &response); 1228 if (status != AE_OK) { 1229 printk(ACER_WARNING "bad event status 0x%x\n", status); 1230 return; 1231 } 1232 1233 obj = (union acpi_object *)response.pointer; 1234 1235 if (!obj) 1236 return; 1237 if (obj->type != ACPI_TYPE_BUFFER) { 1238 printk(ACER_WARNING "Unknown response received %d\n", 1239 obj->type); 1240 kfree(obj); 1241 return; 1242 } 1243 if (obj->buffer.length != 8) { 1244 printk(ACER_WARNING "Unknown buffer length %d\n", 1245 obj->buffer.length); 1246 kfree(obj); 1247 return; 1248 } 1249 1250 return_value = *((struct event_return_value *)obj->buffer.pointer); 1251 kfree(obj); 1252 1253 switch (return_value.function) { 1254 case WMID_HOTKEY_EVENT: 1255 if (!sparse_keymap_report_event(acer_wmi_input_dev, 1256 return_value.key_num, 1, true)) 1257 printk(ACER_WARNING "Unknown key number - 0x%x\n", 1258 return_value.key_num); 1259 break; 1260 default: 1261 printk(ACER_WARNING "Unknown function number - %d - %d\n", 1262 return_value.function, return_value.key_num); 1263 break; 1264 } 1265} 1266 1267static int __init acer_wmi_input_setup(void) 1268{ 1269 acpi_status status; 1270 int err; 1271 1272 acer_wmi_input_dev = input_allocate_device(); 1273 if (!acer_wmi_input_dev) 1274 return -ENOMEM; 1275 1276 acer_wmi_input_dev->name = "Acer WMI hotkeys"; 1277 acer_wmi_input_dev->phys = "wmi/input0"; 1278 acer_wmi_input_dev->id.bustype = BUS_HOST; 1279 1280 err = sparse_keymap_setup(acer_wmi_input_dev, acer_wmi_keymap, NULL); 1281 if (err) 1282 goto err_free_dev; 1283 1284 status = wmi_install_notify_handler(ACERWMID_EVENT_GUID, 1285 acer_wmi_notify, NULL); 1286 if (ACPI_FAILURE(status)) { 1287 err = -EIO; 1288 goto err_free_keymap; 1289 } 1290 1291 err = input_register_device(acer_wmi_input_dev); 1292 if (err) 1293 goto err_uninstall_notifier; 1294 1295 return 0; 1296 1297err_uninstall_notifier: 1298 wmi_remove_notify_handler(ACERWMID_EVENT_GUID); 1299err_free_keymap: 1300 sparse_keymap_free(acer_wmi_input_dev); 1301err_free_dev: 1302 input_free_device(acer_wmi_input_dev); 1303 return err; 1304} 1305 1306static void acer_wmi_input_destroy(void) 1307{ 1308 wmi_remove_notify_handler(ACERWMID_EVENT_GUID); 1309 sparse_keymap_free(acer_wmi_input_dev); 1310 input_unregister_device(acer_wmi_input_dev); 1311} 1312 1313/* 1314 * debugfs functions 1315 */ 1316static u32 get_wmid_devices(void) 1317{ 1318 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; 1319 union acpi_object *obj; 1320 acpi_status status; 1321 u32 devices = 0; 1322 1323 status = wmi_query_block(WMID_GUID2, 1, &out); 1324 if (ACPI_FAILURE(status)) 1325 return 0; 1326 1327 obj = (union acpi_object *) out.pointer; 1328 if (obj && obj->type == ACPI_TYPE_BUFFER && 1329 obj->buffer.length == sizeof(u32)) { 1330 devices = *((u32 *) obj->buffer.pointer); 1331 } 1332 1333 kfree(out.pointer); 1334 return devices; 1335} 1336 1337/* 1338 * Platform device 1339 */ 1340static int __devinit acer_platform_probe(struct platform_device *device) 1341{ 1342 int err; 1343 1344 if (has_cap(ACER_CAP_MAILLED)) { 1345 err = acer_led_init(&device->dev); 1346 if (err) 1347 goto error_mailled; 1348 } 1349 1350 if (has_cap(ACER_CAP_BRIGHTNESS)) { 1351 err = acer_backlight_init(&device->dev); 1352 if (err) 1353 goto error_brightness; 1354 } 1355 1356 err = acer_rfkill_init(&device->dev); 1357 if (err) 1358 goto error_rfkill; 1359 1360 return err; 1361 1362error_rfkill: 1363 if (has_cap(ACER_CAP_BRIGHTNESS)) 1364 acer_backlight_exit(); 1365error_brightness: 1366 if (has_cap(ACER_CAP_MAILLED)) 1367 acer_led_exit(); 1368error_mailled: 1369 return err; 1370} 1371 1372static int acer_platform_remove(struct platform_device *device) 1373{ 1374 if (has_cap(ACER_CAP_MAILLED)) 1375 acer_led_exit(); 1376 if (has_cap(ACER_CAP_BRIGHTNESS)) 1377 acer_backlight_exit(); 1378 1379 acer_rfkill_exit(); 1380 return 0; 1381} 1382 1383static int acer_platform_suspend(struct platform_device *dev, 1384pm_message_t state) 1385{ 1386 u32 value; 1387 struct acer_data *data = &interface->data; 1388 1389 if (!data) 1390 return -ENOMEM; 1391 1392 if (has_cap(ACER_CAP_MAILLED)) { 1393 get_u32(&value, ACER_CAP_MAILLED); 1394 data->mailled = value; 1395 } 1396 1397 if (has_cap(ACER_CAP_BRIGHTNESS)) { 1398 get_u32(&value, ACER_CAP_BRIGHTNESS); 1399 data->brightness = value; 1400 } 1401 1402 return 0; 1403} 1404 1405static int acer_platform_resume(struct platform_device *device) 1406{ 1407 struct acer_data *data = &interface->data; 1408 1409 if (!data) 1410 return -ENOMEM; 1411 1412 if (has_cap(ACER_CAP_MAILLED)) 1413 set_u32(data->mailled, ACER_CAP_MAILLED); 1414 1415 if (has_cap(ACER_CAP_BRIGHTNESS)) 1416 set_u32(data->brightness, ACER_CAP_BRIGHTNESS); 1417 1418 return 0; 1419} 1420 1421static struct platform_driver acer_platform_driver = { 1422 .driver = { 1423 .name = "acer-wmi", 1424 .owner = THIS_MODULE, 1425 }, 1426 .probe = acer_platform_probe, 1427 .remove = acer_platform_remove, 1428 .suspend = acer_platform_suspend, 1429 .resume = acer_platform_resume, 1430}; 1431 1432static struct platform_device *acer_platform_device; 1433 1434static int remove_sysfs(struct platform_device *device) 1435{ 1436 if (has_cap(ACER_CAP_THREEG)) 1437 device_remove_file(&device->dev, &dev_attr_threeg); 1438 1439 device_remove_file(&device->dev, &dev_attr_interface); 1440 1441 return 0; 1442} 1443 1444static int create_sysfs(void) 1445{ 1446 int retval = -ENOMEM; 1447 1448 if (has_cap(ACER_CAP_THREEG)) { 1449 retval = device_create_file(&acer_platform_device->dev, 1450 &dev_attr_threeg); 1451 if (retval) 1452 goto error_sysfs; 1453 } 1454 1455 retval = device_create_file(&acer_platform_device->dev, 1456 &dev_attr_interface); 1457 if (retval) 1458 goto error_sysfs; 1459 1460 return 0; 1461 1462error_sysfs: 1463 remove_sysfs(acer_platform_device); 1464 return retval; 1465} 1466 1467static void remove_debugfs(void) 1468{ 1469 debugfs_remove(interface->debug.devices); 1470 debugfs_remove(interface->debug.root); 1471} 1472 1473static int create_debugfs(void) 1474{ 1475 interface->debug.root = debugfs_create_dir("acer-wmi", NULL); 1476 if (!interface->debug.root) { 1477 printk(ACER_ERR "Failed to create debugfs directory"); 1478 return -ENOMEM; 1479 } 1480 1481 interface->debug.devices = debugfs_create_u32("devices", S_IRUGO, 1482 interface->debug.root, 1483 &interface->debug.wmid_devices); 1484 if (!interface->debug.devices) 1485 goto error_debugfs; 1486 1487 return 0; 1488 1489error_debugfs: 1490 remove_debugfs(); 1491 return -ENOMEM; 1492} 1493 1494static int __init acer_wmi_init(void) 1495{ 1496 int err; 1497 1498 printk(ACER_INFO "Acer Laptop ACPI-WMI Extras\n"); 1499 1500 if (dmi_check_system(acer_blacklist)) { 1501 printk(ACER_INFO "Blacklisted hardware detected - " 1502 "not loading\n"); 1503 return -ENODEV; 1504 } 1505 1506 find_quirks(); 1507 1508 /* 1509 * Detect which ACPI-WMI interface we're using. 1510 */ 1511 if (wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1)) 1512 interface = &AMW0_V2_interface; 1513 1514 if (!wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1)) 1515 interface = &wmid_interface; 1516 1517 if (wmi_has_guid(WMID_GUID2) && interface) { 1518 if (ACPI_FAILURE(WMID_set_capabilities())) { 1519 printk(ACER_ERR "Unable to detect available WMID " 1520 "devices\n"); 1521 return -ENODEV; 1522 } 1523 } else if (!wmi_has_guid(WMID_GUID2) && interface) { 1524 printk(ACER_ERR "No WMID device detection method found\n"); 1525 return -ENODEV; 1526 } 1527 1528 if (wmi_has_guid(AMW0_GUID1) && !wmi_has_guid(WMID_GUID1)) { 1529 interface = &AMW0_interface; 1530 1531 if (ACPI_FAILURE(AMW0_set_capabilities())) { 1532 printk(ACER_ERR "Unable to detect available AMW0 " 1533 "devices\n"); 1534 return -ENODEV; 1535 } 1536 } 1537 1538 if (wmi_has_guid(AMW0_GUID1)) 1539 AMW0_find_mailled(); 1540 1541 if (!interface) { 1542 printk(ACER_INFO "No or unsupported WMI interface, unable to " 1543 "load\n"); 1544 return -ENODEV; 1545 } 1546 1547 set_quirks(); 1548 1549 if (acpi_video_backlight_support() && has_cap(ACER_CAP_BRIGHTNESS)) { 1550 interface->capability &= ~ACER_CAP_BRIGHTNESS; 1551 printk(ACER_INFO "Brightness must be controlled by " 1552 "generic video driver\n"); 1553 } 1554 1555 if (wmi_has_guid(ACERWMID_EVENT_GUID)) { 1556 err = acer_wmi_input_setup(); 1557 if (err) 1558 return err; 1559 } 1560 1561 err = platform_driver_register(&acer_platform_driver); 1562 if (err) { 1563 printk(ACER_ERR "Unable to register platform driver.\n"); 1564 goto error_platform_register; 1565 } 1566 1567 acer_platform_device = platform_device_alloc("acer-wmi", -1); 1568 if (!acer_platform_device) { 1569 err = -ENOMEM; 1570 goto error_device_alloc; 1571 } 1572 1573 err = platform_device_add(acer_platform_device); 1574 if (err) 1575 goto error_device_add; 1576 1577 err = create_sysfs(); 1578 if (err) 1579 goto error_create_sys; 1580 1581 if (wmi_has_guid(WMID_GUID2)) { 1582 interface->debug.wmid_devices = get_wmid_devices(); 1583 err = create_debugfs(); 1584 if (err) 1585 goto error_create_debugfs; 1586 } 1587 1588 /* Override any initial settings with values from the commandline */ 1589 acer_commandline_init(); 1590 1591 return 0; 1592 1593error_create_debugfs: 1594 remove_sysfs(acer_platform_device); 1595error_create_sys: 1596 platform_device_del(acer_platform_device); 1597error_device_add: 1598 platform_device_put(acer_platform_device); 1599error_device_alloc: 1600 platform_driver_unregister(&acer_platform_driver); 1601error_platform_register: 1602 if (wmi_has_guid(ACERWMID_EVENT_GUID)) 1603 acer_wmi_input_destroy(); 1604 1605 return err; 1606} 1607 1608static void __exit acer_wmi_exit(void) 1609{ 1610 if (wmi_has_guid(ACERWMID_EVENT_GUID)) 1611 acer_wmi_input_destroy(); 1612 1613 remove_sysfs(acer_platform_device); 1614 remove_debugfs(); 1615 platform_device_unregister(acer_platform_device); 1616 platform_driver_unregister(&acer_platform_driver); 1617 1618 printk(ACER_INFO "Acer Laptop WMI Extras unloaded\n"); 1619 return; 1620} 1621 1622module_init(acer_wmi_init); 1623module_exit(acer_wmi_exit); 1624