diff options
| author | Len Brown <len.brown@intel.com> | 2009-01-09 03:37:26 -0500 |
|---|---|---|
| committer | Len Brown <len.brown@intel.com> | 2009-01-09 03:37:26 -0500 |
| commit | 106ad8d6b0a7c1a597fab56ec692c39f553fabbc (patch) | |
| tree | 7f14ff31b4e158d9ecbc8f46e9c135c5472c3aaf | |
| parent | 33a8c927e423a205bcbbecdc43b451bad781a08e (diff) | |
| parent | f87a1a5f6cdaff6232fed2ef0ae0479df9e781e8 (diff) | |
Merge branch 'fujitsu-laptop' into release
| -rw-r--r-- | drivers/misc/fujitsu-laptop.c | 419 |
1 files changed, 293 insertions, 126 deletions
diff --git a/drivers/misc/fujitsu-laptop.c b/drivers/misc/fujitsu-laptop.c index a7dd3e9fb79d..65dc41540c62 100644 --- a/drivers/misc/fujitsu-laptop.c +++ b/drivers/misc/fujitsu-laptop.c | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | /* | 3 | /* |
| 4 | Copyright (C) 2007,2008 Jonathan Woithe <jwoithe@physics.adelaide.edu.au> | 4 | Copyright (C) 2007,2008 Jonathan Woithe <jwoithe@physics.adelaide.edu.au> |
| 5 | Copyright (C) 2008 Peter Gruber <nokos@gmx.net> | 5 | Copyright (C) 2008 Peter Gruber <nokos@gmx.net> |
| 6 | Copyright (C) 2008 Tony Vroon <tony@linx.net> | ||
| 6 | Based on earlier work: | 7 | Based on earlier work: |
| 7 | Copyright (C) 2003 Shane Spencer <shane@bogomip.com> | 8 | Copyright (C) 2003 Shane Spencer <shane@bogomip.com> |
| 8 | Adrian Yee <brewt-fujitsu@brewt.org> | 9 | Adrian Yee <brewt-fujitsu@brewt.org> |
| @@ -65,8 +66,11 @@ | |||
| 65 | #include <linux/kfifo.h> | 66 | #include <linux/kfifo.h> |
| 66 | #include <linux/video_output.h> | 67 | #include <linux/video_output.h> |
| 67 | #include <linux/platform_device.h> | 68 | #include <linux/platform_device.h> |
| 69 | #ifdef CONFIG_LEDS_CLASS | ||
| 70 | #include <linux/leds.h> | ||
| 71 | #endif | ||
| 68 | 72 | ||
| 69 | #define FUJITSU_DRIVER_VERSION "0.4.3" | 73 | #define FUJITSU_DRIVER_VERSION "0.5.0" |
| 70 | 74 | ||
| 71 | #define FUJITSU_LCD_N_LEVELS 8 | 75 | #define FUJITSU_LCD_N_LEVELS 8 |
| 72 | 76 | ||
| @@ -83,6 +87,24 @@ | |||
| 83 | #define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x86 | 87 | #define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x86 |
| 84 | #define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87 | 88 | #define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87 |
| 85 | 89 | ||
| 90 | /* FUNC interface - command values */ | ||
| 91 | #define FUNC_RFKILL 0x1000 | ||
| 92 | #define FUNC_LEDS 0x1001 | ||
| 93 | #define FUNC_BUTTONS 0x1002 | ||
| 94 | #define FUNC_BACKLIGHT 0x1004 | ||
| 95 | |||
| 96 | /* FUNC interface - responses */ | ||
| 97 | #define UNSUPPORTED_CMD 0x80000000 | ||
| 98 | |||
| 99 | #ifdef CONFIG_LEDS_CLASS | ||
| 100 | /* FUNC interface - LED control */ | ||
| 101 | #define FUNC_LED_OFF 0x1 | ||
| 102 | #define FUNC_LED_ON 0x30001 | ||
| 103 | #define KEYBOARD_LAMPS 0x100 | ||
| 104 | #define LOGOLAMP_POWERON 0x2000 | ||
| 105 | #define LOGOLAMP_ALWAYS 0x4000 | ||
| 106 | #endif | ||
| 107 | |||
| 86 | /* Hotkey details */ | 108 | /* Hotkey details */ |
| 87 | #define KEY1_CODE 0x410 /* codes for the keys in the GIRB register */ | 109 | #define KEY1_CODE 0x410 /* codes for the keys in the GIRB register */ |
| 88 | #define KEY2_CODE 0x411 | 110 | #define KEY2_CODE 0x411 |
| @@ -133,7 +155,6 @@ struct fujitsu_t { | |||
| 133 | 155 | ||
| 134 | static struct fujitsu_t *fujitsu; | 156 | static struct fujitsu_t *fujitsu; |
| 135 | static int use_alt_lcd_levels = -1; | 157 | static int use_alt_lcd_levels = -1; |
| 136 | static int disable_brightness_keys = -1; | ||
| 137 | static int disable_brightness_adjust = -1; | 158 | static int disable_brightness_adjust = -1; |
| 138 | 159 | ||
| 139 | /* Device used to access other hotkeys on the laptop */ | 160 | /* Device used to access other hotkeys on the laptop */ |
| @@ -145,8 +166,9 @@ struct fujitsu_hotkey_t { | |||
| 145 | struct platform_device *pf_device; | 166 | struct platform_device *pf_device; |
| 146 | struct kfifo *fifo; | 167 | struct kfifo *fifo; |
| 147 | spinlock_t fifo_lock; | 168 | spinlock_t fifo_lock; |
| 148 | 169 | int rfkill_state; | |
| 149 | unsigned int irb; /* info about the pressed buttons */ | 170 | int logolamp_registered; |
| 171 | int kblamps_registered; | ||
| 150 | }; | 172 | }; |
| 151 | 173 | ||
| 152 | static struct fujitsu_hotkey_t *fujitsu_hotkey; | 174 | static struct fujitsu_hotkey_t *fujitsu_hotkey; |
| @@ -154,12 +176,139 @@ static struct fujitsu_hotkey_t *fujitsu_hotkey; | |||
| 154 | static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event, | 176 | static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event, |
| 155 | void *data); | 177 | void *data); |
| 156 | 178 | ||
| 179 | #ifdef CONFIG_LEDS_CLASS | ||
| 180 | static enum led_brightness logolamp_get(struct led_classdev *cdev); | ||
| 181 | static void logolamp_set(struct led_classdev *cdev, | ||
| 182 | enum led_brightness brightness); | ||
| 183 | |||
| 184 | struct led_classdev logolamp_led = { | ||
| 185 | .name = "fujitsu::logolamp", | ||
| 186 | .brightness_get = logolamp_get, | ||
| 187 | .brightness_set = logolamp_set | ||
| 188 | }; | ||
| 189 | |||
| 190 | static enum led_brightness kblamps_get(struct led_classdev *cdev); | ||
| 191 | static void kblamps_set(struct led_classdev *cdev, | ||
| 192 | enum led_brightness brightness); | ||
| 193 | |||
| 194 | struct led_classdev kblamps_led = { | ||
| 195 | .name = "fujitsu::kblamps", | ||
| 196 | .brightness_get = kblamps_get, | ||
| 197 | .brightness_set = kblamps_set | ||
| 198 | }; | ||
| 199 | #endif | ||
| 200 | |||
| 157 | #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG | 201 | #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG |
| 158 | static u32 dbg_level = 0x03; | 202 | static u32 dbg_level = 0x03; |
| 159 | #endif | 203 | #endif |
| 160 | 204 | ||
| 161 | static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data); | 205 | static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data); |
| 162 | 206 | ||
| 207 | /* Fujitsu ACPI interface function */ | ||
| 208 | |||
| 209 | static int call_fext_func(int cmd, int arg0, int arg1, int arg2) | ||
| 210 | { | ||
| 211 | acpi_status status = AE_OK; | ||
| 212 | union acpi_object params[4] = { | ||
| 213 | { .type = ACPI_TYPE_INTEGER }, | ||
| 214 | { .type = ACPI_TYPE_INTEGER }, | ||
| 215 | { .type = ACPI_TYPE_INTEGER }, | ||
| 216 | { .type = ACPI_TYPE_INTEGER } | ||
| 217 | }; | ||
| 218 | struct acpi_object_list arg_list = { 4, ¶ms[0] }; | ||
| 219 | struct acpi_buffer output; | ||
| 220 | union acpi_object out_obj; | ||
| 221 | acpi_handle handle = NULL; | ||
| 222 | |||
| 223 | status = acpi_get_handle(fujitsu_hotkey->acpi_handle, "FUNC", &handle); | ||
| 224 | if (ACPI_FAILURE(status)) { | ||
| 225 | vdbg_printk(FUJLAPTOP_DBG_ERROR, | ||
| 226 | "FUNC interface is not present\n"); | ||
| 227 | return -ENODEV; | ||
| 228 | } | ||
| 229 | |||
| 230 | params[0].integer.value = cmd; | ||
| 231 | params[1].integer.value = arg0; | ||
| 232 | params[2].integer.value = arg1; | ||
| 233 | params[3].integer.value = arg2; | ||
| 234 | |||
| 235 | output.length = sizeof(out_obj); | ||
| 236 | output.pointer = &out_obj; | ||
| 237 | |||
| 238 | status = acpi_evaluate_object(handle, NULL, &arg_list, &output); | ||
| 239 | if (ACPI_FAILURE(status)) { | ||
| 240 | vdbg_printk(FUJLAPTOP_DBG_WARN, | ||
| 241 | "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) call failed\n", | ||
| 242 | cmd, arg0, arg1, arg2); | ||
| 243 | return -ENODEV; | ||
| 244 | } | ||
| 245 | |||
| 246 | if (out_obj.type != ACPI_TYPE_INTEGER) { | ||
| 247 | vdbg_printk(FUJLAPTOP_DBG_WARN, | ||
| 248 | "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) did not " | ||
| 249 | "return an integer\n", | ||
| 250 | cmd, arg0, arg1, arg2); | ||
| 251 | return -ENODEV; | ||
| 252 | } | ||
| 253 | |||
| 254 | vdbg_printk(FUJLAPTOP_DBG_TRACE, | ||
| 255 | "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n", | ||
| 256 | cmd, arg0, arg1, arg2, (int)out_obj.integer.value); | ||
| 257 | return out_obj.integer.value; | ||
| 258 | } | ||
| 259 | |||
| 260 | #ifdef CONFIG_LEDS_CLASS | ||
| 261 | /* LED class callbacks */ | ||
| 262 | |||
| 263 | static void logolamp_set(struct led_classdev *cdev, | ||
| 264 | enum led_brightness brightness) | ||
| 265 | { | ||
| 266 | if (brightness >= LED_FULL) { | ||
| 267 | call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON); | ||
| 268 | call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_ON); | ||
| 269 | } else if (brightness >= LED_HALF) { | ||
| 270 | call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON); | ||
| 271 | call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_OFF); | ||
| 272 | } else { | ||
| 273 | call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_OFF); | ||
| 274 | } | ||
| 275 | } | ||
| 276 | |||
| 277 | static void kblamps_set(struct led_classdev *cdev, | ||
| 278 | enum led_brightness brightness) | ||
| 279 | { | ||
| 280 | if (brightness >= LED_FULL) | ||
| 281 | call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_ON); | ||
| 282 | else | ||
| 283 | call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_OFF); | ||
| 284 | } | ||
| 285 | |||
| 286 | static enum led_brightness logolamp_get(struct led_classdev *cdev) | ||
| 287 | { | ||
| 288 | enum led_brightness brightness = LED_OFF; | ||
| 289 | int poweron, always; | ||
| 290 | |||
| 291 | poweron = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0); | ||
| 292 | if (poweron == FUNC_LED_ON) { | ||
| 293 | brightness = LED_HALF; | ||
| 294 | always = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0); | ||
| 295 | if (always == FUNC_LED_ON) | ||
| 296 | brightness = LED_FULL; | ||
| 297 | } | ||
| 298 | return brightness; | ||
| 299 | } | ||
| 300 | |||
| 301 | static enum led_brightness kblamps_get(struct led_classdev *cdev) | ||
| 302 | { | ||
| 303 | enum led_brightness brightness = LED_OFF; | ||
| 304 | |||
| 305 | if (call_fext_func(FUNC_LEDS, 0x2, KEYBOARD_LAMPS, 0x0) == FUNC_LED_ON) | ||
| 306 | brightness = LED_FULL; | ||
| 307 | |||
| 308 | return brightness; | ||
| 309 | } | ||
| 310 | #endif | ||
| 311 | |||
| 163 | /* Hardware access for LCD brightness control */ | 312 | /* Hardware access for LCD brightness control */ |
| 164 | 313 | ||
| 165 | static int set_lcd_level(int level) | 314 | static int set_lcd_level(int level) |
| @@ -263,44 +412,34 @@ static int get_max_brightness(void) | |||
| 263 | return fujitsu->max_brightness; | 412 | return fujitsu->max_brightness; |
| 264 | } | 413 | } |
| 265 | 414 | ||
| 266 | static int get_lcd_level_alt(void) | ||
| 267 | { | ||
| 268 | unsigned long long state = 0; | ||
| 269 | acpi_status status = AE_OK; | ||
| 270 | |||
| 271 | vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLS\n"); | ||
| 272 | |||
| 273 | status = | ||
| 274 | acpi_evaluate_integer(fujitsu->acpi_handle, "GBLS", NULL, &state); | ||
| 275 | if (status < 0) | ||
| 276 | return status; | ||
| 277 | |||
| 278 | fujitsu->brightness_level = state & 0x0fffffff; | ||
| 279 | |||
| 280 | if (state & 0x80000000) | ||
| 281 | fujitsu->brightness_changed = 1; | ||
| 282 | else | ||
| 283 | fujitsu->brightness_changed = 0; | ||
| 284 | |||
| 285 | return fujitsu->brightness_level; | ||
| 286 | } | ||
| 287 | |||
| 288 | /* Backlight device stuff */ | 415 | /* Backlight device stuff */ |
| 289 | 416 | ||
| 290 | static int bl_get_brightness(struct backlight_device *b) | 417 | static int bl_get_brightness(struct backlight_device *b) |
| 291 | { | 418 | { |
| 292 | if (use_alt_lcd_levels) | 419 | return get_lcd_level(); |
| 293 | return get_lcd_level_alt(); | ||
| 294 | else | ||
| 295 | return get_lcd_level(); | ||
| 296 | } | 420 | } |
| 297 | 421 | ||
| 298 | static int bl_update_status(struct backlight_device *b) | 422 | static int bl_update_status(struct backlight_device *b) |
| 299 | { | 423 | { |
| 424 | int ret; | ||
| 425 | if (b->props.power == 4) | ||
| 426 | ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x3); | ||
| 427 | else | ||
| 428 | ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x0); | ||
| 429 | if (ret != 0) | ||
| 430 | vdbg_printk(FUJLAPTOP_DBG_ERROR, | ||
| 431 | "Unable to adjust backlight power, error code %i\n", | ||
| 432 | ret); | ||
| 433 | |||
| 300 | if (use_alt_lcd_levels) | 434 | if (use_alt_lcd_levels) |
| 301 | return set_lcd_level_alt(b->props.brightness); | 435 | ret = set_lcd_level_alt(b->props.brightness); |
| 302 | else | 436 | else |
| 303 | return set_lcd_level(b->props.brightness); | 437 | ret = set_lcd_level(b->props.brightness); |
| 438 | if (ret != 0) | ||
| 439 | vdbg_printk(FUJLAPTOP_DBG_ERROR, | ||
| 440 | "Unable to adjust LCD brightness, error code %i\n", | ||
| 441 | ret); | ||
| 442 | return ret; | ||
| 304 | } | 443 | } |
| 305 | 444 | ||
| 306 | static struct backlight_ops fujitsubl_ops = { | 445 | static struct backlight_ops fujitsubl_ops = { |
| @@ -344,10 +483,7 @@ static ssize_t show_lcd_level(struct device *dev, | |||
| 344 | 483 | ||
| 345 | int ret; | 484 | int ret; |
| 346 | 485 | ||
| 347 | if (use_alt_lcd_levels) | 486 | ret = get_lcd_level(); |
| 348 | ret = get_lcd_level_alt(); | ||
| 349 | else | ||
| 350 | ret = get_lcd_level(); | ||
| 351 | if (ret < 0) | 487 | if (ret < 0) |
| 352 | return ret; | 488 | return ret; |
| 353 | 489 | ||
| @@ -372,52 +508,71 @@ static ssize_t store_lcd_level(struct device *dev, | |||
| 372 | if (ret < 0) | 508 | if (ret < 0) |
| 373 | return ret; | 509 | return ret; |
| 374 | 510 | ||
| 375 | if (use_alt_lcd_levels) | 511 | ret = get_lcd_level(); |
| 376 | ret = get_lcd_level_alt(); | ||
| 377 | else | ||
| 378 | ret = get_lcd_level(); | ||
| 379 | if (ret < 0) | 512 | if (ret < 0) |
| 380 | return ret; | 513 | return ret; |
| 381 | 514 | ||
| 382 | return count; | 515 | return count; |
| 383 | } | 516 | } |
| 384 | 517 | ||
| 385 | /* Hardware access for hotkey device */ | 518 | static ssize_t |
| 386 | 519 | ignore_store(struct device *dev, | |
| 387 | static int get_irb(void) | 520 | struct device_attribute *attr, const char *buf, size_t count) |
| 388 | { | 521 | { |
| 389 | unsigned long long state = 0; | 522 | return count; |
| 390 | acpi_status status = AE_OK; | 523 | } |
| 391 | |||
| 392 | vdbg_printk(FUJLAPTOP_DBG_TRACE, "Get irb\n"); | ||
| 393 | |||
| 394 | status = | ||
| 395 | acpi_evaluate_integer(fujitsu_hotkey->acpi_handle, "GIRB", NULL, | ||
| 396 | &state); | ||
| 397 | if (status < 0) | ||
| 398 | return status; | ||
| 399 | 524 | ||
| 400 | fujitsu_hotkey->irb = state; | 525 | static ssize_t |
| 526 | show_lid_state(struct device *dev, | ||
| 527 | struct device_attribute *attr, char *buf) | ||
| 528 | { | ||
| 529 | if (fujitsu_hotkey->rfkill_state == UNSUPPORTED_CMD) | ||
| 530 | return sprintf(buf, "unknown\n"); | ||
| 531 | if (fujitsu_hotkey->rfkill_state & 0x100) | ||
| 532 | return sprintf(buf, "open\n"); | ||
| 533 | else | ||
| 534 | return sprintf(buf, "closed\n"); | ||
| 535 | } | ||
| 401 | 536 | ||
| 402 | return fujitsu_hotkey->irb; | 537 | static ssize_t |
| 538 | show_dock_state(struct device *dev, | ||
| 539 | struct device_attribute *attr, char *buf) | ||
| 540 | { | ||
| 541 | if (fujitsu_hotkey->rfkill_state == UNSUPPORTED_CMD) | ||
| 542 | return sprintf(buf, "unknown\n"); | ||
| 543 | if (fujitsu_hotkey->rfkill_state & 0x200) | ||
| 544 | return sprintf(buf, "docked\n"); | ||
| 545 | else | ||
| 546 | return sprintf(buf, "undocked\n"); | ||
| 403 | } | 547 | } |
| 404 | 548 | ||
| 405 | static ssize_t | 549 | static ssize_t |
| 406 | ignore_store(struct device *dev, | 550 | show_radios_state(struct device *dev, |
| 407 | struct device_attribute *attr, const char *buf, size_t count) | 551 | struct device_attribute *attr, char *buf) |
| 408 | { | 552 | { |
| 409 | return count; | 553 | if (fujitsu_hotkey->rfkill_state == UNSUPPORTED_CMD) |
| 554 | return sprintf(buf, "unknown\n"); | ||
| 555 | if (fujitsu_hotkey->rfkill_state & 0x20) | ||
| 556 | return sprintf(buf, "on\n"); | ||
| 557 | else | ||
| 558 | return sprintf(buf, "killed\n"); | ||
| 410 | } | 559 | } |
| 411 | 560 | ||
| 412 | static DEVICE_ATTR(max_brightness, 0444, show_max_brightness, ignore_store); | 561 | static DEVICE_ATTR(max_brightness, 0444, show_max_brightness, ignore_store); |
| 413 | static DEVICE_ATTR(brightness_changed, 0444, show_brightness_changed, | 562 | static DEVICE_ATTR(brightness_changed, 0444, show_brightness_changed, |
| 414 | ignore_store); | 563 | ignore_store); |
| 415 | static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level); | 564 | static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level); |
| 565 | static DEVICE_ATTR(lid, 0444, show_lid_state, ignore_store); | ||
| 566 | static DEVICE_ATTR(dock, 0444, show_dock_state, ignore_store); | ||
| 567 | static DEVICE_ATTR(radios, 0444, show_radios_state, ignore_store); | ||
| 416 | 568 | ||
| 417 | static struct attribute *fujitsupf_attributes[] = { | 569 | static struct attribute *fujitsupf_attributes[] = { |
| 418 | &dev_attr_brightness_changed.attr, | 570 | &dev_attr_brightness_changed.attr, |
| 419 | &dev_attr_max_brightness.attr, | 571 | &dev_attr_max_brightness.attr, |
| 420 | &dev_attr_lcd_level.attr, | 572 | &dev_attr_lcd_level.attr, |
| 573 | &dev_attr_lid.attr, | ||
| 574 | &dev_attr_dock.attr, | ||
| 575 | &dev_attr_radios.attr, | ||
| 421 | NULL | 576 | NULL |
| 422 | }; | 577 | }; |
| 423 | 578 | ||
| @@ -435,24 +590,16 @@ static struct platform_driver fujitsupf_driver = { | |||
| 435 | static void dmi_check_cb_common(const struct dmi_system_id *id) | 590 | static void dmi_check_cb_common(const struct dmi_system_id *id) |
| 436 | { | 591 | { |
| 437 | acpi_handle handle; | 592 | acpi_handle handle; |
| 438 | int have_blnf; | ||
| 439 | printk(KERN_INFO "fujitsu-laptop: Identified laptop model '%s'.\n", | 593 | printk(KERN_INFO "fujitsu-laptop: Identified laptop model '%s'.\n", |
| 440 | id->ident); | 594 | id->ident); |
| 441 | have_blnf = ACPI_SUCCESS | ||
| 442 | (acpi_get_handle(NULL, "\\_SB.PCI0.GFX0.LCD.BLNF", &handle)); | ||
| 443 | if (use_alt_lcd_levels == -1) { | 595 | if (use_alt_lcd_levels == -1) { |
| 444 | vdbg_printk(FUJLAPTOP_DBG_TRACE, "auto-detecting usealt\n"); | 596 | if (ACPI_SUCCESS(acpi_get_handle(NULL, |
| 445 | use_alt_lcd_levels = 1; | 597 | "\\_SB.PCI0.LPCB.FJEX.SBL2", &handle))) |
| 446 | } | 598 | use_alt_lcd_levels = 1; |
| 447 | if (disable_brightness_keys == -1) { | 599 | else |
| 448 | vdbg_printk(FUJLAPTOP_DBG_TRACE, | 600 | use_alt_lcd_levels = 0; |
| 449 | "auto-detecting disable_keys\n"); | 601 | vdbg_printk(FUJLAPTOP_DBG_TRACE, "auto-detected usealt as " |
| 450 | disable_brightness_keys = have_blnf ? 1 : 0; | 602 | "%i\n", use_alt_lcd_levels); |
| 451 | } | ||
| 452 | if (disable_brightness_adjust == -1) { | ||
| 453 | vdbg_printk(FUJLAPTOP_DBG_TRACE, | ||
| 454 | "auto-detecting disable_adjust\n"); | ||
| 455 | disable_brightness_adjust = have_blnf ? 0 : 1; | ||
| 456 | } | 603 | } |
| 457 | } | 604 | } |
| 458 | 605 | ||
| @@ -581,19 +728,14 @@ static int acpi_fujitsu_add(struct acpi_device *device) | |||
| 581 | 728 | ||
| 582 | /* do config (detect defaults) */ | 729 | /* do config (detect defaults) */ |
| 583 | use_alt_lcd_levels = use_alt_lcd_levels == 1 ? 1 : 0; | 730 | use_alt_lcd_levels = use_alt_lcd_levels == 1 ? 1 : 0; |
| 584 | disable_brightness_keys = disable_brightness_keys == 1 ? 1 : 0; | ||
| 585 | disable_brightness_adjust = disable_brightness_adjust == 1 ? 1 : 0; | 731 | disable_brightness_adjust = disable_brightness_adjust == 1 ? 1 : 0; |
| 586 | vdbg_printk(FUJLAPTOP_DBG_INFO, | 732 | vdbg_printk(FUJLAPTOP_DBG_INFO, |
| 587 | "config: [alt interface: %d], [key disable: %d], [adjust disable: %d]\n", | 733 | "config: [alt interface: %d], [adjust disable: %d]\n", |
| 588 | use_alt_lcd_levels, disable_brightness_keys, | 734 | use_alt_lcd_levels, disable_brightness_adjust); |
| 589 | disable_brightness_adjust); | ||
| 590 | 735 | ||
| 591 | if (get_max_brightness() <= 0) | 736 | if (get_max_brightness() <= 0) |
| 592 | fujitsu->max_brightness = FUJITSU_LCD_N_LEVELS; | 737 | fujitsu->max_brightness = FUJITSU_LCD_N_LEVELS; |
| 593 | if (use_alt_lcd_levels) | 738 | get_lcd_level(); |
| 594 | get_lcd_level_alt(); | ||
| 595 | else | ||
| 596 | get_lcd_level(); | ||
| 597 | 739 | ||
| 598 | return result; | 740 | return result; |
| 599 | 741 | ||
| @@ -644,43 +786,23 @@ static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data) | |||
| 644 | case ACPI_FUJITSU_NOTIFY_CODE1: | 786 | case ACPI_FUJITSU_NOTIFY_CODE1: |
| 645 | keycode = 0; | 787 | keycode = 0; |
| 646 | oldb = fujitsu->brightness_level; | 788 | oldb = fujitsu->brightness_level; |
| 647 | get_lcd_level(); /* the alt version always yields changed */ | 789 | get_lcd_level(); |
| 648 | newb = fujitsu->brightness_level; | 790 | newb = fujitsu->brightness_level; |
| 649 | 791 | ||
| 650 | vdbg_printk(FUJLAPTOP_DBG_TRACE, | 792 | vdbg_printk(FUJLAPTOP_DBG_TRACE, |
| 651 | "brightness button event [%i -> %i (%i)]\n", | 793 | "brightness button event [%i -> %i (%i)]\n", |
| 652 | oldb, newb, fujitsu->brightness_changed); | 794 | oldb, newb, fujitsu->brightness_changed); |
| 653 | 795 | ||
| 654 | if (oldb == newb && fujitsu->brightness_changed) { | 796 | if (oldb < newb) { |
| 655 | keycode = 0; | ||
| 656 | if (disable_brightness_keys != 1) { | ||
| 657 | if (oldb == 0) { | ||
| 658 | acpi_bus_generate_proc_event | ||
| 659 | (fujitsu->dev, | ||
| 660 | ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, | ||
| 661 | 0); | ||
| 662 | keycode = KEY_BRIGHTNESSDOWN; | ||
| 663 | } else if (oldb == | ||
| 664 | (fujitsu->max_brightness) - 1) { | ||
| 665 | acpi_bus_generate_proc_event | ||
| 666 | (fujitsu->dev, | ||
| 667 | ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, | ||
| 668 | 0); | ||
| 669 | keycode = KEY_BRIGHTNESSUP; | ||
| 670 | } | ||
| 671 | } | ||
| 672 | } else if (oldb < newb) { | ||
| 673 | if (disable_brightness_adjust != 1) { | 797 | if (disable_brightness_adjust != 1) { |
| 674 | if (use_alt_lcd_levels) | 798 | if (use_alt_lcd_levels) |
| 675 | set_lcd_level_alt(newb); | 799 | set_lcd_level_alt(newb); |
| 676 | else | 800 | else |
| 677 | set_lcd_level(newb); | 801 | set_lcd_level(newb); |
| 678 | } | 802 | } |
| 679 | if (disable_brightness_keys != 1) { | 803 | acpi_bus_generate_proc_event(fujitsu->dev, |
| 680 | acpi_bus_generate_proc_event(fujitsu->dev, | 804 | ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, 0); |
| 681 | ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, 0); | 805 | keycode = KEY_BRIGHTNESSUP; |
| 682 | keycode = KEY_BRIGHTNESSUP; | ||
| 683 | } | ||
| 684 | } else if (oldb > newb) { | 806 | } else if (oldb > newb) { |
| 685 | if (disable_brightness_adjust != 1) { | 807 | if (disable_brightness_adjust != 1) { |
| 686 | if (use_alt_lcd_levels) | 808 | if (use_alt_lcd_levels) |
| @@ -688,13 +810,9 @@ static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data) | |||
| 688 | else | 810 | else |
| 689 | set_lcd_level(newb); | 811 | set_lcd_level(newb); |
| 690 | } | 812 | } |
| 691 | if (disable_brightness_keys != 1) { | 813 | acpi_bus_generate_proc_event(fujitsu->dev, |
| 692 | acpi_bus_generate_proc_event(fujitsu->dev, | 814 | ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, 0); |
| 693 | ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, 0); | 815 | keycode = KEY_BRIGHTNESSDOWN; |
| 694 | keycode = KEY_BRIGHTNESSDOWN; | ||
| 695 | } | ||
| 696 | } else { | ||
| 697 | keycode = KEY_UNKNOWN; | ||
| 698 | } | 816 | } |
| 699 | break; | 817 | break; |
| 700 | default: | 818 | default: |
| @@ -771,7 +889,8 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device) | |||
| 771 | input->id.bustype = BUS_HOST; | 889 | input->id.bustype = BUS_HOST; |
| 772 | input->id.product = 0x06; | 890 | input->id.product = 0x06; |
| 773 | input->dev.parent = &device->dev; | 891 | input->dev.parent = &device->dev; |
| 774 | input->evbit[0] = BIT(EV_KEY); | 892 | |
| 893 | set_bit(EV_KEY, input->evbit); | ||
| 775 | set_bit(fujitsu->keycode1, input->keybit); | 894 | set_bit(fujitsu->keycode1, input->keybit); |
| 776 | set_bit(fujitsu->keycode2, input->keybit); | 895 | set_bit(fujitsu->keycode2, input->keybit); |
| 777 | set_bit(fujitsu->keycode3, input->keybit); | 896 | set_bit(fujitsu->keycode3, input->keybit); |
| @@ -803,10 +922,44 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device) | |||
| 803 | printk(KERN_ERR "_INI Method failed\n"); | 922 | printk(KERN_ERR "_INI Method failed\n"); |
| 804 | } | 923 | } |
| 805 | 924 | ||
| 806 | i = 0; /* Discard hotkey ringbuffer */ | 925 | i = 0; |
| 807 | while (get_irb() != 0 && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) ; | 926 | while (call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0 |
| 927 | && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) | ||
| 928 | ; /* No action, result is discarded */ | ||
| 808 | vdbg_printk(FUJLAPTOP_DBG_INFO, "Discarded %i ringbuffer entries\n", i); | 929 | vdbg_printk(FUJLAPTOP_DBG_INFO, "Discarded %i ringbuffer entries\n", i); |
| 809 | 930 | ||
| 931 | fujitsu_hotkey->rfkill_state = | ||
| 932 | call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0); | ||
| 933 | |||
| 934 | /* Suspect this is a keymap of the application panel, print it */ | ||
| 935 | printk(KERN_INFO "fujitsu-laptop: BTNI: [0x%x]\n", | ||
| 936 | call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0)); | ||
| 937 | |||
| 938 | #ifdef CONFIG_LEDS_CLASS | ||
| 939 | if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) { | ||
| 940 | result = led_classdev_register(&fujitsu->pf_device->dev, | ||
| 941 | &logolamp_led); | ||
| 942 | if (result == 0) { | ||
| 943 | fujitsu_hotkey->logolamp_registered = 1; | ||
| 944 | } else { | ||
| 945 | printk(KERN_ERR "fujitsu-laptop: Could not register " | ||
| 946 | "LED handler for logo lamp, error %i\n", result); | ||
| 947 | } | ||
| 948 | } | ||
| 949 | |||
| 950 | if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) && | ||
| 951 | (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) { | ||
| 952 | result = led_classdev_register(&fujitsu->pf_device->dev, | ||
| 953 | &kblamps_led); | ||
| 954 | if (result == 0) { | ||
| 955 | fujitsu_hotkey->kblamps_registered = 1; | ||
| 956 | } else { | ||
| 957 | printk(KERN_ERR "fujitsu-laptop: Could not register " | ||
| 958 | "LED handler for keyboard lamps, error %i\n", result); | ||
| 959 | } | ||
| 960 | } | ||
| 961 | #endif | ||
| 962 | |||
| 810 | return result; | 963 | return result; |
| 811 | 964 | ||
| 812 | end: | 965 | end: |
| @@ -852,16 +1005,15 @@ static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event, | |||
| 852 | 1005 | ||
| 853 | input = fujitsu_hotkey->input; | 1006 | input = fujitsu_hotkey->input; |
| 854 | 1007 | ||
| 855 | vdbg_printk(FUJLAPTOP_DBG_TRACE, "Hotkey event\n"); | 1008 | fujitsu_hotkey->rfkill_state = |
| 1009 | call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0); | ||
| 856 | 1010 | ||
| 857 | switch (event) { | 1011 | switch (event) { |
| 858 | case ACPI_FUJITSU_NOTIFY_CODE1: | 1012 | case ACPI_FUJITSU_NOTIFY_CODE1: |
| 859 | i = 0; | 1013 | i = 0; |
| 860 | while ((irb = get_irb()) != 0 | 1014 | while ((irb = |
| 861 | && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) { | 1015 | call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0 |
| 862 | vdbg_printk(FUJLAPTOP_DBG_TRACE, "GIRB result [%x]\n", | 1016 | && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) { |
| 863 | irb); | ||
| 864 | |||
| 865 | switch (irb & 0x4ff) { | 1017 | switch (irb & 0x4ff) { |
| 866 | case KEY1_CODE: | 1018 | case KEY1_CODE: |
| 867 | keycode = fujitsu->keycode1; | 1019 | keycode = fujitsu->keycode1; |
| @@ -1035,6 +1187,15 @@ static int __init fujitsu_init(void) | |||
| 1035 | goto fail_hotkey1; | 1187 | goto fail_hotkey1; |
| 1036 | } | 1188 | } |
| 1037 | 1189 | ||
| 1190 | /* Sync backlight power status (needs FUJ02E3 device, hence deferred) */ | ||
| 1191 | |||
| 1192 | if (!acpi_video_backlight_support()) { | ||
| 1193 | if (call_fext_func(FUNC_BACKLIGHT, 0x2, 0x4, 0x0) == 3) | ||
| 1194 | fujitsu->bl_device->props.power = 4; | ||
| 1195 | else | ||
| 1196 | fujitsu->bl_device->props.power = 0; | ||
| 1197 | } | ||
| 1198 | |||
| 1038 | printk(KERN_INFO "fujitsu-laptop: driver " FUJITSU_DRIVER_VERSION | 1199 | printk(KERN_INFO "fujitsu-laptop: driver " FUJITSU_DRIVER_VERSION |
| 1039 | " successfully loaded.\n"); | 1200 | " successfully loaded.\n"); |
| 1040 | 1201 | ||
| @@ -1074,6 +1235,14 @@ fail_acpi: | |||
| 1074 | 1235 | ||
| 1075 | static void __exit fujitsu_cleanup(void) | 1236 | static void __exit fujitsu_cleanup(void) |
| 1076 | { | 1237 | { |
| 1238 | #ifdef CONFIG_LEDS_CLASS | ||
| 1239 | if (fujitsu_hotkey->logolamp_registered != 0) | ||
| 1240 | led_classdev_unregister(&logolamp_led); | ||
| 1241 | |||
| 1242 | if (fujitsu_hotkey->kblamps_registered != 0) | ||
| 1243 | led_classdev_unregister(&kblamps_led); | ||
| 1244 | #endif | ||
| 1245 | |||
| 1077 | sysfs_remove_group(&fujitsu->pf_device->dev.kobj, | 1246 | sysfs_remove_group(&fujitsu->pf_device->dev.kobj, |
| 1078 | &fujitsupf_attribute_group); | 1247 | &fujitsupf_attribute_group); |
| 1079 | platform_device_unregister(fujitsu->pf_device); | 1248 | platform_device_unregister(fujitsu->pf_device); |
| @@ -1098,9 +1267,6 @@ module_exit(fujitsu_cleanup); | |||
| 1098 | module_param(use_alt_lcd_levels, uint, 0644); | 1267 | module_param(use_alt_lcd_levels, uint, 0644); |
| 1099 | MODULE_PARM_DESC(use_alt_lcd_levels, | 1268 | MODULE_PARM_DESC(use_alt_lcd_levels, |
| 1100 | "Use alternative interface for lcd_levels (needed for Lifebook s6410)."); | 1269 | "Use alternative interface for lcd_levels (needed for Lifebook s6410)."); |
| 1101 | module_param(disable_brightness_keys, uint, 0644); | ||
| 1102 | MODULE_PARM_DESC(disable_brightness_keys, | ||
| 1103 | "Disable brightness keys (eg. if they are already handled by the generic ACPI_VIDEO device)."); | ||
| 1104 | module_param(disable_brightness_adjust, uint, 0644); | 1270 | module_param(disable_brightness_adjust, uint, 0644); |
| 1105 | MODULE_PARM_DESC(disable_brightness_adjust, "Disable brightness adjustment ."); | 1271 | MODULE_PARM_DESC(disable_brightness_adjust, "Disable brightness adjustment ."); |
| 1106 | #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG | 1272 | #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG |
| @@ -1108,12 +1274,13 @@ module_param_named(debug, dbg_level, uint, 0644); | |||
| 1108 | MODULE_PARM_DESC(debug, "Sets debug level bit-mask"); | 1274 | MODULE_PARM_DESC(debug, "Sets debug level bit-mask"); |
| 1109 | #endif | 1275 | #endif |
| 1110 | 1276 | ||
| 1111 | MODULE_AUTHOR("Jonathan Woithe, Peter Gruber"); | 1277 | MODULE_AUTHOR("Jonathan Woithe, Peter Gruber, Tony Vroon"); |
| 1112 | MODULE_DESCRIPTION("Fujitsu laptop extras support"); | 1278 | MODULE_DESCRIPTION("Fujitsu laptop extras support"); |
| 1113 | MODULE_VERSION(FUJITSU_DRIVER_VERSION); | 1279 | MODULE_VERSION(FUJITSU_DRIVER_VERSION); |
| 1114 | MODULE_LICENSE("GPL"); | 1280 | MODULE_LICENSE("GPL"); |
| 1115 | 1281 | ||
| 1116 | MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1D3:*:cvrS6410:*"); | 1282 | MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1D3:*:cvrS6410:*"); |
| 1283 | MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1E6:*:cvrS6420:*"); | ||
| 1117 | MODULE_ALIAS("dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*"); | 1284 | MODULE_ALIAS("dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*"); |
| 1118 | 1285 | ||
| 1119 | static struct pnp_device_id pnp_ids[] = { | 1286 | static struct pnp_device_id pnp_ids[] = { |
