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