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_command(¶m, 0x1059); 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_device *bd; 927 928 bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops); 929 if (IS_ERR(bd)) { 930 printk(ACER_ERR "Could not register Acer backlight device\n"); 931 acer_backlight_device = NULL; 932 return PTR_ERR(bd); 933 } 934 935 acer_backlight_device = bd; 936 937 bd->props.power = FB_BLANK_UNBLANK; 938 bd->props.brightness = max_brightness; 939 bd->props.max_brightness = max_brightness; 940 backlight_update_status(bd); 941 return 0; 942 } 943 944 static void acer_backlight_exit(void) 945 { 946 backlight_device_unregister(acer_backlight_device); 947 } 948 949 /* 950 * Rfkill devices 951 */ 952 static void acer_rfkill_update(struct work_struct *ignored); 953 static DECLARE_DELAYED_WORK(acer_rfkill_work, acer_rfkill_update); 954 static void acer_rfkill_update(struct work_struct *ignored) 955 { 956 u32 state; 957 acpi_status status; 958 959 status = get_u32(&state, ACER_CAP_WIRELESS); 960 if (ACPI_SUCCESS(status)) 961 rfkill_set_sw_state(wireless_rfkill, !state); 962 963 if (has_cap(ACER_CAP_BLUETOOTH)) { 964 status = get_u32(&state, ACER_CAP_BLUETOOTH); 965 if (ACPI_SUCCESS(status)) 966 rfkill_set_sw_state(bluetooth_rfkill, !state); 967 } 968 969 schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); 970 } 971 972 static int acer_rfkill_set(void *data, bool blocked) 973 { 974 acpi_status status; 975 u32 cap = (unsigned long)data; 976 status = set_u32(!blocked, cap); 977 if (ACPI_FAILURE(status)) 978 return -ENODEV; 979 return 0; 980 } 981 982 static const struct rfkill_ops acer_rfkill_ops = { 983 .set_block = acer_rfkill_set, 984 }; 985 986 static struct rfkill *acer_rfkill_register(struct device *dev, 987 enum rfkill_type type, 988 char *name, u32 cap) 989 { 990 int err; 991 struct rfkill *rfkill_dev; 992 993 rfkill_dev = rfkill_alloc(name, dev, type, 994 &acer_rfkill_ops, 995 (void *)(unsigned long)cap); 996 if (!rfkill_dev) 997 return ERR_PTR(-ENOMEM); 998 999 err = rfkill_register(rfkill_dev); 1000 if (err) { 1001 rfkill_destroy(rfkill_dev); 1002 return ERR_PTR(err); 1003 } 1004 return rfkill_dev; 1005 } 1006 1007 static int acer_rfkill_init(struct device *dev) 1008 { 1009 wireless_rfkill = acer_rfkill_register(dev, RFKILL_TYPE_WLAN, 1010 "acer-wireless", ACER_CAP_WIRELESS); 1011 if (IS_ERR(wireless_rfkill)) 1012 return PTR_ERR(wireless_rfkill); 1013 1014 if (has_cap(ACER_CAP_BLUETOOTH)) { 1015 bluetooth_rfkill = acer_rfkill_register(dev, 1016 RFKILL_TYPE_BLUETOOTH, "acer-bluetooth", 1017 ACER_CAP_BLUETOOTH); 1018 if (IS_ERR(bluetooth_rfkill)) { 1019 rfkill_unregister(wireless_rfkill); 1020 rfkill_destroy(wireless_rfkill); 1021 return PTR_ERR(bluetooth_rfkill); 1022 } 1023 } 1024 1025 schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); 1026 1027 return 0; 1028 } 1029 1030 static void acer_rfkill_exit(void) 1031 { 1032 cancel_delayed_work_sync(&acer_rfkill_work); 1033 1034 rfkill_unregister(wireless_rfkill); 1035 rfkill_destroy(wireless_rfkill); 1036 1037 if (has_cap(ACER_CAP_BLUETOOTH)) { 1038 rfkill_unregister(bluetooth_rfkill); 1039 rfkill_destroy(bluetooth_rfkill); 1040 } 1041 return; 1042 } 1043 1044 /* 1045 * sysfs interface 1046 */ 1047 static ssize_t show_bool_threeg(struct device *dev, 1048 struct device_attribute *attr, char *buf) 1049 { 1050 u32 result; \ 1051 acpi_status status = get_u32(&result, ACER_CAP_THREEG); 1052 if (ACPI_SUCCESS(status)) 1053 return sprintf(buf, "%u\n", result); 1054 return sprintf(buf, "Read error\n"); 1055 } 1056 1057 static ssize_t set_bool_threeg(struct device *dev, 1058 struct device_attribute *attr, const char *buf, size_t count) 1059 { 1060 u32 tmp = simple_strtoul(buf, NULL, 10); 1061 acpi_status status = set_u32(tmp, ACER_CAP_THREEG); 1062 if (ACPI_FAILURE(status)) 1063 return -EINVAL; 1064 return count; 1065 } 1066 static DEVICE_ATTR(threeg, S_IWUGO | S_IRUGO | S_IWUSR, show_bool_threeg, 1067 set_bool_threeg); 1068 1069 static ssize_t show_interface(struct device *dev, struct device_attribute *attr, 1070 char *buf) 1071 { 1072 switch (interface->type) { 1073 case ACER_AMW0: 1074 return sprintf(buf, "AMW0\n"); 1075 case ACER_AMW0_V2: 1076 return sprintf(buf, "AMW0 v2\n"); 1077 case ACER_WMID: 1078 return sprintf(buf, "WMID\n"); 1079 default: 1080 return sprintf(buf, "Error!\n"); 1081 } 1082 } 1083 1084 static DEVICE_ATTR(interface, S_IWUGO | S_IRUGO | S_IWUSR, 1085 show_interface, NULL); 1086 1087 /* 1088 * debugfs functions 1089 */ 1090 static u32 get_wmid_devices(void) 1091 { 1092 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; 1093 union acpi_object *obj; 1094 acpi_status status; 1095 1096 status = wmi_query_block(WMID_GUID2, 1, &out); 1097 if (ACPI_FAILURE(status)) 1098 return 0; 1099 1100 obj = (union acpi_object *) out.pointer; 1101 if (obj && obj->type == ACPI_TYPE_BUFFER && 1102 obj->buffer.length == sizeof(u32)) { 1103 return *((u32 *) obj->buffer.pointer); 1104 } else { 1105 return 0; 1106 } 1107 } 1108 1109 /* 1110 * Platform device 1111 */ 1112 static int __devinit acer_platform_probe(struct platform_device *device) 1113 { 1114 int err; 1115 1116 if (has_cap(ACER_CAP_MAILLED)) { 1117 err = acer_led_init(&device->dev); 1118 if (err) 1119 goto error_mailled; 1120 } 1121 1122 if (has_cap(ACER_CAP_BRIGHTNESS)) { 1123 err = acer_backlight_init(&device->dev); 1124 if (err) 1125 goto error_brightness; 1126 } 1127 1128 err = acer_rfkill_init(&device->dev); 1129 if (err) 1130 goto error_rfkill; 1131 1132 return err; 1133 1134 error_rfkill: 1135 if (has_cap(ACER_CAP_BRIGHTNESS)) 1136 acer_backlight_exit(); 1137 error_brightness: 1138 if (has_cap(ACER_CAP_MAILLED)) 1139 acer_led_exit(); 1140 error_mailled: 1141 return err; 1142 } 1143 1144 static int acer_platform_remove(struct platform_device *device) 1145 { 1146 if (has_cap(ACER_CAP_MAILLED)) 1147 acer_led_exit(); 1148 if (has_cap(ACER_CAP_BRIGHTNESS)) 1149 acer_backlight_exit(); 1150 1151 acer_rfkill_exit(); 1152 return 0; 1153 } 1154 1155 static int acer_platform_suspend(struct platform_device *dev, 1156 pm_message_t state) 1157 { 1158 u32 value; 1159 struct acer_data *data = &interface->data; 1160 1161 if (!data) 1162 return -ENOMEM; 1163 1164 if (has_cap(ACER_CAP_MAILLED)) { 1165 get_u32(&value, ACER_CAP_MAILLED); 1166 data->mailled = value; 1167 } 1168 1169 if (has_cap(ACER_CAP_BRIGHTNESS)) { 1170 get_u32(&value, ACER_CAP_BRIGHTNESS); 1171 data->brightness = value; 1172 } 1173 1174 return 0; 1175 } 1176 1177 static int acer_platform_resume(struct platform_device *device) 1178 { 1179 struct acer_data *data = &interface->data; 1180 1181 if (!data) 1182 return -ENOMEM; 1183 1184 if (has_cap(ACER_CAP_MAILLED)) 1185 set_u32(data->mailled, ACER_CAP_MAILLED); 1186 1187 if (has_cap(ACER_CAP_BRIGHTNESS)) 1188 set_u32(data->brightness, ACER_CAP_BRIGHTNESS); 1189 1190 return 0; 1191 } 1192 1193 static struct platform_driver acer_platform_driver = { 1194 .driver = { 1195 .name = "acer-wmi", 1196 .owner = THIS_MODULE, 1197 }, 1198 .probe = acer_platform_probe, 1199 .remove = acer_platform_remove, 1200 .suspend = acer_platform_suspend, 1201 .resume = acer_platform_resume, 1202 }; 1203 1204 static struct platform_device *acer_platform_device; 1205 1206 static int remove_sysfs(struct platform_device *device) 1207 { 1208 if (has_cap(ACER_CAP_THREEG)) 1209 device_remove_file(&device->dev, &dev_attr_threeg); 1210 1211 device_remove_file(&device->dev, &dev_attr_interface); 1212 1213 return 0; 1214 } 1215 1216 static int create_sysfs(void) 1217 { 1218 int retval = -ENOMEM; 1219 1220 if (has_cap(ACER_CAP_THREEG)) { 1221 retval = device_create_file(&acer_platform_device->dev, 1222 &dev_attr_threeg); 1223 if (retval) 1224 goto error_sysfs; 1225 } 1226 1227 retval = device_create_file(&acer_platform_device->dev, 1228 &dev_attr_interface); 1229 if (retval) 1230 goto error_sysfs; 1231 1232 return 0; 1233 1234 error_sysfs: 1235 remove_sysfs(acer_platform_device); 1236 return retval; 1237 } 1238 1239 static void remove_debugfs(void) 1240 { 1241 debugfs_remove(interface->debug.devices); 1242 debugfs_remove(interface->debug.root); 1243 } 1244 1245 static int create_debugfs(void) 1246 { 1247 interface->debug.root = debugfs_create_dir("acer-wmi", NULL); 1248 if (!interface->debug.root) { 1249 printk(ACER_ERR "Failed to create debugfs directory"); 1250 return -ENOMEM; 1251 } 1252 1253 interface->debug.devices = debugfs_create_u32("devices", S_IRUGO, 1254 interface->debug.root, 1255 &interface->debug.wmid_devices); 1256 if (!interface->debug.devices) 1257 goto error_debugfs; 1258 1259 return 0; 1260 1261 error_debugfs: 1262 remove_debugfs(); 1263 return -ENOMEM; 1264 } 1265 1266 static int __init acer_wmi_init(void) 1267 { 1268 int err; 1269 1270 printk(ACER_INFO "Acer Laptop ACPI-WMI Extras\n"); 1271 1272 if (dmi_check_system(acer_blacklist)) { 1273 printk(ACER_INFO "Blacklisted hardware detected - " 1274 "not loading\n"); 1275 return -ENODEV; 1276 } 1277 1278 find_quirks(); 1279 1280 /* 1281 * Detect which ACPI-WMI interface we're using. 1282 */ 1283 if (wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1)) 1284 interface = &AMW0_V2_interface; 1285 1286 if (!wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1)) 1287 interface = &wmid_interface; 1288 1289 if (wmi_has_guid(WMID_GUID2) && interface) { 1290 if (ACPI_FAILURE(WMID_set_capabilities())) { 1291 printk(ACER_ERR "Unable to detect available WMID " 1292 "devices\n"); 1293 return -ENODEV; 1294 } 1295 } else if (!wmi_has_guid(WMID_GUID2) && interface) { 1296 printk(ACER_ERR "No WMID device detection method found\n"); 1297 return -ENODEV; 1298 } 1299 1300 if (wmi_has_guid(AMW0_GUID1) && !wmi_has_guid(WMID_GUID1)) { 1301 interface = &AMW0_interface; 1302 1303 if (ACPI_FAILURE(AMW0_set_capabilities())) { 1304 printk(ACER_ERR "Unable to detect available AMW0 " 1305 "devices\n"); 1306 return -ENODEV; 1307 } 1308 } 1309 1310 if (wmi_has_guid(AMW0_GUID1)) 1311 AMW0_find_mailled(); 1312 1313 if (!interface) { 1314 printk(ACER_ERR "No or unsupported WMI interface, unable to " 1315 "load\n"); 1316 return -ENODEV; 1317 } 1318 1319 set_quirks(); 1320 1321 if (acpi_video_backlight_support() && has_cap(ACER_CAP_BRIGHTNESS)) { 1322 interface->capability &= ~ACER_CAP_BRIGHTNESS; 1323 printk(ACER_INFO "Brightness must be controlled by " 1324 "generic video driver\n"); 1325 } 1326 1327 if (platform_driver_register(&acer_platform_driver)) { 1328 printk(ACER_ERR "Unable to register platform driver.\n"); 1329 goto error_platform_register; 1330 } 1331 acer_platform_device = platform_device_alloc("acer-wmi", -1); 1332 platform_device_add(acer_platform_device); 1333 1334 err = create_sysfs(); 1335 if (err) 1336 return err; 1337 1338 if (wmi_has_guid(WMID_GUID2)) { 1339 interface->debug.wmid_devices = get_wmid_devices(); 1340 err = create_debugfs(); 1341 if (err) 1342 return err; 1343 } 1344 1345 /* Override any initial settings with values from the commandline */ 1346 acer_commandline_init(); 1347 1348 return 0; 1349 1350 error_platform_register: 1351 return -ENODEV; 1352 } 1353 1354 static void __exit acer_wmi_exit(void) 1355 { 1356 remove_sysfs(acer_platform_device); 1357 remove_debugfs(); 1358 platform_device_del(acer_platform_device); 1359 platform_driver_unregister(&acer_platform_driver); 1360 1361 printk(ACER_INFO "Acer Laptop WMI Extras unloaded\n"); 1362 return; 1363 } 1364 1365 module_init(acer_wmi_init); 1366 module_exit(acer_wmi_exit); 1367