HP Mobile Data Protection System 3D ACPI driver. Similar to hdaps in 
functionality.
This driver provides 4 kinds of functionality:
1) Creates a misc device /dev/accel that acts similar to /dev/rtc and unblocks
the process reading from it when the device detects free-fall interrupt
2) Functions as an input class device to provide similar functionality to
hdaps, in order to be able to use the laptop as a joystick
3) Provides an interface similar to hdaps, so that hdapsd could work with it
4) Makes it possible to power the device off.

Applications such as hdaps-gl and hdapsd as well as neverball work with
this driver unmodified.

Signed-off-by: Yan Burman <[EMAIL PROTECTED]>

diff -Nrubp linux-2.6.21-rc4_orig/Documentation/hwmon/mdps 
linux-2.6.21-rc4/Documentation/hwmon/mdps
--- linux-2.6.21-rc4_orig/Documentation/hwmon/mdps      1970-01-01 
02:00:00.000000000 +0200
+++ linux-2.6.21-rc4/Documentation/hwmon/mdps   2007-03-23 16:06:09.000000000 
+0200
@@ -0,0 +1,86 @@
+Kernel driver mdps
+==================
+
+Supported chips:
+
+  * STMicroelectronics LIS3LV02DL and LIS3LV02DQ
+
+Author:
+        Yan Burman <[EMAIL PROTECTED]>
+
+
+Description
+-----------
+
+This driver provides support for the HP Mobile Data Protection
+System 3D (mdps), which is an accelerometer. HP nc6420 and nx9420
+are supported right now, but it may work on other models as well. The
+accelerometer data is readable via /sys/devices/platform/mdps.
+
+Sysfs attributes under /sys/devices/platform/mdps/:
+position - 2D position that the accelerometer reports. Format: "(x,y)"
+position3d - 3D position that the accelerometer reports. Format: "(x,y,z)"
+calibrate - read: values (x, y) that are used as the base for input class 
device operation.
+            write: forces the base to be recalibrated.
+rate - reports the sampling rate of the accelerometer device in HZ
+state - read: the current power state of the accelerometer device
+        write: "0" or "1" to power on/off the device
+joystick - read: whether the input class device is active or not
+           write: "0" or "1" to enable/disable the input device
+
+Load time parameters:
+bool joystick - whether to enable the input class device or not (default 1)
+bool power_off - whether to power off the device on module load (default 0)
+bool hdaps_compat - Make the driver export same interfaces as hdaps,
+       so that apps like hdaps-gl will work the same as with hdaps (default 0)
+       The effect of this is:
+       1) Instead of /sys/devices/platform/mdps/, /sys/devices/platform/hdaps/ 
is created
+       2) Sensitivity is adjusted to match that of hdaps
+bool input_3d - Whether to operate as a 3D input device. (default 0)
+               BIG FAT WARNING: Do not enable this mode unless you are sure
+               that you want it, since it eats more CPU
+
+This driver also provides an absolute input class device, allowing
+the laptop to act as a pinball machine-esque joystick.
+
+Another feature of the driver is misc device called accel that acts
+similar to /dev/rtc and reacts on free-fall interrupts received from
+the device. It supports blocking operations, poll/select and fasync
+operation modes. You must read 4 bytes from the device.
+The result is number of free-fall interrupts since the last successful read.
+
+Example userspace code:
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdint.h>
+
+int main(int argc, char* argv[])
+{
+       int fd, ret;
+       uint32_t count;
+
+       fd = open("/dev/accel", O_RDONLY);
+       if (fd < 0) {
+               perror("open");
+               return EXIT_FAILURE;
+       }
+
+       for (;;) {
+               ret = read(fd, &count, sizeof(count));
+               if (ret != sizeof(count)) {
+                       perror("read");
+                       break;
+               }
+
+               printf("Got %d free-fall interrupts\n", count);
+       }
+
+       close(fd);
+       return EXIT_SUCCESS;
+}
diff -Nrubp linux-2.6.21-rc4_orig/drivers/hwmon/Kconfig 
linux-2.6.21-rc4/drivers/hwmon/Kconfig
--- linux-2.6.21-rc4_orig/drivers/hwmon/Kconfig 2007-03-23 15:59:59.000000000 
+0200
+++ linux-2.6.21-rc4/drivers/hwmon/Kconfig      2007-03-23 16:07:24.000000000 
+0200
@@ -593,6 +593,26 @@ config SENSORS_HDAPS
          Say Y here if you have an applicable laptop and want to experience
          the awesome power of hdaps.
 
