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