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