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 41 #include <acpi/acpi_drivers.h> 42 43 MODULE_AUTHOR("Carlos Corbacho"); 44 MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver"); 45 MODULE_LICENSE("GPL"); 46 47 #define ACER_LOGPREFIX "acer-wmi: " 48 #define ACER_ERR KERN_ERR ACER_LOGPREFIX 49 #define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX 50 #define ACER_INFO KERN_INFO ACER_LOGPREFIX 51 52 /* 53 * The following defines quirks to get some specific functions to work 54 * which are known to not be supported over ACPI-WMI (such as the mail LED 55 * on WMID based Acer's) 56 */ 57 struct acer_quirks { 58 const char *vendor; 59 const char *model; 60 u16 quirks; 61 }; 62 63 /* 64 * Magic Number 65 * Meaning is unknown - this number is required for writing to ACPI for AMW0 66 * (it's also used in acerhk when directly accessing the BIOS) 67 */ 68 #define ACER_AMW0_WRITE 0x9610 69 70 /* 71 * Bit masks for the AMW0 interface 72 */ 73 #define ACER_AMW0_WIRELESS_MASK 0x35 74 #define ACER_AMW0_BLUETOOTH_MASK 0x34 75 #define ACER_AMW0_MAILLED_MASK 0x31 76 77 /* 78 * Method IDs for WMID interface 79 */ 80 #define ACER_WMID_GET_WIRELESS_METHODID 1 81 #define ACER_WMID_GET_BLUETOOTH_METHODID 2 82 #define ACER_WMID_GET_BRIGHTNESS_METHODID 3 83 #define ACER_WMID_SET_WIRELESS_METHODID 4 84 #define ACER_WMID_SET_BLUETOOTH_METHODID 5 85 #define ACER_WMID_SET_BRIGHTNESS_METHODID 6 86 #define ACER_WMID_GET_THREEG_METHODID 10 87 #define ACER_WMID_SET_THREEG_METHODID 11 88 89 /* 90 * Acer ACPI method GUIDs 91 */ 92 #define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB" 93 #define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C" 94 #define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3" 95 #define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A" 96 97 MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB"); 98 MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"); 99 100 /* 101 * Interface capability flags 102 */ 103 #define ACER_CAP_MAILLED (1<<0) 104 #define ACER_CAP_WIRELESS (1<<1) 105 #define ACER_CAP_BLUETOOTH (1<<2) 106 #define ACER_CAP_BRIGHTNESS (1<<3) 107 #define ACER_CAP_THREEG (1<<4) 108 #define ACER_CAP_ANY (0xFFFFFFFF) 109 110 /* 111 * Interface type flags 112 */ 113 enum interface_flags { 114 ACER_AMW0, 115 ACER_AMW0_V2, 116 ACER_WMID, 117 }; 118 119 #define ACER_DEFAULT_WIRELESS 0 120 #define ACER_DEFAULT_BLUETOOTH 0 121 #define ACER_DEFAULT_MAILLED 0 122 #define ACER_DEFAULT_THREEG 0 123 124 static int max_brightness = 0xF; 125 126 static int mailled = -1; 127 static int brightness = -1; 128 static int threeg = -1; 129 static int force_series; 130 131 module_param(mailled, int, 0444); 132 module_param(brightness, int, 0444); 133 module_param(threeg, int, 0444); 134 module_param(force_series, int, 0444); 135 MODULE_PARM_DESC(mailled, "Set initial state of Mail LED"); 136 MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness"); 137 MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware"); 138 MODULE_PARM_DESC(force_series, "Force a different laptop series"); 139 140 struct acer_data { 141 int mailled; 142 int threeg; 143 int brightness; 144 }; 145 146 struct acer_debug { 147 struct dentry *root; 148 struct dentry *devices; 149 u32 wmid_devices; 150 }; 151 152 static struct rfkill *wireless_rfkill; 153 static struct rfkill *bluetooth_rfkill; 154 155 /* Each low-level interface must define at least some of the following */ 156 struct wmi_interface { 157 /* The WMI device type */ 158 u32 type; 159 160 /* The capabilities this interface provides */ 161 u32 capability; 162 163 /* Private data for the current interface */ 164 struct acer_data data; 165 166 /* debugfs entries associated with this interface */ 167 struct acer_debug debug; 168 }; 169 170 /* The static interface pointer, points to the currently detected interface */ 171 static struct wmi_interface *interface; 172 173 /* 174 * Embedded Controller quirks 175 * Some laptops require us to directly access the EC to either enable or query 176 * features that are not available through WMI. 177 */ 178 179 struct quirk_entry { 180 u8 wireless; 181 u8 mailled; 182 s8 brightness; 183 u8 bluetooth; 184 }; 185 186 static struct quirk_entry *quirks; 187 188 static void set_quirks(void) 189 { 190 if (!interface) 191 return; 192 193 if (quirks->mailled) 194 interface->capability |= ACER_CAP_MAILLED; 195 196 if (quirks->brightness) 197 interface->capability |= ACER_CAP_BRIGHTNESS; 198 } 199 200 static int dmi_matched(const struct dmi_system_id *dmi) 201 { 202 quirks = dmi->driver_data; 203 return 0; 204 } 205 206 static struct quirk_entry quirk_unknown = { 207 }; 208 209 static struct quirk_entry quirk_acer_aspire_1520 = { 210 .brightness = -1, 211 }; 212 213 static struct quirk_entry quirk_acer_travelmate_2490 = { 214 .mailled = 1, 215 }; 216 217 /* This AMW0 laptop has no bluetooth */ 218 static struct quirk_entry quirk_medion_md_98300 = { 219 .wireless = 1, 220 }; 221 222 static struct quirk_entry quirk_fujitsu_amilo_li_1718 = { 223 .wireless = 2, 224 }; 225 226 /* The Aspire One has a dummy ACPI-WMI interface - disable it */ 227 static struct dmi_system_id __devinitdata acer_blacklist[] = { 228 { 229 .ident = "Acer Aspire One (SSD)", 230 .matches = { 231 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 232 DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"), 233 }, 234 }, 235 { 236 .ident = "Acer Aspire One (HDD)", 237 .matches = { 238 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 239 DMI_MATCH(DMI_PRODUCT_NAME, "AOA150"), 240 }, 241 }, 242 {} 243 }; 244 245 static struct dmi_system_id acer_quirks[] = { 246 { 247 .callback = dmi_matched, 248 .ident = "Acer Aspire 1360", 249 .matches = { 250 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 251 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"), 252 }, 253 .driver_data = &quirk_acer_aspire_1520, 254 }, 255 { 256 .callback = dmi_matched, 257 .ident = "Acer Aspire 1520", 258 .matches = { 259 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 260 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1520"), 261 }, 262 .driver_data = &quirk_acer_aspire_1520, 263 }, 264 { 265 .callback = dmi_matched, 266 .ident = "Acer Aspire 3100", 267 .matches = { 268 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 269 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"), 270 }, 271 .driver_data = &quirk_acer_travelmate_2490, 272 }, 273 { 274 .callback = dmi_matched, 275 .ident = "Acer Aspire 3610", 276 .matches = { 277 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 278 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3610"), 279 }, 280 .driver_data = &quirk_acer_travelmate_2490, 281 }, 282 { 283 .callback = dmi_matched, 284 .ident = "Acer Aspire 5100", 285 .matches = { 286 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 287 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"), 288 }, 289 .driver_data = &quirk_acer_travelmate_2490, 290 }, 291 { 292 .callback = dmi_matched, 293 .ident = "Acer Aspire 5610", 294 .matches = { 295 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 296 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"), 297 }, 298 .driver_data = &quirk_acer_travelmate_2490, 299 }, 300 { 301 .callback = dmi_matched, 302 .ident = "Acer Aspire 5630", 303 .matches = { 304 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 305 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"), 306 }, 307 .driver_data = &quirk_acer_travelmate_2490, 308 }, 309 { 310 .callback = dmi_matched, 311 .ident = "Acer Aspire 5650", 312 .matches = { 313 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 314 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"), 315 }, 316 .driver_data = &quirk_acer_travelmate_2490, 317 }, 318 { 319 .callback = dmi_matched, 320 .ident = "Acer Aspire 5680", 321 .matches = { 322 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 323 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"), 324 }, 325 .driver_data = &quirk_acer_travelmate_2490, 326 }, 327 { 328 .callback = dmi_matched, 329 .ident = "Acer Aspire 9110", 330 .matches = { 331 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 332 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"), 333 }, 334 .driver_data = &quirk_acer_travelmate_2490, 335 }, 336 { 337 .callback = dmi_matched, 338 .ident = "Acer TravelMate 2490", 339 .matches = { 340 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 341 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"), 342 }, 343 .driver_data = &quirk_acer_travelmate_2490, 344 }, 345 { 346 .callback = dmi_matched, 347 .ident = "Acer TravelMate 4200", 348 .matches = { 349 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 350 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4200"), 351 }, 352 .driver_data = &quirk_acer_travelmate_2490, 353 }, 354 { 355 .callback = dmi_matched, 356 .ident = "Fujitsu Siemens Amilo Li 1718", 357 .matches = { 358 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 359 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Li 1718"), 360 }, 361 .driver_data = &quirk_fujitsu_amilo_li_1718, 362 }, 363 { 364 .callback = dmi_matched, 365 .ident = "Medion MD 98300", 366 .matches = { 367 DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), 368 DMI_MATCH(DMI_PRODUCT_NAME, "WAM2030"), 369 }, 370 .driver_data = &quirk_medion_md_98300, 371 }, 372 {} 373 }; 374 375 /* Find which quirks are needed for a particular vendor/ model pair */ 376 static void find_quirks(void) 377 { 378 if (!force_series) { 379 dmi_check_system(acer_quirks); 380 } else if (force_series == 2490) { 381 quirks = &quirk_acer_travelmate_2490; 382 } 383 384 if (quirks == NULL) 385 quirks = &quirk_unknown; 386 387 set_quirks(); 388 } 389 390 /* 391 * General interface convenience methods 392 */ 393 394 static bool has_cap(u32 cap) 395 { 396 if ((interface->capability & cap) != 0) 397 return 1; 398 399 return 0; 400 } 401 402 /* 403 * AMW0 (V1) interface 404 */ 405 struct wmab_args { 406 u32 eax; 407 u32 ebx; 408 u32 ecx; 409 u32 edx; 410 }; 411 412 struct wmab_ret { 413 u32 eax; 414 u32 ebx; 415 u32 ecx; 416 u32 edx; 417 u32 eex; 418 }; 419 420 static acpi_status wmab_execute(struct wmab_args *regbuf, 421 struct acpi_buffer *result) 422 { 423 struct acpi_buffer input; 424 acpi_status status; 425 input.length = sizeof(struct wmab_args); 426 input.pointer = (u8 *)regbuf; 427 428 status = wmi_evaluate_method(AMW0_GUID1, 1, 1, &input, result); 429 430 return status; 431 } 432 433 static acpi_status AMW0_get_u32(u32 *value, u32 cap, 434 struct wmi_interface *iface) 435 { 436 int err; 437 u8 result; 438 439 switch (cap) { 440 case ACER_CAP_MAILLED: 441 switch (quirks->mailled) { 442 default: 443 err = ec_read(0xA, &result); 444 if (err) 445 return AE_ERROR; 446 *value = (result >> 7) & 0x1; 447 return AE_OK; 448 } 449 break; 450 case ACER_CAP_WIRELESS: 451 switch (quirks->wireless) { 452 case 1: 453 err = ec_read(0x7B, &result); 454 if (err) 455 return AE_ERROR; 456 *value = result & 0x1; 457 return AE_OK; 458 case 2: 459 err = ec_read(0x71, &result); 460 if (err) 461 return AE_ERROR; 462 *value = result & 0x1; 463 return AE_OK; 464 default: 465 err = ec_read(0xA, &result); 466 if (err) 467 return AE_ERROR; 468 *value = (result >> 2) & 0x1; 469 return AE_OK; 470 } 471 break; 472 case ACER_CAP_BLUETOOTH: 473 switch (quirks->bluetooth) { 474 default: 475 err = ec_read(0xA, &result); 476 if (err) 477 return AE_ERROR; 478 *value = (result >> 4) & 0x1; 479 return AE_OK; 480 } 481 break; 482 case ACER_CAP_BRIGHTNESS: 483 switch (quirks->brightness) { 484 default: 485 err = ec_read(0x83, &result); 486 if (err) 487 return AE_ERROR; 488 *value = result; 489 return AE_OK; 490 } 491 break; 492 default: 493 return AE_ERROR; 494 } 495 return AE_OK; 496 } 497 498 static acpi_status AMW0_set_u32(u32 value, u32 cap, struct wmi_interface *iface) 499 { 500 struct wmab_args args; 501 502 args.eax = ACER_AMW0_WRITE; 503 args.ebx = value ? (1<<8) : 0; 504 args.ecx = args.edx = 0; 505 506 switch (cap) { 507 case ACER_CAP_MAILLED: 508 if (value > 1) 509 return AE_BAD_PARAMETER; 510 args.ebx |= ACER_AMW0_MAILLED_MASK; 511 break; 512 case ACER_CAP_WIRELESS: 513 if (value > 1) 514 return AE_BAD_PARAMETER; 515 args.ebx |= ACER_AMW0_WIRELESS_MASK; 516 break; 517 case ACER_CAP_BLUETOOTH: 518 if (value > 1) 519 return AE_BAD_PARAMETER; 520 args.ebx |= ACER_AMW0_BLUETOOTH_MASK; 521 break; 522 case ACER_CAP_BRIGHTNESS: 523 if (value > max_brightness) 524 return AE_BAD_PARAMETER; 525 switch (quirks->brightness) { 526 default: 527 return ec_write(0x83, value); 528 break; 529 } 530 default: 531 return AE_ERROR; 532 } 533 534 /* Actually do the set */ 535 return wmab_execute(&args, NULL); 536 } 537 538 static acpi_status AMW0_find_mailled(void) 539 { 540 struct wmab_args args; 541 struct wmab_ret ret; 542 acpi_status status = AE_OK; 543 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; 544 union acpi_object *obj; 545 546 args.eax = 0x86; 547 args.ebx = args.ecx = args.edx = 0; 548 549 status = wmab_execute(&args, &out); 550 if (ACPI_FAILURE(status)) 551 return status; 552 553 obj = (union acpi_object *) out.pointer; 554 if (obj && obj->type == ACPI_TYPE_BUFFER && 555 obj->buffer.length == sizeof(struct wmab_ret)) { 556 ret = *((struct wmab_ret *) obj->buffer.pointer); 557 } else { 558 return AE_ERROR; 559 } 560 561 if (ret.eex & 0x1) 562 interface->capability |= ACER_CAP_MAILLED; 563 564 kfree(out.pointer); 565 566 return AE_OK; 567 } 568 569 static acpi_status AMW0_set_capabilities(void) 570 { 571 struct wmab_args args; 572 struct wmab_ret ret; 573 acpi_status status = AE_OK; 574 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; 575 union acpi_object *obj; 576 577 /* 578 * On laptops with this strange GUID (non Acer), normal probing doesn't 579 * work. 580 */ 581 if (wmi_has_guid(AMW0_GUID2)) { 582 interface->capability |= ACER_CAP_WIRELESS; 583 return AE_OK; 584 } 585 586 args.eax = ACER_AMW0_WRITE; 587 args.ecx = args.edx = 0; 588 589 args.ebx = 0xa2 << 8; 590 args.ebx |= ACER_AMW0_WIRELESS_MASK; 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 return AE_ERROR; 602 } 603 604 if (ret.eax & 0x1) 605 interface->capability |= ACER_CAP_WIRELESS; 606 607 args.ebx = 2 << 8; 608 args.ebx |= ACER_AMW0_BLUETOOTH_MASK; 609 610 status = wmab_execute(&args, &out); 611 if (ACPI_FAILURE(status)) 612 return status; 613 614 obj = (union acpi_object *) out.pointer; 615 if (obj && obj->type == ACPI_TYPE_BUFFER 616 && obj->buffer.length == sizeof(struct wmab_ret)) { 617 ret = *((struct wmab_ret *) obj->buffer.pointer); 618 } else { 619 return AE_ERROR; 620 } 621 622 if (ret.eax & 0x1) 623 interface->capability |= ACER_CAP_BLUETOOTH; 624 625 kfree(out.pointer); 626 627 /* 628 * This appears to be safe to enable, since all Wistron based laptops 629 * appear to use the same EC register for brightness, even if they 630 * differ for wireless, etc 631 */ 632 if (quirks->brightness >= 0) 633 interface->capability |= ACER_CAP_BRIGHTNESS; 634 635 return AE_OK; 636 } 637 638 static struct wmi_interface AMW0_interface = { 639 .type = ACER_AMW0, 640 }; 641 642 static struct wmi_interface AMW0_V2_interface = { 643 .type = ACER_AMW0_V2, 644 }; 645 646 /* 647 * New interface (The WMID interface) 648 */ 649 static acpi_status 650 WMI_execute_u32(u32 method_id, u32 in, u32 *out) 651 { 652 struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) }; 653 struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL }; 654 union acpi_object *obj; 655 u32 tmp; 656 acpi_status status; 657 658 status = wmi_evaluate_method(WMID_GUID1, 1, method_id, &input, &result); 659 660 if (ACPI_FAILURE(status)) 661 return status; 662 663 obj = (union acpi_object *) result.pointer; 664 if (obj && obj->type == ACPI_TYPE_BUFFER && 665 obj->buffer.length == sizeof(u32)) { 666 tmp = *((u32 *) obj->buffer.pointer); 667 } else { 668 tmp = 0; 669 } 670 671 if (out) 672 *out = tmp; 673 674 kfree(result.pointer); 675 676 return status; 677 } 678 679 static acpi_status WMID_get_u32(u32 *value, u32 cap, 680 struct wmi_interface *iface) 681 { 682 acpi_status status; 683 u8 tmp; 684 u32 result, method_id = 0; 685 686 switch (cap) { 687 case ACER_CAP_WIRELESS: 688 method_id = ACER_WMID_GET_WIRELESS_METHODID; 689 break; 690 case ACER_CAP_BLUETOOTH: 691 method_id = ACER_WMID_GET_BLUETOOTH_METHODID; 692 break; 693 case ACER_CAP_BRIGHTNESS: 694 method_id = ACER_WMID_GET_BRIGHTNESS_METHODID; 695 break; 696 case ACER_CAP_THREEG: 697 method_id = ACER_WMID_GET_THREEG_METHODID; 698 break; 699 case ACER_CAP_MAILLED: 700 if (quirks->mailled == 1) { 701 ec_read(0x9f, &tmp); 702 *value = tmp & 0x1; 703 return 0; 704 } 705 default: 706 return AE_ERROR; 707 } 708 status = WMI_execute_u32(method_id, 0, &result); 709 710 if (ACPI_SUCCESS(status)) 711 *value = (u8)result; 712 713 return status; 714 } 715 716 static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface) 717 { 718 u32 method_id = 0; 719 char param; 720 721 switch (cap) { 722 case ACER_CAP_BRIGHTNESS: 723 if (value > max_brightness) 724 return AE_BAD_PARAMETER; 725 method_id = ACER_WMID_SET_BRIGHTNESS_METHODID; 726 break; 727 case ACER_CAP_WIRELESS: 728 if (value > 1) 729 return AE_BAD_PARAMETER; 730 method_id = ACER_WMID_SET_WIRELESS_METHODID; 731 break; 732 case ACER_CAP_BLUETOOTH: 733 if (value > 1) 734 return AE_BAD_PARAMETER; 735 method_id = ACER_WMID_SET_BLUETOOTH_METHODID; 736 break; 737 case ACER_CAP_THREEG: 738 if (value > 1) 739 return AE_BAD_PARAMETER; 740 method_id = ACER_WMID_SET_THREEG_METHODID; 741 break; 742 case ACER_CAP_MAILLED: 743 if (value > 1) 744 return AE_BAD_PARAMETER; 745 if (quirks->mailled == 1) { 746 param = value ? 0x92 : 0x93; 747 i8042_lock_chip(); 748 i8042_command(¶m, 0x1059); 749 i8042_unlock_chip(); 750 return 0; 751 } 752 break; 753 default: 754 return AE_ERROR; 755 } 756 return WMI_execute_u32(method_id, (u32)value, NULL); 757 } 758 759 static acpi_status WMID_set_capabilities(void) 760 { 761 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; 762 union acpi_object *obj; 763 acpi_status status; 764 u32 devices; 765 766 status = wmi_query_block(WMID_GUID2, 1, &out); 767 if (ACPI_FAILURE(status)) 768 return status; 769 770 obj = (union acpi_object *) out.pointer; 771 if (obj && obj->type == ACPI_TYPE_BUFFER && 772 obj->buffer.length == sizeof(u32)) { 773 devices = *((u32 *) obj->buffer.pointer); 774 } else { 775 return AE_ERROR; 776 } 777 778 /* Not sure on the meaning of the relevant bits yet to detect these */ 779 interface->capability |= ACER_CAP_WIRELESS; 780 interface->capability |= ACER_CAP_THREEG; 781 782 /* WMID always provides brightness methods */ 783 interface->capability |= ACER_CAP_BRIGHTNESS; 784 785 if (devices & 0x10) 786 interface->capability |= ACER_CAP_BLUETOOTH; 787 788 if (!(devices & 0x20)) 789 max_brightness = 0x9; 790 791 return status; 792 } 793 794 static struct wmi_interface wmid_interface = { 795 .type = ACER_WMID, 796 }; 797 798 /* 799 * Generic Device (interface-independent) 800 */ 801 802 static acpi_status get_u32(u32 *value, u32 cap) 803 { 804 acpi_status status = AE_ERROR; 805 806 switch (interface->type) { 807 case ACER_AMW0: 808 status = AMW0_get_u32(value, cap, interface); 809 break; 810 case ACER_AMW0_V2: 811 if (cap == ACER_CAP_MAILLED) { 812 status = AMW0_get_u32(value, cap, interface); 813 break; 814 } 815 case ACER_WMID: 816 status = WMID_get_u32(value, cap, interface); 817 break; 818 } 819 820 return status; 821 } 822 823 static acpi_status set_u32(u32 value, u32 cap) 824 { 825 acpi_status status; 826 827 if (interface->capability & cap) { 828 switch (interface->type) { 829 case ACER_AMW0: 830 return AMW0_set_u32(value, cap, interface); 831 case ACER_AMW0_V2: 832 if (cap == ACER_CAP_MAILLED) 833 return AMW0_set_u32(value, cap, interface); 834 835 /* 836 * On some models, some WMID methods don't toggle 837 * properly. For those cases, we want to run the AMW0 838 * method afterwards to be certain we've really toggled 839 * the device state. 840 */ 841 if (cap == ACER_CAP_WIRELESS || 842 cap == ACER_CAP_BLUETOOTH) { 843 status = WMID_set_u32(value, cap, interface); 844 if (ACPI_FAILURE(status)) 845 return status; 846 847 return AMW0_set_u32(value, cap, interface); 848 } 849 case ACER_WMID: 850 return WMID_set_u32(value, cap, interface); 851 default: 852 return AE_BAD_PARAMETER; 853 } 854 } 855 return AE_BAD_PARAMETER; 856 } 857 858 static void __init acer_commandline_init(void) 859 { 860 /* 861 * These will all fail silently if the value given is invalid, or the 862 * capability isn't available on the given interface 863 */ 864 set_u32(mailled, ACER_CAP_MAILLED); 865 set_u32(threeg, ACER_CAP_THREEG); 866 set_u32(brightness, ACER_CAP_BRIGHTNESS); 867 } 868 869 /* 870 * LED device (Mail LED only, no other LEDs known yet) 871 */ 872 static void mail_led_set(struct led_classdev *led_cdev, 873 enum led_brightness value) 874 { 875 set_u32(value, ACER_CAP_MAILLED); 876 } 877 878 static struct led_classdev mail_led = { 879 .name = "acer-wmi::mail", 880 .brightness_set = mail_led_set, 881 }; 882 883 static int __devinit acer_led_init(struct device *dev) 884 { 885 return led_classdev_register(dev, &mail_led); 886 } 887 888 static void acer_led_exit(void) 889 { 890 led_classdev_unregister(&mail_led); 891 } 892 893 /* 894 * Backlight device 895 */ 896 static struct backlight_device *acer_backlight_device; 897 898 static int read_brightness(struct backlight_device *bd) 899 { 900 u32 value; 901 get_u32(&value, ACER_CAP_BRIGHTNESS); 902 return value; 903 } 904 905 static int update_bl_status(struct backlight_device *bd) 906 { 907 int intensity = bd->props.brightness; 908 909 if (bd->props.power != FB_BLANK_UNBLANK) 910 intensity = 0; 911 if (bd->props.fb_blank != FB_BLANK_UNBLANK) 912 intensity = 0; 913 914 set_u32(intensity, ACER_CAP_BRIGHTNESS); 915 916 return 0; 917 } 918 919 static struct backlight_ops acer_bl_ops = { 920 .get_brightness = read_brightness, 921 .update_status = update_bl_status, 922 }; 923 924 static int __devinit acer_backlight_init(struct device *dev) 925 { 926 struct backlight_properties props; 927 struct backlight_device *bd; 928 929 memset(&props, 0, sizeof(struct backlight_properties)); 930 props.max_brightness = max_brightness; 931 bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops, 932 &props); 933 if (IS_ERR(bd)) { 934 printk(ACER_ERR "Could not register Acer backlight device\n"); 935 acer_backlight_device = NULL; 936 return PTR_ERR(bd); 937 } 938 939 acer_backlight_device = bd; 940 941 bd->props.power = FB_BLANK_UNBLANK; 942 bd->props.brightness = read_brightness(bd); 943 backlight_update_status(bd); 944 return 0; 945 } 946 947 static void acer_backlight_exit(void) 948 { 949 backlight_device_unregister(acer_backlight_device); 950 } 951 952 /* 953 * Rfkill devices 954 */ 955 static void acer_rfkill_update(struct work_struct *ignored); 956 static DECLARE_DELAYED_WORK(acer_rfkill_work, acer_rfkill_update); 957 static void acer_rfkill_update(struct work_struct *ignored) 958 { 959 u32 state; 960 acpi_status status; 961 962 status = get_u32(&state, ACER_CAP_WIRELESS); 963 if (ACPI_SUCCESS(status)) 964 rfkill_set_sw_state(wireless_rfkill, !state); 965 966 if (has_cap(ACER_CAP_BLUETOOTH)) { 967 status = get_u32(&state, ACER_CAP_BLUETOOTH); 968 if (ACPI_SUCCESS(status)) 969 rfkill_set_sw_state(bluetooth_rfkill, !state); 970 } 971 972 schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); 973 } 974 975 static int acer_rfkill_set(void *data, bool blocked) 976 { 977 acpi_status status; 978 u32 cap = (unsigned long)data; 979 status = set_u32(!blocked, cap); 980 if (ACPI_FAILURE(status)) 981 return -ENODEV; 982 return 0; 983 } 984 985 static const struct rfkill_ops acer_rfkill_ops = { 986 .set_block = acer_rfkill_set, 987 }; 988 989 static struct rfkill *acer_rfkill_register(struct device *dev, 990 enum rfkill_type type, 991 char *name, u32 cap) 992 { 993 int err; 994 struct rfkill *rfkill_dev; 995 996 rfkill_dev = rfkill_alloc(name, dev, type, 997 &acer_rfkill_ops, 998 (void *)(unsigned long)cap); 999 if (!rfkill_dev) 1000 return ERR_PTR(-ENOMEM); 1001 1002 err = rfkill_register(rfkill_dev); 1003 if (err) { 1004 rfkill_destroy(rfkill_dev); 1005 return ERR_PTR(err); 1006 } 1007 return rfkill_dev; 1008 } 1009 1010 static int acer_rfkill_init(struct device *dev) 1011 { 1012 wireless_rfkill = acer_rfkill_register(dev, RFKILL_TYPE_WLAN, 1013 "acer-wireless", ACER_CAP_WIRELESS); 1014 if (IS_ERR(wireless_rfkill)) 1015 return PTR_ERR(wireless_rfkill); 1016 1017 if (has_cap(ACER_CAP_BLUETOOTH)) { 1018 bluetooth_rfkill = acer_rfkill_register(dev, 1019 RFKILL_TYPE_BLUETOOTH, "acer-bluetooth", 1020 ACER_CAP_BLUETOOTH); 1021 if (IS_ERR(bluetooth_rfkill)) { 1022 rfkill_unregister(wireless_rfkill); 1023 rfkill_destroy(wireless_rfkill); 1024 return PTR_ERR(bluetooth_rfkill); 1025 } 1026 } 1027 1028 schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); 1029 1030 return 0; 1031 } 1032 1033 static void acer_rfkill_exit(void) 1034 { 1035 cancel_delayed_work_sync(&acer_rfkill_work); 1036 1037 rfkill_unregister(wireless_rfkill); 1038 rfkill_destroy(wireless_rfkill); 1039 1040 if (has_cap(ACER_CAP_BLUETOOTH)) { 1041 rfkill_unregister(bluetooth_rfkill); 1042 rfkill_destroy(bluetooth_rfkill); 1043 } 1044 return; 1045 } 1046 1047 /* 1048 * sysfs interface 1049 */ 1050 static ssize_t show_bool_threeg(struct device *dev, 1051 struct device_attribute *attr, char *buf) 1052 { 1053 u32 result; \ 1054 acpi_status status = get_u32(&result, ACER_CAP_THREEG); 1055 if (ACPI_SUCCESS(status)) 1056 return sprintf(buf, "%u\n", result); 1057 return sprintf(buf, "Read error\n"); 1058 } 1059 1060 static ssize_t set_bool_threeg(struct device *dev, 1061 struct device_attribute *attr, const char *buf, size_t count) 1062 { 1063 u32 tmp = simple_strtoul(buf, NULL, 10); 1064 acpi_status status = set_u32(tmp, ACER_CAP_THREEG); 1065 if (ACPI_FAILURE(status)) 1066 return -EINVAL; 1067 return count; 1068 } 1069 static DEVICE_ATTR(threeg, S_IWUGO | S_IRUGO | S_IWUSR, show_bool_threeg, 1070 set_bool_threeg); 1071 1072 static ssize_t show_interface(struct device *dev, struct device_attribute *attr, 1073 char *buf) 1074 { 1075 switch (interface->type) { 1076 case ACER_AMW0: 1077 return sprintf(buf, "AMW0\n"); 1078 case ACER_AMW0_V2: 1079 return sprintf(buf, "AMW0 v2\n"); 1080 case ACER_WMID: 1081 return sprintf(buf, "WMID\n"); 1082 default: 1083 return sprintf(buf, "Error!\n"); 1084 } 1085 } 1086 1087 static DEVICE_ATTR(interface, S_IWUGO | S_IRUGO | S_IWUSR, 1088 show_interface, NULL); 1089 1090 /* 1091 * debugfs functions 1092 */ 1093 static u32 get_wmid_devices(void) 1094 { 1095 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; 1096 union acpi_object *obj; 1097 acpi_status status; 1098 1099 status = wmi_query_block(WMID_GUID2, 1, &out); 1100 if (ACPI_FAILURE(status)) 1101 return 0; 1102 1103 obj = (union acpi_object *) out.pointer; 1104 if (obj && obj->type == ACPI_TYPE_BUFFER && 1105 obj->buffer.length == sizeof(u32)) { 1106 return *((u32 *) obj->buffer.pointer); 1107 } else { 1108 return 0; 1109 } 1110 } 1111 1112 /* 1113 * Platform device 1114 */ 1115 static int __devinit acer_platform_probe(struct platform_device *device) 1116 { 1117 int err; 1118 1119 if (has_cap(ACER_CAP_MAILLED)) { 1120 err = acer_led_init(&device->dev); 1121 if (err) 1122 goto error_mailled; 1123 } 1124 1125 if (has_cap(ACER_CAP_BRIGHTNESS)) { 1126 err = acer_backlight_init(&device->dev); 1127 if (err) 1128 goto error_brightness; 1129 } 1130 1131 err = acer_rfkill_init(&device->dev); 1132 if (err) 1133 goto error_rfkill; 1134 1135 return err; 1136 1137 error_rfkill: 1138 if (has_cap(ACER_CAP_BRIGHTNESS)) 1139 acer_backlight_exit(); 1140 error_brightness: 1141 if (has_cap(ACER_CAP_MAILLED)) 1142 acer_led_exit(); 1143 error_mailled: 1144 return err; 1145 } 1146 1147 static int acer_platform_remove(struct platform_device *device) 1148 { 1149 if (has_cap(ACER_CAP_MAILLED)) 1150 acer_led_exit(); 1151 if (has_cap(ACER_CAP_BRIGHTNESS)) 1152 acer_backlight_exit(); 1153 1154 acer_rfkill_exit(); 1155 return 0; 1156 } 1157 1158 static int acer_platform_suspend(struct platform_device *dev, 1159 pm_message_t state) 1160 { 1161 u32 value; 1162 struct acer_data *data = &interface->data; 1163 1164 if (!data) 1165 return -ENOMEM; 1166 1167 if (has_cap(ACER_CAP_MAILLED)) { 1168 get_u32(&value, ACER_CAP_MAILLED); 1169 data->mailled = value; 1170 } 1171 1172 if (has_cap(ACER_CAP_BRIGHTNESS)) { 1173 get_u32(&value, ACER_CAP_BRIGHTNESS); 1174 data->brightness = value; 1175 } 1176 1177 return 0; 1178 } 1179 1180 static int acer_platform_resume(struct platform_device *device) 1181 { 1182 struct acer_data *data = &interface->data; 1183 1184 if (!data) 1185 return -ENOMEM; 1186 1187 if (has_cap(ACER_CAP_MAILLED)) 1188 set_u32(data->mailled, ACER_CAP_MAILLED); 1189 1190 if (has_cap(ACER_CAP_BRIGHTNESS)) 1191 set_u32(data->brightness, ACER_CAP_BRIGHTNESS); 1192 1193 return 0; 1194 } 1195 1196 static struct platform_driver acer_platform_driver = { 1197 .driver = { 1198 .name = "acer-wmi", 1199 .owner = THIS_MODULE, 1200 }, 1201 .probe = acer_platform_probe, 1202 .remove = acer_platform_remove, 1203 .suspend = acer_platform_suspend, 1204 .resume = acer_platform_resume, 1205 }; 1206 1207 static struct platform_device *acer_platform_device; 1208 1209 static int remove_sysfs(struct platform_device *device) 1210 { 1211 if (has_cap(ACER_CAP_THREEG)) 1212 device_remove_file(&device->dev, &dev_attr_threeg); 1213 1214 device_remove_file(&device->dev, &dev_attr_interface); 1215 1216 return 0; 1217 } 1218 1219 static int create_sysfs(void) 1220 { 1221 int retval = -ENOMEM; 1222 1223 if (has_cap(ACER_CAP_THREEG)) { 1224 retval = device_create_file(&acer_platform_device->dev, 1225 &dev_attr_threeg); 1226 if (retval) 1227 goto error_sysfs; 1228 } 1229 1230 retval = device_create_file(&acer_platform_device->dev, 1231 &dev_attr_interface); 1232 if (retval) 1233 goto error_sysfs; 1234 1235 return 0; 1236 1237 error_sysfs: 1238 remove_sysfs(acer_platform_device); 1239 return retval; 1240 } 1241 1242 static void remove_debugfs(void) 1243 { 1244 debugfs_remove(interface->debug.devices); 1245 debugfs_remove(interface->debug.root); 1246 } 1247 1248 static int create_debugfs(void) 1249 { 1250 interface->debug.root = debugfs_create_dir("acer-wmi", NULL); 1251 if (!interface->debug.root) { 1252 printk(ACER_ERR "Failed to create debugfs directory"); 1253 return -ENOMEM; 1254 } 1255 1256 interface->debug.devices = debugfs_create_u32("devices", S_IRUGO, 1257 interface->debug.root, 1258 &interface->debug.wmid_devices); 1259 if (!interface->debug.devices) 1260 goto error_debugfs; 1261 1262 return 0; 1263 1264 error_debugfs: 1265 remove_debugfs(); 1266 return -ENOMEM; 1267 } 1268 1269 static int __init acer_wmi_init(void) 1270 { 1271 int err; 1272 1273 printk(ACER_INFO "Acer Laptop ACPI-WMI Extras\n"); 1274 1275 if (dmi_check_system(acer_blacklist)) { 1276 printk(ACER_INFO "Blacklisted hardware detected - " 1277 "not loading\n"); 1278 return -ENODEV; 1279 } 1280 1281 find_quirks(); 1282 1283 /* 1284 * Detect which ACPI-WMI interface we're using. 1285 */ 1286 if (wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1)) 1287 interface = &AMW0_V2_interface; 1288 1289 if (!wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1)) 1290 interface = &wmid_interface; 1291 1292 if (wmi_has_guid(WMID_GUID2) && interface) { 1293 if (ACPI_FAILURE(WMID_set_capabilities())) { 1294 printk(ACER_ERR "Unable to detect available WMID " 1295 "devices\n"); 1296 return -ENODEV; 1297 } 1298 } else if (!wmi_has_guid(WMID_GUID2) && interface) { 1299 printk(ACER_ERR "No WMID device detection method found\n"); 1300 return -ENODEV; 1301 } 1302 1303 if (wmi_has_guid(AMW0_GUID1) && !wmi_has_guid(WMID_GUID1)) { 1304 interface = &AMW0_interface; 1305 1306 if (ACPI_FAILURE(AMW0_set_capabilities())) { 1307 printk(ACER_ERR "Unable to detect available AMW0 " 1308 "devices\n"); 1309 return -ENODEV; 1310 } 1311 } 1312 1313 if (wmi_has_guid(AMW0_GUID1)) 1314 AMW0_find_mailled(); 1315 1316 if (!interface) { 1317 printk(ACER_ERR "No or unsupported WMI interface, unable to " 1318 "load\n"); 1319 return -ENODEV; 1320 } 1321 1322 set_quirks(); 1323 1324 if (acpi_video_backlight_support() && has_cap(ACER_CAP_BRIGHTNESS)) { 1325 interface->capability &= ~ACER_CAP_BRIGHTNESS; 1326 printk(ACER_INFO "Brightness must be controlled by " 1327 "generic video driver\n"); 1328 } 1329 1330 if (platform_driver_register(&acer_platform_driver)) { 1331 printk(ACER_ERR "Unable to register platform driver.\n"); 1332 goto error_platform_register; 1333 } 1334 acer_platform_device = platform_device_alloc("acer-wmi", -1); 1335 platform_device_add(acer_platform_device); 1336 1337 err = create_sysfs(); 1338 if (err) 1339 return err; 1340 1341 if (wmi_has_guid(WMID_GUID2)) { 1342 interface->debug.wmid_devices = get_wmid_devices(); 1343 err = create_debugfs(); 1344 if (err) 1345 return err; 1346 } 1347 1348 /* Override any initial settings with values from the commandline */ 1349 acer_commandline_init(); 1350 1351 return 0; 1352 1353 error_platform_register: 1354 return -ENODEV; 1355 } 1356 1357 static void __exit acer_wmi_exit(void) 1358 { 1359 remove_sysfs(acer_platform_device); 1360 remove_debugfs(); 1361 platform_device_del(acer_platform_device); 1362 platform_driver_unregister(&acer_platform_driver); 1363 1364 printk(ACER_INFO "Acer Laptop WMI Extras unloaded\n"); 1365 return; 1366 } 1367 1368 module_init(acer_wmi_init); 1369 module_exit(acer_wmi_exit); 1370