1 /* 2 * Acer WMI Laptop Extras 3 * 4 * Copyright (C) 2007-2009 Carlos Corbacho <carlos@strangeworlds.co.uk> 5 * 6 * Based on acer_acpi: 7 * Copyright (C) 2005-2007 E.M. Smith 8 * Copyright (C) 2007-2008 Carlos Corbacho <cathectic@gmail.com> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23 */ 24 25 #include <linux/kernel.h> 26 #include <linux/module.h> 27 #include <linux/init.h> 28 #include <linux/types.h> 29 #include <linux/dmi.h> 30 #include <linux/fb.h> 31 #include <linux/backlight.h> 32 #include <linux/leds.h> 33 #include <linux/platform_device.h> 34 #include <linux/acpi.h> 35 #include <linux/i8042.h> 36 #include <linux/rfkill.h> 37 #include <linux/workqueue.h> 38 #include <linux/debugfs.h> 39 #include <linux/slab.h> 40 41 #include <acpi/acpi_drivers.h> 42 43 MODULE_AUTHOR("Carlos Corbacho"); 44 MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver"); 45 MODULE_LICENSE("GPL"); 46 47 #define ACER_LOGPREFIX "acer-wmi: " 48 #define ACER_ERR KERN_ERR ACER_LOGPREFIX 49 #define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX 50 #define ACER_INFO KERN_INFO ACER_LOGPREFIX 51 52 /* 53 * Magic Number 54 * Meaning is unknown - this number is required for writing to ACPI for AMW0 55 * (it's also used in acerhk when directly accessing the BIOS) 56 */ 57 #define ACER_AMW0_WRITE 0x9610 58 59 /* 60 * Bit masks for the AMW0 interface 61 */ 62 #define ACER_AMW0_WIRELESS_MASK 0x35 63 #define ACER_AMW0_BLUETOOTH_MASK 0x34 64 #define ACER_AMW0_MAILLED_MASK 0x31 65 66 /* 67 * Method IDs for WMID interface 68 */ 69 #define ACER_WMID_GET_WIRELESS_METHODID 1 70 #define ACER_WMID_GET_BLUETOOTH_METHODID 2 71 #define ACER_WMID_GET_BRIGHTNESS_METHODID 3 72 #define ACER_WMID_SET_WIRELESS_METHODID 4 73 #define ACER_WMID_SET_BLUETOOTH_METHODID 5 74 #define ACER_WMID_SET_BRIGHTNESS_METHODID 6 75 #define ACER_WMID_GET_THREEG_METHODID 10 76 #define ACER_WMID_SET_THREEG_METHODID 11 77 78 /* 79 * Acer ACPI method GUIDs 80 */ 81 #define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB" 82 #define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C" 83 #define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3" 84 #define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A" 85 86 MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB"); 87 MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"); 88 89 /* 90 * Interface capability flags 91 */ 92 #define ACER_CAP_MAILLED (1<<0) 93 #define ACER_CAP_WIRELESS (1<<1) 94 #define ACER_CAP_BLUETOOTH (1<<2) 95 #define ACER_CAP_BRIGHTNESS (1<<3) 96 #define ACER_CAP_THREEG (1<<4) 97 #define ACER_CAP_ANY (0xFFFFFFFF) 98 99 /* 100 * Interface type flags 101 */ 102 enum interface_flags { 103 ACER_AMW0, 104 ACER_AMW0_V2, 105 ACER_WMID, 106 }; 107 108 #define ACER_DEFAULT_WIRELESS 0 109 #define ACER_DEFAULT_BLUETOOTH 0 110 #define ACER_DEFAULT_MAILLED 0 111 #define ACER_DEFAULT_THREEG 0 112 113 static int max_brightness = 0xF; 114 115 static int mailled = -1; 116 static int brightness = -1; 117 static int threeg = -1; 118 static int force_series; 119 120 module_param(mailled, int, 0444); 121 module_param(brightness, int, 0444); 122 module_param(threeg, int, 0444); 123 module_param(force_series, int, 0444); 124 MODULE_PARM_DESC(mailled, "Set initial state of Mail LED"); 125 MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness"); 126 MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware"); 127 MODULE_PARM_DESC(force_series, "Force a different laptop series"); 128 129 struct acer_data { 130 int mailled; 131 int threeg; 132 int brightness; 133 }; 134 135 struct acer_debug { 136 struct dentry *root; 137 struct dentry *devices; 138 u32 wmid_devices; 139 }; 140 141 static struct rfkill *wireless_rfkill; 142 static struct rfkill *bluetooth_rfkill; 143 144 /* Each low-level interface must define at least some of the following */ 145 struct wmi_interface { 146 /* The WMI device type */ 147 u32 type; 148 149 /* The capabilities this interface provides */ 150 u32 capability; 151 152 /* Private data for the current interface */ 153 struct acer_data data; 154 155 /* debugfs entries associated with this interface */ 156 struct acer_debug debug; 157 }; 158 159 /* The static interface pointer, points to the currently detected interface */ 160 static struct wmi_interface *interface; 161 162 /* 163 * Embedded Controller quirks 164 * Some laptops require us to directly access the EC to either enable or query 165 * features that are not available through WMI. 166 */ 167 168 struct quirk_entry { 169 u8 wireless; 170 u8 mailled; 171 s8 brightness; 172 u8 bluetooth; 173 }; 174 175 static struct quirk_entry *quirks; 176 177 static void set_quirks(void) 178 { 179 if (!interface) 180 return; 181 182 if (quirks->mailled) 183 interface->capability |= ACER_CAP_MAILLED; 184 185 if (quirks->brightness) 186 interface->capability |= ACER_CAP_BRIGHTNESS; 187 } 188 189 static int dmi_matched(const struct dmi_system_id *dmi) 190 { 191 quirks = dmi->driver_data; 192 return 1; 193 } 194 195 static struct quirk_entry quirk_unknown = { 196 }; 197 198 static struct quirk_entry quirk_acer_aspire_1520 = { 199 .brightness = -1, 200 }; 201 202 static struct quirk_entry quirk_acer_travelmate_2490 = { 203 .mailled = 1, 204 }; 205 206 /* This AMW0 laptop has no bluetooth */ 207 static struct quirk_entry quirk_medion_md_98300 = { 208 .wireless = 1, 209 }; 210 211 static struct quirk_entry quirk_fujitsu_amilo_li_1718 = { 212 .wireless = 2, 213 }; 214 215 /* The Aspire One has a dummy ACPI-WMI interface - disable it */ 216 static struct dmi_system_id __devinitdata acer_blacklist[] = { 217 { 218 .ident = "Acer Aspire One (SSD)", 219 .matches = { 220 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 221 DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"), 222 }, 223 }, 224 { 225 .ident = "Acer Aspire One (HDD)", 226 .matches = { 227 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 228 DMI_MATCH(DMI_PRODUCT_NAME, "AOA150"), 229 }, 230 }, 231 {} 232 }; 233 234 static struct dmi_system_id acer_quirks[] = { 235 { 236 .callback = dmi_matched, 237 .ident = "Acer Aspire 1360", 238 .matches = { 239 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 240 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"), 241 }, 242 .driver_data = &quirk_acer_aspire_1520, 243 }, 244 { 245 .callback = dmi_matched, 246 .ident = "Acer Aspire 1520", 247 .matches = { 248 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 249 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1520"), 250 }, 251 .driver_data = &quirk_acer_aspire_1520, 252 }, 253 { 254 .callback = dmi_matched, 255 .ident = "Acer Aspire 3100", 256 .matches = { 257 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 258 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"), 259 }, 260 .driver_data = &quirk_acer_travelmate_2490, 261 }, 262 { 263 .callback = dmi_matched, 264 .ident = "Acer Aspire 3610", 265 .matches = { 266 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 267 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3610"), 268 }, 269 .driver_data = &quirk_acer_travelmate_2490, 270 }, 271 { 272 .callback = dmi_matched, 273 .ident = "Acer Aspire 5100", 274 .matches = { 275 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 276 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"), 277 }, 278 .driver_data = &quirk_acer_travelmate_2490, 279 }, 280 { 281 .callback = dmi_matched, 282 .ident = "Acer Aspire 5610", 283 .matches = { 284 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 285 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"), 286 }, 287 .driver_data = &quirk_acer_travelmate_2490, 288 }, 289 { 290 .callback = dmi_matched, 291 .ident = "Acer Aspire 5630", 292 .matches = { 293 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 294 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"), 295 }, 296 .driver_data = &quirk_acer_travelmate_2490, 297 }, 298 { 299 .callback = dmi_matched, 300 .ident = "Acer Aspire 5650", 301 .matches = { 302 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 303 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"), 304 }, 305 .driver_data = &quirk_acer_travelmate_2490, 306 }, 307 { 308 .callback = dmi_matched, 309 .ident = "Acer Aspire 5680", 310 .matches = { 311 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 312 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"), 313 }, 314 .driver_data = &quirk_acer_travelmate_2490, 315 }, 316 { 317 .callback = dmi_matched, 318 .ident = "Acer Aspire 9110", 319 .matches = { 320 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 321 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"), 322 }, 323 .driver_data = &quirk_acer_travelmate_2490, 324 }, 325 { 326 .callback = dmi_matched, 327 .ident = "Acer TravelMate 2490", 328 .matches = { 329 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 330 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"), 331 }, 332 .driver_data = &quirk_acer_travelmate_2490, 333 }, 334 { 335 .callback = dmi_matched, 336 .ident = "Acer TravelMate 4200", 337 .matches = { 338 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 339 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4200"), 340 }, 341 .driver_data = &quirk_acer_travelmate_2490, 342 }, 343 { 344 .callback = dmi_matched, 345 .ident = "Fujitsu Siemens Amilo Li 1718", 346 .matches = { 347 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 348 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Li 1718"), 349 }, 350 .driver_data = &quirk_fujitsu_amilo_li_1718, 351 }, 352 { 353 .callback = dmi_matched, 354 .ident = "Medion MD 98300", 355 .matches = { 356 DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), 357 DMI_MATCH(DMI_PRODUCT_NAME, "WAM2030"), 358 }, 359 .driver_data = &quirk_medion_md_98300, 360 }, 361 {} 362 }; 363 364 /* Find which quirks are needed for a particular vendor/ model pair */ 365 static void find_quirks(void) 366 { 367 if (!force_series) { 368 dmi_check_system(acer_quirks); 369 } else if (force_series == 2490) { 370 quirks = &quirk_acer_travelmate_2490; 371 } 372 373 if (quirks == NULL) 374 quirks = &quirk_unknown; 375 376 set_quirks(); 377 } 378 379 /* 380 * General interface convenience methods 381 */ 382 383 static bool has_cap(u32 cap) 384 { 385 if ((interface->capability & cap) != 0) 386 return 1; 387 388 return 0; 389 } 390 391 /* 392 * AMW0 (V1) interface 393 */ 394 struct wmab_args { 395 u32 eax; 396 u32 ebx; 397 u32 ecx; 398 u32 edx; 399 }; 400 401 struct wmab_ret { 402 u32 eax; 403 u32 ebx; 404 u32 ecx; 405 u32 edx; 406 u32 eex; 407 }; 408 409 static acpi_status wmab_execute(struct wmab_args *regbuf, 410 struct acpi_buffer *result) 411 { 412 struct acpi_buffer input; 413 acpi_status status; 414 input.length = sizeof(struct wmab_args); 415 input.pointer = (u8 *)regbuf; 416 417 status = wmi_evaluate_method(AMW0_GUID1, 1, 1, &input, result); 418 419 return status; 420 } 421 422 static acpi_status AMW0_get_u32(u32 *value, u32 cap, 423 struct wmi_interface *iface) 424 { 425 int err; 426 u8 result; 427 428 switch (cap) { 429 case ACER_CAP_MAILLED: 430 switch (quirks->mailled) { 431 default: 432 err = ec_read(0xA, &result); 433 if (err) 434 return AE_ERROR; 435 *value = (result >> 7) & 0x1; 436 return AE_OK; 437 } 438 break; 439 case ACER_CAP_WIRELESS: 440 switch (quirks->wireless) { 441 case 1: 442 err = ec_read(0x7B, &result); 443 if (err) 444 return AE_ERROR; 445 *value = result & 0x1; 446 return AE_OK; 447 case 2: 448 err = ec_read(0x71, &result); 449 if (err) 450 return AE_ERROR; 451 *value = result & 0x1; 452 return AE_OK; 453 default: 454 err = ec_read(0xA, &result); 455 if (err) 456 return AE_ERROR; 457 *value = (result >> 2) & 0x1; 458 return AE_OK; 459 } 460 break; 461 case ACER_CAP_BLUETOOTH: 462 switch (quirks->bluetooth) { 463 default: 464 err = ec_read(0xA, &result); 465 if (err) 466 return AE_ERROR; 467 *value = (result >> 4) & 0x1; 468 return AE_OK; 469 } 470 break; 471 case ACER_CAP_BRIGHTNESS: 472 switch (quirks->brightness) { 473 default: 474 err = ec_read(0x83, &result); 475 if (err) 476 return AE_ERROR; 477 *value = result; 478 return AE_OK; 479 } 480 break; 481 default: 482 return AE_ERROR; 483 } 484 return AE_OK; 485 } 486 487 static acpi_status AMW0_set_u32(u32 value, u32 cap, struct wmi_interface *iface) 488 { 489 struct wmab_args args; 490 491 args.eax = ACER_AMW0_WRITE; 492 args.ebx = value ? (1<<8) : 0; 493 args.ecx = args.edx = 0; 494 495 switch (cap) { 496 case ACER_CAP_MAILLED: 497 if (value > 1) 498 return AE_BAD_PARAMETER; 499 args.ebx |= ACER_AMW0_MAILLED_MASK; 500 break; 501 case ACER_CAP_WIRELESS: 502 if (value > 1) 503 return AE_BAD_PARAMETER; 504 args.ebx |= ACER_AMW0_WIRELESS_MASK; 505 break; 506 case ACER_CAP_BLUETOOTH: 507 if (value > 1) 508 return AE_BAD_PARAMETER; 509 args.ebx |= ACER_AMW0_BLUETOOTH_MASK; 510 break; 511 case ACER_CAP_BRIGHTNESS: 512 if (value > max_brightness) 513 return AE_BAD_PARAMETER; 514 switch (quirks->brightness) { 515 default: 516 return ec_write(0x83, value); 517 break; 518 } 519 default: 520 return AE_ERROR; 521 } 522 523 /* Actually do the set */ 524 return wmab_execute(&args, NULL); 525 } 526 527 static acpi_status AMW0_find_mailled(void) 528 { 529 struct wmab_args args; 530 struct wmab_ret ret; 531 acpi_status status = AE_OK; 532 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; 533 union acpi_object *obj; 534 535 args.eax = 0x86; 536 args.ebx = args.ecx = args.edx = 0; 537 538 status = wmab_execute(&args, &out); 539 if (ACPI_FAILURE(status)) 540 return status; 541 542 obj = (union acpi_object *) out.pointer; 543 if (obj && obj->type == ACPI_TYPE_BUFFER && 544 obj->buffer.length == sizeof(struct wmab_ret)) { 545 ret = *((struct wmab_ret *) obj->buffer.pointer); 546 } else { 547 kfree(out.pointer); 548 return AE_ERROR; 549 } 550 551 if (ret.eex & 0x1) 552 interface->capability |= ACER_CAP_MAILLED; 553 554 kfree(out.pointer); 555 556 return AE_OK; 557 } 558 559 static acpi_status AMW0_set_capabilities(void) 560 { 561 struct wmab_args args; 562 struct wmab_ret ret; 563 acpi_status status; 564 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; 565 union acpi_object *obj; 566 567 /* 568 * On laptops with this strange GUID (non Acer), normal probing doesn't 569 * work. 570 */ 571 if (wmi_has_guid(AMW0_GUID2)) { 572 interface->capability |= ACER_CAP_WIRELESS; 573 return AE_OK; 574 } 575 576 args.eax = ACER_AMW0_WRITE; 577 args.ecx = args.edx = 0; 578 579 args.ebx = 0xa2 << 8; 580 args.ebx |= ACER_AMW0_WIRELESS_MASK; 581 582 status = wmab_execute(&args, &out); 583 if (ACPI_FAILURE(status)) 584 return status; 585 586 obj = out.pointer; 587 if (obj && obj->type == ACPI_TYPE_BUFFER && 588 obj->buffer.length == sizeof(struct wmab_ret)) { 589 ret = *((struct wmab_ret *) obj->buffer.pointer); 590 } else { 591 status = AE_ERROR; 592 goto out; 593 } 594 595 if (ret.eax & 0x1) 596 interface->capability |= ACER_CAP_WIRELESS; 597 598 args.ebx = 2 << 8; 599 args.ebx |= ACER_AMW0_BLUETOOTH_MASK; 600 601 /* 602 * It's ok to use existing buffer for next wmab_execute call. 603 * But we need to kfree(out.pointer) if next wmab_execute fail. 604 */ 605 status = wmab_execute(&args, &out); 606 if (ACPI_FAILURE(status)) 607 goto out; 608 609 obj = (union acpi_object *) out.pointer; 610 if (obj && obj->type == ACPI_TYPE_BUFFER 611 && obj->buffer.length == sizeof(struct wmab_ret)) { 612 ret = *((struct wmab_ret *) obj->buffer.pointer); 613 } else { 614 status = AE_ERROR; 615 goto out; 616 } 617 618 if (ret.eax & 0x1) 619 interface->capability |= ACER_CAP_BLUETOOTH; 620 621 /* 622 * This appears to be safe to enable, since all Wistron based laptops 623 * appear to use the same EC register for brightness, even if they 624 * differ for wireless, etc 625 */ 626 if (quirks->brightness >= 0) 627 interface->capability |= ACER_CAP_BRIGHTNESS; 628 629 status = AE_OK; 630 out: 631 kfree(out.pointer); 632 return status; 633 } 634 635 static struct wmi_interface AMW0_interface = { 636 .type = ACER_AMW0, 637 }; 638 639 static struct wmi_interface AMW0_V2_interface = { 640 .type = ACER_AMW0_V2, 641 }; 642 643 /* 644 * New interface (The WMID interface) 645 */ 646 static acpi_status 647 WMI_execute_u32(u32 method_id, u32 in, u32 *out) 648 { 649 struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) }; 650 struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL }; 651 union acpi_object *obj; 652 u32 tmp; 653 acpi_status status; 654 655 status = wmi_evaluate_method(WMID_GUID1, 1, method_id, &input, &result); 656 657 if (ACPI_FAILURE(status)) 658 return status; 659 660 obj = (union acpi_object *) result.pointer; 661 if (obj && obj->type == ACPI_TYPE_BUFFER && 662 obj->buffer.length == sizeof(u32)) { 663 tmp = *((u32 *) obj->buffer.pointer); 664 } else { 665 tmp = 0; 666 } 667 668 if (out) 669 *out = tmp; 670 671 kfree(result.pointer); 672 673 return status; 674 } 675 676 static acpi_status WMID_get_u32(u32 *value, u32 cap, 677 struct wmi_interface *iface) 678 { 679 acpi_status status; 680 u8 tmp; 681 u32 result, method_id = 0; 682 683 switch (cap) { 684 case ACER_CAP_WIRELESS: 685 method_id = ACER_WMID_GET_WIRELESS_METHODID; 686 break; 687 case ACER_CAP_BLUETOOTH: 688 method_id = ACER_WMID_GET_BLUETOOTH_METHODID; 689 break; 690 case ACER_CAP_BRIGHTNESS: 691 method_id = ACER_WMID_GET_BRIGHTNESS_METHODID; 692 break; 693 case ACER_CAP_THREEG: 694 method_id = ACER_WMID_GET_THREEG_METHODID; 695 break; 696 case ACER_CAP_MAILLED: 697 if (quirks->mailled == 1) { 698 ec_read(0x9f, &tmp); 699 *value = tmp & 0x1; 700 return 0; 701 } 702 default: 703 return AE_ERROR; 704 } 705 status = WMI_execute_u32(method_id, 0, &result); 706 707 if (ACPI_SUCCESS(status)) 708 *value = (u8)result; 709 710 return status; 711 } 712 713 static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface) 714 { 715 u32 method_id = 0; 716 char param; 717 718 switch (cap) { 719 case ACER_CAP_BRIGHTNESS: 720 if (value > max_brightness) 721 return AE_BAD_PARAMETER; 722 method_id = ACER_WMID_SET_BRIGHTNESS_METHODID; 723 break; 724 case ACER_CAP_WIRELESS: 725 if (value > 1) 726 return AE_BAD_PARAMETER; 727 method_id = ACER_WMID_SET_WIRELESS_METHODID; 728 break; 729 case ACER_CAP_BLUETOOTH: 730 if (value > 1) 731 return AE_BAD_PARAMETER; 732 method_id = ACER_WMID_SET_BLUETOOTH_METHODID; 733 break; 734 case ACER_CAP_THREEG: 735 if (value > 1) 736 return AE_BAD_PARAMETER; 737 method_id = ACER_WMID_SET_THREEG_METHODID; 738 break; 739 case ACER_CAP_MAILLED: 740 if (value > 1) 741 return AE_BAD_PARAMETER; 742 if (quirks->mailled == 1) { 743 param = value ? 0x92 : 0x93; 744 i8042_lock_chip(); 745 i8042_command(¶m, 0x1059); 746 i8042_unlock_chip(); 747 return 0; 748 } 749 break; 750 default: 751 return AE_ERROR; 752 } 753 return WMI_execute_u32(method_id, (u32)value, NULL); 754 } 755 756 static acpi_status WMID_set_capabilities(void) 757 { 758 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; 759 union acpi_object *obj; 760 acpi_status status; 761 u32 devices; 762 763 status = wmi_query_block(WMID_GUID2, 1, &out); 764 if (ACPI_FAILURE(status)) 765 return status; 766 767 obj = (union acpi_object *) out.pointer; 768 if (obj && obj->type == ACPI_TYPE_BUFFER && 769 obj->buffer.length == sizeof(u32)) { 770 devices = *((u32 *) obj->buffer.pointer); 771 } else { 772 kfree(out.pointer); 773 return AE_ERROR; 774 } 775 776 /* Not sure on the meaning of the relevant bits yet to detect these */ 777 interface->capability |= ACER_CAP_WIRELESS; 778 interface->capability |= ACER_CAP_THREEG; 779 780 /* WMID always provides brightness methods */ 781 interface->capability |= ACER_CAP_BRIGHTNESS; 782 783 if (devices & 0x10) 784 interface->capability |= ACER_CAP_BLUETOOTH; 785 786 if (!(devices & 0x20)) 787 max_brightness = 0x9; 788 789 kfree(out.pointer); 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_properties props; 926 struct backlight_device *bd; 927 928 memset(&props, 0, sizeof(struct backlight_properties)); 929 props.max_brightness = max_brightness; 930 bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops, 931 &props); 932 if (IS_ERR(bd)) { 933 printk(ACER_ERR "Could not register Acer backlight device\n"); 934 acer_backlight_device = NULL; 935 return PTR_ERR(bd); 936 } 937 938 acer_backlight_device = bd; 939 940 bd->props.power = FB_BLANK_UNBLANK; 941 bd->props.brightness = read_brightness(bd); 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_IRUGO, show_interface, NULL); 1087 1088 /* 1089 * debugfs functions 1090 */ 1091 static u32 get_wmid_devices(void) 1092 { 1093 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; 1094 union acpi_object *obj; 1095 acpi_status status; 1096 u32 devices = 0; 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 devices = *((u32 *) obj->buffer.pointer); 1106 } 1107 1108 kfree(out.pointer); 1109 return devices; 1110 } 1111 1112 /* 1113 * Platform device 1114 */ 1115 static int __devinit acer_platform_probe(struct platform_device *device) 1116 { 1117 int err; 1118 1119 if (has_cap(ACER_CAP_MAILLED)) { 1120 err = acer_led_init(&device->dev); 1121 if (err) 1122 goto error_mailled; 1123 } 1124 1125 if (has_cap(ACER_CAP_BRIGHTNESS)) { 1126 err = acer_backlight_init(&device->dev); 1127 if (err) 1128 goto error_brightness; 1129 } 1130 1131 err = acer_rfkill_init(&device->dev); 1132 if (err) 1133 goto error_rfkill; 1134 1135 return err; 1136 1137 error_rfkill: 1138 if (has_cap(ACER_CAP_BRIGHTNESS)) 1139 acer_backlight_exit(); 1140 error_brightness: 1141 if (has_cap(ACER_CAP_MAILLED)) 1142 acer_led_exit(); 1143 error_mailled: 1144 return err; 1145 } 1146 1147 static int acer_platform_remove(struct platform_device *device) 1148 { 1149 if (has_cap(ACER_CAP_MAILLED)) 1150 acer_led_exit(); 1151 if (has_cap(ACER_CAP_BRIGHTNESS)) 1152 acer_backlight_exit(); 1153 1154 acer_rfkill_exit(); 1155 return 0; 1156 } 1157 1158 static int acer_platform_suspend(struct platform_device *dev, 1159 pm_message_t state) 1160 { 1161 u32 value; 1162 struct acer_data *data = &interface->data; 1163 1164 if (!data) 1165 return -ENOMEM; 1166 1167 if (has_cap(ACER_CAP_MAILLED)) { 1168 get_u32(&value, ACER_CAP_MAILLED); 1169 data->mailled = value; 1170 } 1171 1172 if (has_cap(ACER_CAP_BRIGHTNESS)) { 1173 get_u32(&value, ACER_CAP_BRIGHTNESS); 1174 data->brightness = value; 1175 } 1176 1177 return 0; 1178 } 1179 1180 static int acer_platform_resume(struct platform_device *device) 1181 { 1182 struct acer_data *data = &interface->data; 1183 1184 if (!data) 1185 return -ENOMEM; 1186 1187 if (has_cap(ACER_CAP_MAILLED)) 1188 set_u32(data->mailled, ACER_CAP_MAILLED); 1189 1190 if (has_cap(ACER_CAP_BRIGHTNESS)) 1191 set_u32(data->brightness, ACER_CAP_BRIGHTNESS); 1192 1193 return 0; 1194 } 1195 1196 static struct platform_driver acer_platform_driver = { 1197 .driver = { 1198 .name = "acer-wmi", 1199 .owner = THIS_MODULE, 1200 }, 1201 .probe = acer_platform_probe, 1202 .remove = acer_platform_remove, 1203 .suspend = acer_platform_suspend, 1204 .resume = acer_platform_resume, 1205 }; 1206 1207 static struct platform_device *acer_platform_device; 1208 1209 static int remove_sysfs(struct platform_device *device) 1210 { 1211 if (has_cap(ACER_CAP_THREEG)) 1212 device_remove_file(&device->dev, &dev_attr_threeg); 1213 1214 device_remove_file(&device->dev, &dev_attr_interface); 1215 1216 return 0; 1217 } 1218 1219 static int create_sysfs(void) 1220 { 1221 int retval = -ENOMEM; 1222 1223 if (has_cap(ACER_CAP_THREEG)) { 1224 retval = device_create_file(&acer_platform_device->dev, 1225 &dev_attr_threeg); 1226 if (retval) 1227 goto error_sysfs; 1228 } 1229 1230 retval = device_create_file(&acer_platform_device->dev, 1231 &dev_attr_interface); 1232 if (retval) 1233 goto error_sysfs; 1234 1235 return 0; 1236 1237 error_sysfs: 1238 remove_sysfs(acer_platform_device); 1239 return retval; 1240 } 1241 1242 static void remove_debugfs(void) 1243 { 1244 debugfs_remove(interface->debug.devices); 1245 debugfs_remove(interface->debug.root); 1246 } 1247 1248 static int create_debugfs(void) 1249 { 1250 interface->debug.root = debugfs_create_dir("acer-wmi", NULL); 1251 if (!interface->debug.root) { 1252 printk(ACER_ERR "Failed to create debugfs directory"); 1253 return -ENOMEM; 1254 } 1255 1256 interface->debug.devices = debugfs_create_u32("devices", S_IRUGO, 1257 interface->debug.root, 1258 &interface->debug.wmid_devices); 1259 if (!interface->debug.devices) 1260 goto error_debugfs; 1261 1262 return 0; 1263 1264 error_debugfs: 1265 remove_debugfs(); 1266 return -ENOMEM; 1267 } 1268 1269 static int __init acer_wmi_init(void) 1270 { 1271 int err; 1272 1273 printk(ACER_INFO "Acer Laptop ACPI-WMI Extras\n"); 1274 1275 if (dmi_check_system(acer_blacklist)) { 1276 printk(ACER_INFO "Blacklisted hardware detected - " 1277 "not loading\n"); 1278 return -ENODEV; 1279 } 1280 1281 find_quirks(); 1282 1283 /* 1284 * Detect which ACPI-WMI interface we're using. 1285 */ 1286 if (wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1)) 1287 interface = &AMW0_V2_interface; 1288 1289 if (!wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1)) 1290 interface = &wmid_interface; 1291 1292 if (wmi_has_guid(WMID_GUID2) && interface) { 1293 if (ACPI_FAILURE(WMID_set_capabilities())) { 1294 printk(ACER_ERR "Unable to detect available WMID " 1295 "devices\n"); 1296 return -ENODEV; 1297 } 1298 } else if (!wmi_has_guid(WMID_GUID2) && interface) { 1299 printk(ACER_ERR "No WMID device detection method found\n"); 1300 return -ENODEV; 1301 } 1302 1303 if (wmi_has_guid(AMW0_GUID1) && !wmi_has_guid(WMID_GUID1)) { 1304 interface = &AMW0_interface; 1305 1306 if (ACPI_FAILURE(AMW0_set_capabilities())) { 1307 printk(ACER_ERR "Unable to detect available AMW0 " 1308 "devices\n"); 1309 return -ENODEV; 1310 } 1311 } 1312 1313 if (wmi_has_guid(AMW0_GUID1)) 1314 AMW0_find_mailled(); 1315 1316 if (!interface) { 1317 printk(ACER_INFO "No or unsupported WMI interface, unable to " 1318 "load\n"); 1319 return -ENODEV; 1320 } 1321 1322 set_quirks(); 1323 1324 if (acpi_video_backlight_support() && has_cap(ACER_CAP_BRIGHTNESS)) { 1325 interface->capability &= ~ACER_CAP_BRIGHTNESS; 1326 printk(ACER_INFO "Brightness must be controlled by " 1327 "generic video driver\n"); 1328 } 1329 1330 err = platform_driver_register(&acer_platform_driver); 1331 if (err) { 1332 printk(ACER_ERR "Unable to register platform driver.\n"); 1333 goto error_platform_register; 1334 } 1335 1336 acer_platform_device = platform_device_alloc("acer-wmi", -1); 1337 if (!acer_platform_device) { 1338 err = -ENOMEM; 1339 goto error_device_alloc; 1340 } 1341 1342 err = platform_device_add(acer_platform_device); 1343 if (err) 1344 goto error_device_add; 1345 1346 err = create_sysfs(); 1347 if (err) 1348 goto error_create_sys; 1349 1350 if (wmi_has_guid(WMID_GUID2)) { 1351 interface->debug.wmid_devices = get_wmid_devices(); 1352 err = create_debugfs(); 1353 if (err) 1354 goto error_create_debugfs; 1355 } 1356 1357 /* Override any initial settings with values from the commandline */ 1358 acer_commandline_init(); 1359 1360 return 0; 1361 1362 error_create_debugfs: 1363 remove_sysfs(acer_platform_device); 1364 error_create_sys: 1365 platform_device_del(acer_platform_device); 1366 error_device_add: 1367 platform_device_put(acer_platform_device); 1368 error_device_alloc: 1369 platform_driver_unregister(&acer_platform_driver); 1370 error_platform_register: 1371 return err; 1372 } 1373 1374 static void __exit acer_wmi_exit(void) 1375 { 1376 remove_sysfs(acer_platform_device); 1377 remove_debugfs(); 1378 platform_device_unregister(acer_platform_device); 1379 platform_driver_unregister(&acer_platform_driver); 1380 1381 printk(ACER_INFO "Acer Laptop WMI Extras unloaded\n"); 1382 return; 1383 } 1384 1385 module_init(acer_wmi_init); 1386 module_exit(acer_wmi_exit); 1387