Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Copyright (C) 2009  Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
0004  */
0005 
0006 
0007 #include <linux/init.h>
0008 #include <linux/module.h>
0009 #include <linux/slab.h>
0010 #include <linux/workqueue.h>
0011 #include <linux/acpi.h>
0012 #include <linux/backlight.h>
0013 #include <linux/input.h>
0014 #include <linux/rfkill.h>
0015 
0016 MODULE_LICENSE("GPL");
0017 
0018 struct cmpc_accel {
0019     int sensitivity;
0020     int g_select;
0021     int inputdev_state;
0022 };
0023 
0024 #define CMPC_ACCEL_DEV_STATE_CLOSED 0
0025 #define CMPC_ACCEL_DEV_STATE_OPEN   1
0026 
0027 #define CMPC_ACCEL_SENSITIVITY_DEFAULT      5
0028 #define CMPC_ACCEL_G_SELECT_DEFAULT     0
0029 
0030 #define CMPC_ACCEL_HID      "ACCE0000"
0031 #define CMPC_ACCEL_HID_V4   "ACCE0001"
0032 #define CMPC_TABLET_HID     "TBLT0000"
0033 #define CMPC_IPML_HID   "IPML200"
0034 #define CMPC_KEYS_HID       "FNBT0000"
0035 
0036 /*
0037  * Generic input device code.
0038  */
0039 
0040 typedef void (*input_device_init)(struct input_dev *dev);
0041 
0042 static int cmpc_add_acpi_notify_device(struct acpi_device *acpi, char *name,
0043                        input_device_init idev_init)
0044 {
0045     struct input_dev *inputdev;
0046     int error;
0047 
0048     inputdev = input_allocate_device();
0049     if (!inputdev)
0050         return -ENOMEM;
0051     inputdev->name = name;
0052     inputdev->dev.parent = &acpi->dev;
0053     idev_init(inputdev);
0054     error = input_register_device(inputdev);
0055     if (error) {
0056         input_free_device(inputdev);
0057         return error;
0058     }
0059     dev_set_drvdata(&acpi->dev, inputdev);
0060     return 0;
0061 }
0062 
0063 static int cmpc_remove_acpi_notify_device(struct acpi_device *acpi)
0064 {
0065     struct input_dev *inputdev = dev_get_drvdata(&acpi->dev);
0066     input_unregister_device(inputdev);
0067     return 0;
0068 }
0069 
0070 /*
0071  * Accelerometer code for Classmate V4
0072  */
0073 static acpi_status cmpc_start_accel_v4(acpi_handle handle)
0074 {
0075     union acpi_object param[4];
0076     struct acpi_object_list input;
0077     acpi_status status;
0078 
0079     param[0].type = ACPI_TYPE_INTEGER;
0080     param[0].integer.value = 0x3;
0081     param[1].type = ACPI_TYPE_INTEGER;
0082     param[1].integer.value = 0;
0083     param[2].type = ACPI_TYPE_INTEGER;
0084     param[2].integer.value = 0;
0085     param[3].type = ACPI_TYPE_INTEGER;
0086     param[3].integer.value = 0;
0087     input.count = 4;
0088     input.pointer = param;
0089     status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
0090     return status;
0091 }
0092 
0093 static acpi_status cmpc_stop_accel_v4(acpi_handle handle)
0094 {
0095     union acpi_object param[4];
0096     struct acpi_object_list input;
0097     acpi_status status;
0098 
0099     param[0].type = ACPI_TYPE_INTEGER;
0100     param[0].integer.value = 0x4;
0101     param[1].type = ACPI_TYPE_INTEGER;
0102     param[1].integer.value = 0;
0103     param[2].type = ACPI_TYPE_INTEGER;
0104     param[2].integer.value = 0;
0105     param[3].type = ACPI_TYPE_INTEGER;
0106     param[3].integer.value = 0;
0107     input.count = 4;
0108     input.pointer = param;
0109     status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
0110     return status;
0111 }
0112 
0113 static acpi_status cmpc_accel_set_sensitivity_v4(acpi_handle handle, int val)
0114 {
0115     union acpi_object param[4];
0116     struct acpi_object_list input;
0117 
0118     param[0].type = ACPI_TYPE_INTEGER;
0119     param[0].integer.value = 0x02;
0120     param[1].type = ACPI_TYPE_INTEGER;
0121     param[1].integer.value = val;
0122     param[2].type = ACPI_TYPE_INTEGER;
0123     param[2].integer.value = 0;
0124     param[3].type = ACPI_TYPE_INTEGER;
0125     param[3].integer.value = 0;
0126     input.count = 4;
0127     input.pointer = param;
0128     return acpi_evaluate_object(handle, "ACMD", &input, NULL);
0129 }
0130 
0131 static acpi_status cmpc_accel_set_g_select_v4(acpi_handle handle, int val)
0132 {
0133     union acpi_object param[4];
0134     struct acpi_object_list input;
0135 
0136     param[0].type = ACPI_TYPE_INTEGER;
0137     param[0].integer.value = 0x05;
0138     param[1].type = ACPI_TYPE_INTEGER;
0139     param[1].integer.value = val;
0140     param[2].type = ACPI_TYPE_INTEGER;
0141     param[2].integer.value = 0;
0142     param[3].type = ACPI_TYPE_INTEGER;
0143     param[3].integer.value = 0;
0144     input.count = 4;
0145     input.pointer = param;
0146     return acpi_evaluate_object(handle, "ACMD", &input, NULL);
0147 }
0148 
0149 static acpi_status cmpc_get_accel_v4(acpi_handle handle,
0150                      int16_t *x,
0151                      int16_t *y,
0152                      int16_t *z)
0153 {
0154     union acpi_object param[4];
0155     struct acpi_object_list input;
0156     struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
0157     int16_t *locs;
0158     acpi_status status;
0159 
0160     param[0].type = ACPI_TYPE_INTEGER;
0161     param[0].integer.value = 0x01;
0162     param[1].type = ACPI_TYPE_INTEGER;
0163     param[1].integer.value = 0;
0164     param[2].type = ACPI_TYPE_INTEGER;
0165     param[2].integer.value = 0;
0166     param[3].type = ACPI_TYPE_INTEGER;
0167     param[3].integer.value = 0;
0168     input.count = 4;
0169     input.pointer = param;
0170     status = acpi_evaluate_object(handle, "ACMD", &input, &output);
0171     if (ACPI_SUCCESS(status)) {
0172         union acpi_object *obj;
0173         obj = output.pointer;
0174         locs = (int16_t *) obj->buffer.pointer;
0175         *x = locs[0];
0176         *y = locs[1];
0177         *z = locs[2];
0178         kfree(output.pointer);
0179     }
0180     return status;
0181 }
0182 
0183 static void cmpc_accel_handler_v4(struct acpi_device *dev, u32 event)
0184 {
0185     if (event == 0x81) {
0186         int16_t x, y, z;
0187         acpi_status status;
0188 
0189         status = cmpc_get_accel_v4(dev->handle, &x, &y, &z);
0190         if (ACPI_SUCCESS(status)) {
0191             struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
0192 
0193             input_report_abs(inputdev, ABS_X, x);
0194             input_report_abs(inputdev, ABS_Y, y);
0195             input_report_abs(inputdev, ABS_Z, z);
0196             input_sync(inputdev);
0197         }
0198     }
0199 }
0200 
0201 static ssize_t cmpc_accel_sensitivity_show_v4(struct device *dev,
0202                           struct device_attribute *attr,
0203                           char *buf)
0204 {
0205     struct acpi_device *acpi;
0206     struct input_dev *inputdev;
0207     struct cmpc_accel *accel;
0208 
0209     acpi = to_acpi_device(dev);
0210     inputdev = dev_get_drvdata(&acpi->dev);
0211     accel = dev_get_drvdata(&inputdev->dev);
0212 
0213     return sprintf(buf, "%d\n", accel->sensitivity);
0214 }
0215 
0216 static ssize_t cmpc_accel_sensitivity_store_v4(struct device *dev,
0217                            struct device_attribute *attr,
0218                            const char *buf, size_t count)
0219 {
0220     struct acpi_device *acpi;
0221     struct input_dev *inputdev;
0222     struct cmpc_accel *accel;
0223     unsigned long sensitivity;
0224     int r;
0225 
0226     acpi = to_acpi_device(dev);
0227     inputdev = dev_get_drvdata(&acpi->dev);
0228     accel = dev_get_drvdata(&inputdev->dev);
0229 
0230     r = kstrtoul(buf, 0, &sensitivity);
0231     if (r)
0232         return r;
0233 
0234     /* sensitivity must be between 1 and 127 */
0235     if (sensitivity < 1 || sensitivity > 127)
0236         return -EINVAL;
0237 
0238     accel->sensitivity = sensitivity;
0239     cmpc_accel_set_sensitivity_v4(acpi->handle, sensitivity);
0240 
0241     return strnlen(buf, count);
0242 }
0243 
0244 static struct device_attribute cmpc_accel_sensitivity_attr_v4 = {
0245     .attr = { .name = "sensitivity", .mode = 0660 },
0246     .show = cmpc_accel_sensitivity_show_v4,
0247     .store = cmpc_accel_sensitivity_store_v4
0248 };
0249 
0250 static ssize_t cmpc_accel_g_select_show_v4(struct device *dev,
0251                        struct device_attribute *attr,
0252                        char *buf)
0253 {
0254     struct acpi_device *acpi;
0255     struct input_dev *inputdev;
0256     struct cmpc_accel *accel;
0257 
0258     acpi = to_acpi_device(dev);
0259     inputdev = dev_get_drvdata(&acpi->dev);
0260     accel = dev_get_drvdata(&inputdev->dev);
0261 
0262     return sprintf(buf, "%d\n", accel->g_select);
0263 }
0264 
0265 static ssize_t cmpc_accel_g_select_store_v4(struct device *dev,
0266                         struct device_attribute *attr,
0267                         const char *buf, size_t count)
0268 {
0269     struct acpi_device *acpi;
0270     struct input_dev *inputdev;
0271     struct cmpc_accel *accel;
0272     unsigned long g_select;
0273     int r;
0274 
0275     acpi = to_acpi_device(dev);
0276     inputdev = dev_get_drvdata(&acpi->dev);
0277     accel = dev_get_drvdata(&inputdev->dev);
0278 
0279     r = kstrtoul(buf, 0, &g_select);
0280     if (r)
0281         return r;
0282 
0283     /* 0 means 1.5g, 1 means 6g, everything else is wrong */
0284     if (g_select != 0 && g_select != 1)
0285         return -EINVAL;
0286 
0287     accel->g_select = g_select;
0288     cmpc_accel_set_g_select_v4(acpi->handle, g_select);
0289 
0290     return strnlen(buf, count);
0291 }
0292 
0293 static struct device_attribute cmpc_accel_g_select_attr_v4 = {
0294     .attr = { .name = "g_select", .mode = 0660 },
0295     .show = cmpc_accel_g_select_show_v4,
0296     .store = cmpc_accel_g_select_store_v4
0297 };
0298 
0299 static int cmpc_accel_open_v4(struct input_dev *input)
0300 {
0301     struct acpi_device *acpi;
0302     struct cmpc_accel *accel;
0303 
0304     acpi = to_acpi_device(input->dev.parent);
0305     accel = dev_get_drvdata(&input->dev);
0306 
0307     cmpc_accel_set_sensitivity_v4(acpi->handle, accel->sensitivity);
0308     cmpc_accel_set_g_select_v4(acpi->handle, accel->g_select);
0309 
0310     if (ACPI_SUCCESS(cmpc_start_accel_v4(acpi->handle))) {
0311         accel->inputdev_state = CMPC_ACCEL_DEV_STATE_OPEN;
0312         return 0;
0313     }
0314     return -EIO;
0315 }
0316 
0317 static void cmpc_accel_close_v4(struct input_dev *input)
0318 {
0319     struct acpi_device *acpi;
0320     struct cmpc_accel *accel;
0321 
0322     acpi = to_acpi_device(input->dev.parent);
0323     accel = dev_get_drvdata(&input->dev);
0324 
0325     cmpc_stop_accel_v4(acpi->handle);
0326     accel->inputdev_state = CMPC_ACCEL_DEV_STATE_CLOSED;
0327 }
0328 
0329 static void cmpc_accel_idev_init_v4(struct input_dev *inputdev)
0330 {
0331     set_bit(EV_ABS, inputdev->evbit);
0332     input_set_abs_params(inputdev, ABS_X, -255, 255, 16, 0);
0333     input_set_abs_params(inputdev, ABS_Y, -255, 255, 16, 0);
0334     input_set_abs_params(inputdev, ABS_Z, -255, 255, 16, 0);
0335     inputdev->open = cmpc_accel_open_v4;
0336     inputdev->close = cmpc_accel_close_v4;
0337 }
0338 
0339 #ifdef CONFIG_PM_SLEEP
0340 static int cmpc_accel_suspend_v4(struct device *dev)
0341 {
0342     struct input_dev *inputdev;
0343     struct cmpc_accel *accel;
0344 
0345     inputdev = dev_get_drvdata(dev);
0346     accel = dev_get_drvdata(&inputdev->dev);
0347 
0348     if (accel->inputdev_state == CMPC_ACCEL_DEV_STATE_OPEN)
0349         return cmpc_stop_accel_v4(to_acpi_device(dev)->handle);
0350 
0351     return 0;
0352 }
0353 
0354 static int cmpc_accel_resume_v4(struct device *dev)
0355 {
0356     struct input_dev *inputdev;
0357     struct cmpc_accel *accel;
0358 
0359     inputdev = dev_get_drvdata(dev);
0360     accel = dev_get_drvdata(&inputdev->dev);
0361 
0362     if (accel->inputdev_state == CMPC_ACCEL_DEV_STATE_OPEN) {
0363         cmpc_accel_set_sensitivity_v4(to_acpi_device(dev)->handle,
0364                           accel->sensitivity);
0365         cmpc_accel_set_g_select_v4(to_acpi_device(dev)->handle,
0366                        accel->g_select);
0367 
0368         if (ACPI_FAILURE(cmpc_start_accel_v4(to_acpi_device(dev)->handle)))
0369             return -EIO;
0370     }
0371 
0372     return 0;
0373 }
0374 #endif
0375 
0376 static int cmpc_accel_add_v4(struct acpi_device *acpi)
0377 {
0378     int error;
0379     struct input_dev *inputdev;
0380     struct cmpc_accel *accel;
0381 
0382     accel = kmalloc(sizeof(*accel), GFP_KERNEL);
0383     if (!accel)
0384         return -ENOMEM;
0385 
0386     accel->inputdev_state = CMPC_ACCEL_DEV_STATE_CLOSED;
0387 
0388     accel->sensitivity = CMPC_ACCEL_SENSITIVITY_DEFAULT;
0389     cmpc_accel_set_sensitivity_v4(acpi->handle, accel->sensitivity);
0390 
0391     error = device_create_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
0392     if (error)
0393         goto failed_sensitivity;
0394 
0395     accel->g_select = CMPC_ACCEL_G_SELECT_DEFAULT;
0396     cmpc_accel_set_g_select_v4(acpi->handle, accel->g_select);
0397 
0398     error = device_create_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
0399     if (error)
0400         goto failed_g_select;
0401 
0402     error = cmpc_add_acpi_notify_device(acpi, "cmpc_accel_v4",
0403                         cmpc_accel_idev_init_v4);
0404     if (error)
0405         goto failed_input;
0406 
0407     inputdev = dev_get_drvdata(&acpi->dev);
0408     dev_set_drvdata(&inputdev->dev, accel);
0409 
0410     return 0;
0411 
0412 failed_input:
0413     device_remove_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
0414 failed_g_select:
0415     device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
0416 failed_sensitivity:
0417     kfree(accel);
0418     return error;
0419 }
0420 
0421 static int cmpc_accel_remove_v4(struct acpi_device *acpi)
0422 {
0423     device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
0424     device_remove_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
0425     return cmpc_remove_acpi_notify_device(acpi);
0426 }
0427 
0428 static SIMPLE_DEV_PM_OPS(cmpc_accel_pm, cmpc_accel_suspend_v4,
0429              cmpc_accel_resume_v4);
0430 
0431 static const struct acpi_device_id cmpc_accel_device_ids_v4[] = {
0432     {CMPC_ACCEL_HID_V4, 0},
0433     {"", 0}
0434 };
0435 
0436 static struct acpi_driver cmpc_accel_acpi_driver_v4 = {
0437     .owner = THIS_MODULE,
0438     .name = "cmpc_accel_v4",
0439     .class = "cmpc_accel_v4",
0440     .ids = cmpc_accel_device_ids_v4,
0441     .ops = {
0442         .add = cmpc_accel_add_v4,
0443         .remove = cmpc_accel_remove_v4,
0444         .notify = cmpc_accel_handler_v4,
0445     },
0446     .drv.pm = &cmpc_accel_pm,
0447 };
0448 
0449 
0450 /*
0451  * Accelerometer code for Classmate versions prior to V4
0452  */
0453 static acpi_status cmpc_start_accel(acpi_handle handle)
0454 {
0455     union acpi_object param[2];
0456     struct acpi_object_list input;
0457     acpi_status status;
0458 
0459     param[0].type = ACPI_TYPE_INTEGER;
0460     param[0].integer.value = 0x3;
0461     param[1].type = ACPI_TYPE_INTEGER;
0462     input.count = 2;
0463     input.pointer = param;
0464     status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
0465     return status;
0466 }
0467 
0468 static acpi_status cmpc_stop_accel(acpi_handle handle)
0469 {
0470     union acpi_object param[2];
0471     struct acpi_object_list input;
0472     acpi_status status;
0473 
0474     param[0].type = ACPI_TYPE_INTEGER;
0475     param[0].integer.value = 0x4;
0476     param[1].type = ACPI_TYPE_INTEGER;
0477     input.count = 2;
0478     input.pointer = param;
0479     status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
0480     return status;
0481 }
0482 
0483 static acpi_status cmpc_accel_set_sensitivity(acpi_handle handle, int val)
0484 {
0485     union acpi_object param[2];
0486     struct acpi_object_list input;
0487 
0488     param[0].type = ACPI_TYPE_INTEGER;
0489     param[0].integer.value = 0x02;
0490     param[1].type = ACPI_TYPE_INTEGER;
0491     param[1].integer.value = val;
0492     input.count = 2;
0493     input.pointer = param;
0494     return acpi_evaluate_object(handle, "ACMD", &input, NULL);
0495 }
0496 
0497 static acpi_status cmpc_get_accel(acpi_handle handle,
0498                   unsigned char *x,
0499                   unsigned char *y,
0500                   unsigned char *z)
0501 {
0502     union acpi_object param[2];
0503     struct acpi_object_list input;
0504     struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
0505     unsigned char *locs;
0506     acpi_status status;
0507 
0508     param[0].type = ACPI_TYPE_INTEGER;
0509     param[0].integer.value = 0x01;
0510     param[1].type = ACPI_TYPE_INTEGER;
0511     input.count = 2;
0512     input.pointer = param;
0513     status = acpi_evaluate_object(handle, "ACMD", &input, &output);
0514     if (ACPI_SUCCESS(status)) {
0515         union acpi_object *obj;
0516         obj = output.pointer;
0517         locs = obj->buffer.pointer;
0518         *x = locs[0];
0519         *y = locs[1];
0520         *z = locs[2];
0521         kfree(output.pointer);
0522     }
0523     return status;
0524 }
0525 
0526 static void cmpc_accel_handler(struct acpi_device *dev, u32 event)
0527 {
0528     if (event == 0x81) {
0529         unsigned char x, y, z;
0530         acpi_status status;
0531 
0532         status = cmpc_get_accel(dev->handle, &x, &y, &z);
0533         if (ACPI_SUCCESS(status)) {
0534             struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
0535 
0536             input_report_abs(inputdev, ABS_X, x);
0537             input_report_abs(inputdev, ABS_Y, y);
0538             input_report_abs(inputdev, ABS_Z, z);
0539             input_sync(inputdev);
0540         }
0541     }
0542 }
0543 
0544 static ssize_t cmpc_accel_sensitivity_show(struct device *dev,
0545                        struct device_attribute *attr,
0546                        char *buf)
0547 {
0548     struct acpi_device *acpi;
0549     struct input_dev *inputdev;
0550     struct cmpc_accel *accel;
0551 
0552     acpi = to_acpi_device(dev);
0553     inputdev = dev_get_drvdata(&acpi->dev);
0554     accel = dev_get_drvdata(&inputdev->dev);
0555 
0556     return sprintf(buf, "%d\n", accel->sensitivity);
0557 }
0558 
0559 static ssize_t cmpc_accel_sensitivity_store(struct device *dev,
0560                         struct device_attribute *attr,
0561                         const char *buf, size_t count)
0562 {
0563     struct acpi_device *acpi;
0564     struct input_dev *inputdev;
0565     struct cmpc_accel *accel;
0566     unsigned long sensitivity;
0567     int r;
0568 
0569     acpi = to_acpi_device(dev);
0570     inputdev = dev_get_drvdata(&acpi->dev);
0571     accel = dev_get_drvdata(&inputdev->dev);
0572 
0573     r = kstrtoul(buf, 0, &sensitivity);
0574     if (r)
0575         return r;
0576 
0577     accel->sensitivity = sensitivity;
0578     cmpc_accel_set_sensitivity(acpi->handle, sensitivity);
0579 
0580     return strnlen(buf, count);
0581 }
0582 
0583 static struct device_attribute cmpc_accel_sensitivity_attr = {
0584     .attr = { .name = "sensitivity", .mode = 0660 },
0585     .show = cmpc_accel_sensitivity_show,
0586     .store = cmpc_accel_sensitivity_store
0587 };
0588 
0589 static int cmpc_accel_open(struct input_dev *input)
0590 {
0591     struct acpi_device *acpi;
0592 
0593     acpi = to_acpi_device(input->dev.parent);
0594     if (ACPI_SUCCESS(cmpc_start_accel(acpi->handle)))
0595         return 0;
0596     return -EIO;
0597 }
0598 
0599 static void cmpc_accel_close(struct input_dev *input)
0600 {
0601     struct acpi_device *acpi;
0602 
0603     acpi = to_acpi_device(input->dev.parent);
0604     cmpc_stop_accel(acpi->handle);
0605 }
0606 
0607 static void cmpc_accel_idev_init(struct input_dev *inputdev)
0608 {
0609     set_bit(EV_ABS, inputdev->evbit);
0610     input_set_abs_params(inputdev, ABS_X, 0, 255, 8, 0);
0611     input_set_abs_params(inputdev, ABS_Y, 0, 255, 8, 0);
0612     input_set_abs_params(inputdev, ABS_Z, 0, 255, 8, 0);
0613     inputdev->open = cmpc_accel_open;
0614     inputdev->close = cmpc_accel_close;
0615 }
0616 
0617 static int cmpc_accel_add(struct acpi_device *acpi)
0618 {
0619     int error;
0620     struct input_dev *inputdev;
0621     struct cmpc_accel *accel;
0622 
0623     accel = kmalloc(sizeof(*accel), GFP_KERNEL);
0624     if (!accel)
0625         return -ENOMEM;
0626 
0627     accel->sensitivity = CMPC_ACCEL_SENSITIVITY_DEFAULT;
0628     cmpc_accel_set_sensitivity(acpi->handle, accel->sensitivity);
0629 
0630     error = device_create_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
0631     if (error)
0632         goto failed_file;
0633 
0634     error = cmpc_add_acpi_notify_device(acpi, "cmpc_accel",
0635                         cmpc_accel_idev_init);
0636     if (error)
0637         goto failed_input;
0638 
0639     inputdev = dev_get_drvdata(&acpi->dev);
0640     dev_set_drvdata(&inputdev->dev, accel);
0641 
0642     return 0;
0643 
0644 failed_input:
0645     device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
0646 failed_file:
0647     kfree(accel);
0648     return error;
0649 }
0650 
0651 static int cmpc_accel_remove(struct acpi_device *acpi)
0652 {
0653     device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
0654     return cmpc_remove_acpi_notify_device(acpi);
0655 }
0656 
0657 static const struct acpi_device_id cmpc_accel_device_ids[] = {
0658     {CMPC_ACCEL_HID, 0},
0659     {"", 0}
0660 };
0661 
0662 static struct acpi_driver cmpc_accel_acpi_driver = {
0663     .owner = THIS_MODULE,
0664     .name = "cmpc_accel",
0665     .class = "cmpc_accel",
0666     .ids = cmpc_accel_device_ids,
0667     .ops = {
0668         .add = cmpc_accel_add,
0669         .remove = cmpc_accel_remove,
0670         .notify = cmpc_accel_handler,
0671     }
0672 };
0673 
0674 
0675 /*
0676  * Tablet mode code.
0677  */
0678 static acpi_status cmpc_get_tablet(acpi_handle handle,
0679                    unsigned long long *value)
0680 {
0681     union acpi_object param;
0682     struct acpi_object_list input;
0683     unsigned long long output;
0684     acpi_status status;
0685 
0686     param.type = ACPI_TYPE_INTEGER;
0687     param.integer.value = 0x01;
0688     input.count = 1;
0689     input.pointer = &param;
0690     status = acpi_evaluate_integer(handle, "TCMD", &input, &output);
0691     if (ACPI_SUCCESS(status))
0692         *value = output;
0693     return status;
0694 }
0695 
0696 static void cmpc_tablet_handler(struct acpi_device *dev, u32 event)
0697 {
0698     unsigned long long val = 0;
0699     struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
0700 
0701     if (event == 0x81) {
0702         if (ACPI_SUCCESS(cmpc_get_tablet(dev->handle, &val))) {
0703             input_report_switch(inputdev, SW_TABLET_MODE, !val);
0704             input_sync(inputdev);
0705         }
0706     }
0707 }
0708 
0709 static void cmpc_tablet_idev_init(struct input_dev *inputdev)
0710 {
0711     unsigned long long val = 0;
0712     struct acpi_device *acpi;
0713 
0714     set_bit(EV_SW, inputdev->evbit);
0715     set_bit(SW_TABLET_MODE, inputdev->swbit);
0716 
0717     acpi = to_acpi_device(inputdev->dev.parent);
0718     if (ACPI_SUCCESS(cmpc_get_tablet(acpi->handle, &val))) {
0719         input_report_switch(inputdev, SW_TABLET_MODE, !val);
0720         input_sync(inputdev);
0721     }
0722 }
0723 
0724 static int cmpc_tablet_add(struct acpi_device *acpi)
0725 {
0726     return cmpc_add_acpi_notify_device(acpi, "cmpc_tablet",
0727                        cmpc_tablet_idev_init);
0728 }
0729 
0730 static int cmpc_tablet_remove(struct acpi_device *acpi)
0731 {
0732     return cmpc_remove_acpi_notify_device(acpi);
0733 }
0734 
0735 #ifdef CONFIG_PM_SLEEP
0736 static int cmpc_tablet_resume(struct device *dev)
0737 {
0738     struct input_dev *inputdev = dev_get_drvdata(dev);
0739 
0740     unsigned long long val = 0;
0741     if (ACPI_SUCCESS(cmpc_get_tablet(to_acpi_device(dev)->handle, &val))) {
0742         input_report_switch(inputdev, SW_TABLET_MODE, !val);
0743         input_sync(inputdev);
0744     }
0745     return 0;
0746 }
0747 #endif
0748 
0749 static SIMPLE_DEV_PM_OPS(cmpc_tablet_pm, NULL, cmpc_tablet_resume);
0750 
0751 static const struct acpi_device_id cmpc_tablet_device_ids[] = {
0752     {CMPC_TABLET_HID, 0},
0753     {"", 0}
0754 };
0755 
0756 static struct acpi_driver cmpc_tablet_acpi_driver = {
0757     .owner = THIS_MODULE,
0758     .name = "cmpc_tablet",
0759     .class = "cmpc_tablet",
0760     .ids = cmpc_tablet_device_ids,
0761     .ops = {
0762         .add = cmpc_tablet_add,
0763         .remove = cmpc_tablet_remove,
0764         .notify = cmpc_tablet_handler,
0765     },
0766     .drv.pm = &cmpc_tablet_pm,
0767 };
0768 
0769 
0770 /*
0771  * Backlight code.
0772  */
0773 
0774 static acpi_status cmpc_get_brightness(acpi_handle handle,
0775                        unsigned long long *value)
0776 {
0777     union acpi_object param;
0778     struct acpi_object_list input;
0779     unsigned long long output;
0780     acpi_status status;
0781 
0782     param.type = ACPI_TYPE_INTEGER;
0783     param.integer.value = 0xC0;
0784     input.count = 1;
0785     input.pointer = &param;
0786     status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
0787     if (ACPI_SUCCESS(status))
0788         *value = output;
0789     return status;
0790 }
0791 
0792 static acpi_status cmpc_set_brightness(acpi_handle handle,
0793                        unsigned long long value)
0794 {
0795     union acpi_object param[2];
0796     struct acpi_object_list input;
0797     acpi_status status;
0798     unsigned long long output;
0799 
0800     param[0].type = ACPI_TYPE_INTEGER;
0801     param[0].integer.value = 0xC0;
0802     param[1].type = ACPI_TYPE_INTEGER;
0803     param[1].integer.value = value;
0804     input.count = 2;
0805     input.pointer = param;
0806     status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
0807     return status;
0808 }
0809 
0810 static int cmpc_bl_get_brightness(struct backlight_device *bd)
0811 {
0812     acpi_status status;
0813     acpi_handle handle;
0814     unsigned long long brightness;
0815 
0816     handle = bl_get_data(bd);
0817     status = cmpc_get_brightness(handle, &brightness);
0818     if (ACPI_SUCCESS(status))
0819         return brightness;
0820     else
0821         return -1;
0822 }
0823 
0824 static int cmpc_bl_update_status(struct backlight_device *bd)
0825 {
0826     acpi_status status;
0827     acpi_handle handle;
0828 
0829     handle = bl_get_data(bd);
0830     status = cmpc_set_brightness(handle, bd->props.brightness);
0831     if (ACPI_SUCCESS(status))
0832         return 0;
0833     else
0834         return -1;
0835 }
0836 
0837 static const struct backlight_ops cmpc_bl_ops = {
0838     .get_brightness = cmpc_bl_get_brightness,
0839     .update_status = cmpc_bl_update_status
0840 };
0841 
0842 /*
0843  * RFKILL code.
0844  */
0845 
0846 static acpi_status cmpc_get_rfkill_wlan(acpi_handle handle,
0847                     unsigned long long *value)
0848 {
0849     union acpi_object param;
0850     struct acpi_object_list input;
0851     unsigned long long output;
0852     acpi_status status;
0853 
0854     param.type = ACPI_TYPE_INTEGER;
0855     param.integer.value = 0xC1;
0856     input.count = 1;
0857     input.pointer = &param;
0858     status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
0859     if (ACPI_SUCCESS(status))
0860         *value = output;
0861     return status;
0862 }
0863 
0864 static acpi_status cmpc_set_rfkill_wlan(acpi_handle handle,
0865                     unsigned long long value)
0866 {
0867     union acpi_object param[2];
0868     struct acpi_object_list input;
0869     acpi_status status;
0870     unsigned long long output;
0871 
0872     param[0].type = ACPI_TYPE_INTEGER;
0873     param[0].integer.value = 0xC1;
0874     param[1].type = ACPI_TYPE_INTEGER;
0875     param[1].integer.value = value;
0876     input.count = 2;
0877     input.pointer = param;
0878     status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
0879     return status;
0880 }
0881 
0882 static void cmpc_rfkill_query(struct rfkill *rfkill, void *data)
0883 {
0884     acpi_status status;
0885     acpi_handle handle;
0886     unsigned long long state;
0887     bool blocked;
0888 
0889     handle = data;
0890     status = cmpc_get_rfkill_wlan(handle, &state);
0891     if (ACPI_SUCCESS(status)) {
0892         blocked = state & 1 ? false : true;
0893         rfkill_set_sw_state(rfkill, blocked);
0894     }
0895 }
0896 
0897 static int cmpc_rfkill_block(void *data, bool blocked)
0898 {
0899     acpi_status status;
0900     acpi_handle handle;
0901     unsigned long long state;
0902     bool is_blocked;
0903 
0904     handle = data;
0905     status = cmpc_get_rfkill_wlan(handle, &state);
0906     if (ACPI_FAILURE(status))
0907         return -ENODEV;
0908     /* Check if we really need to call cmpc_set_rfkill_wlan */
0909     is_blocked = state & 1 ? false : true;
0910     if (is_blocked != blocked) {
0911         state = blocked ? 0 : 1;
0912         status = cmpc_set_rfkill_wlan(handle, state);
0913         if (ACPI_FAILURE(status))
0914             return -ENODEV;
0915     }
0916     return 0;
0917 }
0918 
0919 static const struct rfkill_ops cmpc_rfkill_ops = {
0920     .query = cmpc_rfkill_query,
0921     .set_block = cmpc_rfkill_block,
0922 };
0923 
0924 /*
0925  * Common backlight and rfkill code.
0926  */
0927 
0928 struct ipml200_dev {
0929     struct backlight_device *bd;
0930     struct rfkill *rf;
0931 };
0932 
0933 static int cmpc_ipml_add(struct acpi_device *acpi)
0934 {
0935     int retval;
0936     struct ipml200_dev *ipml;
0937     struct backlight_properties props;
0938 
0939     ipml = kmalloc(sizeof(*ipml), GFP_KERNEL);
0940     if (ipml == NULL)
0941         return -ENOMEM;
0942 
0943     memset(&props, 0, sizeof(struct backlight_properties));
0944     props.type = BACKLIGHT_PLATFORM;
0945     props.max_brightness = 7;
0946     ipml->bd = backlight_device_register("cmpc_bl", &acpi->dev,
0947                          acpi->handle, &cmpc_bl_ops,
0948                          &props);
0949     if (IS_ERR(ipml->bd)) {
0950         retval = PTR_ERR(ipml->bd);
0951         goto out_bd;
0952     }
0953 
0954     ipml->rf = rfkill_alloc("cmpc_rfkill", &acpi->dev, RFKILL_TYPE_WLAN,
0955                 &cmpc_rfkill_ops, acpi->handle);
0956     /*
0957      * If RFKILL is disabled, rfkill_alloc will return ERR_PTR(-ENODEV).
0958      * This is OK, however, since all other uses of the device will not
0959      * dereference it.
0960      */
0961     if (ipml->rf) {
0962         retval = rfkill_register(ipml->rf);
0963         if (retval) {
0964             rfkill_destroy(ipml->rf);
0965             ipml->rf = NULL;
0966         }
0967     }
0968 
0969     dev_set_drvdata(&acpi->dev, ipml);
0970     return 0;
0971 
0972 out_bd:
0973     kfree(ipml);
0974     return retval;
0975 }
0976 
0977 static int cmpc_ipml_remove(struct acpi_device *acpi)
0978 {
0979     struct ipml200_dev *ipml;
0980 
0981     ipml = dev_get_drvdata(&acpi->dev);
0982 
0983     backlight_device_unregister(ipml->bd);
0984 
0985     if (ipml->rf) {
0986         rfkill_unregister(ipml->rf);
0987         rfkill_destroy(ipml->rf);
0988     }
0989 
0990     kfree(ipml);
0991 
0992     return 0;
0993 }
0994 
0995 static const struct acpi_device_id cmpc_ipml_device_ids[] = {
0996     {CMPC_IPML_HID, 0},
0997     {"", 0}
0998 };
0999 
1000 static struct acpi_driver cmpc_ipml_acpi_driver = {
1001     .owner = THIS_MODULE,
1002     .name = "cmpc",
1003     .class = "cmpc",
1004     .ids = cmpc_ipml_device_ids,
1005     .ops = {
1006         .add = cmpc_ipml_add,
1007         .remove = cmpc_ipml_remove
1008     }
1009 };
1010 
1011 
1012 /*
1013  * Extra keys code.
1014  */
1015 static int cmpc_keys_codes[] = {
1016     KEY_UNKNOWN,
1017     KEY_WLAN,
1018     KEY_SWITCHVIDEOMODE,
1019     KEY_BRIGHTNESSDOWN,
1020     KEY_BRIGHTNESSUP,
1021     KEY_VENDOR,
1022     KEY_UNKNOWN,
1023     KEY_CAMERA,
1024     KEY_BACK,
1025     KEY_FORWARD,
1026     KEY_UNKNOWN,
1027     KEY_WLAN, /* NL3: 0x8b (press), 0x9b (release) */
1028     KEY_MAX
1029 };
1030 
1031 static void cmpc_keys_handler(struct acpi_device *dev, u32 event)
1032 {
1033     struct input_dev *inputdev;
1034     int code = KEY_MAX;
1035 
1036     if ((event & 0x0F) < ARRAY_SIZE(cmpc_keys_codes))
1037         code = cmpc_keys_codes[event & 0x0F];
1038     inputdev = dev_get_drvdata(&dev->dev);
1039     input_report_key(inputdev, code, !(event & 0x10));
1040     input_sync(inputdev);
1041 }
1042 
1043 static void cmpc_keys_idev_init(struct input_dev *inputdev)
1044 {
1045     int i;
1046 
1047     set_bit(EV_KEY, inputdev->evbit);
1048     for (i = 0; cmpc_keys_codes[i] != KEY_MAX; i++)
1049         set_bit(cmpc_keys_codes[i], inputdev->keybit);
1050 }
1051 
1052 static int cmpc_keys_add(struct acpi_device *acpi)
1053 {
1054     return cmpc_add_acpi_notify_device(acpi, "cmpc_keys",
1055                        cmpc_keys_idev_init);
1056 }
1057 
1058 static int cmpc_keys_remove(struct acpi_device *acpi)
1059 {
1060     return cmpc_remove_acpi_notify_device(acpi);
1061 }
1062 
1063 static const struct acpi_device_id cmpc_keys_device_ids[] = {
1064     {CMPC_KEYS_HID, 0},
1065     {"", 0}
1066 };
1067 
1068 static struct acpi_driver cmpc_keys_acpi_driver = {
1069     .owner = THIS_MODULE,
1070     .name = "cmpc_keys",
1071     .class = "cmpc_keys",
1072     .ids = cmpc_keys_device_ids,
1073     .ops = {
1074         .add = cmpc_keys_add,
1075         .remove = cmpc_keys_remove,
1076         .notify = cmpc_keys_handler,
1077     }
1078 };
1079 
1080 
1081 /*
1082  * General init/exit code.
1083  */
1084 
1085 static int cmpc_init(void)
1086 {
1087     int r;
1088 
1089     r = acpi_bus_register_driver(&cmpc_keys_acpi_driver);
1090     if (r)
1091         goto failed_keys;
1092 
1093     r = acpi_bus_register_driver(&cmpc_ipml_acpi_driver);
1094     if (r)
1095         goto failed_bl;
1096 
1097     r = acpi_bus_register_driver(&cmpc_tablet_acpi_driver);
1098     if (r)
1099         goto failed_tablet;
1100 
1101     r = acpi_bus_register_driver(&cmpc_accel_acpi_driver);
1102     if (r)
1103         goto failed_accel;
1104 
1105     r = acpi_bus_register_driver(&cmpc_accel_acpi_driver_v4);
1106     if (r)
1107         goto failed_accel_v4;
1108 
1109     return r;
1110 
1111 failed_accel_v4:
1112     acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
1113 
1114 failed_accel:
1115     acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
1116 
1117 failed_tablet:
1118     acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
1119 
1120 failed_bl:
1121     acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
1122 
1123 failed_keys:
1124     return r;
1125 }
1126 
1127 static void cmpc_exit(void)
1128 {
1129     acpi_bus_unregister_driver(&cmpc_accel_acpi_driver_v4);
1130     acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
1131     acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
1132     acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
1133     acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
1134 }
1135 
1136 module_init(cmpc_init);
1137 module_exit(cmpc_exit);
1138 
1139 static const struct acpi_device_id cmpc_device_ids[] = {
1140     {CMPC_ACCEL_HID, 0},
1141     {CMPC_ACCEL_HID_V4, 0},
1142     {CMPC_TABLET_HID, 0},
1143     {CMPC_IPML_HID, 0},
1144     {CMPC_KEYS_HID, 0},
1145     {"", 0}
1146 };
1147 
1148 MODULE_DEVICE_TABLE(acpi, cmpc_device_ids);