diff options
Diffstat (limited to 'drivers/misc/fujitsu-laptop.c')
-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[] = { |