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