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