hdaps: Add a 2nd input device for raw accelerometer data The current interface used for reading the HDAPS accelerometer requires userspace daemons to poll a sysfs attribute. This causes interrupts on tickless kernels, and introduces a phase difference between the userspace->kernel polling and kernel->hardware polling. To solve this, this patch introduces an input dev interface to the accelerometer data. It differs from the existing hdaps input dev in that it produces raw measurements, without fuzzing or calibration (but with axis reversal, this the model-specific knowledge is already encoded in the driver). Signed-off-by: Shem Multinymous --- drivers/hwmon/Kconfig | 7 ++++--- drivers/hwmon/hdaps.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 0780255..ab993fc 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -608,10 +608,11 @@ config SENSORS_HDAPS This driver provides support for the IBM Hard Drive Active Protection System (hdaps), which provides an accelerometer and other misc. data. ThinkPads starting with the R50, T41, and X40 are supported. The - accelerometer data is readable via sysfs. + accelerometer data is readable via sysfs and via an input device. - This driver also provides an absolute input class device, allowing - the laptop to act as a pinball machine-esque joystick. + This driver also provides another absolute input class device with + calibration and fuzzing, allowing the laptop to act as a pinball + machine-esque joystick. Say Y here if you have an applicable laptop and want to experience the awesome power of hdaps. diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c index 423f348..47ee3f1 100644 --- a/drivers/hwmon/hdaps.c +++ b/drivers/hwmon/hdaps.c @@ -67,10 +67,12 @@ static const struct thinkpad_ec_row ec_accel_args = #define HDAPS_INPUT_VENDOR PCI_VENDOR_ID_IBM #define HDAPS_INPUT_PRODUCT 0x5054 /* "TP", shared with thinkpad_acpi */ #define HDAPS_INPUT_JS_VERSION 0x6801 /* Joystick emulation input device */ +#define HDAPS_INPUT_RAW_VERSION 0x4801 /* Raw accelerometer input device */ static struct timer_list hdaps_timer; static struct platform_device *pdev; static struct input_dev *hdaps_idev; /* joystick-like device with fuzz */ +static struct input_dev *hdaps_idev_raw; /* raw hdaps sensor readouts */ static unsigned int hdaps_invert; static int needs_calibration; @@ -477,6 +479,9 @@ keep_active: input_report_abs(hdaps_idev, ABS_X, pos_x - rest_x); input_report_abs(hdaps_idev, ABS_Y, pos_y - rest_y); input_sync(hdaps_idev); + input_report_abs(hdaps_idev_raw, ABS_X, pos_x); + input_report_abs(hdaps_idev_raw, ABS_Y, pos_y); + input_sync(hdaps_idev_raw); mod_timer(&hdaps_timer, jiffies + HZ/sampling_rate); } @@ -747,6 +752,12 @@ static int __init hdaps_init(void) goto out_group; } + hdaps_idev_raw = input_allocate_device(); + if (!hdaps_idev_raw) { + ret = -ENOMEM; + goto out_idev_first; + } + /* calibration for the input device (deferred to avoid delay) */ needs_calibration = 1; @@ -768,12 +779,32 @@ static int __init hdaps_init(void) if (ret) goto out_idev; + /* initialize the raw data input device */ + hdaps_idev_raw->name = "ThinkPad HDAPS accelerometer data"; + hdaps_idev_raw->phys = "hdaps/input1"; + hdaps_idev_raw->id.bustype = BUS_HOST; + hdaps_idev_raw->id.vendor = HDAPS_INPUT_VENDOR; + hdaps_idev_raw->id.product = HDAPS_INPUT_PRODUCT; + hdaps_idev_raw->id.version = HDAPS_INPUT_RAW_VERSION; + hdaps_idev_raw->dev.parent = &pdev->dev; + hdaps_idev_raw->evbit[0] = BIT(EV_ABS); + input_set_abs_params(hdaps_idev_raw, ABS_X, -32768, 32767, 0, 0); + input_set_abs_params(hdaps_idev_raw, ABS_Y, -32768, 32767, 0, 0); + + ret = input_register_device(hdaps_idev_raw); + if (ret) + goto out_idev_reg_first; + mod_timer(&hdaps_timer, jiffies + HZ/sampling_rate); printk(KERN_INFO "hdaps: driver successfully loaded.\n"); return 0; +out_idev_reg_first: + input_unregister_device(hdaps_idev); out_idev: + input_free_device(hdaps_idev_raw); +out_idev_first: input_free_device(hdaps_idev); out_group: sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group); @@ -790,6 +821,7 @@ out: static void __exit hdaps_exit(void) { del_timer_sync(&hdaps_timer); + input_unregister_device(hdaps_idev_raw); input_unregister_device(hdaps_idev); hdaps_device_shutdown(); /* ignore errors, effect is negligible */ sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group); -- 1.5.2.4