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