Add support for Classmate V3 accelerometer to classmate-laptop
Subsystems (2)
cover Add support for Classmate V3 accelerometer to classmate-laptop
Classmate V3 has a different accelerometer than the previous versions. Main differences between the new (ACCE0001) and the old one (ACCE0000) are:
* ACPI method calls need to receive 4 parameters instead of 2
* Values returned by the accelerometer are 2 bytes signed integers, instead of one unsigned byte
* New accelerometer has a new attribute (g_select) besides the sensitivity one. This attribute's possible values are 0 (meaning 1.5g) and 1 (meaning 6g).
I haven't been able to find the datasheet of the accelerometer, so I got most of the behaviour of the device by looking at the previous model driver and by experimenting with the hardware. Due to this, the range of the axis values (currently defined as -255-255) may not be exact, and also the fuzz value (16) may not be the best. But, with this configuration, the programs handling the screen rotation developed for previous versions of Classmate are working properly.
Initially I thought of modifying the ACCE0000 driver to be able to handle both devices, but the patch was quite big and messy, and it might add problems to the previous hardware, so I decided to implement it as a new driver, following the structure of the ACCE0000 driver. This way the new code won't break the old one.
In order to differenciate the new driver code from the old one, all the function names that belong to the new driver end with "v3".
Hope everything is ok :)
Regards!
Miguel Gómez (1):
classmate-laptop: Add support for accelerometer in classmate V3.
drivers/platform/x86/classmate-laptop.c | 400 ++++++++++++++++++++++++++++++- 1 file changed, 398 insertions(+), 2 deletions(-)
Signature · 1 line
1.7.9.5
PATCH 1/1 classmate-laptop: Add support for Classmate V3 accelerometer.
Classmate V3 laptop includes a new accelerometer that can't be handled by previous driver. This patch adds a new driver to handle it.
--- drivers/platform/x86/classmate-laptop.c | 400 ++++++++++++++++++++++++++++++- 1 file changed, 398 insertions(+), 2 deletions(-)
drivers/platform/x86/classmate-laptop.c +398 -2
@@ -31,12 +31,18 @@ MODULE_LICENSE("GPL");struct cmpc_accel {int sensitivity; +int g_select; +int inputdev_state; }; -#define CMPC_ACCEL_SENSITIVITY_DEFAULT 5 +#define CMPC_ACCEL_DEV_STATE_CLOSED 0 +#define CMPC_ACCEL_DEV_STATE_OPEN 1 +#define CMPC_ACCEL_SENSITIVITY_DEFAULT 5 +#define CMPC_ACCEL_G_SELECT_DEFAULT 0#define CMPC_ACCEL_HID "ACCE0000" +#define CMPC_ACCEL_HID_V3 "ACCE0001"#define CMPC_TABLET_HID "TBLT0000"#define CMPC_IPML_HID "IPML200"#define CMPC_KEYS_HID "FnBT0000"
@@ -76,7 +82,388 @@ static int cmpc_remove_acpi_notify_device(struct acpi_device *acpi) }/* -* Accelerometer code. +* Accelerometer code for Classmate V3 +*/ +static acpi_status cmpc_start_accel_v3 (acpi_handle handle) +{ +union acpi_object param[4 ]; +struct acpi_object_list input; +acpi_status status; + + param[0 ].type =ACPI_TYPE_INTEGER ; + param[0 ].integer.value =0x3 ; + param[1 ].type =ACPI_TYPE_INTEGER ; + param[1 ].integer.value =0 ; + param[2 ].type =ACPI_TYPE_INTEGER ; + param[2 ].integer.value =0 ; + param[3 ].type =ACPI_TYPE_INTEGER ; + param[3 ].integer.value =0 ; + input.count =4 ; + input.pointer = param; + status =acpi_evaluate_object (handle,"ACMD" , &input,NULL ); +return status; +} + +static acpi_status cmpc_stop_accel_v3 (acpi_handle handle) +{ +union acpi_object param[4 ]; +struct acpi_object_list input; +acpi_status status; + + param[0 ].type =ACPI_TYPE_INTEGER ; + param[0 ].integer.value =0x4 ; + param[1 ].type =ACPI_TYPE_INTEGER ; + param[1 ].integer.value =0 ; + param[2 ].type =ACPI_TYPE_INTEGER ; + param[2 ].integer.value =0 ; + param[3 ].type =ACPI_TYPE_INTEGER ; + param[3 ].integer.value =0 ; + input.count =4 ; + input.pointer = param; + status =acpi_evaluate_object (handle,"ACMD" , &input,NULL ); +return status; +} + +static acpi_status cmpc_accel_set_sensitivity_v3 (acpi_handle handle,int val) +{ +union acpi_object param[4 ]; +struct acpi_object_list input; + + param[0 ].type =ACPI_TYPE_INTEGER ; + param[0 ].integer.value =0x02 ; + param[1 ].type =ACPI_TYPE_INTEGER ; + param[1 ].integer.value = val; + param[2 ].type =ACPI_TYPE_INTEGER ; + param[2 ].integer.value =0 ; + param[3 ].type =ACPI_TYPE_INTEGER ; + param[3 ].integer.value =0 ; + input.count =4 ; + input.pointer = param; +return acpi_evaluate_object (handle,"ACMD" , &input,NULL ); +} + +static acpi_status cmpc_accel_set_g_select_v3 (acpi_handle handle,int val) +{ +union acpi_object param[4 ]; +struct acpi_object_list input; + + param[0 ].type =ACPI_TYPE_INTEGER ; + param[0 ].integer.value =0x05 ; + param[1 ].type =ACPI_TYPE_INTEGER ; + param[1 ].integer.value = val; + param[2 ].type =ACPI_TYPE_INTEGER ; + param[2 ].integer.value =0 ; + param[3 ].type =ACPI_TYPE_INTEGER ; + param[3 ].integer.value =0 ; + input.count =4 ; + input.pointer = param; +return acpi_evaluate_object (handle,"ACMD" , &input,NULL ); +} + +static acpi_status cmpc_get_accel_v3 (acpi_handle handle, +int16_t *x, +int16_t *y, +int16_t *z) +{ +union acpi_object param[4 ]; +struct acpi_object_list input; +struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER ,NULL }; +int16_t *locs; +acpi_status status; + + param[0 ].type =ACPI_TYPE_INTEGER ; + param[0 ].integer.value =0x01 ; + param[1 ].type =ACPI_TYPE_INTEGER ; + param[1 ].integer.value =0 ; + param[2 ].type =ACPI_TYPE_INTEGER ; + param[2 ].integer.value =0 ; + param[3 ].type =ACPI_TYPE_INTEGER ; + param[3 ].integer.value =0 ; + input.count =4 ; + input.pointer = param; + status =acpi_evaluate_object (handle,"ACMD" , &input, &output); +if (ACPI_SUCCESS (status)) { +union acpi_object *obj; + obj = output.pointer; + locs = (int16_t *) obj->buffer.pointer; + *x = locs[0 ]; + *y = locs[1 ]; + *z = locs[2 ]; +kfree (output.pointer); + } +return status; +} + +static void cmpc_accel_handler_v3 (struct acpi_device *dev,u32 event) +{ +if (event ==0x81 ) { +int16_t x, y, z; +acpi_status status; + + status =cmpc_get_accel_v3 (dev->handle, &x, &y, &z); +if (ACPI_SUCCESS (status)) { +struct input_dev *inputdev =dev_get_drvdata (&dev->dev); + +input_report_abs (inputdev,ABS_X , x); +input_report_abs (inputdev,ABS_Y , y); +input_report_abs (inputdev,ABS_Z , z); +input_sync (inputdev); + } + } +} + +static ssize_t cmpc_accel_sensitivity_show_v3 (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +struct acpi_device *acpi; +struct input_dev *inputdev; +struct cmpc_accel *accel; + + acpi =to_acpi_device (dev); + inputdev =dev_get_drvdata (&acpi->dev); + accel =dev_get_drvdata (&inputdev->dev); + +return sprintf (buf,"%d\n" , accel->sensitivity); +} + +static ssize_t cmpc_accel_sensitivity_store_v3 (struct device *dev, +struct device_attribute *attr, +const char *buf,size_t count) +{ +struct acpi_device *acpi; +struct input_dev *inputdev; +struct cmpc_accel *accel; +unsigned long sensitivity; +int r; + + acpi =to_acpi_device (dev); + inputdev =dev_get_drvdata (&acpi->dev); + accel =dev_get_drvdata (&inputdev->dev); + + r =kstrtoul (buf,0 , &sensitivity); +if (r) +return r; + +/* sensitivity must be between 1 and 127 */ +if (sensitivity <1 || sensitivity >127 ) +return -EINVAL ; + + accel->sensitivity = sensitivity; +cmpc_accel_set_sensitivity_v3 (acpi->handle, sensitivity); + +return strnlen (buf, count); +} + +static struct device_attribute cmpc_accel_sensitivity_attr_v3 = { + .attr = { .name ="sensitivity" , .mode =0660 }, + .show = cmpc_accel_sensitivity_show_v3, + .store = cmpc_accel_sensitivity_store_v3 +}; + +static ssize_t cmpc_accel_g_select_show_v3 (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +struct acpi_device *acpi; +struct input_dev *inputdev; +struct cmpc_accel *accel; + + acpi =to_acpi_device (dev); + inputdev =dev_get_drvdata (&acpi->dev); + accel =dev_get_drvdata (&inputdev->dev); + +return sprintf (buf,"%d\n" , accel->g_select); +} + +static ssize_t cmpc_accel_g_select_store_v3 (struct device *dev, +struct device_attribute *attr, +const char *buf,size_t count) +{ +struct acpi_device *acpi; +struct input_dev *inputdev; +struct cmpc_accel *accel; +unsigned long g_select; +int r; + + acpi =to_acpi_device (dev); + inputdev =dev_get_drvdata (&acpi->dev); + accel =dev_get_drvdata (&inputdev->dev); + + r =kstrtoul (buf,0 , &g_select); +if (r) +return r; + +/* 0 means 1.5g, 1 means 6g, everything else is wrong */ +if (g_select !=0 && g_select !=1 ) +return -EINVAL ; + + accel->g_select = g_select; +cmpc_accel_set_g_select_v3 (acpi->handle, g_select); + +return strnlen (buf, count); +} + +static struct device_attribute cmpc_accel_g_select_attr_v3 = { + .attr = { .name ="g_select" , .mode =0660 }, + .show = cmpc_accel_g_select_show_v3, + .store = cmpc_accel_g_select_store_v3 +}; + +static int cmpc_accel_open_v3 (struct input_dev *input) +{ +struct acpi_device *acpi; +struct cmpc_accel *accel; + + acpi =to_acpi_device (input->dev.parent); + accel =dev_get_drvdata (&input->dev); + +cmpc_accel_set_sensitivity_v3 (acpi->handle, accel->sensitivity); +cmpc_accel_set_g_select_v3 (acpi->handle, accel->g_select); + +if (ACPI_SUCCESS (cmpc_start_accel_v3 (acpi->handle))) { + accel->inputdev_state =CMPC_ACCEL_DEV_STATE_OPEN ; +return 0 ; + } +return -EIO ; +} + +static void cmpc_accel_close_v3 (struct input_dev *input) +{ +struct acpi_device *acpi; +struct cmpc_accel *accel; + + acpi =to_acpi_device (input->dev.parent); + accel =dev_get_drvdata (&input->dev); + +cmpc_stop_accel_v3 (acpi->handle); + accel->inputdev_state =CMPC_ACCEL_DEV_STATE_CLOSED ; +} + +static void cmpc_accel_idev_init_v3 (struct input_dev *inputdev) +{ +set_bit (EV_ABS , inputdev->evbit); +input_set_abs_params (inputdev,ABS_X ,-255 ,255 ,16 ,0 ); +input_set_abs_params (inputdev,ABS_Y ,-255 ,255 ,16 ,0 ); +input_set_abs_params (inputdev,ABS_Z ,-255 ,255 ,16 ,0 ); + inputdev->open = cmpc_accel_open_v3; + inputdev->close = cmpc_accel_close_v3; +} + +static int cmpc_accel_suspend_v3 (struct acpi_device *acpi,pm_message_t state) +{ +struct input_dev *inputdev; +struct cmpc_accel *accel; + + inputdev =dev_get_drvdata (&acpi->dev); + accel =dev_get_drvdata (&inputdev->dev); + +if (accel->inputdev_state ==CMPC_ACCEL_DEV_STATE_OPEN ) +return cmpc_stop_accel_v3 (acpi->handle); + +return 0 ; +} + +static int cmpc_accel_resume_v3 (struct acpi_device *acpi) +{ + +struct input_dev *inputdev; +struct cmpc_accel *accel; + + inputdev =dev_get_drvdata (&acpi->dev); + accel =dev_get_drvdata (&inputdev->dev); + +if (accel->inputdev_state ==CMPC_ACCEL_DEV_STATE_OPEN ) { +cmpc_accel_set_sensitivity_v3 (acpi->handle, accel->sensitivity); +cmpc_accel_set_g_select_v3 (acpi->handle, accel->g_select); + +if (ACPI_FAILURE (cmpc_start_accel_v3 (acpi->handle))) +return -EIO ; + } + +return 0 ; +} + +static int cmpc_accel_add_v3 (struct acpi_device *acpi) +{ +int error; +struct input_dev *inputdev; +struct cmpc_accel *accel; + + accel =kmalloc (sizeof (*accel),GFP_KERNEL ); +if (!accel) +return -ENOMEM ; + + accel->inputdev_state =CMPC_ACCEL_DEV_STATE_CLOSED ; + + accel->sensitivity =CMPC_ACCEL_SENSITIVITY_DEFAULT ; +cmpc_accel_set_sensitivity_v3 (acpi->handle, accel->sensitivity); + + error =device_create_file (&acpi->dev, &cmpc_accel_sensitivity_attr_v3); +if (error) + goto failed_sensitivity; + + accel->g_select =CMPC_ACCEL_G_SELECT_DEFAULT ; +cmpc_accel_set_g_select_v3 (acpi->handle, accel->g_select); + + error =device_create_file (&acpi->dev, &cmpc_accel_g_select_attr_v3); +if (error) + goto failed_g_select; + + error =cmpc_add_acpi_notify_device (acpi,"cmpc_accel_v3" , + cmpc_accel_idev_init_v3); +if (error) + goto failed_input; + + inputdev =dev_get_drvdata (&acpi->dev); +dev_set_drvdata (&inputdev->dev, accel); + +return 0 ; + +failed_input: +device_remove_file (&acpi->dev, &cmpc_accel_g_select_attr_v3); +failed_g_select: +device_remove_file (&acpi->dev, &cmpc_accel_sensitivity_attr_v3); +failed_sensitivity: +kfree (accel); +return error; +} + +static int cmpc_accel_remove_v3 (struct acpi_device *acpi,int type) +{ +struct input_dev *inputdev; +struct cmpc_accel *accel; + + inputdev =dev_get_drvdata (&acpi->dev); + accel =dev_get_drvdata (&inputdev->dev); + +device_remove_file (&acpi->dev, &cmpc_accel_sensitivity_attr_v3); +device_remove_file (&acpi->dev, &cmpc_accel_g_select_attr_v3); +return cmpc_remove_acpi_notify_device (acpi); +} + +static const struct acpi_device_id cmpc_accel_device_ids_v3[] = { + {CMPC_ACCEL_HID_V3 ,0 }, + {"" ,0 } +}; + +static struct acpi_driver cmpc_accel_acpi_driver_v3 = { + .owner =THIS_MODULE , + .name ="cmpc_accel_v3" , + .class ="cmpc_accel_v3" , + .ids = cmpc_accel_device_ids_v3, + .ops = { + .add = cmpc_accel_add_v3, + .remove = cmpc_accel_remove_v3, + .notify = cmpc_accel_handler_v3, + .suspend = cmpc_accel_suspend_v3, + .resume = cmpc_accel_resume_v3, + } +}; + + +/* +* Accelerometer code for classmate V1 and V2 */ static acpi_status cmpc_start_accel (acpi_handle handle) {
@@ -723,8 +1110,15 @@ static int cmpc_init(void)if (r) goto failed_accel; + r =acpi_bus_register_driver (&cmpc_accel_acpi_driver_v3); +if (r) + goto failed_accel_v3; +return r; +failed_accel_v3: +acpi_bus_unregister_driver (&cmpc_accel_acpi_driver); + failed_accel:acpi_bus_unregister_driver (&cmpc_tablet_acpi_driver);
@@ -740,6 +1134,7 @@ failed_keys:static void cmpc_exit (void ) { +acpi_bus_unregister_driver (&cmpc_accel_acpi_driver_v3);acpi_bus_unregister_driver (&cmpc_accel_acpi_driver);acpi_bus_unregister_driver (&cmpc_tablet_acpi_driver);acpi_bus_unregister_driver (&cmpc_ipml_acpi_driver);
@@ -751,6 +1146,7 @@ module_exit(cmpc_exit);static const struct acpi_device_id cmpc_device_ids[] = { {CMPC_ACCEL_HID ,0 }, + {CMPC_ACCEL_HID_V3 ,0 }, {CMPC_TABLET_HID ,0 }, {CMPC_IPML_HID ,0 }, {CMPC_KEYS_HID ,0 },
Signature · 1 line
1.7.9.5
v2 cover Add support for Classmate V4 accelerometer to classmate-laptop
In reply to Miguel Gómez************************************************************************
Sorry, I made a mistake with the version. The patch is for Classmate V4 and not for V3, so I adjusted it accordingly.
************************************************************************
Classmate V4 has a different accelerometer than the previous versions. Main differences between the new (ACCE0001) and the old one (ACCE0000) are:
* ACPI method calls need to receive 4 parameters instead of 2
* Values returned by the accelerometer are 2 bytes signed integers, instead of one unsigned byte
* New accelerometer has a new attribute (g_select) besides the sensitivity one. This attribute's possible values are 0 (meaning 1.5g) and 1 (meaning 6g).
I haven't been able to find the datasheet of the accelerometer, so I got most of the behaviour of the device by looking at the previous model driver and by experimenting with the hardware. Due to this, the range of the axis values (currently defined as -255-255) may not be exact, and also the fuzz value (16) may not be the best. But, with this configuration, the programs handling the screen rotation developed for previous versions of Classmate are working properly.
Initially I thought of modifying the ACCE0000 driver to be able to handle both devices, but the patch was quite big and messy, and it might add problems to the previous hardware, so I decided to implement it as a new driver, following the structure of the ACCE0000 driver. This way the new code won't break the old one.
In order to differenciate the new driver code from the old one, all the function names that belong to the new driver end with "v4".
Hope everything is ok :)
Regards!
Miguel Gómez (1):
classmate-laptop: Add support for Classmate V4 accelerometer.
drivers/platform/x86/classmate-laptop.c | 400 ++++++++++++++++++++++++++++++- 1 file changed, 398 insertions(+), 2 deletions(-)
Signature · 1 line
1.7.9.5
PATCH v2 1/1 classmate-laptop: Add support for Classmate V4 accelerometer.
Classmate V4 laptop includes a new accelerometer that can't be handled by previous driver. This patch adds a new driver to handle it.
--- drivers/platform/x86/classmate-laptop.c | 400 ++++++++++++++++++++++++++++++- 1 file changed, 398 insertions(+), 2 deletions(-)
drivers/platform/x86/classmate-laptop.c +398 -2
@@ -31,12 +31,18 @@ MODULE_LICENSE("GPL");struct cmpc_accel {int sensitivity; +int g_select; +int inputdev_state; }; -#define CMPC_ACCEL_SENSITIVITY_DEFAULT 5 +#define CMPC_ACCEL_DEV_STATE_CLOSED 0 +#define CMPC_ACCEL_DEV_STATE_OPEN 1 +#define CMPC_ACCEL_SENSITIVITY_DEFAULT 5 +#define CMPC_ACCEL_G_SELECT_DEFAULT 0#define CMPC_ACCEL_HID "ACCE0000" +#define CMPC_ACCEL_HID_V4 "ACCE0001"#define CMPC_TABLET_HID "TBLT0000"#define CMPC_IPML_HID "IPML200"#define CMPC_KEYS_HID "FnBT0000"
@@ -76,7 +82,388 @@ static int cmpc_remove_acpi_notify_device(struct acpi_device *acpi) }/* -* Accelerometer code. +* Accelerometer code for Classmate V4 +*/ +static acpi_status cmpc_start_accel_v4 (acpi_handle handle) +{ +union acpi_object param[4 ]; +struct acpi_object_list input; +acpi_status status; + + param[0 ].type =ACPI_TYPE_INTEGER ; + param[0 ].integer.value =0x3 ; + param[1 ].type =ACPI_TYPE_INTEGER ; + param[1 ].integer.value =0 ; + param[2 ].type =ACPI_TYPE_INTEGER ; + param[2 ].integer.value =0 ; + param[3 ].type =ACPI_TYPE_INTEGER ; + param[3 ].integer.value =0 ; + input.count =4 ; + input.pointer = param; + status =acpi_evaluate_object (handle,"ACMD" , &input,NULL ); +return status; +} + +static acpi_status cmpc_stop_accel_v4 (acpi_handle handle) +{ +union acpi_object param[4 ]; +struct acpi_object_list input; +acpi_status status; + + param[0 ].type =ACPI_TYPE_INTEGER ; + param[0 ].integer.value =0x4 ; + param[1 ].type =ACPI_TYPE_INTEGER ; + param[1 ].integer.value =0 ; + param[2 ].type =ACPI_TYPE_INTEGER ; + param[2 ].integer.value =0 ; + param[3 ].type =ACPI_TYPE_INTEGER ; + param[3 ].integer.value =0 ; + input.count =4 ; + input.pointer = param; + status =acpi_evaluate_object (handle,"ACMD" , &input,NULL ); +return status; +} + +static acpi_status cmpc_accel_set_sensitivity_v4 (acpi_handle handle,int val) +{ +union acpi_object param[4 ]; +struct acpi_object_list input; + + param[0 ].type =ACPI_TYPE_INTEGER ; + param[0 ].integer.value =0x02 ; + param[1 ].type =ACPI_TYPE_INTEGER ; + param[1 ].integer.value = val; + param[2 ].type =ACPI_TYPE_INTEGER ; + param[2 ].integer.value =0 ; + param[3 ].type =ACPI_TYPE_INTEGER ; + param[3 ].integer.value =0 ; + input.count =4 ; + input.pointer = param; +return acpi_evaluate_object (handle,"ACMD" , &input,NULL ); +} + +static acpi_status cmpc_accel_set_g_select_v4 (acpi_handle handle,int val) +{ +union acpi_object param[4 ]; +struct acpi_object_list input; + + param[0 ].type =ACPI_TYPE_INTEGER ; + param[0 ].integer.value =0x05 ; + param[1 ].type =ACPI_TYPE_INTEGER ; + param[1 ].integer.value = val; + param[2 ].type =ACPI_TYPE_INTEGER ; + param[2 ].integer.value =0 ; + param[3 ].type =ACPI_TYPE_INTEGER ; + param[3 ].integer.value =0 ; + input.count =4 ; + input.pointer = param; +return acpi_evaluate_object (handle,"ACMD" , &input,NULL ); +} + +static acpi_status cmpc_get_accel_v4 (acpi_handle handle, +int16_t *x, +int16_t *y, +int16_t *z) +{ +union acpi_object param[4 ]; +struct acpi_object_list input; +struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER ,NULL }; +int16_t *locs; +acpi_status status; + + param[0 ].type =ACPI_TYPE_INTEGER ; + param[0 ].integer.value =0x01 ; + param[1 ].type =ACPI_TYPE_INTEGER ; + param[1 ].integer.value =0 ; + param[2 ].type =ACPI_TYPE_INTEGER ; + param[2 ].integer.value =0 ; + param[3 ].type =ACPI_TYPE_INTEGER ; + param[3 ].integer.value =0 ; + input.count =4 ; + input.pointer = param; + status =acpi_evaluate_object (handle,"ACMD" , &input, &output); +if (ACPI_SUCCESS (status)) { +union acpi_object *obj; + obj = output.pointer; + locs = (int16_t *) obj->buffer.pointer; + *x = locs[0 ]; + *y = locs[1 ]; + *z = locs[2 ]; +kfree (output.pointer); + } +return status; +} + +static void cmpc_accel_handler_v4 (struct acpi_device *dev,u32 event) +{ +if (event ==0x81 ) { +int16_t x, y, z; +acpi_status status; + + status =cmpc_get_accel_v4 (dev->handle, &x, &y, &z); +if (ACPI_SUCCESS (status)) { +struct input_dev *inputdev =dev_get_drvdata (&dev->dev); + +input_report_abs (inputdev,ABS_X , x); +input_report_abs (inputdev,ABS_Y , y); +input_report_abs (inputdev,ABS_Z , z); +input_sync (inputdev); + } + } +} + +static ssize_t cmpc_accel_sensitivity_show_v4 (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +struct acpi_device *acpi; +struct input_dev *inputdev; +struct cmpc_accel *accel; + + acpi =to_acpi_device (dev); + inputdev =dev_get_drvdata (&acpi->dev); + accel =dev_get_drvdata (&inputdev->dev); + +return sprintf (buf,"%d\n" , accel->sensitivity); +} + +static ssize_t cmpc_accel_sensitivity_store_v4 (struct device *dev, +struct device_attribute *attr, +const char *buf,size_t count) +{ +struct acpi_device *acpi; +struct input_dev *inputdev; +struct cmpc_accel *accel; +unsigned long sensitivity; +int r; + + acpi =to_acpi_device (dev); + inputdev =dev_get_drvdata (&acpi->dev); + accel =dev_get_drvdata (&inputdev->dev); + + r =kstrtoul (buf,0 , &sensitivity); +if (r) +return r; + +/* sensitivity must be between 1 and 127 */ +if (sensitivity <1 || sensitivity >127 ) +return -EINVAL ; + + accel->sensitivity = sensitivity; +cmpc_accel_set_sensitivity_v4 (acpi->handle, sensitivity); + +return strnlen (buf, count); +} + +static struct device_attribute cmpc_accel_sensitivity_attr_v4 = { + .attr = { .name ="sensitivity" , .mode =0660 }, + .show = cmpc_accel_sensitivity_show_v4, + .store = cmpc_accel_sensitivity_store_v4 +}; + +static ssize_t cmpc_accel_g_select_show_v4 (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +struct acpi_device *acpi; +struct input_dev *inputdev; +struct cmpc_accel *accel; + + acpi =to_acpi_device (dev); + inputdev =dev_get_drvdata (&acpi->dev); + accel =dev_get_drvdata (&inputdev->dev); + +return sprintf (buf,"%d\n" , accel->g_select); +} + +static ssize_t cmpc_accel_g_select_store_v4 (struct device *dev, +struct device_attribute *attr, +const char *buf,size_t count) +{ +struct acpi_device *acpi; +struct input_dev *inputdev; +struct cmpc_accel *accel; +unsigned long g_select; +int r; + + acpi =to_acpi_device (dev); + inputdev =dev_get_drvdata (&acpi->dev); + accel =dev_get_drvdata (&inputdev->dev); + + r =kstrtoul (buf,0 , &g_select); +if (r) +return r; + +/* 0 means 1.5g, 1 means 6g, everything else is wrong */ +if (g_select !=0 && g_select !=1 ) +return -EINVAL ; + + accel->g_select = g_select; +cmpc_accel_set_g_select_v4 (acpi->handle, g_select); + +return strnlen (buf, count); +} + +static struct device_attribute cmpc_accel_g_select_attr_v4 = { + .attr = { .name ="g_select" , .mode =0660 }, + .show = cmpc_accel_g_select_show_v4, + .store = cmpc_accel_g_select_store_v4 +}; + +static int cmpc_accel_open_v4 (struct input_dev *input) +{ +struct acpi_device *acpi; +struct cmpc_accel *accel; + + acpi =to_acpi_device (input->dev.parent); + accel =dev_get_drvdata (&input->dev); + +cmpc_accel_set_sensitivity_v4 (acpi->handle, accel->sensitivity); +cmpc_accel_set_g_select_v4 (acpi->handle, accel->g_select); + +if (ACPI_SUCCESS (cmpc_start_accel_v4 (acpi->handle))) { + accel->inputdev_state =CMPC_ACCEL_DEV_STATE_OPEN ; +return 0 ; + } +return -EIO ; +} + +static void cmpc_accel_close_v4 (struct input_dev *input) +{ +struct acpi_device *acpi; +struct cmpc_accel *accel; + + acpi =to_acpi_device (input->dev.parent); + accel =dev_get_drvdata (&input->dev); + +cmpc_stop_accel_v4 (acpi->handle); + accel->inputdev_state =CMPC_ACCEL_DEV_STATE_CLOSED ; +} + +static void cmpc_accel_idev_init_v4 (struct input_dev *inputdev) +{ +set_bit (EV_ABS , inputdev->evbit); +input_set_abs_params (inputdev,ABS_X ,-255 ,255 ,16 ,0 ); +input_set_abs_params (inputdev,ABS_Y ,-255 ,255 ,16 ,0 ); +input_set_abs_params (inputdev,ABS_Z ,-255 ,255 ,16 ,0 ); + inputdev->open = cmpc_accel_open_v4; + inputdev->close = cmpc_accel_close_v4; +} + +static int cmpc_accel_suspend_v4 (struct acpi_device *acpi,pm_message_t state) +{ +struct input_dev *inputdev; +struct cmpc_accel *accel; + + inputdev =dev_get_drvdata (&acpi->dev); + accel =dev_get_drvdata (&inputdev->dev); + +if (accel->inputdev_state ==CMPC_ACCEL_DEV_STATE_OPEN ) +return cmpc_stop_accel_v4 (acpi->handle); + +return 0 ; +} + +static int cmpc_accel_resume_v4 (struct acpi_device *acpi) +{ + +struct input_dev *inputdev; +struct cmpc_accel *accel; + + inputdev =dev_get_drvdata (&acpi->dev); + accel =dev_get_drvdata (&inputdev->dev); + +if (accel->inputdev_state ==CMPC_ACCEL_DEV_STATE_OPEN ) { +cmpc_accel_set_sensitivity_v4 (acpi->handle, accel->sensitivity); +cmpc_accel_set_g_select_v4 (acpi->handle, accel->g_select); + +if (ACPI_FAILURE (cmpc_start_accel_v4 (acpi->handle))) +return -EIO ; + } + +return 0 ; +} + +static int cmpc_accel_add_v4 (struct acpi_device *acpi) +{ +int error; +struct input_dev *inputdev; +struct cmpc_accel *accel; + + accel =kmalloc (sizeof (*accel),GFP_KERNEL ); +if (!accel) +return -ENOMEM ; + + accel->inputdev_state =CMPC_ACCEL_DEV_STATE_CLOSED ; + + accel->sensitivity =CMPC_ACCEL_SENSITIVITY_DEFAULT ; +cmpc_accel_set_sensitivity_v4 (acpi->handle, accel->sensitivity); + + error =device_create_file (&acpi->dev, &cmpc_accel_sensitivity_attr_v4); +if (error) + goto failed_sensitivity; + + accel->g_select =CMPC_ACCEL_G_SELECT_DEFAULT ; +cmpc_accel_set_g_select_v4 (acpi->handle, accel->g_select); + + error =device_create_file (&acpi->dev, &cmpc_accel_g_select_attr_v4); +if (error) + goto failed_g_select; + + error =cmpc_add_acpi_notify_device (acpi,"cmpc_accel_v4" , + cmpc_accel_idev_init_v4); +if (error) + goto failed_input; + + inputdev =dev_get_drvdata (&acpi->dev); +dev_set_drvdata (&inputdev->dev, accel); + +return 0 ; + +failed_input: +device_remove_file (&acpi->dev, &cmpc_accel_g_select_attr_v4); +failed_g_select: +device_remove_file (&acpi->dev, &cmpc_accel_sensitivity_attr_v4); +failed_sensitivity: +kfree (accel); +return error; +} + +static int cmpc_accel_remove_v4 (struct acpi_device *acpi,int type) +{ +struct input_dev *inputdev; +struct cmpc_accel *accel; + + inputdev =dev_get_drvdata (&acpi->dev); + accel =dev_get_drvdata (&inputdev->dev); + +device_remove_file (&acpi->dev, &cmpc_accel_sensitivity_attr_v4); +device_remove_file (&acpi->dev, &cmpc_accel_g_select_attr_v4); +return cmpc_remove_acpi_notify_device (acpi); +} + +static const struct acpi_device_id cmpc_accel_device_ids_v4[] = { + {CMPC_ACCEL_HID_V4 ,0 }, + {"" ,0 } +}; + +static struct acpi_driver cmpc_accel_acpi_driver_v4 = { + .owner =THIS_MODULE , + .name ="cmpc_accel_v4" , + .class ="cmpc_accel_v4" , + .ids = cmpc_accel_device_ids_v4, + .ops = { + .add = cmpc_accel_add_v4, + .remove = cmpc_accel_remove_v4, + .notify = cmpc_accel_handler_v4, + .suspend = cmpc_accel_suspend_v4, + .resume = cmpc_accel_resume_v4, + } +}; + + +/* +* Accelerometer code for Classmate versions prior to V4 */ static acpi_status cmpc_start_accel (acpi_handle handle) {
@@ -723,8 +1110,15 @@ static int cmpc_init(void)if (r) goto failed_accel; + r =acpi_bus_register_driver (&cmpc_accel_acpi_driver_v4); +if (r) + goto failed_accel_v4; +return r; +failed_accel_v4: +acpi_bus_unregister_driver (&cmpc_accel_acpi_driver); + failed_accel:acpi_bus_unregister_driver (&cmpc_tablet_acpi_driver);
@@ -740,6 +1134,7 @@ failed_keys:static void cmpc_exit (void ) { +acpi_bus_unregister_driver (&cmpc_accel_acpi_driver_v4);acpi_bus_unregister_driver (&cmpc_accel_acpi_driver);acpi_bus_unregister_driver (&cmpc_tablet_acpi_driver);acpi_bus_unregister_driver (&cmpc_ipml_acpi_driver);
@@ -751,6 +1146,7 @@ module_exit(cmpc_exit);static const struct acpi_device_id cmpc_device_ids[] = { {CMPC_ACCEL_HID ,0 }, + {CMPC_ACCEL_HID_V4 ,0 }, {CMPC_TABLET_HID ,0 }, {CMPC_IPML_HID ,0 }, {CMPC_KEYS_HID ,0 },
Signature · 1 line
1.7.9.5
Re: [PATCH 1/1 v2] classmate-laptop: Add support for Classmate V4 accelerometer.
Quoted 4 lines · Miguel Gómez
Classmate V4 laptop includes a new accelerometer that can't be handled by previous driver. This patch adds a new driver to handle it.
Signed-off-by Miguel Gómez <[email protected]>
Hi, Miguel.
This seems OK to me. Thanks for this work. Do you have the other functionality of the driver working? I am interested to know if you have the function buttons working.
Regards.
Cascardo.
Quoted 453 lines
--- drivers/platform/x86/classmate-laptop.c | 400 ++++++++++++++++++++++++++++++- 1 file changed, 398 insertions(+), 2 deletions(-)drivers/platform/x86/classmate-laptop.c +398
-2@@ -31,12 +31,18 @@ MODULE_LICENSE("GPL");struct cmpc_accel {int sensitivity; +int g_select; +int inputdev_state; }; -#define CMPC_ACCEL_SENSITIVITY_DEFAULT 5 +#define CMPC_ACCEL_DEV_STATE_CLOSED 0 +#define CMPC_ACCEL_DEV_STATE_OPEN 1 +#define CMPC_ACCEL_SENSITIVITY_DEFAULT 5 +#define CMPC_ACCEL_G_SELECT_DEFAULT 0#define CMPC_ACCEL_HID "ACCE0000" +#define CMPC_ACCEL_HID_V4 "ACCE0001"#define CMPC_TABLET_HID "TBLT0000"#define CMPC_IPML_HID "IPML200"#define CMPC_KEYS_HID "FnBT0000"@@ -76,7 +82,388 @@ static int cmpc_remove_acpi_notify_device(struct acpi_device *acpi) }/* -* Accelerometer code. +* Accelerometer code for Classmate V4 +*/ +static acpi_status cmpc_start_accel_v4 (acpi_handle handle) +{ +union acpi_object param[4 ]; +struct acpi_object_list input; +acpi_status status; + + param[0 ].type =ACPI_TYPE_INTEGER ; + param[0 ].integer.value =0x3 ; + param[1 ].type =ACPI_TYPE_INTEGER ; + param[1 ].integer.value =0 ; + param[2 ].type =ACPI_TYPE_INTEGER ; + param[2 ].integer.value =0 ; + param[3 ].type =ACPI_TYPE_INTEGER ; + param[3 ].integer.value =0 ; + input.count =4 ; + input.pointer = param; + status =acpi_evaluate_object (handle,"ACMD" , &input,NULL ); +return status; +} + +static acpi_status cmpc_stop_accel_v4 (acpi_handle handle) +{ +union acpi_object param[4 ]; +struct acpi_object_list input; +acpi_status status; + + param[0 ].type =ACPI_TYPE_INTEGER ; + param[0 ].integer.value =0x4 ; + param[1 ].type =ACPI_TYPE_INTEGER ; + param[1 ].integer.value =0 ; + param[2 ].type =ACPI_TYPE_INTEGER ; + param[2 ].integer.value =0 ; + param[3 ].type =ACPI_TYPE_INTEGER ; + param[3 ].integer.value =0 ; + input.count =4 ; + input.pointer = param; + status =acpi_evaluate_object (handle,"ACMD" , &input,NULL ); +return status; +} + +static acpi_status cmpc_accel_set_sensitivity_v4 (acpi_handle handle,int val) +{ +union acpi_object param[4 ]; +struct acpi_object_list input; + + param[0 ].type =ACPI_TYPE_INTEGER ; + param[0 ].integer.value =0x02 ; + param[1 ].type =ACPI_TYPE_INTEGER ; + param[1 ].integer.value = val; + param[2 ].type =ACPI_TYPE_INTEGER ; + param[2 ].integer.value =0 ; + param[3 ].type =ACPI_TYPE_INTEGER ; + param[3 ].integer.value =0 ; + input.count =4 ; + input.pointer = param; +return acpi_evaluate_object (handle,"ACMD" , &input,NULL ); +} + +static acpi_status cmpc_accel_set_g_select_v4 (acpi_handle handle,int val) +{ +union acpi_object param[4 ]; +struct acpi_object_list input; + + param[0 ].type =ACPI_TYPE_INTEGER ; + param[0 ].integer.value =0x05 ; + param[1 ].type =ACPI_TYPE_INTEGER ; + param[1 ].integer.value = val; + param[2 ].type =ACPI_TYPE_INTEGER ; + param[2 ].integer.value =0 ; + param[3 ].type =ACPI_TYPE_INTEGER ; + param[3 ].integer.value =0 ; + input.count =4 ; + input.pointer = param; +return acpi_evaluate_object (handle,"ACMD" , &input,NULL ); +} + +static acpi_status cmpc_get_accel_v4 (acpi_handle handle, +int16_t *x, +int16_t *y, +int16_t *z) +{ +union acpi_object param[4 ]; +struct acpi_object_list input; +struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER ,NULL }; +int16_t *locs; +acpi_status status; + + param[0 ].type =ACPI_TYPE_INTEGER ; + param[0 ].integer.value =0x01 ; + param[1 ].type =ACPI_TYPE_INTEGER ; + param[1 ].integer.value =0 ; + param[2 ].type =ACPI_TYPE_INTEGER ; + param[2 ].integer.value =0 ; + param[3 ].type =ACPI_TYPE_INTEGER ; + param[3 ].integer.value =0 ; + input.count =4 ; + input.pointer = param; + status =acpi_evaluate_object (handle,"ACMD" , &input, &output); +if (ACPI_SUCCESS (status)) { +union acpi_object *obj; + obj = output.pointer; + locs = (int16_t *) obj->buffer.pointer; + *x = locs[0 ]; + *y = locs[1 ]; + *z = locs[2 ]; +kfree (output.pointer); + } +return status; +} + +static void cmpc_accel_handler_v4 (struct acpi_device *dev,u32 event) +{ +if (event ==0x81 ) { +int16_t x, y, z; +acpi_status status; + + status =cmpc_get_accel_v4 (dev->handle, &x, &y, &z); +if (ACPI_SUCCESS (status)) { +struct input_dev *inputdev =dev_get_drvdata (&dev->dev); + +input_report_abs (inputdev,ABS_X , x); +input_report_abs (inputdev,ABS_Y , y); +input_report_abs (inputdev,ABS_Z , z); +input_sync (inputdev); + } + } +} + +static ssize_t cmpc_accel_sensitivity_show_v4 (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +struct acpi_device *acpi; +struct input_dev *inputdev; +struct cmpc_accel *accel; + + acpi =to_acpi_device (dev); + inputdev =dev_get_drvdata (&acpi->dev); + accel =dev_get_drvdata (&inputdev->dev); + +return sprintf (buf,"%d\n" , accel->sensitivity); +} + +static ssize_t cmpc_accel_sensitivity_store_v4 (struct device *dev, +struct device_attribute *attr, +const char *buf,size_t count) +{ +struct acpi_device *acpi; +struct input_dev *inputdev; +struct cmpc_accel *accel; +unsigned long sensitivity; +int r; + + acpi =to_acpi_device (dev); + inputdev =dev_get_drvdata (&acpi->dev); + accel =dev_get_drvdata (&inputdev->dev); + + r =kstrtoul (buf,0 , &sensitivity); +if (r) +return r; + +/* sensitivity must be between 1 and 127 */ +if (sensitivity <1 || sensitivity >127 ) +return -EINVAL ; + + accel->sensitivity = sensitivity; +cmpc_accel_set_sensitivity_v4 (acpi->handle, sensitivity); + +return strnlen (buf, count); +} + +static struct device_attribute cmpc_accel_sensitivity_attr_v4 = { + .attr = { .name ="sensitivity" , .mode =0660 }, + .show = cmpc_accel_sensitivity_show_v4, + .store = cmpc_accel_sensitivity_store_v4 +}; + +static ssize_t cmpc_accel_g_select_show_v4 (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +struct acpi_device *acpi; +struct input_dev *inputdev; +struct cmpc_accel *accel; + + acpi =to_acpi_device (dev); + inputdev =dev_get_drvdata (&acpi->dev); + accel =dev_get_drvdata (&inputdev->dev); + +return sprintf (buf,"%d\n" , accel->g_select); +} + +static ssize_t cmpc_accel_g_select_store_v4 (struct device *dev, +struct device_attribute *attr, +const char *buf,size_t count) +{ +struct acpi_device *acpi; +struct input_dev *inputdev; +struct cmpc_accel *accel; +unsigned long g_select; +int r; + + acpi =to_acpi_device (dev); + inputdev =dev_get_drvdata (&acpi->dev); + accel =dev_get_drvdata (&inputdev->dev); + + r =kstrtoul (buf,0 , &g_select); +if (r) +return r; + +/* 0 means 1.5g, 1 means 6g, everything else is wrong */ +if (g_select !=0 && g_select !=1 ) +return -EINVAL ; + + accel->g_select = g_select; +cmpc_accel_set_g_select_v4 (acpi->handle, g_select); + +return strnlen (buf, count); +} + +static struct device_attribute cmpc_accel_g_select_attr_v4 = { + .attr = { .name ="g_select" , .mode =0660 }, + .show = cmpc_accel_g_select_show_v4, + .store = cmpc_accel_g_select_store_v4 +}; + +static int cmpc_accel_open_v4 (struct input_dev *input) +{ +struct acpi_device *acpi; +struct cmpc_accel *accel; + + acpi =to_acpi_device (input->dev.parent); + accel =dev_get_drvdata (&input->dev); + +cmpc_accel_set_sensitivity_v4 (acpi->handle, accel->sensitivity); +cmpc_accel_set_g_select_v4 (acpi->handle, accel->g_select); + +if (ACPI_SUCCESS (cmpc_start_accel_v4 (acpi->handle))) { + accel->inputdev_state =CMPC_ACCEL_DEV_STATE_OPEN ; +return 0 ; + } +return -EIO ; +} + +static void cmpc_accel_close_v4 (struct input_dev *input) +{ +struct acpi_device *acpi; +struct cmpc_accel *accel; + + acpi =to_acpi_device (input->dev.parent); + accel =dev_get_drvdata (&input->dev); + +cmpc_stop_accel_v4 (acpi->handle); + accel->inputdev_state =CMPC_ACCEL_DEV_STATE_CLOSED ; +} + +static void cmpc_accel_idev_init_v4 (struct input_dev *inputdev) +{ +set_bit (EV_ABS , inputdev->evbit); +input_set_abs_params (inputdev,ABS_X ,-255 ,255 ,16 ,0 ); +input_set_abs_params (inputdev,ABS_Y ,-255 ,255 ,16 ,0 ); +input_set_abs_params (inputdev,ABS_Z ,-255 ,255 ,16 ,0 ); + inputdev->open = cmpc_accel_open_v4; + inputdev->close = cmpc_accel_close_v4; +} + +static int cmpc_accel_suspend_v4 (struct acpi_device *acpi,pm_message_t state) +{ +struct input_dev *inputdev; +struct cmpc_accel *accel; + + inputdev =dev_get_drvdata (&acpi->dev); + accel =dev_get_drvdata (&inputdev->dev); + +if (accel->inputdev_state ==CMPC_ACCEL_DEV_STATE_OPEN ) +return cmpc_stop_accel_v4 (acpi->handle); + +return 0 ; +} + +static int cmpc_accel_resume_v4 (struct acpi_device *acpi) +{ + +struct input_dev *inputdev; +struct cmpc_accel *accel; + + inputdev =dev_get_drvdata (&acpi->dev); + accel =dev_get_drvdata (&inputdev->dev); + +if (accel->inputdev_state ==CMPC_ACCEL_DEV_STATE_OPEN ) { +cmpc_accel_set_sensitivity_v4 (acpi->handle, accel->sensitivity); +cmpc_accel_set_g_select_v4 (acpi->handle, accel->g_select); + +if (ACPI_FAILURE (cmpc_start_accel_v4 (acpi->handle))) +return -EIO ; + } + +return 0 ; +} + +static int cmpc_accel_add_v4 (struct acpi_device *acpi) +{ +int error; +struct input_dev *inputdev; +struct cmpc_accel *accel; + + accel =kmalloc (sizeof (*accel),GFP_KERNEL ); +if (!accel) +return -ENOMEM ; + + accel->inputdev_state =CMPC_ACCEL_DEV_STATE_CLOSED ; + + accel->sensitivity =CMPC_ACCEL_SENSITIVITY_DEFAULT ; +cmpc_accel_set_sensitivity_v4 (acpi->handle, accel->sensitivity); + + error =device_create_file (&acpi->dev, &cmpc_accel_sensitivity_attr_v4); +if (error) + goto failed_sensitivity; + + accel->g_select =CMPC_ACCEL_G_SELECT_DEFAULT ; +cmpc_accel_set_g_select_v4 (acpi->handle, accel->g_select); + + error =device_create_file (&acpi->dev, &cmpc_accel_g_select_attr_v4); +if (error) + goto failed_g_select; + + error =cmpc_add_acpi_notify_device (acpi,"cmpc_accel_v4" , + cmpc_accel_idev_init_v4); +if (error) + goto failed_input; + + inputdev =dev_get_drvdata (&acpi->dev); +dev_set_drvdata (&inputdev->dev, accel); + +return 0 ; + +failed_input: +device_remove_file (&acpi->dev, &cmpc_accel_g_select_attr_v4); +failed_g_select: +device_remove_file (&acpi->dev, &cmpc_accel_sensitivity_attr_v4); +failed_sensitivity: +kfree (accel); +return error; +} + +static int cmpc_accel_remove_v4 (struct acpi_device *acpi,int type) +{ +struct input_dev *inputdev; +struct cmpc_accel *accel; + + inputdev =dev_get_drvdata (&acpi->dev); + accel =dev_get_drvdata (&inputdev->dev); + +device_remove_file (&acpi->dev, &cmpc_accel_sensitivity_attr_v4); +device_remove_file (&acpi->dev, &cmpc_accel_g_select_attr_v4); +return cmpc_remove_acpi_notify_device (acpi); +} + +static const struct acpi_device_id cmpc_accel_device_ids_v4[] = { + {CMPC_ACCEL_HID_V4 ,0 }, + {"" ,0 } +}; + +static struct acpi_driver cmpc_accel_acpi_driver_v4 = { + .owner =THIS_MODULE , + .name ="cmpc_accel_v4" , + .class ="cmpc_accel_v4" , + .ids = cmpc_accel_device_ids_v4, + .ops = { + .add = cmpc_accel_add_v4, + .remove = cmpc_accel_remove_v4, + .notify = cmpc_accel_handler_v4, + .suspend = cmpc_accel_suspend_v4, + .resume = cmpc_accel_resume_v4, + } +}; + + +/* +* Accelerometer code for Classmate versions prior to V4 */ static acpi_status cmpc_start_accel (acpi_handle handle) {@@ -723,8 +1110,15 @@ static int cmpc_init(void)if (r) goto failed_accel; + r =acpi_bus_register_driver (&cmpc_accel_acpi_driver_v4); +if (r) + goto failed_accel_v4; +return r; +failed_accel_v4: +acpi_bus_unregister_driver (&cmpc_accel_acpi_driver); + failed_accel:acpi_bus_unregister_driver (&cmpc_tablet_acpi_driver);@@ -740,6 +1134,7 @@ failed_keys:static void cmpc_exit (void ) { +acpi_bus_unregister_driver (&cmpc_accel_acpi_driver_v4);acpi_bus_unregister_driver (&cmpc_accel_acpi_driver);acpi_bus_unregister_driver (&cmpc_tablet_acpi_driver);acpi_bus_unregister_driver (&cmpc_ipml_acpi_driver);@@ -751,6 +1146,7 @@ module_exit(cmpc_exit);static const struct acpi_device_id cmpc_device_ids[] = { {CMPC_ACCEL_HID ,0 }, + {CMPC_ACCEL_HID_V4 ,0 }, {CMPC_TABLET_HID ,0 }, {CMPC_IPML_HID ,0 }, {CMPC_KEYS_HID ,0 },Signature · 1 line
1.7.9.5
Re: [PATCH 1/1 v2] classmate-laptop: Add support for Classmate V4 accelerometer.
Quoted 11 lines · Miguel Gómez
Quoted 4 lines
Classmate V4 laptop includes a new accelerometer that can't be handled by previous driver. This patch adds a new driver to handle it.
Signed-off-by Miguel Gómez <[email protected]>Hi, Miguel.
This seems OK to me. Thanks for this work. Do you have the other functionality of the driver working? I am interested to know if you have the function buttons working.
Hi Thadeu
I've been giving a look to the buttons code. Currently they are not working because the hardware id reported by the device (FNBT0000) is not the same as the one defined by the driver (FnBT0000), as you an one of my colleagues commented in this thread:
https://lkml.org/lkml/2011/6/21/341
I've replaced the id in the driver to FNBT0000 and it made the buttons work like a charm (enabling control of the backlight and LAN as well). To ensure compatibility with older versions of the kernel, a new id can be added (FNBT0000) besides the existent one (FnBT0000), and that works as well (as proposed in the thread).
It seems that this problem got a bit forgotten in the lists. Quoting yourself from the last email in the thread:
Quoted 6 lines
I am copying the acpi list and Len Brown to see if they can tell us which one should be the right solution:
1) reverting the patch in acpica that puts all names in uppercase
2) using a case-insensitive match in acpi bus driver
3) using uppercase name in classmate-laptop driver
I think the easiest and less risky way to fix this is by adding a new hardware id (as proposed in the thread's patch), as it doesn't add any side effects (that the other solutions might add), and it doesn't break the behaviour of the old code.
What do you think?
Regards!
Signature · 2 lines
Miguel Gómez Igalia - http://www.igalia.com
Re: [PATCH 1/1 v2] classmate-laptop: Add support for Classmate V4 accelerometer.
Quoted 8 lines · Miguel Gómez
Quoted 3 lines
1) reverting the patch in acpica that puts all names in uppercase
2) using a case-insensitive match in acpi bus driver
3) using uppercase name in classmate-laptop driverI think the easiest and less risky way to fix this is by adding a new hardware id (as proposed in the thread's patch), as it doesn't add any side effects (that the other solutions might add), and it doesn't break the behaviour of the old code.
I've lost track of the implementation state here - if all names are upper-cased in acpica, why is this not already matching?
Signature · 1 line
Matthew Garrett | [email protected]
Re: [PATCH 1/1 v2] classmate-laptop: Add support for Classmate V4 accelerometer.
Quoted 6 lines · Matthew Garrett
Quoted 4 lines · Miguel Gómez
Quoted 3 lines
1) reverting the patch in acpica that puts all names in uppercase
2) using a case-insensitive match in acpi bus driver
3) using uppercase name in classmate-laptop driver
Quoted 7 lines
Quoted 4 lines
I think the easiest and less risky way to fix this is by adding a new hardware id (as proposed in the thread's patch), as it doesn't add any side effects (that the other solutions might add), and it doesn't break the behaviour of the old code.
I've lost track of the implementation state here - if all names are upper-cased in acpica, why is this not already matching?
Names are upper-cased in acpica, so the device is reported as FNBT0000. But in the driver it's named FnBT0000, and that's why it doesn't match.
Signature · 2 lines
Miguel Gómez Igalia - http://www.igalia.com
Re: [PATCH 1/1 v2] classmate-laptop: Add support for Classmate V4 accelerometer.
Quoted 3 lines · Miguel Gómez
Names are upper-cased in acpica, so the device is reported as FNBT0000. But in the driver it's named FnBT0000, and that's why it doesn't match.
So just change the existing entry in the driver to FNBT0000?
Signature · 1 line
Matthew Garrett | [email protected]
Re: [PATCH 1/1 v2] classmate-laptop: Add support for Classmate V4 accelerometer.
Quoted 7 lines · Matthew Garrett
Quoted 3 lines · Miguel Gómez
Names are upper-cased in acpica, so the device is reported as FNBT0000. But in the driver it's named FnBT0000, and that's why it doesn't match.
So just change the existing entry in the driver to FNBT0000?
I'd go for it. I can send a patch if you want. But not sure about Thadeu's opinion. In the old thread it seems that he wanted to explore other options besides that.
Do you agree with that change Thadeu?
Signature · 2 lines
Miguel Gómez Igalia - http://www.igalia.com
Thadeu Lima de Souza Cascardo
maintainerRe: [PATCH 1/1 v2] classmate-laptop: Add support for Classmate V4 accelerometer.
Quoted 7 lines · Miguel Gómez
Quoted 6 lines · Matthew Garrett
Quoted 3 lines · Miguel Gómez
Names are upper-cased in acpica, so the device is reported as FNBT0000. But in the driver it's named FnBT0000, and that's why it doesn't match.
Quoted 8 lines
Quoted 1 line
So just change the existing entry in the driver to FNBT0000?
I'd go for it. I can send a patch if you want. But not sure about Thadeu's opinion. In the old thread it seems that he wanted to explore other options besides that.
Do you agree with that change Thadeu?
I'd say the other options were met with silence. So, go forward with the patch and I'll ack it.
Thanks.
Cascardo.
Quoted 4 lines
Signature · 3 lines
-- Miguel Gómez Igalia - http://www.igalia.com
PATCH 1/1 classmate-laptop: Fix extra keys hardware id.
Since ACPI devices ids were changed to use always upper-case letters, the ACPI id of the extra keys (FNBT0000) was not maching the one defined in the driver (FnBT0000), causing the extra keys not to work.
The patch replaces the driver id with the one reported by ACPI, fixing the problem.
--- drivers/platform/x86/classmate-laptop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/platform/x86/classmate-laptop.c +1 -1
@@ -39,7 +39,7 @@ struct cmpc_accel {#define CMPC_ACCEL_HID "ACCE0000"#define CMPC_TABLET_HID "TBLT0000"#define CMPC_IPML_HID "IPML200" -#define CMPC_KEYS_HID "FnBT0000" +#define CMPC_KEYS_HID "FNBT0000"/* * Generic input device code.
Signature · 1 line
1.7.9.5
Re: [PATCH] classmate-laptop: Fix extra keys hardware id.
Quoted 8 lines
Since ACPI devices ids were changed to use always upper-case letters, the ACPI id of the extra keys (FNBT0000) was not maching the one defined in the driver (FnBT0000), causing the extra keys not to work.
The patch replaces the driver id with the one reported by ACPI, fixing the problem.
Signed-off-by Miguel Gómez <[email protected]>
I've created this patch on top of linux-next, but it won't apply over the patch I've just sent for the accelerometer (neither the later over the former).
How do you want me to proceed? Should I sent this again over the accelerometer patch?
Regards!
Signature · 2 lines
Miguel Gómez Igalia - http://www.igalia.com
Re: [PATCH] classmate-laptop: Fix extra keys hardware id.
Quoted 6 lines · Miguel Gómez
I've created this patch on top of linux-next, but it won't apply over the patch I've just sent for the accelerometer (neither the later over the former).
How do you want me to proceed? Should I sent this again over the accelerometer patch?
I can merge them. Thanks for the patch!
Signature · 1 line
Matthew Garrett | [email protected]
Re: [PATCH 0/1 v2] Add support for Classmate V4 accelerometer to classmate-laptop
In reply to Miguel GómezHi!
Quoted 5 lines
Miguel Gómez (1):
classmate-laptop: Add support for Classmate V4 accelerometer.drivers/platform/x86/classmate-laptop.c | 400 ++++++++++++++++++++++++++++++- 1 file changed, 398 insertions(+), 2 deletions(-)
Anyone had a moment to give a look to this code? I'm eager to get some feedback and fix whatever is needed to put it in shape... and start playing Tux Racer with the Classmate 4 accelerometer :)
Regards!!
Signature · 2 lines
Miguel Gómez Igalia - http://www.igalia.com