diff options
-rw-r--r-- | drivers/misc/fujitsu-laptop.c | 305 |
1 files changed, 272 insertions, 33 deletions
diff --git a/drivers/misc/fujitsu-laptop.c b/drivers/misc/fujitsu-laptop.c index a7dd3e9fb79d..9c407ab9ba2b 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 |
@@ -145,8 +167,9 @@ struct fujitsu_hotkey_t { | |||
145 | struct platform_device *pf_device; | 167 | struct platform_device *pf_device; |
146 | struct kfifo *fifo; | 168 | struct kfifo *fifo; |
147 | spinlock_t fifo_lock; | 169 | spinlock_t fifo_lock; |
148 | 170 | int rfkill_state; | |
149 | unsigned int irb; /* info about the pressed buttons */ | 171 | int logolamp_registered; |
172 | int kblamps_registered; | ||
150 | }; | 173 | }; |
151 | 174 | ||
152 | static struct fujitsu_hotkey_t *fujitsu_hotkey; | 175 | static struct fujitsu_hotkey_t *fujitsu_hotkey; |
@@ -154,12 +177,139 @@ static struct fujitsu_hotkey_t *fujitsu_hotkey; | |||
154 | static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event, | 177 | static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event, |
155 | void *data); | 178 | void *data); |
156 | 179 | ||
180 | #ifdef CONFIG_LEDS_CLASS | ||
181 | static enum led_brightness logolamp_get(struct led_classdev *cdev); | ||
182 | static void logolamp_set(struct led_classdev *cdev, | ||
183 | enum led_brightness brightness); | ||
184 | |||
185 | struct led_classdev logolamp_led = { | ||
186 | .name = "fujitsu::logolamp", | ||
187 | .brightness_get = logolamp_get, | ||
188 | .brightness_set = logolamp_set | ||
189 | }; | ||
190 | |||
191 | static enum led_brightness kblamps_get(struct led_classdev *cdev); | ||
192 | static void kblamps_set(struct led_classdev *cdev, | ||
193 | enum led_brightness brightness); | ||
194 | |||
195 | struct led_classdev kblamps_led = { | ||
196 | .name = "fujitsu::kblamps", | ||
197 | .brightness_get = kblamps_get, | ||
198 | .brightness_set = kblamps_set | ||
199 | }; | ||
200 | #endif | ||
201 | |||
157 | #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG | 202 | #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG |
158 | static u32 dbg_level = 0x03; | 203 | static u32 dbg_level = 0x03; |
159 | #endif | 204 | #endif |
160 | 205 | ||
161 | static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data); | 206 | static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data); |
162 | 207 | ||
208 | /* Fujitsu ACPI interface function */ | ||
209 | |||
210 | static int call_fext_func(int cmd, int arg0, int arg1, int arg2) | ||
211 | { | ||
212 | acpi_status status = AE_OK; | ||
213 | union acpi_object params[4] = { | ||
214 | { .type = ACPI_TYPE_INTEGER }, | ||
215 | { .type = ACPI_TYPE_INTEGER }, | ||
216 | { .type = ACPI_TYPE_INTEGER }, | ||
217 | { .type = ACPI_TYPE_INTEGER } | ||
218 | }; | ||
219 | struct acpi_object_list arg_list = { 4, ¶ms[0] }; | ||
220 | struct acpi_buffer output; | ||
221 | union acpi_object out_obj; | ||
222 | acpi_handle handle = NULL; | ||
223 | |||
224 | status = acpi_get_handle(fujitsu_hotkey->acpi_handle, "FUNC", &handle); | ||
225 | if (ACPI_FAILURE(status)) { | ||
226 | vdbg_printk(FUJLAPTOP_DBG_ERROR, | ||
227 | "FUNC interface is not present\n"); | ||
228 | return -ENODEV; | ||
229 | } | ||
230 | |||
231 | params[0].integer.value = cmd; | ||
232 | params[1].integer.value = arg0; | ||
233 | params[2].integer.value = arg1; | ||
234 | params[3].integer.value = arg2; | ||
235 | |||
236 | output.length = sizeof(out_obj); | ||
237 | output.pointer = &out_obj; | ||
238 | |||
239 | status = acpi_evaluate_object(handle, NULL, &arg_list, &output); | ||
240 | if (ACPI_FAILURE(status)) { | ||
241 | vdbg_printk(FUJLAPTOP_DBG_WARN, | ||
242 | "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) call failed\n", | ||
243 | cmd, arg0, arg1, arg2); | ||
244 | return -ENODEV; | ||
245 | } | ||
246 | |||
247 | if (out_obj.type != ACPI_TYPE_INTEGER) { | ||
248 | vdbg_printk(FUJLAPTOP_DBG_WARN, | ||
249 | "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) did not " | ||
250 | "return an integer\n", | ||
251 | cmd, arg0, arg1, arg2); | ||
252 | return -ENODEV; | ||
253 | } | ||
254 | |||
255 | vdbg_printk(FUJLAPTOP_DBG_TRACE, | ||
256 | "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n", | ||
257 | cmd, arg0, arg1, arg2, (int)out_obj.integer.value); | ||
258 | return out_obj.integer.value; | ||
259 | } | ||
260 | |||
261 | #ifdef CONFIG_LEDS_CLASS | ||
262 | /* LED class callbacks */ | ||
263 | |||
264 | static void logolamp_set(struct led_classdev *cdev, | ||
265 | enum led_brightness brightness) | ||
266 | { | ||
267 | if (brightness >= LED_FULL) { | ||
268 | call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON); | ||
269 | call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_ON); | ||
270 | } else if (brightness >= LED_HALF) { | ||
271 | call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON); | ||
272 | call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_OFF); | ||
273 | } else { | ||
274 | call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_OFF); | ||
275 | } | ||
276 | } | ||
277 | |||
278 | static void kblamps_set(struct led_classdev *cdev, | ||
279 | enum led_brightness brightness) | ||
280 | { | ||
281 | if (brightness >= LED_FULL) | ||
282 | call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_ON); | ||
283 | else | ||
284 | call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_OFF); | ||
285 | } | ||
286 | |||
287 | static enum led_brightness logolamp_get(struct led_classdev *cdev) | ||
288 | { | ||
289 | enum led_brightness brightness = LED_OFF; | ||
290 | int poweron, always; | ||
291 | |||
292 | poweron = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0); | ||
293 | if (poweron == FUNC_LED_ON) { | ||
294 | brightness = LED_HALF; | ||
295 | always = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0); | ||
296 | if (always == FUNC_LED_ON) | ||
297 | brightness = LED_FULL; | ||
298 | } | ||
299 | return brightness; | ||
300 | } | ||
301 | |||
302 | static enum led_brightness kblamps_get(struct led_classdev *cdev) | ||
303 | { | ||
304 | enum led_brightness brightness = LED_OFF; | ||
305 | |||
306 | if (call_fext_func(FUNC_LEDS, 0x2, KEYBOARD_LAMPS, 0x0) == FUNC_LED_ON) | ||
307 | brightness = LED_FULL; | ||
308 | |||
309 | return brightness; | ||
310 | } | ||
311 | #endif | ||
312 | |||
163 | /* Hardware access for LCD brightness control */ | 313 | /* Hardware access for LCD brightness control */ |
164 | 314 | ||
165 | static int set_lcd_level(int level) | 315 | static int set_lcd_level(int level) |
@@ -297,10 +447,25 @@ static int bl_get_brightness(struct backlight_device *b) | |||
297 | 447 | ||
298 | static int bl_update_status(struct backlight_device *b) | 448 | static int bl_update_status(struct backlight_device *b) |
299 | { | 449 | { |
450 | int ret; | ||
451 | if (b->props.power == 4) | ||
452 | ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x3); | ||
453 | else | ||
454 | ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x0); | ||
455 | if (ret != 0) | ||
456 | vdbg_printk(FUJLAPTOP_DBG_ERROR, | ||
457 | "Unable to adjust backlight power, error code %i\n", | ||
458 | ret); | ||
459 | |||
300 | if (use_alt_lcd_levels) | 460 | if (use_alt_lcd_levels) |
301 | return set_lcd_level_alt(b->props.brightness); | 461 | ret = set_lcd_level_alt(b->props.brightness); |
302 | else | 462 | else |
303 | return set_lcd_level(b->props.brightness); | 463 | ret = set_lcd_level(b->props.brightness); |
464 | if (ret != 0) | ||
465 | vdbg_printk(FUJLAPTOP_DBG_ERROR, | ||
466 | "Unable to adjust LCD brightness, error code %i\n", | ||
467 | ret); | ||
468 | return ret; | ||
304 | } | 469 | } |
305 | 470 | ||
306 | static struct backlight_ops fujitsubl_ops = { | 471 | static struct backlight_ops fujitsubl_ops = { |
@@ -382,42 +547,64 @@ static ssize_t store_lcd_level(struct device *dev, | |||
382 | return count; | 547 | return count; |
383 | } | 548 | } |
384 | 549 | ||
385 | /* Hardware access for hotkey device */ | 550 | static ssize_t |
386 | 551 | ignore_store(struct device *dev, | |
387 | static int get_irb(void) | 552 | struct device_attribute *attr, const char *buf, size_t count) |
388 | { | 553 | { |
389 | unsigned long long state = 0; | 554 | return count; |
390 | acpi_status status = AE_OK; | 555 | } |
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 | 556 | ||
400 | fujitsu_hotkey->irb = state; | 557 | static ssize_t |
558 | show_lid_state(struct device *dev, | ||
559 | struct device_attribute *attr, char *buf) | ||
560 | { | ||
561 | if (fujitsu_hotkey->rfkill_state == UNSUPPORTED_CMD) | ||
562 | return sprintf(buf, "unknown\n"); | ||
563 | if (fujitsu_hotkey->rfkill_state & 0x100) | ||
564 | return sprintf(buf, "open\n"); | ||
565 | else | ||
566 | return sprintf(buf, "closed\n"); | ||
567 | } | ||
401 | 568 | ||
402 | return fujitsu_hotkey->irb; | 569 | static ssize_t |
570 | show_dock_state(struct device *dev, | ||
571 | struct device_attribute *attr, char *buf) | ||
572 | { | ||
573 | if (fujitsu_hotkey->rfkill_state == UNSUPPORTED_CMD) | ||
574 | return sprintf(buf, "unknown\n"); | ||
575 | if (fujitsu_hotkey->rfkill_state & 0x200) | ||
576 | return sprintf(buf, "docked\n"); | ||
577 | else | ||
578 | return sprintf(buf, "undocked\n"); | ||
403 | } | 579 | } |
404 | 580 | ||
405 | static ssize_t | 581 | static ssize_t |
406 | ignore_store(struct device *dev, | 582 | show_radios_state(struct device *dev, |
407 | struct device_attribute *attr, const char *buf, size_t count) | 583 | struct device_attribute *attr, char *buf) |
408 | { | 584 | { |
409 | return count; | 585 | if (fujitsu_hotkey->rfkill_state == UNSUPPORTED_CMD) |
586 | return sprintf(buf, "unknown\n"); | ||
587 | if (fujitsu_hotkey->rfkill_state & 0x20) | ||
588 | return sprintf(buf, "on\n"); | ||
589 | else | ||
590 | return sprintf(buf, "killed\n"); | ||
410 | } | 591 | } |
411 | 592 | ||
412 | static DEVICE_ATTR(max_brightness, 0444, show_max_brightness, ignore_store); | 593 | static DEVICE_ATTR(max_brightness, 0444, show_max_brightness, ignore_store); |
413 | static DEVICE_ATTR(brightness_changed, 0444, show_brightness_changed, | 594 | static DEVICE_ATTR(brightness_changed, 0444, show_brightness_changed, |
414 | ignore_store); | 595 | ignore_store); |
415 | static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level); | 596 | static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level); |
597 | static DEVICE_ATTR(lid, 0444, show_lid_state, ignore_store); | ||
598 | static DEVICE_ATTR(dock, 0444, show_dock_state, ignore_store); | ||
599 | static DEVICE_ATTR(radios, 0444, show_radios_state, ignore_store); | ||
416 | 600 | ||
417 | static struct attribute *fujitsupf_attributes[] = { | 601 | static struct attribute *fujitsupf_attributes[] = { |
418 | &dev_attr_brightness_changed.attr, | 602 | &dev_attr_brightness_changed.attr, |
419 | &dev_attr_max_brightness.attr, | 603 | &dev_attr_max_brightness.attr, |
420 | &dev_attr_lcd_level.attr, | 604 | &dev_attr_lcd_level.attr, |
605 | &dev_attr_lid.attr, | ||
606 | &dev_attr_dock.attr, | ||
607 | &dev_attr_radios.attr, | ||
421 | NULL | 608 | NULL |
422 | }; | 609 | }; |
423 | 610 | ||
@@ -771,7 +958,8 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device) | |||
771 | input->id.bustype = BUS_HOST; | 958 | input->id.bustype = BUS_HOST; |
772 | input->id.product = 0x06; | 959 | input->id.product = 0x06; |
773 | input->dev.parent = &device->dev; | 960 | input->dev.parent = &device->dev; |
774 | input->evbit[0] = BIT(EV_KEY); | 961 | |
962 | set_bit(EV_KEY, input->evbit); | ||
775 | set_bit(fujitsu->keycode1, input->keybit); | 963 | set_bit(fujitsu->keycode1, input->keybit); |
776 | set_bit(fujitsu->keycode2, input->keybit); | 964 | set_bit(fujitsu->keycode2, input->keybit); |
777 | set_bit(fujitsu->keycode3, input->keybit); | 965 | set_bit(fujitsu->keycode3, input->keybit); |
@@ -803,10 +991,44 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device) | |||
803 | printk(KERN_ERR "_INI Method failed\n"); | 991 | printk(KERN_ERR "_INI Method failed\n"); |
804 | } | 992 | } |
805 | 993 | ||
806 | i = 0; /* Discard hotkey ringbuffer */ | 994 | i = 0; |
807 | while (get_irb() != 0 && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) ; | 995 | while (call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0 |
996 | && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) | ||
997 | ; /* No action, result is discarded */ | ||
808 | vdbg_printk(FUJLAPTOP_DBG_INFO, "Discarded %i ringbuffer entries\n", i); | 998 | vdbg_printk(FUJLAPTOP_DBG_INFO, "Discarded %i ringbuffer entries\n", i); |
809 | 999 | ||
1000 | fujitsu_hotkey->rfkill_state = | ||
1001 | call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0); | ||
1002 | |||
1003 | /* Suspect this is a keymap of the application panel, print it */ | ||
1004 | printk(KERN_INFO "fujitsu-laptop: BTNI: [0x%x]\n", | ||
1005 | call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0)); | ||
1006 | |||
1007 | #ifdef CONFIG_LEDS_CLASS | ||
1008 | if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) { | ||
1009 | result = led_classdev_register(&fujitsu->pf_device->dev, | ||
1010 | &logolamp_led); | ||
1011 | if (result == 0) { | ||
1012 | fujitsu_hotkey->logolamp_registered = 1; | ||
1013 | } else { | ||
1014 | printk(KERN_ERR "fujitsu-laptop: Could not register " | ||
1015 | "LED handler for logo lamp, error %i\n", result); | ||
1016 | } | ||
1017 | } | ||
1018 | |||
1019 | if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) && | ||
1020 | (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) { | ||
1021 | result = led_classdev_register(&fujitsu->pf_device->dev, | ||
1022 | &kblamps_led); | ||
1023 | if (result == 0) { | ||
1024 | fujitsu_hotkey->kblamps_registered = 1; | ||
1025 | } else { | ||
1026 | printk(KERN_ERR "fujitsu-laptop: Could not register " | ||
1027 | "LED handler for keyboard lamps, error %i\n", result); | ||
1028 | } | ||
1029 | } | ||
1030 | #endif | ||
1031 | |||
810 | return result; | 1032 | return result; |
811 | 1033 | ||
812 | end: | 1034 | end: |
@@ -852,16 +1074,15 @@ static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event, | |||
852 | 1074 | ||
853 | input = fujitsu_hotkey->input; | 1075 | input = fujitsu_hotkey->input; |
854 | 1076 | ||
855 | vdbg_printk(FUJLAPTOP_DBG_TRACE, "Hotkey event\n"); | 1077 | fujitsu_hotkey->rfkill_state = |
1078 | call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0); | ||
856 | 1079 | ||
857 | switch (event) { | 1080 | switch (event) { |
858 | case ACPI_FUJITSU_NOTIFY_CODE1: | 1081 | case ACPI_FUJITSU_NOTIFY_CODE1: |
859 | i = 0; | 1082 | i = 0; |
860 | while ((irb = get_irb()) != 0 | 1083 | while ((irb = |
861 | && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) { | 1084 | call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0 |
862 | vdbg_printk(FUJLAPTOP_DBG_TRACE, "GIRB result [%x]\n", | 1085 | && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) { |
863 | irb); | ||
864 | |||
865 | switch (irb & 0x4ff) { | 1086 | switch (irb & 0x4ff) { |
866 | case KEY1_CODE: | 1087 | case KEY1_CODE: |
867 | keycode = fujitsu->keycode1; | 1088 | keycode = fujitsu->keycode1; |
@@ -1035,6 +1256,15 @@ static int __init fujitsu_init(void) | |||
1035 | goto fail_hotkey1; | 1256 | goto fail_hotkey1; |
1036 | } | 1257 | } |
1037 | 1258 | ||
1259 | /* Sync backlight power status (needs FUJ02E3 device, hence deferred) */ | ||
1260 | |||
1261 | if (!acpi_video_backlight_support()) { | ||
1262 | if (call_fext_func(FUNC_BACKLIGHT, 0x2, 0x4, 0x0) == 3) | ||
1263 | fujitsu->bl_device->props.power = 4; | ||
1264 | else | ||
1265 | fujitsu->bl_device->props.power = 0; | ||
1266 | } | ||
1267 | |||
1038 | printk(KERN_INFO "fujitsu-laptop: driver " FUJITSU_DRIVER_VERSION | 1268 | printk(KERN_INFO "fujitsu-laptop: driver " FUJITSU_DRIVER_VERSION |
1039 | " successfully loaded.\n"); | 1269 | " successfully loaded.\n"); |
1040 | 1270 | ||
@@ -1074,6 +1304,14 @@ fail_acpi: | |||
1074 | 1304 | ||
1075 | static void __exit fujitsu_cleanup(void) | 1305 | static void __exit fujitsu_cleanup(void) |
1076 | { | 1306 | { |
1307 | #ifdef CONFIG_LEDS_CLASS | ||
1308 | if (fujitsu_hotkey->logolamp_registered != 0) | ||
1309 | led_classdev_unregister(&logolamp_led); | ||
1310 | |||
1311 | if (fujitsu_hotkey->kblamps_registered != 0) | ||
1312 | led_classdev_unregister(&kblamps_led); | ||
1313 | #endif | ||
1314 | |||
1077 | sysfs_remove_group(&fujitsu->pf_device->dev.kobj, | 1315 | sysfs_remove_group(&fujitsu->pf_device->dev.kobj, |
1078 | &fujitsupf_attribute_group); | 1316 | &fujitsupf_attribute_group); |
1079 | platform_device_unregister(fujitsu->pf_device); | 1317 | platform_device_unregister(fujitsu->pf_device); |
@@ -1108,12 +1346,13 @@ module_param_named(debug, dbg_level, uint, 0644); | |||
1108 | MODULE_PARM_DESC(debug, "Sets debug level bit-mask"); | 1346 | MODULE_PARM_DESC(debug, "Sets debug level bit-mask"); |
1109 | #endif | 1347 | #endif |
1110 | 1348 | ||
1111 | MODULE_AUTHOR("Jonathan Woithe, Peter Gruber"); | 1349 | MODULE_AUTHOR("Jonathan Woithe, Peter Gruber, Tony Vroon"); |
1112 | MODULE_DESCRIPTION("Fujitsu laptop extras support"); | 1350 | MODULE_DESCRIPTION("Fujitsu laptop extras support"); |
1113 | MODULE_VERSION(FUJITSU_DRIVER_VERSION); | 1351 | MODULE_VERSION(FUJITSU_DRIVER_VERSION); |
1114 | MODULE_LICENSE("GPL"); | 1352 | MODULE_LICENSE("GPL"); |
1115 | 1353 | ||
1116 | MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1D3:*:cvrS6410:*"); | 1354 | MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1D3:*:cvrS6410:*"); |
1355 | MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1E6:*:cvrS6420:*"); | ||
1117 | MODULE_ALIAS("dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*"); | 1356 | MODULE_ALIAS("dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*"); |
1118 | 1357 | ||
1119 | static struct pnp_device_id pnp_ids[] = { | 1358 | static struct pnp_device_id pnp_ids[] = { |