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