From: Stelian Pop The only issues I know about are: * the driver should do something in case of fall (parking the hard drive heads), but right now it doesn't do it because the proper block layer API doesn't exist yet. * Pavel wanted to expose the z axis movements through the input layer. The patch below implements this feature. * Additionally, there are some incorrect error paths in the original patch (i2c_add_driver() may fail and device_remove_files() won't be called) which were reported to me privately by Aristeu Sergio Rozanski Filho. The patch below takes care of this. Signed-off-by: Stelian Pop Cc: Johannes Berg Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Dmitry Torokhov Cc: Robert Love Cc: Jean Delvare Signed-off-by: Andrew Morton --- drivers/hwmon/ams.c | 57 +++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff -puN drivers/hwmon/ams.c~apple-motion-sensor-driver-update drivers/hwmon/ams.c --- a/drivers/hwmon/ams.c~apple-motion-sensor-driver-update +++ a/drivers/hwmon/ams.c @@ -1,7 +1,7 @@ /* * Apple Motion Sensor driver * - * Copyright (C) 2005 Stelian Pop (stelian@popies.net) + * Copyright (C) 2006 Stelian Pop (stelian@popies.net) * * Clean room implementation based on the reverse engineered OSX driver by * Johannes Berg , documentation available at @@ -100,6 +100,7 @@ struct ams { struct input_dev *idev; /* input device */ int xcalib; /* calibrated null value for x */ int ycalib; /* calibrated null value for y */ + int zcalib; /* calibrated null value for z */ struct task_struct *kthread; /* kthread for input */ }; @@ -212,6 +213,7 @@ static int ams_mouse_kthread(void *data) input_report_abs(ams.idev, ABS_X, x - ams.xcalib); input_report_abs(ams.idev, ABS_Y, y - ams.ycalib); + input_report_abs(ams.idev, ABS_Z, z - ams.zcalib); input_sync(ams.idev); @@ -230,6 +232,7 @@ static void ams_mouse_enable(void) ams_sensors(&x, &y, &z); ams.xcalib = x; ams.ycalib = y; + ams.zcalib = z; ams.idev = input_allocate_device(); if (!ams.idev) @@ -241,6 +244,7 @@ static void ams_mouse_enable(void) input_set_abs_params(ams.idev, ABS_X, -50, 50, 3, 0); input_set_abs_params(ams.idev, ABS_Y, -50, 50, 3, 0); + input_set_abs_params(ams.idev, ABS_Z, -50, 50, 3, 0); set_bit(EV_ABS, ams.idev->evbit); set_bit(EV_KEY, ams.idev->evbit); @@ -430,22 +434,25 @@ static int __init ams_init(void) { struct device_node* np; u32 *prop; + int retval = -ENODEV; np = of_find_node_by_name(NULL, "accelerometer"); if (!np) - return -ENODEV; + goto out; if (!device_is_compatible(np, "AAPL,accelerometer_1")) - return -ENODEV; + goto out; prop = (u32 *)get_property(np, "orientation", NULL); - if (!prop) - return -EIO; + if (!prop) { + retval = -EIO; + goto out; + } ams.orient1 = *prop; ams.orient2 = *(prop + 1); prop = (u32 *)get_property(np, "reg", NULL); if (!prop) - return -ENODEV; + goto out; /* look for bus either by path or using "reg" */ if (strstr(np->full_name, "/i2c-bus@") != NULL) { @@ -458,46 +465,50 @@ static int __init ams_init(void) np = of_find_node_by_name(NULL, "accelerometer-1"); if (!np || np->n_intrs < 1) - return -ENODEV; + goto out; ams.irq1 = np->intrs[0].line; np = of_find_node_by_name(NULL, "accelerometer-2"); if (!np || np->n_intrs < 1) - return -ENODEV; + goto out; ams.irq2 = np->intrs[0].line; if (request_irq(ams.irq1, ams_interrupt, 0, "accelerometer-1", NULL < 0)) - return -ENODEV; + goto out; if (request_irq(ams.irq2, ams_interrupt, 0, "accelerometer-2", - NULL < 0)) { - free_irq(ams.irq1, NULL); - return -ENODEV; - } + NULL < 0)) + goto free_irq1; INIT_WORK(&ams.worker, ams_worker, NULL); - if ((ams.of_dev = of_platform_device_create(np, "ams", NULL)) == NULL) { - free_irq(ams.irq1, NULL); - free_irq(ams.irq2, NULL); - return -ENODEV; - } + if ((ams.of_dev = of_platform_device_create(np, "ams", NULL)) == NULL) + goto free_irq2; device_create_file(&ams.of_dev->dev, &dev_attr_x); device_create_file(&ams.of_dev->dev, &dev_attr_y); device_create_file(&ams.of_dev->dev, &dev_attr_z); device_create_file(&ams.of_dev->dev, &dev_attr_mouse); - if (i2c_add_driver(&ams_driver) < 0) { - free_irq(ams.irq1, NULL); - free_irq(ams.irq2, NULL); - return -ENODEV; - } + if (i2c_add_driver(&ams_driver) < 0) + goto free_device_files; return 0; + +free_device_files: + device_remove_file(&ams.of_dev->dev, &dev_attr_x); + device_remove_file(&ams.of_dev->dev, &dev_attr_y); + device_remove_file(&ams.of_dev->dev, &dev_attr_z); + device_remove_file(&ams.of_dev->dev, &dev_attr_mouse); +free_irq2: + free_irq(ams.irq2, NULL); +free_irq1: + free_irq(ams.irq1, NULL); +out: + return retval; } static void __exit ams_exit(void) _