root/drivers/platform/x86/classmate-laptop.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cmpc_add_acpi_notify_device
  2. cmpc_remove_acpi_notify_device
  3. cmpc_start_accel_v4
  4. cmpc_stop_accel_v4
  5. cmpc_accel_set_sensitivity_v4
  6. cmpc_accel_set_g_select_v4
  7. cmpc_get_accel_v4
  8. cmpc_accel_handler_v4
  9. cmpc_accel_sensitivity_show_v4
  10. cmpc_accel_sensitivity_store_v4
  11. cmpc_accel_g_select_show_v4
  12. cmpc_accel_g_select_store_v4
  13. cmpc_accel_open_v4
  14. cmpc_accel_close_v4
  15. cmpc_accel_idev_init_v4
  16. cmpc_accel_suspend_v4
  17. cmpc_accel_resume_v4
  18. cmpc_accel_add_v4
  19. cmpc_accel_remove_v4
  20. cmpc_start_accel
  21. cmpc_stop_accel
  22. cmpc_accel_set_sensitivity
  23. cmpc_get_accel
  24. cmpc_accel_handler
  25. cmpc_accel_sensitivity_show
  26. cmpc_accel_sensitivity_store
  27. cmpc_accel_open
  28. cmpc_accel_close
  29. cmpc_accel_idev_init
  30. cmpc_accel_add
  31. cmpc_accel_remove
  32. cmpc_get_tablet
  33. cmpc_tablet_handler
  34. cmpc_tablet_idev_init
  35. cmpc_tablet_add
  36. cmpc_tablet_remove
  37. cmpc_tablet_resume
  38. cmpc_get_brightness
  39. cmpc_set_brightness
  40. cmpc_bl_get_brightness
  41. cmpc_bl_update_status
  42. cmpc_get_rfkill_wlan
  43. cmpc_set_rfkill_wlan
  44. cmpc_rfkill_query
  45. cmpc_rfkill_block
  46. cmpc_ipml_add
  47. cmpc_ipml_remove
  48. cmpc_keys_handler
  49. cmpc_keys_idev_init
  50. cmpc_keys_add
  51. cmpc_keys_remove
  52. cmpc_init
  53. cmpc_exit

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  Copyright (C) 2009  Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
   4  */
   5 
   6 
   7 #include <linux/init.h>
   8 #include <linux/module.h>
   9 #include <linux/slab.h>
  10 #include <linux/workqueue.h>
  11 #include <linux/acpi.h>
  12 #include <linux/backlight.h>
  13 #include <linux/input.h>
  14 #include <linux/rfkill.h>
  15 
  16 MODULE_LICENSE("GPL");
  17 
  18 struct cmpc_accel {
  19         int sensitivity;
  20         int g_select;
  21         int inputdev_state;
  22 };
  23 
  24 #define CMPC_ACCEL_DEV_STATE_CLOSED     0
  25 #define CMPC_ACCEL_DEV_STATE_OPEN       1
  26 
  27 #define CMPC_ACCEL_SENSITIVITY_DEFAULT          5
  28 #define CMPC_ACCEL_G_SELECT_DEFAULT             0
  29 
  30 #define CMPC_ACCEL_HID          "ACCE0000"
  31 #define CMPC_ACCEL_HID_V4       "ACCE0001"
  32 #define CMPC_TABLET_HID         "TBLT0000"
  33 #define CMPC_IPML_HID   "IPML200"
  34 #define CMPC_KEYS_HID           "FNBT0000"
  35 
  36 /*
  37  * Generic input device code.
  38  */
  39 
  40 typedef void (*input_device_init)(struct input_dev *dev);
  41 
  42 static int cmpc_add_acpi_notify_device(struct acpi_device *acpi, char *name,
  43                                        input_device_init idev_init)
  44 {
  45         struct input_dev *inputdev;
  46         int error;
  47 
  48         inputdev = input_allocate_device();
  49         if (!inputdev)
  50                 return -ENOMEM;
  51         inputdev->name = name;
  52         inputdev->dev.parent = &acpi->dev;
  53         idev_init(inputdev);
  54         error = input_register_device(inputdev);
  55         if (error) {
  56                 input_free_device(inputdev);
  57                 return error;
  58         }
  59         dev_set_drvdata(&acpi->dev, inputdev);
  60         return 0;
  61 }
  62 
  63 static int cmpc_remove_acpi_notify_device(struct acpi_device *acpi)
  64 {
  65         struct input_dev *inputdev = dev_get_drvdata(&acpi->dev);
  66         input_unregister_device(inputdev);
  67         return 0;
  68 }
  69 
  70 /*
  71  * Accelerometer code for Classmate V4
  72  */
  73 static acpi_status cmpc_start_accel_v4(acpi_handle handle)
  74 {
  75         union acpi_object param[4];
  76         struct acpi_object_list input;
  77         acpi_status status;
  78 
  79         param[0].type = ACPI_TYPE_INTEGER;
  80         param[0].integer.value = 0x3;
  81         param[1].type = ACPI_TYPE_INTEGER;
  82         param[1].integer.value = 0;
  83         param[2].type = ACPI_TYPE_INTEGER;
  84         param[2].integer.value = 0;
  85         param[3].type = ACPI_TYPE_INTEGER;
  86         param[3].integer.value = 0;
  87         input.count = 4;
  88         input.pointer = param;
  89         status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
  90         return status;
  91 }
  92 
  93 static acpi_status cmpc_stop_accel_v4(acpi_handle handle)
  94 {
  95         union acpi_object param[4];
  96         struct acpi_object_list input;
  97         acpi_status status;
  98 
  99         param[0].type = ACPI_TYPE_INTEGER;
 100         param[0].integer.value = 0x4;
 101         param[1].type = ACPI_TYPE_INTEGER;
 102         param[1].integer.value = 0;
 103         param[2].type = ACPI_TYPE_INTEGER;
 104         param[2].integer.value = 0;
 105         param[3].type = ACPI_TYPE_INTEGER;
 106         param[3].integer.value = 0;
 107         input.count = 4;
 108         input.pointer = param;
 109         status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
 110         return status;
 111 }
 112 
 113 static acpi_status cmpc_accel_set_sensitivity_v4(acpi_handle handle, int val)
 114 {
 115         union acpi_object param[4];
 116         struct acpi_object_list input;
 117 
 118         param[0].type = ACPI_TYPE_INTEGER;
 119         param[0].integer.value = 0x02;
 120         param[1].type = ACPI_TYPE_INTEGER;
 121         param[1].integer.value = val;
 122         param[2].type = ACPI_TYPE_INTEGER;
 123         param[2].integer.value = 0;
 124         param[3].type = ACPI_TYPE_INTEGER;
 125         param[3].integer.value = 0;
 126         input.count = 4;
 127         input.pointer = param;
 128         return acpi_evaluate_object(handle, "ACMD", &input, NULL);
 129 }
 130 
 131 static acpi_status cmpc_accel_set_g_select_v4(acpi_handle handle, int val)
 132 {
 133         union acpi_object param[4];
 134         struct acpi_object_list input;
 135 
 136         param[0].type = ACPI_TYPE_INTEGER;
 137         param[0].integer.value = 0x05;
 138         param[1].type = ACPI_TYPE_INTEGER;
 139         param[1].integer.value = val;
 140         param[2].type = ACPI_TYPE_INTEGER;
 141         param[2].integer.value = 0;
 142         param[3].type = ACPI_TYPE_INTEGER;
 143         param[3].integer.value = 0;
 144         input.count = 4;
 145         input.pointer = param;
 146         return acpi_evaluate_object(handle, "ACMD", &input, NULL);
 147 }
 148 
 149 static acpi_status cmpc_get_accel_v4(acpi_handle handle,
 150                                      int16_t *x,
 151                                      int16_t *y,
 152                                      int16_t *z)
 153 {
 154         union acpi_object param[4];
 155         struct acpi_object_list input;
 156         struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
 157         int16_t *locs;
 158         acpi_status status;
 159 
 160         param[0].type = ACPI_TYPE_INTEGER;
 161         param[0].integer.value = 0x01;
 162         param[1].type = ACPI_TYPE_INTEGER;
 163         param[1].integer.value = 0;
 164         param[2].type = ACPI_TYPE_INTEGER;
 165         param[2].integer.value = 0;
 166         param[3].type = ACPI_TYPE_INTEGER;
 167         param[3].integer.value = 0;
 168         input.count = 4;
 169         input.pointer = param;
 170         status = acpi_evaluate_object(handle, "ACMD", &input, &output);
 171         if (ACPI_SUCCESS(status)) {
 172                 union acpi_object *obj;
 173                 obj = output.pointer;
 174                 locs = (int16_t *) obj->buffer.pointer;
 175                 *x = locs[0];
 176                 *y = locs[1];
 177                 *z = locs[2];
 178                 kfree(output.pointer);
 179         }
 180         return status;
 181 }
 182 
 183 static void cmpc_accel_handler_v4(struct acpi_device *dev, u32 event)
 184 {
 185         if (event == 0x81) {
 186                 int16_t x, y, z;
 187                 acpi_status status;
 188 
 189                 status = cmpc_get_accel_v4(dev->handle, &x, &y, &z);
 190                 if (ACPI_SUCCESS(status)) {
 191                         struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
 192 
 193                         input_report_abs(inputdev, ABS_X, x);
 194                         input_report_abs(inputdev, ABS_Y, y);
 195                         input_report_abs(inputdev, ABS_Z, z);
 196                         input_sync(inputdev);
 197                 }
 198         }
 199 }
 200 
 201 static ssize_t cmpc_accel_sensitivity_show_v4(struct device *dev,
 202                                               struct device_attribute *attr,
 203                                               char *buf)
 204 {
 205         struct acpi_device *acpi;
 206         struct input_dev *inputdev;
 207         struct cmpc_accel *accel;
 208 
 209         acpi = to_acpi_device(dev);
 210         inputdev = dev_get_drvdata(&acpi->dev);
 211         accel = dev_get_drvdata(&inputdev->dev);
 212 
 213         return sprintf(buf, "%d\n", accel->sensitivity);
 214 }
 215 
 216 static ssize_t cmpc_accel_sensitivity_store_v4(struct device *dev,
 217                                                struct device_attribute *attr,
 218                                                const char *buf, size_t count)
 219 {
 220         struct acpi_device *acpi;
 221         struct input_dev *inputdev;
 222         struct cmpc_accel *accel;
 223         unsigned long sensitivity;
 224         int r;
 225 
 226         acpi = to_acpi_device(dev);
 227         inputdev = dev_get_drvdata(&acpi->dev);
 228         accel = dev_get_drvdata(&inputdev->dev);
 229 
 230         r = kstrtoul(buf, 0, &sensitivity);
 231         if (r)
 232                 return r;
 233 
 234         /* sensitivity must be between 1 and 127 */
 235         if (sensitivity < 1 || sensitivity > 127)
 236                 return -EINVAL;
 237 
 238         accel->sensitivity = sensitivity;
 239         cmpc_accel_set_sensitivity_v4(acpi->handle, sensitivity);
 240 
 241         return strnlen(buf, count);
 242 }
 243 
 244 static struct device_attribute cmpc_accel_sensitivity_attr_v4 = {
 245         .attr = { .name = "sensitivity", .mode = 0660 },
 246         .show = cmpc_accel_sensitivity_show_v4,
 247         .store = cmpc_accel_sensitivity_store_v4
 248 };
 249 
 250 static ssize_t cmpc_accel_g_select_show_v4(struct device *dev,
 251                                            struct device_attribute *attr,
 252                                            char *buf)
 253 {
 254         struct acpi_device *acpi;
 255         struct input_dev *inputdev;
 256         struct cmpc_accel *accel;
 257 
 258         acpi = to_acpi_device(dev);
 259         inputdev = dev_get_drvdata(&acpi->dev);
 260         accel = dev_get_drvdata(&inputdev->dev);
 261 
 262         return sprintf(buf, "%d\n", accel->g_select);
 263 }
 264 
 265 static ssize_t cmpc_accel_g_select_store_v4(struct device *dev,
 266                                             struct device_attribute *attr,
 267                                             const char *buf, size_t count)
 268 {
 269         struct acpi_device *acpi;
 270         struct input_dev *inputdev;
 271         struct cmpc_accel *accel;
 272         unsigned long g_select;
 273         int r;
 274 
 275         acpi = to_acpi_device(dev);
 276         inputdev = dev_get_drvdata(&acpi->dev);
 277         accel = dev_get_drvdata(&inputdev->dev);
 278 
 279         r = kstrtoul(buf, 0, &g_select);
 280         if (r)
 281                 return r;
 282 
 283         /* 0 means 1.5g, 1 means 6g, everything else is wrong */
 284         if (g_select != 0 && g_select != 1)
 285                 return -EINVAL;
 286 
 287         accel->g_select = g_select;
 288         cmpc_accel_set_g_select_v4(acpi->handle, g_select);
 289 
 290         return strnlen(buf, count);
 291 }
 292 
 293 static struct device_attribute cmpc_accel_g_select_attr_v4 = {
 294         .attr = { .name = "g_select", .mode = 0660 },
 295         .show = cmpc_accel_g_select_show_v4,
 296         .store = cmpc_accel_g_select_store_v4
 297 };
 298 
 299 static int cmpc_accel_open_v4(struct input_dev *input)
 300 {
 301         struct acpi_device *acpi;
 302         struct cmpc_accel *accel;
 303 
 304         acpi = to_acpi_device(input->dev.parent);
 305         accel = dev_get_drvdata(&input->dev);
 306 
 307         cmpc_accel_set_sensitivity_v4(acpi->handle, accel->sensitivity);
 308         cmpc_accel_set_g_select_v4(acpi->handle, accel->g_select);
 309 
 310         if (ACPI_SUCCESS(cmpc_start_accel_v4(acpi->handle))) {
 311                 accel->inputdev_state = CMPC_ACCEL_DEV_STATE_OPEN;
 312                 return 0;
 313         }
 314         return -EIO;
 315 }
 316 
 317 static void cmpc_accel_close_v4(struct input_dev *input)
 318 {
 319         struct acpi_device *acpi;
 320         struct cmpc_accel *accel;
 321 
 322         acpi = to_acpi_device(input->dev.parent);
 323         accel = dev_get_drvdata(&input->dev);
 324 
 325         cmpc_stop_accel_v4(acpi->handle);
 326         accel->inputdev_state = CMPC_ACCEL_DEV_STATE_CLOSED;
 327 }
 328 
 329 static void cmpc_accel_idev_init_v4(struct input_dev *inputdev)
 330 {
 331         set_bit(EV_ABS, inputdev->evbit);
 332         input_set_abs_params(inputdev, ABS_X, -255, 255, 16, 0);
 333         input_set_abs_params(inputdev, ABS_Y, -255, 255, 16, 0);
 334         input_set_abs_params(inputdev, ABS_Z, -255, 255, 16, 0);
 335         inputdev->open = cmpc_accel_open_v4;
 336         inputdev->close = cmpc_accel_close_v4;
 337 }
 338 
 339 #ifdef CONFIG_PM_SLEEP
 340 static int cmpc_accel_suspend_v4(struct device *dev)
 341 {
 342         struct input_dev *inputdev;
 343         struct cmpc_accel *accel;
 344 
 345         inputdev = dev_get_drvdata(dev);
 346         accel = dev_get_drvdata(&inputdev->dev);
 347 
 348         if (accel->inputdev_state == CMPC_ACCEL_DEV_STATE_OPEN)
 349                 return cmpc_stop_accel_v4(to_acpi_device(dev)->handle);
 350 
 351         return 0;
 352 }
 353 
 354 static int cmpc_accel_resume_v4(struct device *dev)
 355 {
 356         struct input_dev *inputdev;
 357         struct cmpc_accel *accel;
 358 
 359         inputdev = dev_get_drvdata(dev);
 360         accel = dev_get_drvdata(&inputdev->dev);
 361 
 362         if (accel->inputdev_state == CMPC_ACCEL_DEV_STATE_OPEN) {
 363                 cmpc_accel_set_sensitivity_v4(to_acpi_device(dev)->handle,
 364                                               accel->sensitivity);
 365                 cmpc_accel_set_g_select_v4(to_acpi_device(dev)->handle,
 366                                            accel->g_select);
 367 
 368                 if (ACPI_FAILURE(cmpc_start_accel_v4(to_acpi_device(dev)->handle)))
 369                         return -EIO;
 370         }
 371 
 372         return 0;
 373 }
 374 #endif
 375 
 376 static int cmpc_accel_add_v4(struct acpi_device *acpi)
 377 {
 378         int error;
 379         struct input_dev *inputdev;
 380         struct cmpc_accel *accel;
 381 
 382         accel = kmalloc(sizeof(*accel), GFP_KERNEL);
 383         if (!accel)
 384                 return -ENOMEM;
 385 
 386         accel->inputdev_state = CMPC_ACCEL_DEV_STATE_CLOSED;
 387 
 388         accel->sensitivity = CMPC_ACCEL_SENSITIVITY_DEFAULT;
 389         cmpc_accel_set_sensitivity_v4(acpi->handle, accel->sensitivity);
 390 
 391         error = device_create_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
 392         if (error)
 393                 goto failed_sensitivity;
 394 
 395         accel->g_select = CMPC_ACCEL_G_SELECT_DEFAULT;
 396         cmpc_accel_set_g_select_v4(acpi->handle, accel->g_select);
 397 
 398         error = device_create_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
 399         if (error)
 400                 goto failed_g_select;
 401 
 402         error = cmpc_add_acpi_notify_device(acpi, "cmpc_accel_v4",
 403                                             cmpc_accel_idev_init_v4);
 404         if (error)
 405                 goto failed_input;
 406 
 407         inputdev = dev_get_drvdata(&acpi->dev);
 408         dev_set_drvdata(&inputdev->dev, accel);
 409 
 410         return 0;
 411 
 412 failed_input:
 413         device_remove_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
 414 failed_g_select:
 415         device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
 416 failed_sensitivity:
 417         kfree(accel);
 418         return error;
 419 }
 420 
 421 static int cmpc_accel_remove_v4(struct acpi_device *acpi)
 422 {
 423         device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
 424         device_remove_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
 425         return cmpc_remove_acpi_notify_device(acpi);
 426 }
 427 
 428 static SIMPLE_DEV_PM_OPS(cmpc_accel_pm, cmpc_accel_suspend_v4,
 429                          cmpc_accel_resume_v4);
 430 
 431 static const struct acpi_device_id cmpc_accel_device_ids_v4[] = {
 432         {CMPC_ACCEL_HID_V4, 0},
 433         {"", 0}
 434 };
 435 
 436 static struct acpi_driver cmpc_accel_acpi_driver_v4 = {
 437         .owner = THIS_MODULE,
 438         .name = "cmpc_accel_v4",
 439         .class = "cmpc_accel_v4",
 440         .ids = cmpc_accel_device_ids_v4,
 441         .ops = {
 442                 .add = cmpc_accel_add_v4,
 443                 .remove = cmpc_accel_remove_v4,
 444                 .notify = cmpc_accel_handler_v4,
 445         },
 446         .drv.pm = &cmpc_accel_pm,
 447 };
 448 
 449 
 450 /*
 451  * Accelerometer code for Classmate versions prior to V4
 452  */
 453 static acpi_status cmpc_start_accel(acpi_handle handle)
 454 {
 455         union acpi_object param[2];
 456         struct acpi_object_list input;
 457         acpi_status status;
 458 
 459         param[0].type = ACPI_TYPE_INTEGER;
 460         param[0].integer.value = 0x3;
 461         param[1].type = ACPI_TYPE_INTEGER;
 462         input.count = 2;
 463         input.pointer = param;
 464         status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
 465         return status;
 466 }
 467 
 468 static acpi_status cmpc_stop_accel(acpi_handle handle)
 469 {
 470         union acpi_object param[2];
 471         struct acpi_object_list input;
 472         acpi_status status;
 473 
 474         param[0].type = ACPI_TYPE_INTEGER;
 475         param[0].integer.value = 0x4;
 476         param[1].type = ACPI_TYPE_INTEGER;
 477         input.count = 2;
 478         input.pointer = param;
 479         status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
 480         return status;
 481 }
 482 
 483 static acpi_status cmpc_accel_set_sensitivity(acpi_handle handle, int val)
 484 {
 485         union acpi_object param[2];
 486         struct acpi_object_list input;
 487 
 488         param[0].type = ACPI_TYPE_INTEGER;
 489         param[0].integer.value = 0x02;
 490         param[1].type = ACPI_TYPE_INTEGER;
 491         param[1].integer.value = val;
 492         input.count = 2;
 493         input.pointer = param;
 494         return acpi_evaluate_object(handle, "ACMD", &input, NULL);
 495 }
 496 
 497 static acpi_status cmpc_get_accel(acpi_handle handle,
 498                                   unsigned char *x,
 499                                   unsigned char *y,
 500                                   unsigned char *z)
 501 {
 502         union acpi_object param[2];
 503         struct acpi_object_list input;
 504         struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
 505         unsigned char *locs;
 506         acpi_status status;
 507 
 508         param[0].type = ACPI_TYPE_INTEGER;
 509         param[0].integer.value = 0x01;
 510         param[1].type = ACPI_TYPE_INTEGER;
 511         input.count = 2;
 512         input.pointer = param;
 513         status = acpi_evaluate_object(handle, "ACMD", &input, &output);
 514         if (ACPI_SUCCESS(status)) {
 515                 union acpi_object *obj;
 516                 obj = output.pointer;
 517                 locs = obj->buffer.pointer;
 518                 *x = locs[0];
 519                 *y = locs[1];
 520                 *z = locs[2];
 521                 kfree(output.pointer);
 522         }
 523         return status;
 524 }
 525 
 526 static void cmpc_accel_handler(struct acpi_device *dev, u32 event)
 527 {
 528         if (event == 0x81) {
 529                 unsigned char x, y, z;
 530                 acpi_status status;
 531 
 532                 status = cmpc_get_accel(dev->handle, &x, &y, &z);
 533                 if (ACPI_SUCCESS(status)) {
 534                         struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
 535 
 536                         input_report_abs(inputdev, ABS_X, x);
 537                         input_report_abs(inputdev, ABS_Y, y);
 538                         input_report_abs(inputdev, ABS_Z, z);
 539                         input_sync(inputdev);
 540                 }
 541         }
 542 }
 543 
 544 static ssize_t cmpc_accel_sensitivity_show(struct device *dev,
 545                                            struct device_attribute *attr,
 546                                            char *buf)
 547 {
 548         struct acpi_device *acpi;
 549         struct input_dev *inputdev;
 550         struct cmpc_accel *accel;
 551 
 552         acpi = to_acpi_device(dev);
 553         inputdev = dev_get_drvdata(&acpi->dev);
 554         accel = dev_get_drvdata(&inputdev->dev);
 555 
 556         return sprintf(buf, "%d\n", accel->sensitivity);
 557 }
 558 
 559 static ssize_t cmpc_accel_sensitivity_store(struct device *dev,
 560                                             struct device_attribute *attr,
 561                                             const char *buf, size_t count)
 562 {
 563         struct acpi_device *acpi;
 564         struct input_dev *inputdev;
 565         struct cmpc_accel *accel;
 566         unsigned long sensitivity;
 567         int r;
 568 
 569         acpi = to_acpi_device(dev);
 570         inputdev = dev_get_drvdata(&acpi->dev);
 571         accel = dev_get_drvdata(&inputdev->dev);
 572 
 573         r = kstrtoul(buf, 0, &sensitivity);
 574         if (r)
 575                 return r;
 576 
 577         accel->sensitivity = sensitivity;
 578         cmpc_accel_set_sensitivity(acpi->handle, sensitivity);
 579 
 580         return strnlen(buf, count);
 581 }
 582 
 583 static struct device_attribute cmpc_accel_sensitivity_attr = {
 584         .attr = { .name = "sensitivity", .mode = 0660 },
 585         .show = cmpc_accel_sensitivity_show,
 586         .store = cmpc_accel_sensitivity_store
 587 };
 588 
 589 static int cmpc_accel_open(struct input_dev *input)
 590 {
 591         struct acpi_device *acpi;
 592 
 593         acpi = to_acpi_device(input->dev.parent);
 594         if (ACPI_SUCCESS(cmpc_start_accel(acpi->handle)))
 595                 return 0;
 596         return -EIO;
 597 }
 598 
 599 static void cmpc_accel_close(struct input_dev *input)
 600 {
 601         struct acpi_device *acpi;
 602 
 603         acpi = to_acpi_device(input->dev.parent);
 604         cmpc_stop_accel(acpi->handle);
 605 }
 606 
 607 static void cmpc_accel_idev_init(struct input_dev *inputdev)
 608 {
 609         set_bit(EV_ABS, inputdev->evbit);
 610         input_set_abs_params(inputdev, ABS_X, 0, 255, 8, 0);
 611         input_set_abs_params(inputdev, ABS_Y, 0, 255, 8, 0);
 612         input_set_abs_params(inputdev, ABS_Z, 0, 255, 8, 0);
 613         inputdev->open = cmpc_accel_open;
 614         inputdev->close = cmpc_accel_close;
 615 }
 616 
 617 static int cmpc_accel_add(struct acpi_device *acpi)
 618 {
 619         int error;
 620         struct input_dev *inputdev;
 621         struct cmpc_accel *accel;
 622 
 623         accel = kmalloc(sizeof(*accel), GFP_KERNEL);
 624         if (!accel)
 625                 return -ENOMEM;
 626 
 627         accel->sensitivity = CMPC_ACCEL_SENSITIVITY_DEFAULT;
 628         cmpc_accel_set_sensitivity(acpi->handle, accel->sensitivity);
 629 
 630         error = device_create_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
 631         if (error)
 632                 goto failed_file;
 633 
 634         error = cmpc_add_acpi_notify_device(acpi, "cmpc_accel",
 635                                             cmpc_accel_idev_init);
 636         if (error)
 637                 goto failed_input;
 638 
 639         inputdev = dev_get_drvdata(&acpi->dev);
 640         dev_set_drvdata(&inputdev->dev, accel);
 641 
 642         return 0;
 643 
 644 failed_input:
 645         device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
 646 failed_file:
 647         kfree(accel);
 648         return error;
 649 }
 650 
 651 static int cmpc_accel_remove(struct acpi_device *acpi)
 652 {
 653         device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
 654         return cmpc_remove_acpi_notify_device(acpi);
 655 }
 656 
 657 static const struct acpi_device_id cmpc_accel_device_ids[] = {
 658         {CMPC_ACCEL_HID, 0},
 659         {"", 0}
 660 };
 661 
 662 static struct acpi_driver cmpc_accel_acpi_driver = {
 663         .owner = THIS_MODULE,
 664         .name = "cmpc_accel",
 665         .class = "cmpc_accel",
 666         .ids = cmpc_accel_device_ids,
 667         .ops = {
 668                 .add = cmpc_accel_add,
 669                 .remove = cmpc_accel_remove,
 670                 .notify = cmpc_accel_handler,
 671         }
 672 };
 673 
 674 
 675 /*
 676  * Tablet mode code.
 677  */
 678 static acpi_status cmpc_get_tablet(acpi_handle handle,
 679                                    unsigned long long *value)
 680 {
 681         union acpi_object param;
 682         struct acpi_object_list input;
 683         unsigned long long output;
 684         acpi_status status;
 685 
 686         param.type = ACPI_TYPE_INTEGER;
 687         param.integer.value = 0x01;
 688         input.count = 1;
 689         input.pointer = &param;
 690         status = acpi_evaluate_integer(handle, "TCMD", &input, &output);
 691         if (ACPI_SUCCESS(status))
 692                 *value = output;
 693         return status;
 694 }
 695 
 696 static void cmpc_tablet_handler(struct acpi_device *dev, u32 event)
 697 {
 698         unsigned long long val = 0;
 699         struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
 700 
 701         if (event == 0x81) {
 702                 if (ACPI_SUCCESS(cmpc_get_tablet(dev->handle, &val))) {
 703                         input_report_switch(inputdev, SW_TABLET_MODE, !val);
 704                         input_sync(inputdev);
 705                 }
 706         }
 707 }
 708 
 709 static void cmpc_tablet_idev_init(struct input_dev *inputdev)
 710 {
 711         unsigned long long val = 0;
 712         struct acpi_device *acpi;
 713 
 714         set_bit(EV_SW, inputdev->evbit);
 715         set_bit(SW_TABLET_MODE, inputdev->swbit);
 716 
 717         acpi = to_acpi_device(inputdev->dev.parent);
 718         if (ACPI_SUCCESS(cmpc_get_tablet(acpi->handle, &val))) {
 719                 input_report_switch(inputdev, SW_TABLET_MODE, !val);
 720                 input_sync(inputdev);
 721         }
 722 }
 723 
 724 static int cmpc_tablet_add(struct acpi_device *acpi)
 725 {
 726         return cmpc_add_acpi_notify_device(acpi, "cmpc_tablet",
 727                                            cmpc_tablet_idev_init);
 728 }
 729 
 730 static int cmpc_tablet_remove(struct acpi_device *acpi)
 731 {
 732         return cmpc_remove_acpi_notify_device(acpi);
 733 }
 734 
 735 #ifdef CONFIG_PM_SLEEP
 736 static int cmpc_tablet_resume(struct device *dev)
 737 {
 738         struct input_dev *inputdev = dev_get_drvdata(dev);
 739 
 740         unsigned long long val = 0;
 741         if (ACPI_SUCCESS(cmpc_get_tablet(to_acpi_device(dev)->handle, &val))) {
 742                 input_report_switch(inputdev, SW_TABLET_MODE, !val);
 743                 input_sync(inputdev);
 744         }
 745         return 0;
 746 }
 747 #endif
 748 
 749 static SIMPLE_DEV_PM_OPS(cmpc_tablet_pm, NULL, cmpc_tablet_resume);
 750 
 751 static const struct acpi_device_id cmpc_tablet_device_ids[] = {
 752         {CMPC_TABLET_HID, 0},
 753         {"", 0}
 754 };
 755 
 756 static struct acpi_driver cmpc_tablet_acpi_driver = {
 757         .owner = THIS_MODULE,
 758         .name = "cmpc_tablet",
 759         .class = "cmpc_tablet",
 760         .ids = cmpc_tablet_device_ids,
 761         .ops = {
 762                 .add = cmpc_tablet_add,
 763                 .remove = cmpc_tablet_remove,
 764                 .notify = cmpc_tablet_handler,
 765         },
 766         .drv.pm = &cmpc_tablet_pm,
 767 };
 768 
 769 
 770 /*
 771  * Backlight code.
 772  */
 773 
 774 static acpi_status cmpc_get_brightness(acpi_handle handle,
 775                                        unsigned long long *value)
 776 {
 777         union acpi_object param;
 778         struct acpi_object_list input;
 779         unsigned long long output;
 780         acpi_status status;
 781 
 782         param.type = ACPI_TYPE_INTEGER;
 783         param.integer.value = 0xC0;
 784         input.count = 1;
 785         input.pointer = &param;
 786         status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
 787         if (ACPI_SUCCESS(status))
 788                 *value = output;
 789         return status;
 790 }
 791 
 792 static acpi_status cmpc_set_brightness(acpi_handle handle,
 793                                        unsigned long long value)
 794 {
 795         union acpi_object param[2];
 796         struct acpi_object_list input;
 797         acpi_status status;
 798         unsigned long long output;
 799 
 800         param[0].type = ACPI_TYPE_INTEGER;
 801         param[0].integer.value = 0xC0;
 802         param[1].type = ACPI_TYPE_INTEGER;
 803         param[1].integer.value = value;
 804         input.count = 2;
 805         input.pointer = param;
 806         status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
 807         return status;
 808 }
 809 
 810 static int cmpc_bl_get_brightness(struct backlight_device *bd)
 811 {
 812         acpi_status status;
 813         acpi_handle handle;
 814         unsigned long long brightness;
 815 
 816         handle = bl_get_data(bd);
 817         status = cmpc_get_brightness(handle, &brightness);
 818         if (ACPI_SUCCESS(status))
 819                 return brightness;
 820         else
 821                 return -1;
 822 }
 823 
 824 static int cmpc_bl_update_status(struct backlight_device *bd)
 825 {
 826         acpi_status status;
 827         acpi_handle handle;
 828 
 829         handle = bl_get_data(bd);
 830         status = cmpc_set_brightness(handle, bd->props.brightness);
 831         if (ACPI_SUCCESS(status))
 832                 return 0;
 833         else
 834                 return -1;
 835 }
 836 
 837 static const struct backlight_ops cmpc_bl_ops = {
 838         .get_brightness = cmpc_bl_get_brightness,
 839         .update_status = cmpc_bl_update_status
 840 };
 841 
 842 /*
 843  * RFKILL code.
 844  */
 845 
 846 static acpi_status cmpc_get_rfkill_wlan(acpi_handle handle,
 847                                         unsigned long long *value)
 848 {
 849         union acpi_object param;
 850         struct acpi_object_list input;
 851         unsigned long long output;
 852         acpi_status status;
 853 
 854         param.type = ACPI_TYPE_INTEGER;
 855         param.integer.value = 0xC1;
 856         input.count = 1;
 857         input.pointer = &param;
 858         status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
 859         if (ACPI_SUCCESS(status))
 860                 *value = output;
 861         return status;
 862 }
 863 
 864 static acpi_status cmpc_set_rfkill_wlan(acpi_handle handle,
 865                                         unsigned long long value)
 866 {
 867         union acpi_object param[2];
 868         struct acpi_object_list input;
 869         acpi_status status;
 870         unsigned long long output;
 871 
 872         param[0].type = ACPI_TYPE_INTEGER;
 873         param[0].integer.value = 0xC1;
 874         param[1].type = ACPI_TYPE_INTEGER;
 875         param[1].integer.value = value;
 876         input.count = 2;
 877         input.pointer = param;
 878         status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
 879         return status;
 880 }
 881 
 882 static void cmpc_rfkill_query(struct rfkill *rfkill, void *data)
 883 {
 884         acpi_status status;
 885         acpi_handle handle;
 886         unsigned long long state;
 887         bool blocked;
 888 
 889         handle = data;
 890         status = cmpc_get_rfkill_wlan(handle, &state);
 891         if (ACPI_SUCCESS(status)) {
 892                 blocked = state & 1 ? false : true;
 893                 rfkill_set_sw_state(rfkill, blocked);
 894         }
 895 }
 896 
 897 static int cmpc_rfkill_block(void *data, bool blocked)
 898 {
 899         acpi_status status;
 900         acpi_handle handle;
 901         unsigned long long state;
 902         bool is_blocked;
 903 
 904         handle = data;
 905         status = cmpc_get_rfkill_wlan(handle, &state);
 906         if (ACPI_FAILURE(status))
 907                 return -ENODEV;
 908         /* Check if we really need to call cmpc_set_rfkill_wlan */
 909         is_blocked = state & 1 ? false : true;
 910         if (is_blocked != blocked) {
 911                 state = blocked ? 0 : 1;
 912                 status = cmpc_set_rfkill_wlan(handle, state);
 913                 if (ACPI_FAILURE(status))
 914                         return -ENODEV;
 915         }
 916         return 0;
 917 }
 918 
 919 static const struct rfkill_ops cmpc_rfkill_ops = {
 920         .query = cmpc_rfkill_query,
 921         .set_block = cmpc_rfkill_block,
 922 };
 923 
 924 /*
 925  * Common backlight and rfkill code.
 926  */
 927 
 928 struct ipml200_dev {
 929         struct backlight_device *bd;
 930         struct rfkill *rf;
 931 };
 932 
 933 static int cmpc_ipml_add(struct acpi_device *acpi)
 934 {
 935         int retval;
 936         struct ipml200_dev *ipml;
 937         struct backlight_properties props;
 938 
 939         ipml = kmalloc(sizeof(*ipml), GFP_KERNEL);
 940         if (ipml == NULL)
 941                 return -ENOMEM;
 942 
 943         memset(&props, 0, sizeof(struct backlight_properties));
 944         props.type = BACKLIGHT_PLATFORM;
 945         props.max_brightness = 7;
 946         ipml->bd = backlight_device_register("cmpc_bl", &acpi->dev,
 947                                              acpi->handle, &cmpc_bl_ops,
 948                                              &props);
 949         if (IS_ERR(ipml->bd)) {
 950                 retval = PTR_ERR(ipml->bd);
 951                 goto out_bd;
 952         }
 953 
 954         ipml->rf = rfkill_alloc("cmpc_rfkill", &acpi->dev, RFKILL_TYPE_WLAN,
 955                                 &cmpc_rfkill_ops, acpi->handle);
 956         /*
 957          * If RFKILL is disabled, rfkill_alloc will return ERR_PTR(-ENODEV).
 958          * This is OK, however, since all other uses of the device will not
 959          * derefence it.
 960          */
 961         if (ipml->rf) {
 962                 retval = rfkill_register(ipml->rf);
 963                 if (retval) {
 964                         rfkill_destroy(ipml->rf);
 965                         ipml->rf = NULL;
 966                 }
 967         }
 968 
 969         dev_set_drvdata(&acpi->dev, ipml);
 970         return 0;
 971 
 972 out_bd:
 973         kfree(ipml);
 974         return retval;
 975 }
 976 
 977 static int cmpc_ipml_remove(struct acpi_device *acpi)
 978 {
 979         struct ipml200_dev *ipml;
 980 
 981         ipml = dev_get_drvdata(&acpi->dev);
 982 
 983         backlight_device_unregister(ipml->bd);
 984 
 985         if (ipml->rf) {
 986                 rfkill_unregister(ipml->rf);
 987                 rfkill_destroy(ipml->rf);
 988         }
 989 
 990         kfree(ipml);
 991 
 992         return 0;
 993 }
 994 
 995 static const struct acpi_device_id cmpc_ipml_device_ids[] = {
 996         {CMPC_IPML_HID, 0},
 997         {"", 0}
 998 };
 999 
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_MAX
1027 };
1028 
1029 static void cmpc_keys_handler(struct acpi_device *dev, u32 event)
1030 {
1031         struct input_dev *inputdev;
1032         int code = KEY_MAX;
1033 
1034         if ((event & 0x0F) < ARRAY_SIZE(cmpc_keys_codes))
1035                 code = cmpc_keys_codes[event & 0x0F];
1036         inputdev = dev_get_drvdata(&dev->dev);
1037         input_report_key(inputdev, code, !(event & 0x10));
1038         input_sync(inputdev);
1039 }
1040 
1041 static void cmpc_keys_idev_init(struct input_dev *inputdev)
1042 {
1043         int i;
1044 
1045         set_bit(EV_KEY, inputdev->evbit);
1046         for (i = 0; cmpc_keys_codes[i] != KEY_MAX; i++)
1047                 set_bit(cmpc_keys_codes[i], inputdev->keybit);
1048 }
1049 
1050 static int cmpc_keys_add(struct acpi_device *acpi)
1051 {
1052         return cmpc_add_acpi_notify_device(acpi, "cmpc_keys",
1053                                            cmpc_keys_idev_init);
1054 }
1055 
1056 static int cmpc_keys_remove(struct acpi_device *acpi)
1057 {
1058         return cmpc_remove_acpi_notify_device(acpi);
1059 }
1060 
1061 static const struct acpi_device_id cmpc_keys_device_ids[] = {
1062         {CMPC_KEYS_HID, 0},
1063         {"", 0}
1064 };
1065 
1066 static struct acpi_driver cmpc_keys_acpi_driver = {
1067         .owner = THIS_MODULE,
1068         .name = "cmpc_keys",
1069         .class = "cmpc_keys",
1070         .ids = cmpc_keys_device_ids,
1071         .ops = {
1072                 .add = cmpc_keys_add,
1073                 .remove = cmpc_keys_remove,
1074                 .notify = cmpc_keys_handler,
1075         }
1076 };
1077 
1078 
1079 /*
1080  * General init/exit code.
1081  */
1082 
1083 static int cmpc_init(void)
1084 {
1085         int r;
1086 
1087         r = acpi_bus_register_driver(&cmpc_keys_acpi_driver);
1088         if (r)
1089                 goto failed_keys;
1090 
1091         r = acpi_bus_register_driver(&cmpc_ipml_acpi_driver);
1092         if (r)
1093                 goto failed_bl;
1094 
1095         r = acpi_bus_register_driver(&cmpc_tablet_acpi_driver);
1096         if (r)
1097                 goto failed_tablet;
1098 
1099         r = acpi_bus_register_driver(&cmpc_accel_acpi_driver);
1100         if (r)
1101                 goto failed_accel;
1102 
1103         r = acpi_bus_register_driver(&cmpc_accel_acpi_driver_v4);
1104         if (r)
1105                 goto failed_accel_v4;
1106 
1107         return r;
1108 
1109 failed_accel_v4:
1110         acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
1111 
1112 failed_accel:
1113         acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
1114 
1115 failed_tablet:
1116         acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
1117 
1118 failed_bl:
1119         acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
1120 
1121 failed_keys:
1122         return r;
1123 }
1124 
1125 static void cmpc_exit(void)
1126 {
1127         acpi_bus_unregister_driver(&cmpc_accel_acpi_driver_v4);
1128         acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
1129         acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
1130         acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
1131         acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
1132 }
1133 
1134 module_init(cmpc_init);
1135 module_exit(cmpc_exit);
1136 
1137 static const struct acpi_device_id cmpc_device_ids[] = {
1138         {CMPC_ACCEL_HID, 0},
1139         {CMPC_ACCEL_HID_V4, 0},
1140         {CMPC_TABLET_HID, 0},
1141         {CMPC_IPML_HID, 0},
1142         {CMPC_KEYS_HID, 0},
1143         {"", 0}
1144 };
1145 
1146 MODULE_DEVICE_TABLE(acpi, cmpc_device_ids);

/* [<][>][^][v][top][bottom][index][help] */