+config SENSORS_MDPS
+       tristate "HP Mobile Data Protection System 3D (mdps)"
+       depends on ACPI && HWMON && INPUT && X86
+       default n
+       help
+         This driver provides support for the HP Mobile Data Protection
+         System 3D (mdps), which is an accelerometer. HP nc6420 and nx9420
+         are supported right now, but it may work on other models as well. The
+         accelerometer data is readable via /sys/devices/platform/mdps.
+
+         This driver also provides an absolute input class device, allowing
+         the laptop to act as a pinball machine-esque joystick.
+
+         Another feature of the driver is misc device called accel that acts
+         similar to /dev/rtc and reacts on free-fall interrupts received from
+         the device.
+
+         This driver can also be built as a module.  If so, the module
+         will be called mdps.
+
 config HWMON_DEBUG_CHIP
        bool "Hardware Monitoring Chip debugging messages"
        depends on HWMON
diff -Nrubp linux-2.6.21-rc4_orig/drivers/hwmon/Makefile 
linux-2.6.21-rc4/drivers/hwmon/Makefile
--- linux-2.6.21-rc4_orig/drivers/hwmon/Makefile        2007-03-23 
15:59:59.000000000 +0200
+++ linux-2.6.21-rc4/drivers/hwmon/Makefile     2007-03-23 16:08:17.000000000 
+0200
@@ -29,6 +29,7 @@ obj-$(CONFIG_SENSORS_FSCPOS)  += fscpos.o
 obj-$(CONFIG_SENSORS_GL518SM)  += gl518sm.o
 obj-$(CONFIG_SENSORS_GL520SM)  += gl520sm.o
 obj-$(CONFIG_SENSORS_HDAPS)    += hdaps.o
+obj-$(CONFIG_SENSORS_MDPS)     += mdps.o
 obj-$(CONFIG_SENSORS_IT87)     += it87.o
 obj-$(CONFIG_SENSORS_K8TEMP)   += k8temp.o
 obj-$(CONFIG_SENSORS_LM63)     += lm63.o
