aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/platform/x86/Kconfig1
-rw-r--r--drivers/platform/x86/ideapad-laptop.c72
2 files changed, 73 insertions, 0 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 4c7f8b926103..254c4ef6be35 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -226,6 +226,7 @@ config IDEAPAD_LAPTOP
226 tristate "Lenovo IdeaPad Laptop Extras" 226 tristate "Lenovo IdeaPad Laptop Extras"
227 depends on ACPI 227 depends on ACPI
228 depends on RFKILL 228 depends on RFKILL
229 select INPUT_SPARSEKMAP
229 help 230 help
230 This is a driver for the rfkill switches on Lenovo IdeaPad netbooks. 231 This is a driver for the rfkill switches on Lenovo IdeaPad netbooks.
231 232
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index 49f207fc61d2..04b4f5b3114d 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -28,6 +28,8 @@
28#include <acpi/acpi_drivers.h> 28#include <acpi/acpi_drivers.h>
29#include <linux/rfkill.h> 29#include <linux/rfkill.h>
30#include <linux/platform_device.h> 30#include <linux/platform_device.h>
31#include <linux/input.h>
32#include <linux/input/sparse-keymap.h>
31 33
32#define IDEAPAD_DEV_CAMERA 0 34#define IDEAPAD_DEV_CAMERA 0
33#define IDEAPAD_DEV_WLAN 1 35#define IDEAPAD_DEV_WLAN 1
@@ -39,6 +41,7 @@ struct ideapad_private {
39 acpi_handle handle; 41 acpi_handle handle;
40 struct rfkill *rfk[5]; 42 struct rfkill *rfk[5];
41 struct platform_device *platform_device; 43 struct platform_device *platform_device;
44 struct input_dev *inputdev;
42} *ideapad_priv; 45} *ideapad_priv;
43 46
44static struct { 47static struct {
@@ -325,6 +328,66 @@ static void ideapad_platform_exit(void)
325} 328}
326/* the above is platform device */ 329/* the above is platform device */
327 330
331/*
332 * input device
333 */
334static const struct key_entry ideapad_keymap[] = {
335 { KE_KEY, 0x06, { KEY_SWITCHVIDEOMODE } },
336 { KE_KEY, 0x0D, { KEY_WLAN } },
337 { KE_END, 0 },
338};
339
340static int __devinit ideapad_input_init(void)
341{
342 struct input_dev *inputdev;
343 int error;
344
345 inputdev = input_allocate_device();
346 if (!inputdev) {
347 pr_info("Unable to allocate input device\n");
348 return -ENOMEM;
349 }
350
351 inputdev->name = "Ideapad extra buttons";
352 inputdev->phys = "ideapad/input0";
353 inputdev->id.bustype = BUS_HOST;
354 inputdev->dev.parent = &ideapad_priv->platform_device->dev;
355
356 error = sparse_keymap_setup(inputdev, ideapad_keymap, NULL);
357 if (error) {
358 pr_err("Unable to setup input device keymap\n");
359 goto err_free_dev;
360 }
361
362 error = input_register_device(inputdev);
363 if (error) {
364 pr_err("Unable to register input device\n");
365 goto err_free_keymap;
366 }
367
368 ideapad_priv->inputdev = inputdev;
369 return 0;
370
371err_free_keymap:
372 sparse_keymap_free(inputdev);
373err_free_dev:
374 input_free_device(inputdev);
375 return error;
376}
377
378static void __devexit ideapad_input_exit(void)
379{
380 sparse_keymap_free(ideapad_priv->inputdev);
381 input_unregister_device(ideapad_priv->inputdev);
382 ideapad_priv->inputdev = NULL;
383}
384
385static void ideapad_input_report(unsigned long scancode)
386{
387 sparse_keymap_report_event(ideapad_priv->inputdev, scancode, 1, true);
388}
389/* the above is input device */
390
328static const struct acpi_device_id ideapad_device_ids[] = { 391static const struct acpi_device_id ideapad_device_ids[] = {
329 { "VPC2004", 0}, 392 { "VPC2004", 0},
330 { "", 0}, 393 { "", 0},
@@ -350,6 +413,10 @@ static int ideapad_acpi_add(struct acpi_device *adevice)
350 if (ret) 413 if (ret)
351 goto platform_failed; 414 goto platform_failed;
352 415
416 ret = ideapad_input_init();
417 if (ret)
418 goto input_failed;
419
353 for (i = IDEAPAD_DEV_WLAN; i < IDEAPAD_DEV_KILLSW; i++) { 420 for (i = IDEAPAD_DEV_WLAN; i < IDEAPAD_DEV_KILLSW; i++) {
354 if (test_bit(ideapad_rfk_data[i].cfgbit, (unsigned long *)&cfg)) 421 if (test_bit(ideapad_rfk_data[i].cfgbit, (unsigned long *)&cfg))
355 ideapad_register_rfkill(adevice, i); 422 ideapad_register_rfkill(adevice, i);
@@ -358,6 +425,8 @@ static int ideapad_acpi_add(struct acpi_device *adevice)
358 425
359 return 0; 426 return 0;
360 427
428input_failed:
429 ideapad_platform_exit();
361platform_failed: 430platform_failed:
362 kfree(priv); 431 kfree(priv);
363 return ret; 432 return ret;
@@ -370,6 +439,7 @@ static int ideapad_acpi_remove(struct acpi_device *adevice, int type)
370 439
371 for (i = IDEAPAD_DEV_WLAN; i < IDEAPAD_DEV_KILLSW; i++) 440 for (i = IDEAPAD_DEV_WLAN; i < IDEAPAD_DEV_KILLSW; i++)
372 ideapad_unregister_rfkill(adevice, i); 441 ideapad_unregister_rfkill(adevice, i);
442 ideapad_input_exit();
373 ideapad_platform_exit(); 443 ideapad_platform_exit();
374 dev_set_drvdata(&adevice->dev, NULL); 444 dev_set_drvdata(&adevice->dev, NULL);
375 kfree(priv); 445 kfree(priv);
@@ -392,6 +462,8 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
392 if (test_bit(vpc_bit, &vpc1)) { 462 if (test_bit(vpc_bit, &vpc1)) {
393 if (vpc_bit == 9) 463 if (vpc_bit == 9)
394 ideapad_sync_rfk_state(adevice); 464 ideapad_sync_rfk_state(adevice);
465 else
466 ideapad_input_report(vpc_bit);
395 } 467 }
396 } 468 }
397} 469}