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