diff -Nrubp linux-2.6.21-rc4_orig/drivers/hwmon/mdps.c 
linux-2.6.21-rc4/drivers/hwmon/mdps.c
--- linux-2.6.21-rc4_orig/drivers/hwmon/mdps.c  1970-01-01 02:00:00.000000000 
+0200
+++ linux-2.6.21-rc4/drivers/hwmon/mdps.c       2007-03-23 16:05:52.000000000 
+0200
@@ -0,0 +1,801 @@
+/*
+ *  mdps.c - HP Mobile Data Protection System 3D ACPI driver
+ *
+ *  Copyright (C) 2007 Yan Burman
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * 30/12/2006
+ * Added support for NX9420 and hdaps compatibility mode.
+ * Thanks to Jonas Majauskas for testing this on NX9420
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/miscdevice.h>
+#include <linux/wait.h>
+#include <linux/poll.h>
+#include <linux/freezer.h>
+
+#include <acpi/acpi_drivers.h>
+#include <acpi/acnamesp.h>
+
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+
+#define VERSION "0.7"
+
+#define DRIVER_NAME     "mdps"
+#define ACPI_MDPS_CLASS "accelerometer"
+#define ACPI_MDPS_ID    "HPQ0004"
+
+/* The actual chip is STMicroelectronics LIS3LV02DL or LIS3LV02DQ */
+
+#define MDPS_WHO_AM_I        0x0F /*r      00111010 */
+#define MDPS_OFFSET_X        0x16 /*rw              */
+#define MDPS_OFFSET_Y        0x17 /*rw              */
+#define MDPS_OFFSET_Z        0x18 /*rw              */
+#define MDPS_GAIN_X          0x19 /*rw              */
+#define MDPS_GAIN_Y          0x1A /*rw              */
+#define MDPS_GAIN_Z          0x1B /*rw              */
+#define MDPS_CTRL_REG1       0x20 /*rw     00000111 */
+#define MDPS_CTRL_REG2       0x21 /*rw     00000000 */
+#define MDPS_CTRL_REG3       0x22 /*rw     00001000 */
+#define MDPS_HP_FILTER RESET 0x23 /*r               */
+#define MDPS_STATUS_REG      0x27 /*rw     00000000 */
+#define MDPS_OUTX_L          0x28 /*r               */
+#define MDPS_OUTX_H          0x29 /*r               */
+#define MDPS_OUTY_L          0x2A /*r               */
+#define MDPS_OUTY_H          0x2B /*r               */
+#define MDPS_OUTZ_L          0x2C /*r               */
+#define MDPS_OUTZ_H          0x2D /*r               */
+#define MDPS_FF_WU_CFG       0x30 /*rw     00000000 */
+#define MDPS_FF_WU_SRC       0x31 /*rw     00000000 */
+#define MDPS_FF_WU_ACK       0x32 /*r               */
+#define MDPS_FF_WU_THS_L     0x34 /*rw     00000000 */
+#define MDPS_FF_WU_THS_H     0x35 /*rw     00000000 */
+#define MDPS_FF_WU_DURATION  0x36 /*rw     00000000 */
+#define MDPS_DD_CFG          0x38 /*rw     00000000 */
+#define MDPS_DD_SRC          0x39 /*rw     00000000 */
+#define MDPS_DD_ACK          0x3A /*r               */
+#define MDPS_DD_THSI_L       0x3C /*rw     00000000 */
+#define MDPS_DD_THSI_H       0x3D /*rw     00000000 */
+#define MDPS_DD_THSE_L       0x3E /*rw     00000000 */
+#define MDPS_DD_THSE_H       0x3F /*rw     00000000 */
+
+#define MDPS_ID 0x3A
+
+/* joystick device poll interval in milliseconds */
+#define MDPS_POLL_INTERVAL 30
+
+/* Maximum value our axis may get for the input device */
+#define MDPS_MAX_VAL 1024
+
+static unsigned int joystick = 1;
+module_param(joystick, bool, S_IRUGO);
+MODULE_PARM_DESC(joystick, "Enable the input device on module load");
+
+static unsigned int power_off;
+module_param(power_off, bool, S_IRUGO);
+MODULE_PARM_DESC(power_off, "Turn off device on module load");
+
+static unsigned int hdaps_compat;
+module_param(hdaps_compat, bool, S_IRUGO);
+MODULE_PARM_DESC(hdaps_compat, "Operate in hdaps compatibility mode");
+
+static unsigned int input_3d;
+module_param(input_3d, bool, S_IRUGO);
+MODULE_PARM_DESC(input_3d, "Operate as a 3D joystick instead of 2D");
+
+enum mdps_type {
+       MDPS_NC64x0,
+       MDPS_NX9420,
+};
+
+struct acpi_mdps
+{
+       struct acpi_device     *device;    /* The ACPI device */
+       u32                     irq;       /* IRQ number */
+       struct input_dev       *idev;      /* input device */
+       struct task_struct     *kthread;   /* kthread for input */
+       int                     xcalib;    /* calibrated null value for x */
+       int                     ycalib;    /* calibrated null value for y */
+       int                     zcalib;    /* calibrated null value for z */
+       int                     is_on;     /* whether the device is on or off */
+       struct platform_device *pdev;      /* platform device */
+       atomic_t                count;     /* interrupt count after last read */
+       struct fasync_struct   *async_queue;
+       atomic_t                available; /* whether the device is open */
+       wait_queue_head_t       misc_wait; /* Wait queue for the misc device */
+       enum mdps_type          type;
+};
+
+static struct acpi_mdps mdps;
+
+static int mdps_add(struct acpi_device *device);
+static int mdps_remove(struct acpi_device *device, int type);
+static int mdps_suspend(struct acpi_device *device, pm_message_t state);
+static int mdps_resume(struct acpi_device *device);
+static int mdps_remove_fs(void);
+static int mdps_add_fs(struct acpi_device *device);
+static void mdps_joystick_enable(void);
+static void mdps_joystick_disable(void);
+
+static struct acpi_driver mdps_driver =
+{
+       .name  = DRIVER_NAME,
+       .class = ACPI_MDPS_CLASS,
+       .ids   = ACPI_MDPS_ID,
+       .ops = {
+               .add     = mdps_add,
+               .remove  = mdps_remove,
+#ifdef CONFIG_PM
+               .suspend = mdps_suspend,
+               .resume  = mdps_resume
+#endif
+       }
+};
+
+/** Create a single value from 2 bytes received from the accelerometer
+ * @param hi the high byte
+ * @param lo the low byte
+ * @return the resulting value
+ */
+static inline s16 mdps_glue_bytes(unsigned long hi, unsigned long lo)
+{
+       /* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */
+       if (hi & 0x10)
+               hi |= 0xE0;
+       return (s16)((hi << 8) | lo);
+}
+
+/** ACPI ALRD method: read a register
+ * @param handle the handle of the device
+ * @param reg the register to read
+ * @param[out] ret result of the operation
+ * @return AE_OK on success
+ */
+static acpi_status mdps_ALRD(acpi_handle handle, int reg,
+                                    unsigned long *ret)
+{
+       union acpi_object arg0 = { ACPI_TYPE_INTEGER };
+       struct acpi_object_list args = { 1, &arg0 };
+
+       arg0.integer.value = reg;
+
+       return acpi_evaluate_integer(handle, "ALRD", &args, ret);
+}
+
+/** ACPI _INI method: initialize the device.
+ * @param handle the handle of the device
+ * @return 0 on success
+ */
+static inline acpi_status mdps__INI(acpi_handle handle)
+{
+       return acpi_evaluate_object(handle, METHOD_NAME__INI, NULL, NULL);
+}
+
+/** ACPI ALWR method: write to a register
+ * @param handle the handle of the device
+ * @param reg the register to write to
+ * @param val the value to write
+ * @param[out] ret result of the operation
+ * @return AE_OK on success
+ */
+static acpi_status mdps_ALWR(acpi_handle handle, int reg, int val,
+                             unsigned long *ret)
+{
+       union acpi_object in_obj[2];
+       struct acpi_object_list args = { 2, in_obj };
+
+       in_obj[0].type          = ACPI_TYPE_INTEGER;
+       in_obj[0].integer.value = reg;
+       in_obj[1].type          = ACPI_TYPE_INTEGER;
+       in_obj[1].integer.value = val;
+
+       return acpi_evaluate_integer(handle, "ALWR", &args, ret);
+}
+
+/** Get X and Y axis values from the accelerometer
+ * @param handle the handle to the device
+ * @param[out] x where to store the X axis value
+ * @param[out] y where to store the Y axis value
+ */
+static void mdps_get_xy(acpi_handle handle, int *x, int *y)
+{
+       unsigned long x_lo, x_hi, y_lo, y_hi;
+
+       mdps_ALRD(mdps.device->handle, MDPS_OUTX_L, &x_lo);
+       mdps_ALRD(mdps.device->handle, MDPS_OUTX_H, &x_hi);
+       mdps_ALRD(mdps.device->handle, MDPS_OUTY_L, &y_lo);
+       mdps_ALRD(mdps.device->handle, MDPS_OUTY_H, &y_hi);
+
+       if (MDPS_NX9420 == mdps.type) {
+               /* On NX9420 X and Y axis seem to be swapped */
+               *y = mdps_glue_bytes(x_hi, x_lo);
+               *x = mdps_glue_bytes(y_hi, y_lo);
+       } else {
+               /* On NC6420 X is inverted */
+               *x = -mdps_glue_bytes(x_hi, x_lo);
+               *y = mdps_glue_bytes(y_hi, y_lo);
+       }
+}
+
+/** Get X, Y and Z axis values from the accelerometer
+ * @param handle the handle to the device
+ * @param[out] x where to store the X axis value
+ * @param[out] y where to store the Y axis value
+ * @param[out] z where to store the Z axis value
+ */
+static void mdps_get_xyz(acpi_handle handle, int *x, int *y, int *z)
+{
+       unsigned long z_lo, z_hi;
+
+       mdps_get_xy(mdps.device->handle, x, y);
+
+       mdps_ALRD(mdps.device->handle, MDPS_OUTZ_L, &z_lo);
+       mdps_ALRD(mdps.device->handle, MDPS_OUTZ_H, &z_hi);
+       *z = mdps_glue_bytes(z_hi, z_lo);
+}
+
+/** Kthread polling function
+ * @param data unused - here to conform to threadfn prototype
+ */
+static int mdps_joystick_kthread(void *data)
+{
+       int x = 0, y = 0, z = 0;
+
+       while (!kthread_should_stop()) {
+               if (input_3d) {
+                       mdps_get_xyz(mdps.device->handle, &x, &y, &z);
+                       input_report_abs(mdps.idev, ABS_Z, z - mdps.zcalib);
+               } else
+                       mdps_get_xy(mdps.device->handle, &x, &y);
+
+               input_report_abs(mdps.idev, ABS_X, x - mdps.xcalib);
+               input_report_abs(mdps.idev, ABS_Y, y - mdps.ycalib);
+
+               input_sync(mdps.idev);
+
+               try_to_freeze();
+               msleep_interruptible(MDPS_POLL_INTERVAL);
+       }
+
+       return 0;
+}
+
+static inline void mdps_poweroff(acpi_handle handle)
+{
+       unsigned long ret;
+       mdps.is_on = 0;
+       /* disable X,Y,Z axis and power down */
+       mdps_ALWR(handle, MDPS_CTRL_REG1, 0x00, &ret);
+}
+
+static inline void mdps_poweron(acpi_handle handle)
+{
+       mdps.is_on = 1;
+       mdps__INI(handle);
+}
+
+#ifdef CONFIG_PM
+static int mdps_suspend(struct acpi_device *device, pm_message_t state)
+{
+       /* make sure the device is off when we suspend */
+       mdps_poweroff(mdps.device->handle);
+
+       return 0;
+}
+#endif
+
+static int mdps_resume(struct acpi_device *device)
+{
+       /* make sure the device went online */
+       mdps_poweron(mdps.device->handle);
+
+       return 0;
+}
+
+static irqreturn_t mdps_irq(int irq, void *dev_id)
+{
+       atomic_inc(&mdps.count);
+
+       wake_up_interruptible(&mdps.misc_wait);
+       kill_fasync(&mdps.async_queue, SIGIO, POLL_IN);
+
+       return IRQ_HANDLED;
+}
+
+static int mdps_misc_open(struct inode *inode, struct file *file)
+{
+       int ret;
+
+       if (!atomic_dec_and_test(&mdps.available)) {
+               atomic_inc(&mdps.available);
+               return -EBUSY; /* already open */
+       }
+
+       atomic_set(&mdps.count, 0);
+
+       ret = request_irq(mdps.irq, mdps_irq, 0, "mdps", mdps_irq);
+       if (ret) {
+               printk(KERN_ERR "mdps: IRQ%d allocation failed\n", mdps.irq);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int mdps_misc_release(struct inode *inode, struct file *file)
+{
+       fasync_helper(-1, file, 0, &mdps.async_queue);
+
+       free_irq(mdps.irq, mdps_irq);
+
+       atomic_inc(&mdps.available); /* release the device */
+       return 0;
+}
+
+static ssize_t mdps_misc_read(struct file *file, char __user *buf,
+                              size_t count, loff_t *pos)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       u32 data;
+       ssize_t retval = count;
+
+       if (count != sizeof(u32))
+               return -EINVAL;
+
+       add_wait_queue(&mdps.misc_wait, &wait);
+       for (;;) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               data = atomic_xchg(&mdps.count, 0);
+               if (data)
+                       break;
+
+               if (file->f_flags & O_NONBLOCK) {
+                       retval = -EAGAIN;
+                       goto out;
+               }
+
+               if (signal_pending(current)) {
+                       retval = -ERESTARTSYS;
+                       goto out;
+               }
+
+               schedule();
+       }
+
+       if (copy_to_user(buf, &data, sizeof(data)))
+               retval = -EFAULT;
+
+out:
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(&mdps.misc_wait, &wait);
+
+       return retval;
+}
+
+static unsigned int mdps_misc_poll(struct file *file, poll_table *wait)
+{
+       poll_wait(file, &mdps.misc_wait, wait);
+
+       if (atomic_read(&mdps.count))
+               return POLLIN | POLLRDNORM;
+
+       return 0;
+}
+
+static int mdps_misc_fasync(int fd, struct file *file, int on)
+{
+       return fasync_helper(fd, file, on, &mdps.async_queue);
+}
+
+static const struct file_operations mdps_misc_fops = {
+       .owner   = THIS_MODULE,
+       .llseek  = no_llseek,
+       .read    = mdps_misc_read,
+       .open    = mdps_misc_open,
+       .release = mdps_misc_release,
+       .poll    = mdps_misc_poll,
+       .fasync  = mdps_misc_fasync,
+};
+
+static struct miscdevice mdps_misc_device = {
+       .minor   = MISC_DYNAMIC_MINOR,
+       .name    = "accel",
+       .fops    = &mdps_misc_fops,
+};
+
+static acpi_status
+mdps_get_resource(struct acpi_resource *resource, void *context)
+{
+       if (resource->type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
+               struct acpi_resource_extended_irq *irq;
+               u32 *device_irq = context;
+
+               irq = &resource->data.extended_irq;
+               *device_irq = irq->interrupts[0];
+       }
+
+       return AE_OK;
+}
+
+static void mdps_enum_resources(struct acpi_device *device)
+{
+       acpi_status status;
+
+       status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
+                                       mdps_get_resource, &mdps.irq);
+       if (ACPI_FAILURE(status))
+               printk(KERN_DEBUG "mdps: Error getting resources\n");
+}
+
+static int mdps_add(struct acpi_device *device)
+{
+       unsigned long val;
+       int ret;
+
+       if (!device)
+               return -EINVAL;
+
+       mdps.device = device;
+       strcpy(acpi_device_name(device), DRIVER_NAME);
+       strcpy(acpi_device_class(device), ACPI_MDPS_CLASS);
+       acpi_driver_data(device) = &mdps;
+
+       mdps_ALRD(device->handle, MDPS_WHO_AM_I, &val);
+       if (val != MDPS_ID) {
+               printk(KERN_ERR
+                       "mdps: Accelerometer chip not LIS3LV02D{L,Q}\n");
+               return -ENODEV;
+       }
+
+       mdps_add_fs(device);
+       mdps_resume(device);
+
+       if (joystick)
+               mdps_joystick_enable();
+
+       /* obtain IRQ numer of our device from ACPI */
+       mdps_enum_resources(device);
+
+       if (power_off) /* see if user wanted to power off the device on load */
+               mdps_poweroff(mdps.device->handle);
+
+       /* if we did not get an IRQ from ACPI - we have nothing more to do */
+       if (!mdps.irq) {
+               printk(KERN_INFO
+                       "mdps: No IRQ in ACPI. Disabling /dev/accel\n");
+               return 0;
+       }
+
+       atomic_set(&mdps.available, 1); /* init the misc device open count */
+       init_waitqueue_head(&mdps.misc_wait);
+
+       ret = misc_register(&mdps_misc_device);
+       if (ret)
+               printk(KERN_ERR "mdps: misc_register failed\n");
+
+       return 0;
+}
+
+static int mdps_remove(struct acpi_device *device, int type)
+{
+       if (!device)
+               return -EINVAL;
+
+       if (mdps.irq)
+               misc_deregister(&mdps_misc_device);
+
+       mdps_joystick_disable();
+
+       return mdps_remove_fs();
+}
+
+static inline void mdps_calibrate_joystick(void)
+{
+       mdps_get_xyz(mdps.device->handle, &mdps.xcalib, &mdps.ycalib,
+               &mdps.zcalib);
+}
+
+static int mdps_joystick_open(struct input_dev *dev)
+{
+       mdps.kthread = kthread_run(mdps_joystick_kthread, NULL, "kmdps");
+       if (IS_ERR(mdps.kthread))
+               return PTR_ERR(mdps.kthread);
+
+       return 0;
+}
+
+static void mdps_joystick_close(struct input_dev *dev)
+{
+       kthread_stop(mdps.kthread);
+}
+
+static void mdps_joystick_enable(void)
+{
+       if (mdps.idev)
+               return;
+
+       mdps.idev = input_allocate_device();
+       if (!mdps.idev)
+               return;
+
+       mdps_calibrate_joystick();
+
+       mdps.idev->name       = "HP Mobile Data Protection System";
+       mdps.idev->id.bustype = BUS_HOST;
+       mdps.idev->id.vendor  = 0;
+       mdps.idev->cdev.dev   = &mdps.pdev->dev;
+
+       set_bit(EV_ABS, mdps.idev->evbit);
+
+       input_set_abs_params(mdps.idev, ABS_X, -MDPS_MAX_VAL, MDPS_MAX_VAL, 3, 
0);
+       input_set_abs_params(mdps.idev, ABS_Y, -MDPS_MAX_VAL, MDPS_MAX_VAL, 3, 
0);
+       if (input_3d)
+               input_set_abs_params(mdps.idev, ABS_Z, -MDPS_MAX_VAL,
+                       MDPS_MAX_VAL, 3, 0);
+
+       mdps.idev->open  = mdps_joystick_open;
+       mdps.idev->close = mdps_joystick_close;
+
+       if (input_register_device(mdps.idev)) {
+               input_free_device(mdps.idev);
+               mdps.idev = NULL;
+       }
+}
+
+static void mdps_joystick_disable(void)
+{
+       if (!mdps.idev)
+               return;
+
+       input_unregister_device(mdps.idev);
+       mdps.idev = NULL;
+}
+
+/* Sysfs stuff */
+static ssize_t mdps_position_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       int x, y;
+       mdps_get_xy(mdps.device->handle, &x, &y);
+
+       if (hdaps_compat) { /* mdps is 10 times more sensitive than hdaps */
+               x /= 10;
+               y /= 10;
+       }
+
+       return sprintf(buf, "(%d,%d)\n", x, y);
+}
+
+static ssize_t mdps_position3d_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       int x, y, z;
+       mdps_get_xyz(mdps.device->handle, &x, &y, &z);
+
+       return sprintf(buf, "(%d,%d,%d)\n", x, y, z);
+}
+
+static ssize_t mdps_state_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%s\n", (mdps.is_on ? "on" : "off"));
+}
+
+static ssize_t mdps_input_show_joystick(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%s\n", (joystick ? "enabled" : "disabled"));
+}
+
+static ssize_t mdps_input_store_joystick(struct device *dev,
+       struct device_attribute *attr, const char *buf, size_t count)
+{
+       int state;
+       if (sscanf(buf, "%d", &state) != 1 || (state != 1 && state != 0))
+               return -EINVAL;
+
+       joystick = state;
+
+       if (joystick)
+               mdps_joystick_enable();
+       else
+               mdps_joystick_disable();
+
+       return count;
+}
+
+static ssize_t mdps_calibrate_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       if (input_3d)
+               return sprintf(buf, "(%d,%d,%d)\n", mdps.xcalib, mdps.ycalib,
+                       mdps.zcalib);
+
+       return sprintf(buf, "(%d,%d)\n", mdps.xcalib, mdps.ycalib);
+}
+
+static ssize_t mdps_calibrate_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       mdps_calibrate_joystick();
+       return count;
+}
+
+static ssize_t mdps_rate_show(struct device *dev,
+                              struct device_attribute *attr, char *buf)
+{
+       unsigned long ctrl;
+       int rate = 0;
+
+       mdps_ALRD(mdps.device->handle, MDPS_CTRL_REG1, &ctrl);
+
+       /* get the sampling rate of the accelerometer in HZ */
+       switch ((ctrl & 0x30) >> 4)
+       {
+       case 00:
+               rate = 40;
+               break;
+
+       case 01:
+               rate = 160;
+               break;
+
+       case 02:
+               rate = 640;
+               break;
+
+       case 03:
+               rate = 2560;
+               break;
+       }
+
+       return sprintf(buf, "%d\n", rate);
+}
+
+static ssize_t mdps_state_store(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t count)
+{
+       int state;
+       if (sscanf(buf, "%d", &state) != 1 || (state != 1 && state != 0))
+               return -EINVAL;
+
+       mdps.is_on = state;
+
+       if (mdps.is_on)
+               mdps_poweron(mdps.device->handle);
+       else
+               mdps_poweroff(mdps.device->handle);
+
+       return count;
+}
+
+static DEVICE_ATTR(position, S_IRUGO, mdps_position_show, NULL);
+static DEVICE_ATTR(position3d, S_IRUGO, mdps_position3d_show, NULL);
+static DEVICE_ATTR(calibrate, S_IRUGO|S_IWUSR, mdps_calibrate_show,
+       mdps_calibrate_store);
+static DEVICE_ATTR(rate, S_IRUGO, mdps_rate_show, NULL);
+static DEVICE_ATTR(state, S_IRUGO|S_IWUSR, mdps_state_show, mdps_state_store);
+static DEVICE_ATTR(joystick, S_IRUGO|S_IWUSR, mdps_input_show_joystick, 
+       mdps_input_store_joystick);
+
+static struct attribute *mdps_attributes[] = {
+       &dev_attr_position.attr,
+       &dev_attr_position3d.attr,
+       &dev_attr_calibrate.attr,
+       &dev_attr_rate.attr,
+       &dev_attr_state.attr,
+       &dev_attr_joystick.attr,
+       NULL
+};
+
+static struct attribute_group mdps_attribute_group = {
+       .attrs = mdps_attributes
+};
+
+static int mdps_add_fs(struct acpi_device *device)
+{
+       char *name = DRIVER_NAME;
+
+       if (hdaps_compat)
+               name = "hdaps";
+
+       mdps.pdev = platform_device_register_simple(name, -1, NULL, 0);
+       if (IS_ERR(mdps.pdev))
+               return PTR_ERR(mdps.pdev);
+
+       return sysfs_create_group(&mdps.pdev->dev.kobj, &mdps_attribute_group);
+}
+
+static int mdps_remove_fs(void)
+{
+       sysfs_remove_group(&mdps.pdev->dev.kobj, &mdps_attribute_group);
+       platform_device_unregister(mdps.pdev);
+       return 0;
+}
+
+struct mdps_id {
+       acpi_string path;
+       enum mdps_type type;
+};
+
+static struct mdps_id mdps_devices[] __initdata = {
+       {"\\_SB.C002.ACEL", MDPS_NC64x0},
+       {"\\_SB.C003.ACEL", MDPS_NX9420},
+       { }
+};
+
+static int __init mdps_init_module(void)
+{
+       int ret, device_found;
+       unsigned int i;
+       acpi_status status;
+       acpi_handle handle = 0;
+
+       if (acpi_disabled)
+               return -ENODEV;
+
+       /* see if our device is present in ACPI */
+       device_found = 0;
+       for (i = 0; mdps_devices[i].path; ++i) {
+               status = acpi_get_handle(NULL, mdps_devices[i].path, &handle);
+               if (ACPI_SUCCESS(status)) {
+                       mdps.type = mdps_devices[i].type;
+                       device_found = 1;
+                       break;
+               }
+       }
+
+       if (!device_found) {
+               printk(KERN_ERR
+                       "mdps: HP Mobile Data Protection System 3D not 
found\n");
+               return -ENODEV;
+       }
+
+       ret = acpi_bus_register_driver(&mdps_driver);
+       if (ret < 0)
+               return ret;
+       
+       printk(KERN_INFO "mdps: (" VERSION ") loaded.\n");
+
+       return 0;
+}
+
+static void __exit mdps_exit_module(void)
+{
+       acpi_bus_unregister_driver(&mdps_driver);
+}
+
+MODULE_DESCRIPTION("HP three-axis digital accelerometer ACPI driver");
+MODULE_AUTHOR("Yan Burman ([EMAIL PROTECTED])");
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL");
+
+module_init(mdps_init_module);
+module_exit(mdps_exit_module);


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to