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