asus-laptop.c revision be4ee82d3e44c5940a7f77cae5ed3e942e80a723
1/* 2 * asus-laptop.c - Asus Laptop Support 3 * 4 * 5 * Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor 6 * Copyright (C) 2006-2007 Corentin Chary 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * 22 * 23 * The development page for this driver is located at 24 * http://sourceforge.net/projects/acpi4asus/ 25 * 26 * Credits: 27 * Pontus Fuchs - Helper functions, cleanup 28 * Johann Wiesner - Small compile fixes 29 * John Belmonte - ACPI code for Toshiba laptop was a good starting point. 30 * Eric Burghard - LED display support for W1N 31 * Josh Green - Light Sens support 32 * Thomas Tuttle - His first patch for led support was very helpfull 33 * Sam Lin - GPS support 34 */ 35 36#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 37 38#include <linux/kernel.h> 39#include <linux/module.h> 40#include <linux/init.h> 41#include <linux/types.h> 42#include <linux/err.h> 43#include <linux/proc_fs.h> 44#include <linux/backlight.h> 45#include <linux/fb.h> 46#include <linux/leds.h> 47#include <linux/platform_device.h> 48#include <acpi/acpi_drivers.h> 49#include <acpi/acpi_bus.h> 50#include <asm/uaccess.h> 51#include <linux/input.h> 52 53#define ASUS_LAPTOP_VERSION "0.42" 54 55#define ASUS_LAPTOP_NAME "Asus Laptop Support" 56#define ASUS_LAPTOP_CLASS "hotkey" 57#define ASUS_LAPTOP_DEVICE_NAME "Hotkey" 58#define ASUS_LAPTOP_FILE KBUILD_MODNAME 59#define ASUS_LAPTOP_PREFIX "\\_SB.ATKD." 60 61MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary"); 62MODULE_DESCRIPTION(ASUS_LAPTOP_NAME); 63MODULE_LICENSE("GPL"); 64 65/* 66 * WAPF defines the behavior of the Fn+Fx wlan key 67 * The significance of values is yet to be found, but 68 * most of the time: 69 * 0x0 will do nothing 70 * 0x1 will allow to control the device with Fn+Fx key. 71 * 0x4 will send an ACPI event (0x88) while pressing the Fn+Fx key 72 * 0x5 like 0x1 or 0x4 73 * So, if something doesn't work as you want, just try other values =) 74 */ 75static uint wapf = 1; 76module_param(wapf, uint, 0644); 77MODULE_PARM_DESC(wapf, "WAPF value"); 78 79static uint wireless_status = 1; 80static uint bluetooth_status = 1; 81 82module_param(wireless_status, uint, 0644); 83MODULE_PARM_DESC(wireless_status, "Set the wireless status on boot " 84 "(0 = disabled, 1 = enabled, -1 = don't do anything). " 85 "default is 1"); 86 87module_param(bluetooth_status, uint, 0644); 88MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot " 89 "(0 = disabled, 1 = enabled, -1 = don't do anything). " 90 "default is 1"); 91 92/* 93 * Some events we use, same for all Asus 94 */ 95#define ATKD_BR_UP 0x10 96#define ATKD_BR_DOWN 0x20 97#define ATKD_LCD_ON 0x33 98#define ATKD_LCD_OFF 0x34 99 100/* 101 * Known bits returned by \_SB.ATKD.HWRS 102 */ 103#define WL_HWRS 0x80 104#define BT_HWRS 0x100 105 106/* 107 * Flags for hotk status 108 * WL_ON and BT_ON are also used for wireless_status() 109 */ 110#define WL_ON 0x01 /* internal Wifi */ 111#define BT_ON 0x02 /* internal Bluetooth */ 112#define MLED_ON 0x04 /* mail LED */ 113#define TLED_ON 0x08 /* touchpad LED */ 114#define RLED_ON 0x10 /* Record LED */ 115#define PLED_ON 0x20 /* Phone LED */ 116#define GLED_ON 0x40 /* Gaming LED */ 117#define LCD_ON 0x80 /* LCD backlight */ 118#define GPS_ON 0x100 /* GPS */ 119#define KEY_ON 0x200 /* Keyboard backlight */ 120 121#define ASUS_HANDLE(object, paths...) \ 122 static acpi_handle object##_handle = NULL; \ 123 static char *object##_paths[] = { paths } 124 125/* LED */ 126ASUS_HANDLE(mled_set, ASUS_LAPTOP_PREFIX "MLED"); 127ASUS_HANDLE(tled_set, ASUS_LAPTOP_PREFIX "TLED"); 128ASUS_HANDLE(rled_set, ASUS_LAPTOP_PREFIX "RLED"); /* W1JC */ 129ASUS_HANDLE(pled_set, ASUS_LAPTOP_PREFIX "PLED"); /* A7J */ 130ASUS_HANDLE(gled_set, ASUS_LAPTOP_PREFIX "GLED"); /* G1, G2 (probably) */ 131 132/* LEDD */ 133ASUS_HANDLE(ledd_set, ASUS_LAPTOP_PREFIX "SLCM"); 134 135/* 136 * Bluetooth and WLAN 137 * WLED and BLED are not handled like other XLED, because in some dsdt 138 * they also control the WLAN/Bluetooth device. 139 */ 140ASUS_HANDLE(wl_switch, ASUS_LAPTOP_PREFIX "WLED"); 141ASUS_HANDLE(bt_switch, ASUS_LAPTOP_PREFIX "BLED"); 142ASUS_HANDLE(wireless_status, ASUS_LAPTOP_PREFIX "RSTS"); /* All new models */ 143 144/* Brightness */ 145ASUS_HANDLE(brightness_set, ASUS_LAPTOP_PREFIX "SPLV"); 146ASUS_HANDLE(brightness_get, ASUS_LAPTOP_PREFIX "GPLV"); 147 148/* Backlight */ 149ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */ 150 "\\_SB.PCI0.ISA.EC0._Q10", /* A1x */ 151 "\\_SB.PCI0.PX40.ECD0._Q10", /* L3C */ 152 "\\_SB.PCI0.PX40.EC0.Q10", /* M1A */ 153 "\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */ 154 "\\_SB.PCI0.LPCB.EC0._Q0E", /* P30/P35 */ 155 "\\_SB.PCI0.PX40.Q10", /* S1x */ 156 "\\Q10"); /* A2x, L2D, L3D, M2E */ 157 158/* Display */ 159ASUS_HANDLE(display_set, ASUS_LAPTOP_PREFIX "SDSP"); 160ASUS_HANDLE(display_get, 161 /* A6B, A6K A6R A7D F3JM L4R M6R A3G M6A M6V VX-1 V6J V6V W3Z */ 162 "\\_SB.PCI0.P0P1.VGA.GETD", 163 /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V S5A M5A z33A W1Jc W2V G1 */ 164 "\\_SB.PCI0.P0P2.VGA.GETD", 165 /* A6V A6Q */ 166 "\\_SB.PCI0.P0P3.VGA.GETD", 167 /* A6T, A6M */ 168 "\\_SB.PCI0.P0PA.VGA.GETD", 169 /* L3C */ 170 "\\_SB.PCI0.PCI1.VGAC.NMAP", 171 /* Z96F */ 172 "\\_SB.PCI0.VGA.GETD", 173 /* A2D */ 174 "\\ACTD", 175 /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */ 176 "\\ADVG", 177 /* P30 */ 178 "\\DNXT", 179 /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */ 180 "\\INFB", 181 /* A3F A6F A3N A3L M6N W3N W6A */ 182 "\\SSTE"); 183 184ASUS_HANDLE(ls_switch, ASUS_LAPTOP_PREFIX "ALSC"); /* Z71A Z71V */ 185ASUS_HANDLE(ls_level, ASUS_LAPTOP_PREFIX "ALSL"); /* Z71A Z71V */ 186 187/* GPS */ 188/* R2H use different handle for GPS on/off */ 189ASUS_HANDLE(gps_on, ASUS_LAPTOP_PREFIX "SDON"); /* R2H */ 190ASUS_HANDLE(gps_off, ASUS_LAPTOP_PREFIX "SDOF"); /* R2H */ 191ASUS_HANDLE(gps_status, ASUS_LAPTOP_PREFIX "GPST"); 192 193/* Keyboard light */ 194ASUS_HANDLE(kled_set, ASUS_LAPTOP_PREFIX "SLKB"); 195ASUS_HANDLE(kled_get, ASUS_LAPTOP_PREFIX "GLKB"); 196 197/* 198 * Define a specific led structure to keep the main structure clean 199 */ 200#define ASUS_DEFINE_LED(object) \ 201 int object##_wk; \ 202 struct work_struct object##_work; \ 203 struct led_classdev object; 204 205 206#define led_to_asus(led_cdev, led) \ 207 container_of(container_of(led_cdev, struct asus_laptop_leds, \ 208 led), \ 209 struct asus_laptop, leds) 210#define work_to_asus(work, led) \ 211 container_of(container_of(work, struct asus_laptop_leds, \ 212 led##_work), \ 213 struct asus_laptop, leds) 214 215struct asus_laptop_leds { 216 ASUS_DEFINE_LED(mled) 217 ASUS_DEFINE_LED(tled) 218 ASUS_DEFINE_LED(rled) 219 ASUS_DEFINE_LED(pled) 220 ASUS_DEFINE_LED(gled) 221 ASUS_DEFINE_LED(kled) 222 struct workqueue_struct *workqueue; 223}; 224 225/* 226 * This is the main structure, we can use it to store anything interesting 227 * about the hotk device 228 */ 229struct asus_laptop { 230 char *name; /* laptop name */ 231 232 struct acpi_table_header *dsdt_info; 233 struct platform_device *platform_device; 234 struct acpi_device *device; /* the device we are in */ 235 struct backlight_device *backlight_device; 236 237 struct input_dev *inputdev; 238 struct key_entry *keymap; 239 240 struct asus_laptop_leds leds; 241 242 acpi_handle handle; /* the handle of the hotk device */ 243 char status; /* status of the hotk, for LEDs, ... */ 244 u32 ledd_status; /* status of the LED display */ 245 u8 light_level; /* light sensor level */ 246 u8 light_switch; /* light sensor switch value */ 247 u16 event_count[128]; /* count for each event TODO make this better */ 248 u16 *keycode_map; 249}; 250 251struct key_entry { 252 char type; 253 u8 code; 254 u16 keycode; 255}; 256 257enum { KE_KEY, KE_END }; 258 259static const struct key_entry asus_keymap[] = { 260 {KE_KEY, 0x02, KEY_SCREENLOCK}, 261 {KE_KEY, 0x05, KEY_WLAN}, 262 {KE_KEY, 0x08, KEY_F13}, 263 {KE_KEY, 0x17, KEY_ZOOM}, 264 {KE_KEY, 0x1f, KEY_BATTERY}, 265 {KE_KEY, 0x30, KEY_VOLUMEUP}, 266 {KE_KEY, 0x31, KEY_VOLUMEDOWN}, 267 {KE_KEY, 0x32, KEY_MUTE}, 268 {KE_KEY, 0x33, KEY_SWITCHVIDEOMODE}, 269 {KE_KEY, 0x34, KEY_SWITCHVIDEOMODE}, 270 {KE_KEY, 0x40, KEY_PREVIOUSSONG}, 271 {KE_KEY, 0x41, KEY_NEXTSONG}, 272 {KE_KEY, 0x43, KEY_STOPCD}, 273 {KE_KEY, 0x45, KEY_PLAYPAUSE}, 274 {KE_KEY, 0x4c, KEY_MEDIA}, 275 {KE_KEY, 0x50, KEY_EMAIL}, 276 {KE_KEY, 0x51, KEY_WWW}, 277 {KE_KEY, 0x55, KEY_CALC}, 278 {KE_KEY, 0x5C, KEY_SCREENLOCK}, /* Screenlock */ 279 {KE_KEY, 0x5D, KEY_WLAN}, 280 {KE_KEY, 0x5E, KEY_WLAN}, 281 {KE_KEY, 0x5F, KEY_WLAN}, 282 {KE_KEY, 0x60, KEY_SWITCHVIDEOMODE}, 283 {KE_KEY, 0x61, KEY_SWITCHVIDEOMODE}, 284 {KE_KEY, 0x62, KEY_SWITCHVIDEOMODE}, 285 {KE_KEY, 0x63, KEY_SWITCHVIDEOMODE}, 286 {KE_KEY, 0x6B, KEY_F13}, /* Lock Touchpad */ 287 {KE_KEY, 0x82, KEY_CAMERA}, 288 {KE_KEY, 0x88, KEY_WLAN }, 289 {KE_KEY, 0x8A, KEY_PROG1}, 290 {KE_KEY, 0x95, KEY_MEDIA}, 291 {KE_KEY, 0x99, KEY_PHONE}, 292 {KE_KEY, 0xc4, KEY_KBDILLUMUP}, 293 {KE_KEY, 0xc5, KEY_KBDILLUMDOWN}, 294 {KE_END, 0}, 295}; 296 297/* 298 * This function evaluates an ACPI method, given an int as parameter, the 299 * method is searched within the scope of the handle, can be NULL. The output 300 * of the method is written is output, which can also be NULL 301 * 302 * returns 0 if write is successful, -1 else. 303 */ 304static int write_acpi_int_ret(acpi_handle handle, const char *method, int val, 305 struct acpi_buffer *output) 306{ 307 struct acpi_object_list params; /* list of input parameters (an int) */ 308 union acpi_object in_obj; /* the only param we use */ 309 acpi_status status; 310 311 if (!handle) 312 return 0; 313 314 params.count = 1; 315 params.pointer = &in_obj; 316 in_obj.type = ACPI_TYPE_INTEGER; 317 in_obj.integer.value = val; 318 319 status = acpi_evaluate_object(handle, (char *)method, ¶ms, output); 320 if (status == AE_OK) 321 return 0; 322 else 323 return -1; 324} 325 326static int write_acpi_int(acpi_handle handle, const char *method, int val) 327{ 328 return write_acpi_int_ret(handle, method, val, NULL); 329} 330 331static int read_wireless_status(struct asus_laptop *asus, int mask) 332{ 333 unsigned long long status; 334 acpi_status rv = AE_OK; 335 336 if (!wireless_status_handle) 337 return (asus->status & mask) ? 1 : 0; 338 339 rv = acpi_evaluate_integer(wireless_status_handle, NULL, NULL, &status); 340 if (ACPI_FAILURE(rv)) 341 pr_warning("Error reading Wireless status\n"); 342 else 343 return (status & mask) ? 1 : 0; 344 345 return (asus->status & mask) ? 1 : 0; 346} 347 348static int read_gps_status(struct asus_laptop *asus) 349{ 350 unsigned long long status; 351 acpi_status rv = AE_OK; 352 353 rv = acpi_evaluate_integer(gps_status_handle, NULL, NULL, &status); 354 if (ACPI_FAILURE(rv)) 355 pr_warning("Error reading GPS status\n"); 356 else 357 return status ? 1 : 0; 358 359 return (asus->status & GPS_ON) ? 1 : 0; 360} 361 362/* Generic LED functions */ 363static int read_status(struct asus_laptop *asus, int mask) 364{ 365 /* There is a special method for both wireless devices */ 366 if (mask == BT_ON || mask == WL_ON) 367 return read_wireless_status(asus, mask); 368 else if (mask == GPS_ON) 369 return read_gps_status(asus); 370 371 return (asus->status & mask) ? 1 : 0; 372} 373 374static void write_status(struct asus_laptop *asus, acpi_handle handle, 375 int out, int mask) 376{ 377 asus->status = (out) ? (asus->status | mask) : (asus->status & ~mask); 378 379 switch (mask) { 380 case MLED_ON: 381 out = !(out & 0x1); 382 break; 383 case GLED_ON: 384 out = (out & 0x1) + 1; 385 break; 386 case GPS_ON: 387 handle = (out) ? gps_on_handle : gps_off_handle; 388 out = 0x02; 389 break; 390 default: 391 out &= 0x1; 392 break; 393 } 394 395 if (write_acpi_int(handle, NULL, out)) 396 pr_warning(" write failed %x\n", mask); 397} 398 399/* 400 * LEDs 401 */ 402#define ASUS_LED(object, ledname, max) \ 403 static void object##_led_set(struct led_classdev *led_cdev, \ 404 enum led_brightness value); \ 405 static enum led_brightness object##_led_get( \ 406 struct led_classdev *led_cdev); \ 407 static void object##_led_update(struct work_struct *ignored); \ 408 static struct led_classdev object##_led = { \ 409 .name = "asus::" ledname, \ 410 .brightness_set = object##_led_set, \ 411 .brightness_get = object##_led_get, \ 412 .max_brightness = max \ 413 } 414 415ASUS_LED(mled, "mail", 1); 416ASUS_LED(tled, "touchpad", 1); 417ASUS_LED(rled, "record", 1); 418ASUS_LED(pled, "phone", 1); 419ASUS_LED(gled, "gaming", 1); 420ASUS_LED(kled, "kbd_backlight", 3); 421 422/* /sys/class/led handlers */ 423#define ASUS_LED_HANDLER(object, mask) \ 424 static void object##_led_set(struct led_classdev *led_cdev, \ 425 enum led_brightness value) \ 426 { \ 427 struct asus_laptop *asus = \ 428 led_to_asus(led_cdev, object); \ 429 \ 430 asus->leds.object##_wk = (value > 0) ? 1 : 0; \ 431 queue_work(asus->leds.workqueue, \ 432 &asus->leds.object##_work); \ 433 } \ 434 static void object##_led_update(struct work_struct *work) \ 435 { \ 436 struct asus_laptop *asus = work_to_asus(work, object); \ 437 \ 438 int value = asus->leds.object##_wk; \ 439 write_status(asus, object##_set_handle, value, (mask)); \ 440 } \ 441 static enum led_brightness object##_led_get( \ 442 struct led_classdev *led_cdev) \ 443 { \ 444 return led_cdev->brightness; \ 445 } 446 447ASUS_LED_HANDLER(mled, MLED_ON); 448ASUS_LED_HANDLER(pled, PLED_ON); 449ASUS_LED_HANDLER(rled, RLED_ON); 450ASUS_LED_HANDLER(tled, TLED_ON); 451ASUS_LED_HANDLER(gled, GLED_ON); 452 453/* 454 * Keyboard backlight (also a LED) 455 */ 456static int get_kled_lvl(void) 457{ 458 unsigned long long kblv; 459 struct acpi_object_list params; 460 union acpi_object in_obj; 461 acpi_status rv; 462 463 params.count = 1; 464 params.pointer = &in_obj; 465 in_obj.type = ACPI_TYPE_INTEGER; 466 in_obj.integer.value = 2; 467 468 rv = acpi_evaluate_integer(kled_get_handle, NULL, ¶ms, &kblv); 469 if (ACPI_FAILURE(rv)) { 470 pr_warning("Error reading kled level\n"); 471 return 0; 472 } 473 return kblv; 474} 475 476static int set_kled_lvl(struct asus_laptop *asus, int kblv) 477{ 478 if (kblv > 0) 479 kblv = (1 << 7) | (kblv & 0x7F); 480 else 481 kblv = 0; 482 483 if (write_acpi_int(kled_set_handle, NULL, kblv)) { 484 pr_warning("Keyboard LED display write failed\n"); 485 return -EINVAL; 486 } 487 return 0; 488} 489 490static void kled_led_set(struct led_classdev *led_cdev, 491 enum led_brightness value) 492{ 493 struct asus_laptop *asus = led_to_asus(led_cdev, kled); 494 495 asus->leds.kled_wk = value; 496 queue_work(asus->leds.workqueue, &asus->leds.kled_work); 497} 498 499static void kled_led_update(struct work_struct *work) 500{ 501 struct asus_laptop *asus = work_to_asus(work, kled); 502 503 set_kled_lvl(asus, asus->leds.kled_wk); 504} 505 506static enum led_brightness kled_led_get(struct led_classdev *led_cdev) 507{ 508 return get_kled_lvl(); 509} 510 511#define ASUS_LED_UNREGISTER(object) \ 512 if (object##_led.dev) \ 513 led_classdev_unregister(&object##_led) 514 515static void asus_led_exit(struct asus_laptop *asus) 516{ 517 ASUS_LED_UNREGISTER(mled); 518 ASUS_LED_UNREGISTER(tled); 519 ASUS_LED_UNREGISTER(pled); 520 ASUS_LED_UNREGISTER(rled); 521 ASUS_LED_UNREGISTER(gled); 522 ASUS_LED_UNREGISTER(kled); 523 if (asus->leds.workqueue) { 524 destroy_workqueue(asus->leds.workqueue); 525 asus->leds.workqueue = NULL; 526 } 527} 528 529/* Ugly macro, need to fix that later */ 530#define ASUS_LED_REGISTER(asus, object, _name, max) \ 531 do { \ 532 struct led_classdev *ldev = &asus->leds.object; \ 533 if (!object##_set_handle) \ 534 break ; \ 535 \ 536 INIT_WORK(&asus->leds.object##_work, object##_led_update); \ 537 ldev->name = "asus::" _name; \ 538 ldev->brightness_set = object##_led_set; \ 539 ldev->max_brightness = max; \ 540 rv = led_classdev_register(&asus->platform_device->dev, ldev); \ 541 if (rv) \ 542 goto error; \ 543 } while (0) 544 545static int asus_led_init(struct asus_laptop *asus) 546{ 547 int rv; 548 549 /* 550 * Functions that actually update the LED's are called from a 551 * workqueue. By doing this as separate work rather than when the LED 552 * subsystem asks, we avoid messing with the Asus ACPI stuff during a 553 * potentially bad time, such as a timer interrupt. 554 */ 555 asus->leds.workqueue = create_singlethread_workqueue("led_workqueue"); 556 if (!asus->leds.workqueue) 557 return -ENOMEM; 558 559 ASUS_LED_REGISTER(asus, mled, "mail", 1); 560 ASUS_LED_REGISTER(asus, tled, "touchpad", 1); 561 ASUS_LED_REGISTER(asus, rled, "record", 1); 562 ASUS_LED_REGISTER(asus, pled, "phone", 1); 563 ASUS_LED_REGISTER(asus, gled, "gaming", 1); 564 if (kled_set_handle && kled_get_handle) 565 ASUS_LED_REGISTER(asus, kled, "kbd_backlight", 3); 566error: 567 if (rv) 568 asus_led_exit(asus); 569 return rv; 570} 571 572/* 573 * Backlight device 574 */ 575static int get_lcd_state(struct asus_laptop *asus) 576{ 577 return read_status(asus, LCD_ON); 578} 579 580static int set_lcd_state(struct asus_laptop *asus, int value) 581{ 582 int lcd = 0; 583 acpi_status status = 0; 584 585 lcd = value ? 1 : 0; 586 587 if (lcd == get_lcd_state(asus)) 588 return 0; 589 590 if (lcd_switch_handle) { 591 status = acpi_evaluate_object(lcd_switch_handle, 592 NULL, NULL, NULL); 593 594 if (ACPI_FAILURE(status)) 595 pr_warning("Error switching LCD\n"); 596 } 597 598 write_status(asus, NULL, lcd, LCD_ON); 599 return 0; 600} 601 602static void lcd_blank(struct asus_laptop *asus, int blank) 603{ 604 struct backlight_device *bd = asus->backlight_device; 605 606 if (bd) { 607 bd->props.power = blank; 608 backlight_update_status(bd); 609 } 610} 611 612static int read_brightness(struct backlight_device *bd) 613{ 614 unsigned long long value; 615 acpi_status rv = AE_OK; 616 617 rv = acpi_evaluate_integer(brightness_get_handle, NULL, NULL, &value); 618 if (ACPI_FAILURE(rv)) 619 pr_warning("Error reading brightness\n"); 620 621 return value; 622} 623 624static int set_brightness(struct backlight_device *bd, int value) 625{ 626 if (write_acpi_int(brightness_set_handle, NULL, value)) { 627 pr_warning("Error changing brightness\n"); 628 return -EIO; 629 } 630 return 0; 631} 632 633static int update_bl_status(struct backlight_device *bd) 634{ 635 struct asus_laptop *asus = bl_get_data(bd); 636 int rv; 637 int value = bd->props.brightness; 638 639 rv = set_brightness(bd, value); 640 if (rv) 641 return rv; 642 643 value = (bd->props.power == FB_BLANK_UNBLANK) ? 1 : 0; 644 return set_lcd_state(asus, value); 645} 646 647static struct backlight_ops asusbl_ops = { 648 .get_brightness = read_brightness, 649 .update_status = update_bl_status, 650}; 651 652static int asus_backlight_init(struct asus_laptop *asus) 653{ 654 struct backlight_device *bd; 655 struct device *dev = &asus->platform_device->dev; 656 657 if (brightness_set_handle && lcd_switch_handle) { 658 bd = backlight_device_register(ASUS_LAPTOP_FILE, dev, 659 asus, &asusbl_ops); 660 if (IS_ERR(bd)) { 661 pr_err("Could not register asus backlight device\n"); 662 asus->backlight_device = NULL; 663 return PTR_ERR(bd); 664 } 665 666 asus->backlight_device = bd; 667 668 bd->props.max_brightness = 15; 669 bd->props.brightness = read_brightness(NULL); 670 bd->props.power = FB_BLANK_UNBLANK; 671 backlight_update_status(bd); 672 } 673 return 0; 674} 675 676static void asus_backlight_exit(struct asus_laptop *asus) 677{ 678 if (asus->backlight_device) 679 backlight_device_unregister(asus->backlight_device); 680} 681 682/* 683 * Platform device handlers 684 */ 685 686/* 687 * We write our info in page, we begin at offset off and cannot write more 688 * than count bytes. We set eof to 1 if we handle those 2 values. We return the 689 * number of bytes written in page 690 */ 691static ssize_t show_infos(struct device *dev, 692 struct device_attribute *attr, char *page) 693{ 694 struct asus_laptop *asus = dev_get_drvdata(dev); 695 int len = 0; 696 unsigned long long temp; 697 char buf[16]; /* enough for all info */ 698 acpi_status rv = AE_OK; 699 700 /* 701 * We use the easy way, we don't care of off and count, so we don't set eof 702 * to 1 703 */ 704 705 len += sprintf(page, ASUS_LAPTOP_NAME " " ASUS_LAPTOP_VERSION "\n"); 706 len += sprintf(page + len, "Model reference : %s\n", asus->name); 707 /* 708 * The SFUN method probably allows the original driver to get the list 709 * of features supported by a given model. For now, 0x0100 or 0x0800 710 * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card. 711 * The significance of others is yet to be found. 712 */ 713 rv = acpi_evaluate_integer(asus->handle, "SFUN", NULL, &temp); 714 if (!ACPI_FAILURE(rv)) 715 len += sprintf(page + len, "SFUN value : %#x\n", 716 (uint) temp); 717 /* 718 * The HWRS method return informations about the hardware. 719 * 0x80 bit is for WLAN, 0x100 for Bluetooth. 720 * The significance of others is yet to be found. 721 * If we don't find the method, we assume the device are present. 722 */ 723 rv = acpi_evaluate_integer(asus->handle, "HRWS", NULL, &temp); 724 if (!ACPI_FAILURE(rv)) 725 len += sprintf(page + len, "HRWS value : %#x\n", 726 (uint) temp); 727 /* 728 * Another value for userspace: the ASYM method returns 0x02 for 729 * battery low and 0x04 for battery critical, its readings tend to be 730 * more accurate than those provided by _BST. 731 * Note: since not all the laptops provide this method, errors are 732 * silently ignored. 733 */ 734 rv = acpi_evaluate_integer(asus->handle, "ASYM", NULL, &temp); 735 if (!ACPI_FAILURE(rv)) 736 len += sprintf(page + len, "ASYM value : %#x\n", 737 (uint) temp); 738 if (asus->dsdt_info) { 739 snprintf(buf, 16, "%d", asus->dsdt_info->length); 740 len += sprintf(page + len, "DSDT length : %s\n", buf); 741 snprintf(buf, 16, "%d", asus->dsdt_info->checksum); 742 len += sprintf(page + len, "DSDT checksum : %s\n", buf); 743 snprintf(buf, 16, "%d", asus->dsdt_info->revision); 744 len += sprintf(page + len, "DSDT revision : %s\n", buf); 745 snprintf(buf, 7, "%s", asus->dsdt_info->oem_id); 746 len += sprintf(page + len, "OEM id : %s\n", buf); 747 snprintf(buf, 9, "%s", asus->dsdt_info->oem_table_id); 748 len += sprintf(page + len, "OEM table id : %s\n", buf); 749 snprintf(buf, 16, "%x", asus->dsdt_info->oem_revision); 750 len += sprintf(page + len, "OEM revision : 0x%s\n", buf); 751 snprintf(buf, 5, "%s", asus->dsdt_info->asl_compiler_id); 752 len += sprintf(page + len, "ASL comp vendor id : %s\n", buf); 753 snprintf(buf, 16, "%x", asus->dsdt_info->asl_compiler_revision); 754 len += sprintf(page + len, "ASL comp revision : 0x%s\n", buf); 755 } 756 757 return len; 758} 759 760static int parse_arg(const char *buf, unsigned long count, int *val) 761{ 762 if (!count) 763 return 0; 764 if (count > 31) 765 return -EINVAL; 766 if (sscanf(buf, "%i", val) != 1) 767 return -EINVAL; 768 return count; 769} 770 771static ssize_t store_status(struct asus_laptop *asus, 772 const char *buf, size_t count, 773 acpi_handle handle, int mask) 774{ 775 int rv, value; 776 int out = 0; 777 778 rv = parse_arg(buf, count, &value); 779 if (rv > 0) 780 out = value ? 1 : 0; 781 782 write_status(asus, handle, out, mask); 783 784 return rv; 785} 786 787/* 788 * LEDD display 789 */ 790static ssize_t show_ledd(struct device *dev, 791 struct device_attribute *attr, char *buf) 792{ 793 struct asus_laptop *asus = dev_get_drvdata(dev); 794 795 return sprintf(buf, "0x%08x\n", asus->ledd_status); 796} 797 798static ssize_t store_ledd(struct device *dev, struct device_attribute *attr, 799 const char *buf, size_t count) 800{ 801 struct asus_laptop *asus = dev_get_drvdata(dev); 802 int rv, value; 803 804 rv = parse_arg(buf, count, &value); 805 if (rv > 0) { 806 if (write_acpi_int(ledd_set_handle, NULL, value)) 807 pr_warning("LED display write failed\n"); 808 else 809 asus->ledd_status = (u32) value; 810 } 811 return rv; 812} 813 814/* 815 * WLAN 816 */ 817static ssize_t show_wlan(struct device *dev, 818 struct device_attribute *attr, char *buf) 819{ 820 struct asus_laptop *asus = dev_get_drvdata(dev); 821 822 return sprintf(buf, "%d\n", read_status(asus, WL_ON)); 823} 824 825static ssize_t store_wlan(struct device *dev, struct device_attribute *attr, 826 const char *buf, size_t count) 827{ 828 struct asus_laptop *asus = dev_get_drvdata(dev); 829 830 return store_status(asus, buf, count, wl_switch_handle, WL_ON); 831} 832 833/* 834 * Bluetooth 835 */ 836static ssize_t show_bluetooth(struct device *dev, 837 struct device_attribute *attr, char *buf) 838{ 839 struct asus_laptop *asus = dev_get_drvdata(dev); 840 841 return sprintf(buf, "%d\n", read_status(asus, BT_ON)); 842} 843 844static ssize_t store_bluetooth(struct device *dev, 845 struct device_attribute *attr, const char *buf, 846 size_t count) 847{ 848 struct asus_laptop *asus = dev_get_drvdata(dev); 849 850 return store_status(asus, buf, count, bt_switch_handle, BT_ON); 851} 852 853/* 854 * Display 855 */ 856static void set_display(struct asus_laptop *asus, int value) 857{ 858 /* no sanity check needed for now */ 859 if (write_acpi_int(display_set_handle, NULL, value)) 860 pr_warning("Error setting display\n"); 861 return; 862} 863 864static int read_display(struct asus_laptop *asus) 865{ 866 unsigned long long value = 0; 867 acpi_status rv = AE_OK; 868 869 /* 870 * In most of the case, we know how to set the display, but sometime 871 * we can't read it 872 */ 873 if (display_get_handle) { 874 rv = acpi_evaluate_integer(display_get_handle, NULL, 875 NULL, &value); 876 if (ACPI_FAILURE(rv)) 877 pr_warning("Error reading display status\n"); 878 } 879 880 value &= 0x0F; /* needed for some models, shouldn't hurt others */ 881 882 return value; 883} 884 885/* 886 * Now, *this* one could be more user-friendly, but so far, no-one has 887 * complained. The significance of bits is the same as in store_disp() 888 */ 889static ssize_t show_disp(struct device *dev, 890 struct device_attribute *attr, char *buf) 891{ 892 struct asus_laptop *asus = dev_get_drvdata(dev); 893 894 return sprintf(buf, "%d\n", read_display(asus)); 895} 896 897/* 898 * Experimental support for display switching. As of now: 1 should activate 899 * the LCD output, 2 should do for CRT, 4 for TV-Out and 8 for DVI. 900 * Any combination (bitwise) of these will suffice. I never actually tested 4 901 * displays hooked up simultaneously, so be warned. See the acpi4asus README 902 * for more info. 903 */ 904static ssize_t store_disp(struct device *dev, struct device_attribute *attr, 905 const char *buf, size_t count) 906{ 907 struct asus_laptop *asus = dev_get_drvdata(dev); 908 int rv, value; 909 910 rv = parse_arg(buf, count, &value); 911 if (rv > 0) 912 set_display(asus, value); 913 return rv; 914} 915 916/* 917 * Light Sens 918 */ 919static void set_light_sens_switch(struct asus_laptop *asus, int value) 920{ 921 if (write_acpi_int(ls_switch_handle, NULL, value)) 922 pr_warning("Error setting light sensor switch\n"); 923 asus->light_switch = value; 924} 925 926static ssize_t show_lssw(struct device *dev, 927 struct device_attribute *attr, char *buf) 928{ 929 struct asus_laptop *asus = dev_get_drvdata(dev); 930 931 return sprintf(buf, "%d\n", asus->light_switch); 932} 933 934static ssize_t store_lssw(struct device *dev, struct device_attribute *attr, 935 const char *buf, size_t count) 936{ 937 struct asus_laptop *asus = dev_get_drvdata(dev); 938 int rv, value; 939 940 rv = parse_arg(buf, count, &value); 941 if (rv > 0) 942 set_light_sens_switch(asus, value ? 1 : 0); 943 944 return rv; 945} 946 947static void set_light_sens_level(struct asus_laptop *asus, int value) 948{ 949 if (write_acpi_int(ls_level_handle, NULL, value)) 950 pr_warning("Error setting light sensor level\n"); 951 asus->light_level = value; 952} 953 954static ssize_t show_lslvl(struct device *dev, 955 struct device_attribute *attr, char *buf) 956{ 957 struct asus_laptop *asus = dev_get_drvdata(dev); 958 959 return sprintf(buf, "%d\n", asus->light_level); 960} 961 962static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr, 963 const char *buf, size_t count) 964{ 965 struct asus_laptop *asus = dev_get_drvdata(dev); 966 int rv, value; 967 968 rv = parse_arg(buf, count, &value); 969 if (rv > 0) { 970 value = (0 < value) ? ((15 < value) ? 15 : value) : 0; 971 /* 0 <= value <= 15 */ 972 set_light_sens_level(asus, value); 973 } 974 975 return rv; 976} 977 978/* 979 * GPS 980 */ 981static ssize_t show_gps(struct device *dev, 982 struct device_attribute *attr, char *buf) 983{ 984 struct asus_laptop *asus = dev_get_drvdata(dev); 985 986 return sprintf(buf, "%d\n", read_status(asus, GPS_ON)); 987} 988 989static ssize_t store_gps(struct device *dev, struct device_attribute *attr, 990 const char *buf, size_t count) 991{ 992 struct asus_laptop *asus = dev_get_drvdata(dev); 993 994 return store_status(asus, buf, count, NULL, GPS_ON); 995} 996 997/* 998 * Input device (i.e. hotkeys) 999 */ 1000static struct key_entry *asus_get_entry_by_scancode(struct asus_laptop *asus, 1001 int code) 1002{ 1003 struct key_entry *key; 1004 1005 for (key = asus->keymap; key->type != KE_END; key++) 1006 if (code == key->code) 1007 return key; 1008 1009 return NULL; 1010} 1011 1012static struct key_entry *asus_get_entry_by_keycode(struct asus_laptop *asus, 1013 int code) 1014{ 1015 struct key_entry *key; 1016 1017 for (key = asus->keymap; key->type != KE_END; key++) 1018 if (code == key->keycode && key->type == KE_KEY) 1019 return key; 1020 1021 return NULL; 1022} 1023 1024static int asus_getkeycode(struct input_dev *dev, int scancode, int *keycode) 1025{ 1026 struct asus_laptop *asus = input_get_drvdata(dev); 1027 struct key_entry *key = asus_get_entry_by_scancode(asus, scancode); 1028 1029 if (key && key->type == KE_KEY) { 1030 *keycode = key->keycode; 1031 return 0; 1032 } 1033 1034 return -EINVAL; 1035} 1036 1037static int asus_setkeycode(struct input_dev *dev, int scancode, int keycode) 1038{ 1039 struct asus_laptop *asus = input_get_drvdata(dev); 1040 struct key_entry *key; 1041 int old_keycode; 1042 1043 if (keycode < 0 || keycode > KEY_MAX) 1044 return -EINVAL; 1045 1046 key = asus_get_entry_by_scancode(asus, scancode); 1047 if (key && key->type == KE_KEY) { 1048 old_keycode = key->keycode; 1049 key->keycode = keycode; 1050 set_bit(keycode, dev->keybit); 1051 if (!asus_get_entry_by_keycode(asus, old_keycode)) 1052 clear_bit(old_keycode, dev->keybit); 1053 return 0; 1054 } 1055 1056 return -EINVAL; 1057} 1058 1059static void asus_input_notify(struct asus_laptop *asus, int event) 1060{ 1061 struct key_entry *key; 1062 1063 key = asus_get_entry_by_scancode(asus, event); 1064 if (!key) 1065 return ; 1066 1067 switch (key->type) { 1068 case KE_KEY: 1069 input_report_key(asus->inputdev, key->keycode, 1); 1070 input_sync(asus->inputdev); 1071 input_report_key(asus->inputdev, key->keycode, 0); 1072 input_sync(asus->inputdev); 1073 break; 1074 } 1075} 1076 1077static int asus_input_init(struct asus_laptop *asus) 1078{ 1079 const struct key_entry *key; 1080 int result; 1081 1082 asus->inputdev = input_allocate_device(); 1083 if (!asus->inputdev) { 1084 pr_info("Unable to allocate input device\n"); 1085 return 0; 1086 } 1087 asus->inputdev->name = "Asus Laptop extra buttons"; 1088 asus->inputdev->dev.parent = &asus->platform_device->dev; 1089 asus->inputdev->phys = ASUS_LAPTOP_FILE "/input0"; 1090 asus->inputdev->id.bustype = BUS_HOST; 1091 asus->inputdev->getkeycode = asus_getkeycode; 1092 asus->inputdev->setkeycode = asus_setkeycode; 1093 input_set_drvdata(asus->inputdev, asus); 1094 1095 asus->keymap = kmemdup(asus_keymap, sizeof(asus_keymap), 1096 GFP_KERNEL); 1097 for (key = asus->keymap; key->type != KE_END; key++) { 1098 switch (key->type) { 1099 case KE_KEY: 1100 set_bit(EV_KEY, asus->inputdev->evbit); 1101 set_bit(key->keycode, asus->inputdev->keybit); 1102 break; 1103 } 1104 } 1105 result = input_register_device(asus->inputdev); 1106 if (result) { 1107 pr_info("Unable to register input device\n"); 1108 input_free_device(asus->inputdev); 1109 } 1110 return result; 1111} 1112 1113static void asus_input_exit(struct asus_laptop *asus) 1114{ 1115 if (asus->inputdev) 1116 input_unregister_device(asus->inputdev); 1117} 1118 1119/* 1120 * ACPI driver 1121 */ 1122static void asus_acpi_notify(struct acpi_device *device, u32 event) 1123{ 1124 struct asus_laptop *asus = acpi_driver_data(device); 1125 u16 count; 1126 1127 /* 1128 * We need to tell the backlight device when the backlight power is 1129 * switched 1130 */ 1131 if (event == ATKD_LCD_ON) { 1132 write_status(asus, NULL, 1, LCD_ON); 1133 lcd_blank(asus, FB_BLANK_UNBLANK); 1134 } else if (event == ATKD_LCD_OFF) { 1135 write_status(asus, NULL, 0, LCD_ON); 1136 lcd_blank(asus, FB_BLANK_POWERDOWN); 1137 } 1138 1139 /* TODO Find a better way to handle events count. */ 1140 count = asus->event_count[event % 128]++; 1141 acpi_bus_generate_proc_event(asus->device, event, count); 1142 acpi_bus_generate_netlink_event(asus->device->pnp.device_class, 1143 dev_name(&asus->device->dev), event, 1144 count); 1145 1146 asus_input_notify(asus, event); 1147} 1148 1149#define ASUS_CREATE_DEVICE_ATTR(_name) \ 1150 struct device_attribute dev_attr_##_name = { \ 1151 .attr = { \ 1152 .name = __stringify(_name), \ 1153 .mode = 0 }, \ 1154 .show = NULL, \ 1155 .store = NULL, \ 1156 } 1157 1158#define ASUS_SET_DEVICE_ATTR(_name, _mode, _show, _store) \ 1159 do { \ 1160 dev_attr_##_name.attr.mode = _mode; \ 1161 dev_attr_##_name.show = _show; \ 1162 dev_attr_##_name.store = _store; \ 1163 } while(0) 1164 1165static ASUS_CREATE_DEVICE_ATTR(infos); 1166static ASUS_CREATE_DEVICE_ATTR(wlan); 1167static ASUS_CREATE_DEVICE_ATTR(bluetooth); 1168static ASUS_CREATE_DEVICE_ATTR(display); 1169static ASUS_CREATE_DEVICE_ATTR(ledd); 1170static ASUS_CREATE_DEVICE_ATTR(ls_switch); 1171static ASUS_CREATE_DEVICE_ATTR(ls_level); 1172static ASUS_CREATE_DEVICE_ATTR(gps); 1173 1174static struct attribute *asuspf_attributes[] = { 1175 &dev_attr_infos.attr, 1176 &dev_attr_wlan.attr, 1177 &dev_attr_bluetooth.attr, 1178 &dev_attr_display.attr, 1179 &dev_attr_ledd.attr, 1180 &dev_attr_ls_switch.attr, 1181 &dev_attr_ls_level.attr, 1182 &dev_attr_gps.attr, 1183 NULL 1184}; 1185 1186static struct attribute_group platform_attribute_group = { 1187 .attrs = asuspf_attributes 1188}; 1189 1190static int asus_platform_init(struct asus_laptop *asus) 1191{ 1192 int result; 1193 1194 asus->platform_device = platform_device_alloc(ASUS_LAPTOP_FILE, -1); 1195 if (!asus->platform_device) 1196 return -ENOMEM; 1197 platform_set_drvdata(asus->platform_device, asus); 1198 1199 result = platform_device_add(asus->platform_device); 1200 if (result) 1201 goto fail_platform_device; 1202 1203 result = sysfs_create_group(&asus->platform_device->dev.kobj, 1204 &platform_attribute_group); 1205 if (result) 1206 goto fail_sysfs; 1207 return 0; 1208 1209fail_sysfs: 1210 platform_device_del(asus->platform_device); 1211fail_platform_device: 1212 platform_device_put(asus->platform_device); 1213 return result; 1214} 1215 1216static void asus_platform_exit(struct asus_laptop *asus) 1217{ 1218 sysfs_remove_group(&asus->platform_device->dev.kobj, 1219 &platform_attribute_group); 1220 platform_device_unregister(asus->platform_device); 1221} 1222 1223static struct platform_driver platform_driver = { 1224 .driver = { 1225 .name = ASUS_LAPTOP_FILE, 1226 .owner = THIS_MODULE, 1227 } 1228}; 1229 1230static void asus_laptop_add_fs(struct asus_laptop *asus) 1231{ 1232 ASUS_SET_DEVICE_ATTR(infos, 0444, show_infos, NULL); 1233 1234 if (wl_switch_handle) 1235 ASUS_SET_DEVICE_ATTR(wlan, 0644, show_wlan, store_wlan); 1236 1237 if (bt_switch_handle) 1238 ASUS_SET_DEVICE_ATTR(bluetooth, 0644, 1239 show_bluetooth, store_bluetooth); 1240 1241 if (display_set_handle && display_get_handle) 1242 ASUS_SET_DEVICE_ATTR(display, 0644, show_disp, store_disp); 1243 else if (display_set_handle) 1244 ASUS_SET_DEVICE_ATTR(display, 0200, NULL, store_disp); 1245 1246 if (ledd_set_handle) 1247 ASUS_SET_DEVICE_ATTR(ledd, 0644, show_ledd, store_ledd); 1248 1249 if (ls_switch_handle && ls_level_handle) { 1250 ASUS_SET_DEVICE_ATTR(ls_level, 0644, show_lslvl, store_lslvl); 1251 ASUS_SET_DEVICE_ATTR(ls_switch, 0644, show_lssw, store_lssw); 1252 } 1253 1254 if (gps_status_handle && gps_on_handle && gps_off_handle) 1255 ASUS_SET_DEVICE_ATTR(gps, 0644, show_gps, store_gps); 1256} 1257 1258static int asus_handle_init(char *name, acpi_handle * handle, 1259 char **paths, int num_paths) 1260{ 1261 int i; 1262 acpi_status status; 1263 1264 for (i = 0; i < num_paths; i++) { 1265 status = acpi_get_handle(NULL, paths[i], handle); 1266 if (ACPI_SUCCESS(status)) 1267 return 0; 1268 } 1269 1270 *handle = NULL; 1271 return -ENODEV; 1272} 1273 1274#define ASUS_HANDLE_INIT(object) \ 1275 asus_handle_init(#object, &object##_handle, object##_paths, \ 1276 ARRAY_SIZE(object##_paths)) 1277 1278/* 1279 * This function is used to initialize the context with right values. In this 1280 * method, we can make all the detection we want, and modify the asus_laptop 1281 * struct 1282 */ 1283static int asus_laptop_get_info(struct asus_laptop *asus) 1284{ 1285 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 1286 union acpi_object *model = NULL; 1287 unsigned long long bsts_result, hwrs_result; 1288 char *string = NULL; 1289 acpi_status status; 1290 1291 /* 1292 * Get DSDT headers early enough to allow for differentiating between 1293 * models, but late enough to allow acpi_bus_register_driver() to fail 1294 * before doing anything ACPI-specific. Should we encounter a machine, 1295 * which needs special handling (i.e. its hotkey device has a different 1296 * HID), this bit will be moved. 1297 */ 1298 status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus->dsdt_info); 1299 if (ACPI_FAILURE(status)) 1300 pr_warning("Couldn't get the DSDT table header\n"); 1301 1302 /* We have to write 0 on init this far for all ASUS models */ 1303 if (write_acpi_int_ret(asus->handle, "INIT", 0, &buffer)) { 1304 pr_err("Hotkey initialization failed\n"); 1305 return -ENODEV; 1306 } 1307 1308 /* This needs to be called for some laptops to init properly */ 1309 status = 1310 acpi_evaluate_integer(asus->handle, "BSTS", NULL, &bsts_result); 1311 if (ACPI_FAILURE(status)) 1312 pr_warning("Error calling BSTS\n"); 1313 else if (bsts_result) 1314 pr_notice("BSTS called, 0x%02x returned\n", 1315 (uint) bsts_result); 1316 1317 /* This too ... */ 1318 write_acpi_int(asus->handle, "CWAP", wapf); 1319 1320 /* 1321 * Try to match the object returned by INIT to the specific model. 1322 * Handle every possible object (or the lack of thereof) the DSDT 1323 * writers might throw at us. When in trouble, we pass NULL to 1324 * asus_model_match() and try something completely different. 1325 */ 1326 if (buffer.pointer) { 1327 model = buffer.pointer; 1328 switch (model->type) { 1329 case ACPI_TYPE_STRING: 1330 string = model->string.pointer; 1331 break; 1332 case ACPI_TYPE_BUFFER: 1333 string = model->buffer.pointer; 1334 break; 1335 default: 1336 string = ""; 1337 break; 1338 } 1339 } 1340 asus->name = kstrdup(string, GFP_KERNEL); 1341 if (!asus->name) 1342 return -ENOMEM; 1343 1344 if (*string) 1345 pr_notice(" %s model detected\n", string); 1346 1347 ASUS_HANDLE_INIT(mled_set); 1348 ASUS_HANDLE_INIT(tled_set); 1349 ASUS_HANDLE_INIT(rled_set); 1350 ASUS_HANDLE_INIT(pled_set); 1351 ASUS_HANDLE_INIT(gled_set); 1352 1353 ASUS_HANDLE_INIT(ledd_set); 1354 1355 ASUS_HANDLE_INIT(kled_set); 1356 ASUS_HANDLE_INIT(kled_get); 1357 1358 /* 1359 * The HWRS method return informations about the hardware. 1360 * 0x80 bit is for WLAN, 0x100 for Bluetooth. 1361 * The significance of others is yet to be found. 1362 * If we don't find the method, we assume the device are present. 1363 */ 1364 status = 1365 acpi_evaluate_integer(asus->handle, "HRWS", NULL, &hwrs_result); 1366 if (ACPI_FAILURE(status)) 1367 hwrs_result = WL_HWRS | BT_HWRS; 1368 1369 if (hwrs_result & WL_HWRS) 1370 ASUS_HANDLE_INIT(wl_switch); 1371 if (hwrs_result & BT_HWRS) 1372 ASUS_HANDLE_INIT(bt_switch); 1373 1374 ASUS_HANDLE_INIT(wireless_status); 1375 1376 ASUS_HANDLE_INIT(brightness_set); 1377 ASUS_HANDLE_INIT(brightness_get); 1378 1379 ASUS_HANDLE_INIT(lcd_switch); 1380 1381 ASUS_HANDLE_INIT(display_set); 1382 ASUS_HANDLE_INIT(display_get); 1383 1384 /* 1385 * There is a lot of models with "ALSL", but a few get 1386 * a real light sens, so we need to check it. 1387 */ 1388 if (!ASUS_HANDLE_INIT(ls_switch)) 1389 ASUS_HANDLE_INIT(ls_level); 1390 1391 ASUS_HANDLE_INIT(gps_on); 1392 ASUS_HANDLE_INIT(gps_off); 1393 ASUS_HANDLE_INIT(gps_status); 1394 1395 kfree(model); 1396 1397 return AE_OK; 1398} 1399 1400static bool asus_device_present; 1401 1402static int __devinit asus_acpi_init(struct asus_laptop *asus) 1403{ 1404 int result = 0; 1405 1406 result = acpi_bus_get_status(asus->device); 1407 if (result) 1408 return result; 1409 if (!asus->device->status.present) { 1410 pr_err("Hotkey device not present, aborting\n"); 1411 return -ENODEV; 1412 } 1413 1414 result = asus_laptop_get_info(asus); 1415 if (result) 1416 return result; 1417 1418 asus_laptop_add_fs(asus); 1419 1420 /* WLED and BLED are on by default */ 1421 if (bluetooth_status >= 0) 1422 write_status(asus, bt_switch_handle, !!bluetooth_status, BT_ON); 1423 if (wireless_status >= 0) 1424 write_status(asus, wl_switch_handle, !!wireless_status, WL_ON); 1425 1426 /* If the h/w switch is off, we need to check the real status */ 1427 write_status(asus, NULL, read_status(asus, BT_ON), BT_ON); 1428 write_status(asus, NULL, read_status(asus, WL_ON), WL_ON); 1429 1430 /* LCD Backlight is on by default */ 1431 write_status(asus, NULL, 1, LCD_ON); 1432 1433 /* Keyboard Backlight is on by default */ 1434 if (kled_set_handle) 1435 set_kled_lvl(asus, 1); 1436 1437 /* LED display is off by default */ 1438 asus->ledd_status = 0xFFF; 1439 1440 /* Set initial values of light sensor and level */ 1441 asus->light_switch = 0; /* Default to light sensor disabled */ 1442 asus->light_level = 5; /* level 5 for sensor sensitivity */ 1443 1444 if (ls_switch_handle) 1445 set_light_sens_switch(asus, asus->light_switch); 1446 1447 if (ls_level_handle) 1448 set_light_sens_level(asus, asus->light_level); 1449 1450 /* GPS is on by default */ 1451 write_status(asus, NULL, 1, GPS_ON); 1452 return result; 1453} 1454 1455static int __devinit asus_acpi_add(struct acpi_device *device) 1456{ 1457 struct asus_laptop *asus; 1458 int result; 1459 1460 pr_notice("Asus Laptop Support version %s\n", 1461 ASUS_LAPTOP_VERSION); 1462 asus = kzalloc(sizeof(struct asus_laptop), GFP_KERNEL); 1463 if (!asus) 1464 return -ENOMEM; 1465 asus->handle = device->handle; 1466 strcpy(acpi_device_name(device), ASUS_LAPTOP_DEVICE_NAME); 1467 strcpy(acpi_device_class(device), ASUS_LAPTOP_CLASS); 1468 device->driver_data = asus; 1469 asus->device = device; 1470 1471 result = asus_acpi_init(asus); 1472 if (result) 1473 goto fail_platform; 1474 1475 /* 1476 * Register the platform device first. It is used as a parent for the 1477 * sub-devices below. 1478 */ 1479 result = asus_platform_init(asus); 1480 if (result) 1481 goto fail_platform; 1482 1483 if (!acpi_video_backlight_support()) { 1484 result = asus_backlight_init(asus); 1485 if (result) 1486 goto fail_backlight; 1487 } else 1488 pr_info("Backlight controlled by ACPI video driver\n"); 1489 1490 result = asus_input_init(asus); 1491 if (result) 1492 goto fail_input; 1493 1494 result = asus_led_init(asus); 1495 if (result) 1496 goto fail_led; 1497 1498 asus_device_present = true; 1499 return 0; 1500 1501fail_led: 1502 asus_input_exit(asus); 1503fail_input: 1504 asus_backlight_exit(asus); 1505fail_backlight: 1506 asus_platform_exit(asus); 1507fail_platform: 1508 kfree(asus->name); 1509 kfree(asus); 1510 1511 return result; 1512} 1513 1514static int asus_acpi_remove(struct acpi_device *device, int type) 1515{ 1516 struct asus_laptop *asus = acpi_driver_data(device); 1517 1518 asus_backlight_exit(asus); 1519 asus_led_exit(asus); 1520 asus_input_exit(asus); 1521 asus_platform_exit(asus); 1522 1523 kfree(asus->name); 1524 kfree(asus); 1525 return 0; 1526} 1527 1528static const struct acpi_device_id asus_device_ids[] = { 1529 {"ATK0100", 0}, 1530 {"ATK0101", 0}, 1531 {"", 0}, 1532}; 1533MODULE_DEVICE_TABLE(acpi, asus_device_ids); 1534 1535static struct acpi_driver asus_acpi_driver = { 1536 .name = ASUS_LAPTOP_NAME, 1537 .class = ASUS_LAPTOP_CLASS, 1538 .owner = THIS_MODULE, 1539 .ids = asus_device_ids, 1540 .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, 1541 .ops = { 1542 .add = asus_acpi_add, 1543 .remove = asus_acpi_remove, 1544 .notify = asus_acpi_notify, 1545 }, 1546}; 1547 1548static int __init asus_laptop_init(void) 1549{ 1550 int result; 1551 1552 result = platform_driver_register(&platform_driver); 1553 if (result < 0) 1554 return result; 1555 1556 result = acpi_bus_register_driver(&asus_acpi_driver); 1557 if (result < 0) 1558 goto fail_acpi_driver; 1559 if (!asus_device_present) { 1560 result = -ENODEV; 1561 goto fail_no_device; 1562 } 1563 return 0; 1564 1565fail_no_device: 1566 acpi_bus_unregister_driver(&asus_acpi_driver); 1567fail_acpi_driver: 1568 platform_driver_unregister(&platform_driver); 1569 return result; 1570} 1571 1572static void __exit asus_laptop_exit(void) 1573{ 1574 acpi_bus_unregister_driver(&asus_acpi_driver); 1575 platform_driver_unregister(&platform_driver); 1576} 1577 1578module_init(asus_laptop_init); 1579module_exit(asus_laptop_exit); 1580