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