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