panasonic-laptop.c (28074B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Panasonic HotKey and LCD brightness control driver 4 * (C) 2004 Hiroshi Miura <miura@da-cha.org> 5 * (C) 2004 NTT DATA Intellilink Co. http://www.intellilink.co.jp/ 6 * (C) YOKOTA Hiroshi <yokota (at) netlab. is. tsukuba. ac. jp> 7 * (C) 2004 David Bronaugh <dbronaugh> 8 * (C) 2006-2008 Harald Welte <laforge@gnumonks.org> 9 * 10 * derived from toshiba_acpi.c, Copyright (C) 2002-2004 John Belmonte 11 * 12 *--------------------------------------------------------------------------- 13 * 14 * ChangeLog: 15 * Aug.18, 2020 Kenneth Chan <kenneth.t.chan@gmail.com> 16 * -v0.98 add platform devices for firmware brightness registers 17 * add support for battery charging threshold (eco mode) 18 * resolve hotkey double trigger 19 * add write support to mute 20 * fix sticky_key init bug 21 * fix naming of platform files for consistency with other 22 * modules 23 * split MODULE_AUTHOR() by one author per macro call 24 * replace ACPI prints with pr_*() macros 25 * -v0.97 add support for cdpower hardware switch 26 * -v0.96 merge Lucina's enhancement 27 * Jan.13, 2009 Martin Lucina <mato@kotelna.sk> 28 * - add support for optical driver power in 29 * Y and W series 30 * 31 * Sep.23, 2008 Harald Welte <laforge@gnumonks.org> 32 * -v0.95 rename driver from drivers/acpi/pcc_acpi.c to 33 * drivers/misc/panasonic-laptop.c 34 * 35 * Jul.04, 2008 Harald Welte <laforge@gnumonks.org> 36 * -v0.94 replace /proc interface with device attributes 37 * support {set,get}keycode on th input device 38 * 39 * Jun.27, 2008 Harald Welte <laforge@gnumonks.org> 40 * -v0.92 merge with 2.6.26-rc6 input API changes 41 * remove broken <= 2.6.15 kernel support 42 * resolve all compiler warnings 43 * various coding style fixes (checkpatch.pl) 44 * add support for backlight api 45 * major code restructuring 46 * 47 * Dac.28, 2007 Harald Welte <laforge@gnumonks.org> 48 * -v0.91 merge with 2.6.24-rc6 ACPI changes 49 * 50 * Nov.04, 2006 Hiroshi Miura <miura@da-cha.org> 51 * -v0.9 remove warning about section reference. 52 * remove acpi_os_free 53 * add /proc/acpi/pcc/brightness interface for HAL access 54 * merge dbronaugh's enhancement 55 * Aug.17, 2004 David Bronaugh (dbronaugh) 56 * - Added screen brightness setting interface 57 * Thanks to FreeBSD crew (acpi_panasonic.c) 58 * for the ideas I needed to accomplish it 59 * 60 * May.29, 2006 Hiroshi Miura <miura@da-cha.org> 61 * -v0.8.4 follow to change keyinput structure 62 * thanks Fabian Yamaguchi <fabs@cs.tu-berlin.de>, 63 * Jacob Bower <jacob.bower@ic.ac.uk> and 64 * Hiroshi Yokota for providing solutions. 65 * 66 * Oct.02, 2004 Hiroshi Miura <miura@da-cha.org> 67 * -v0.8.2 merge code of YOKOTA Hiroshi 68 * <yokota@netlab.is.tsukuba.ac.jp>. 69 * Add sticky key mode interface. 70 * Refactoring acpi_pcc_generate_keyinput(). 71 * 72 * Sep.15, 2004 Hiroshi Miura <miura@da-cha.org> 73 * -v0.8 Generate key input event on input subsystem. 74 * This is based on yet another driver written by 75 * Ryuta Nakanishi. 76 * 77 * Sep.10, 2004 Hiroshi Miura <miura@da-cha.org> 78 * -v0.7 Change proc interface functions using seq_file 79 * facility as same as other ACPI drivers. 80 * 81 * Aug.28, 2004 Hiroshi Miura <miura@da-cha.org> 82 * -v0.6.4 Fix a silly error with status checking 83 * 84 * Aug.25, 2004 Hiroshi Miura <miura@da-cha.org> 85 * -v0.6.3 replace read_acpi_int by standard function 86 * acpi_evaluate_integer 87 * some clean up and make smart copyright notice. 88 * fix return value of pcc_acpi_get_key() 89 * fix checking return value of acpi_bus_register_driver() 90 * 91 * Aug.22, 2004 David Bronaugh <dbronaugh@linuxboxen.org> 92 * -v0.6.2 Add check on ACPI data (num_sifr) 93 * Coding style cleanups, better error messages/handling 94 * Fixed an off-by-one error in memory allocation 95 * 96 * Aug.21, 2004 David Bronaugh <dbronaugh@linuxboxen.org> 97 * -v0.6.1 Fix a silly error with status checking 98 * 99 * Aug.20, 2004 David Bronaugh <dbronaugh@linuxboxen.org> 100 * - v0.6 Correct brightness controls to reflect reality 101 * based on information gleaned by Hiroshi Miura 102 * and discussions with Hiroshi Miura 103 * 104 * Aug.10, 2004 Hiroshi Miura <miura@da-cha.org> 105 * - v0.5 support LCD brightness control 106 * based on the disclosed information by MEI. 107 * 108 * Jul.25, 2004 Hiroshi Miura <miura@da-cha.org> 109 * - v0.4 first post version 110 * add function to retrive SIFR 111 * 112 * Jul.24, 2004 Hiroshi Miura <miura@da-cha.org> 113 * - v0.3 get proper status of hotkey 114 * 115 * Jul.22, 2004 Hiroshi Miura <miura@da-cha.org> 116 * - v0.2 add HotKey handler 117 * 118 * Jul.17, 2004 Hiroshi Miura <miura@da-cha.org> 119 * - v0.1 start from toshiba_acpi driver written by John Belmonte 120 */ 121 122#include <linux/acpi.h> 123#include <linux/backlight.h> 124#include <linux/ctype.h> 125#include <linux/i8042.h> 126#include <linux/init.h> 127#include <linux/input.h> 128#include <linux/input/sparse-keymap.h> 129#include <linux/kernel.h> 130#include <linux/module.h> 131#include <linux/platform_device.h> 132#include <linux/seq_file.h> 133#include <linux/serio.h> 134#include <linux/slab.h> 135#include <linux/types.h> 136#include <linux/uaccess.h> 137#include <acpi/video.h> 138 139MODULE_AUTHOR("Hiroshi Miura <miura@da-cha.org>"); 140MODULE_AUTHOR("David Bronaugh <dbronaugh@linuxboxen.org>"); 141MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); 142MODULE_AUTHOR("Martin Lucina <mato@kotelna.sk>"); 143MODULE_AUTHOR("Kenneth Chan <kenneth.t.chan@gmail.com>"); 144MODULE_DESCRIPTION("ACPI HotKey driver for Panasonic Let's Note laptops"); 145MODULE_LICENSE("GPL"); 146 147#define LOGPREFIX "pcc_acpi: " 148 149/* Define ACPI PATHs */ 150/* Lets note hotkeys */ 151#define METHOD_HKEY_QUERY "HINF" 152#define METHOD_HKEY_SQTY "SQTY" 153#define METHOD_HKEY_SINF "SINF" 154#define METHOD_HKEY_SSET "SSET" 155#define METHOD_ECWR "\\_SB.ECWR" 156#define HKEY_NOTIFY 0x80 157#define ECO_MODE_OFF 0x00 158#define ECO_MODE_ON 0x80 159 160#define ACPI_PCC_DRIVER_NAME "Panasonic Laptop Support" 161#define ACPI_PCC_DEVICE_NAME "Hotkey" 162#define ACPI_PCC_CLASS "pcc" 163 164#define ACPI_PCC_INPUT_PHYS "panasonic/hkey0" 165 166/* LCD_TYPEs: 0 = Normal, 1 = Semi-transparent 167 ECO_MODEs: 0x03 = off, 0x83 = on 168*/ 169enum SINF_BITS { SINF_NUM_BATTERIES = 0, 170 SINF_LCD_TYPE, 171 SINF_AC_MAX_BRIGHT, 172 SINF_AC_MIN_BRIGHT, 173 SINF_AC_CUR_BRIGHT, 174 SINF_DC_MAX_BRIGHT, 175 SINF_DC_MIN_BRIGHT, 176 SINF_DC_CUR_BRIGHT, 177 SINF_MUTE, 178 SINF_RESERVED, 179 SINF_ECO_MODE = 0x0A, 180 SINF_CUR_BRIGHT = 0x0D, 181 SINF_STICKY_KEY = 0x80, 182 }; 183/* R1 handles SINF_AC_CUR_BRIGHT as SINF_CUR_BRIGHT, doesn't know AC state */ 184 185static int acpi_pcc_hotkey_add(struct acpi_device *device); 186static int acpi_pcc_hotkey_remove(struct acpi_device *device); 187static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event); 188 189static const struct acpi_device_id pcc_device_ids[] = { 190 { "MAT0012", 0}, 191 { "MAT0013", 0}, 192 { "MAT0018", 0}, 193 { "MAT0019", 0}, 194 { "", 0}, 195}; 196MODULE_DEVICE_TABLE(acpi, pcc_device_ids); 197 198#ifdef CONFIG_PM_SLEEP 199static int acpi_pcc_hotkey_resume(struct device *dev); 200#endif 201static SIMPLE_DEV_PM_OPS(acpi_pcc_hotkey_pm, NULL, acpi_pcc_hotkey_resume); 202 203static struct acpi_driver acpi_pcc_driver = { 204 .name = ACPI_PCC_DRIVER_NAME, 205 .class = ACPI_PCC_CLASS, 206 .ids = pcc_device_ids, 207 .ops = { 208 .add = acpi_pcc_hotkey_add, 209 .remove = acpi_pcc_hotkey_remove, 210 .notify = acpi_pcc_hotkey_notify, 211 }, 212 .drv.pm = &acpi_pcc_hotkey_pm, 213}; 214 215static const struct key_entry panasonic_keymap[] = { 216 { KE_KEY, 0, { KEY_RESERVED } }, 217 { KE_KEY, 1, { KEY_BRIGHTNESSDOWN } }, 218 { KE_KEY, 2, { KEY_BRIGHTNESSUP } }, 219 { KE_KEY, 3, { KEY_DISPLAYTOGGLE } }, 220 { KE_KEY, 4, { KEY_MUTE } }, 221 { KE_KEY, 5, { KEY_VOLUMEDOWN } }, 222 { KE_KEY, 6, { KEY_VOLUMEUP } }, 223 { KE_KEY, 7, { KEY_SLEEP } }, 224 { KE_KEY, 8, { KEY_PROG1 } }, /* Change CPU boost */ 225 { KE_KEY, 9, { KEY_BATTERY } }, 226 { KE_KEY, 10, { KEY_SUSPEND } }, 227 { KE_END, 0 } 228}; 229 230struct pcc_acpi { 231 acpi_handle handle; 232 unsigned long num_sifr; 233 int sticky_key; 234 int eco_mode; 235 int mute; 236 int ac_brightness; 237 int dc_brightness; 238 int current_brightness; 239 u32 *sinf; 240 struct acpi_device *device; 241 struct input_dev *input_dev; 242 struct backlight_device *backlight; 243 struct platform_device *platform; 244}; 245 246/* 247 * On some Panasonic models the volume up / down / mute keys send duplicate 248 * keypress events over the PS/2 kbd interface, filter these out. 249 */ 250static bool panasonic_i8042_filter(unsigned char data, unsigned char str, 251 struct serio *port) 252{ 253 static bool extended; 254 255 if (str & I8042_STR_AUXDATA) 256 return false; 257 258 if (data == 0xe0) { 259 extended = true; 260 return true; 261 } else if (extended) { 262 extended = false; 263 264 switch (data & 0x7f) { 265 case 0x20: /* e0 20 / e0 a0, Volume Mute press / release */ 266 case 0x2e: /* e0 2e / e0 ae, Volume Down press / release */ 267 case 0x30: /* e0 30 / e0 b0, Volume Up press / release */ 268 return true; 269 default: 270 /* 271 * Report the previously filtered e0 before continuing 272 * with the next non-filtered byte. 273 */ 274 serio_interrupt(port, 0xe0, 0); 275 return false; 276 } 277 } 278 279 return false; 280} 281 282/* method access functions */ 283static int acpi_pcc_write_sset(struct pcc_acpi *pcc, int func, int val) 284{ 285 union acpi_object in_objs[] = { 286 { .integer.type = ACPI_TYPE_INTEGER, 287 .integer.value = func, }, 288 { .integer.type = ACPI_TYPE_INTEGER, 289 .integer.value = val, }, 290 }; 291 struct acpi_object_list params = { 292 .count = ARRAY_SIZE(in_objs), 293 .pointer = in_objs, 294 }; 295 acpi_status status = AE_OK; 296 297 status = acpi_evaluate_object(pcc->handle, METHOD_HKEY_SSET, 298 ¶ms, NULL); 299 300 return (status == AE_OK) ? 0 : -EIO; 301} 302 303static inline int acpi_pcc_get_sqty(struct acpi_device *device) 304{ 305 unsigned long long s; 306 acpi_status status; 307 308 status = acpi_evaluate_integer(device->handle, METHOD_HKEY_SQTY, 309 NULL, &s); 310 if (ACPI_SUCCESS(status)) 311 return s; 312 else { 313 pr_err("evaluation error HKEY.SQTY\n"); 314 return -EINVAL; 315 } 316} 317 318static int acpi_pcc_retrieve_biosdata(struct pcc_acpi *pcc) 319{ 320 acpi_status status; 321 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; 322 union acpi_object *hkey = NULL; 323 int i; 324 325 status = acpi_evaluate_object(pcc->handle, METHOD_HKEY_SINF, NULL, 326 &buffer); 327 if (ACPI_FAILURE(status)) { 328 pr_err("evaluation error HKEY.SINF\n"); 329 return 0; 330 } 331 332 hkey = buffer.pointer; 333 if (!hkey || (hkey->type != ACPI_TYPE_PACKAGE)) { 334 pr_err("Invalid HKEY.SINF\n"); 335 status = AE_ERROR; 336 goto end; 337 } 338 339 if (pcc->num_sifr < hkey->package.count) { 340 pr_err("SQTY reports bad SINF length\n"); 341 status = AE_ERROR; 342 goto end; 343 } 344 345 for (i = 0; i < hkey->package.count; i++) { 346 union acpi_object *element = &(hkey->package.elements[i]); 347 if (likely(element->type == ACPI_TYPE_INTEGER)) { 348 pcc->sinf[i] = element->integer.value; 349 } else 350 pr_err("Invalid HKEY.SINF data\n"); 351 } 352 pcc->sinf[hkey->package.count] = -1; 353 354end: 355 kfree(buffer.pointer); 356 return status == AE_OK; 357} 358 359/* backlight API interface functions */ 360 361/* This driver currently treats AC and DC brightness identical, 362 * since we don't need to invent an interface to the core ACPI 363 * logic to receive events in case a power supply is plugged in 364 * or removed */ 365 366static int bl_get(struct backlight_device *bd) 367{ 368 struct pcc_acpi *pcc = bl_get_data(bd); 369 370 if (!acpi_pcc_retrieve_biosdata(pcc)) 371 return -EIO; 372 373 return pcc->sinf[SINF_AC_CUR_BRIGHT]; 374} 375 376static int bl_set_status(struct backlight_device *bd) 377{ 378 struct pcc_acpi *pcc = bl_get_data(bd); 379 int bright = bd->props.brightness; 380 int rc; 381 382 if (!acpi_pcc_retrieve_biosdata(pcc)) 383 return -EIO; 384 385 if (bright < pcc->sinf[SINF_AC_MIN_BRIGHT]) 386 bright = pcc->sinf[SINF_AC_MIN_BRIGHT]; 387 388 if (bright < pcc->sinf[SINF_DC_MIN_BRIGHT]) 389 bright = pcc->sinf[SINF_DC_MIN_BRIGHT]; 390 391 if (bright < pcc->sinf[SINF_AC_MIN_BRIGHT] || 392 bright > pcc->sinf[SINF_AC_MAX_BRIGHT]) 393 return -EINVAL; 394 395 rc = acpi_pcc_write_sset(pcc, SINF_AC_CUR_BRIGHT, bright); 396 if (rc < 0) 397 return rc; 398 399 return acpi_pcc_write_sset(pcc, SINF_DC_CUR_BRIGHT, bright); 400} 401 402static const struct backlight_ops pcc_backlight_ops = { 403 .get_brightness = bl_get, 404 .update_status = bl_set_status, 405}; 406 407 408/* returns ACPI_SUCCESS if methods to control optical drive are present */ 409 410static acpi_status check_optd_present(void) 411{ 412 acpi_status status = AE_OK; 413 acpi_handle handle; 414 415 status = acpi_get_handle(NULL, "\\_SB.STAT", &handle); 416 if (ACPI_FAILURE(status)) 417 goto out; 418 status = acpi_get_handle(NULL, "\\_SB.FBAY", &handle); 419 if (ACPI_FAILURE(status)) 420 goto out; 421 status = acpi_get_handle(NULL, "\\_SB.CDDI", &handle); 422 if (ACPI_FAILURE(status)) 423 goto out; 424 425out: 426 return status; 427} 428 429/* get optical driver power state */ 430 431static int get_optd_power_state(void) 432{ 433 acpi_status status; 434 unsigned long long state; 435 int result; 436 437 status = acpi_evaluate_integer(NULL, "\\_SB.STAT", NULL, &state); 438 if (ACPI_FAILURE(status)) { 439 pr_err("evaluation error _SB.STAT\n"); 440 result = -EIO; 441 goto out; 442 } 443 switch (state) { 444 case 0: /* power off */ 445 result = 0; 446 break; 447 case 0x0f: /* power on */ 448 result = 1; 449 break; 450 default: 451 result = -EIO; 452 break; 453 } 454 455out: 456 return result; 457} 458 459/* set optical drive power state */ 460 461static int set_optd_power_state(int new_state) 462{ 463 int result; 464 acpi_status status; 465 466 result = get_optd_power_state(); 467 if (result < 0) 468 goto out; 469 if (new_state == result) 470 goto out; 471 472 switch (new_state) { 473 case 0: /* power off */ 474 /* Call CDDR instead, since they both call the same method 475 * while CDDI takes 1 arg and we are not quite sure what it is. 476 */ 477 status = acpi_evaluate_object(NULL, "\\_SB.CDDR", NULL, NULL); 478 if (ACPI_FAILURE(status)) { 479 pr_err("evaluation error _SB.CDDR\n"); 480 result = -EIO; 481 } 482 break; 483 case 1: /* power on */ 484 status = acpi_evaluate_object(NULL, "\\_SB.FBAY", NULL, NULL); 485 if (ACPI_FAILURE(status)) { 486 pr_err("evaluation error _SB.FBAY\n"); 487 result = -EIO; 488 } 489 break; 490 default: 491 result = -EINVAL; 492 break; 493 } 494 495out: 496 return result; 497} 498 499 500/* sysfs user interface functions */ 501 502static ssize_t numbatt_show(struct device *dev, struct device_attribute *attr, 503 char *buf) 504{ 505 struct acpi_device *acpi = to_acpi_device(dev); 506 struct pcc_acpi *pcc = acpi_driver_data(acpi); 507 508 if (!acpi_pcc_retrieve_biosdata(pcc)) 509 return -EIO; 510 511 return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_NUM_BATTERIES]); 512} 513 514static ssize_t lcdtype_show(struct device *dev, struct device_attribute *attr, 515 char *buf) 516{ 517 struct acpi_device *acpi = to_acpi_device(dev); 518 struct pcc_acpi *pcc = acpi_driver_data(acpi); 519 520 if (!acpi_pcc_retrieve_biosdata(pcc)) 521 return -EIO; 522 523 return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_LCD_TYPE]); 524} 525 526static ssize_t mute_show(struct device *dev, struct device_attribute *attr, 527 char *buf) 528{ 529 struct acpi_device *acpi = to_acpi_device(dev); 530 struct pcc_acpi *pcc = acpi_driver_data(acpi); 531 532 if (!acpi_pcc_retrieve_biosdata(pcc)) 533 return -EIO; 534 535 return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_MUTE]); 536} 537 538static ssize_t mute_store(struct device *dev, struct device_attribute *attr, 539 const char *buf, size_t count) 540{ 541 struct acpi_device *acpi = to_acpi_device(dev); 542 struct pcc_acpi *pcc = acpi_driver_data(acpi); 543 int err, val; 544 545 err = kstrtoint(buf, 0, &val); 546 if (err) 547 return err; 548 if (val == 0 || val == 1) { 549 acpi_pcc_write_sset(pcc, SINF_MUTE, val); 550 pcc->mute = val; 551 } 552 553 return count; 554} 555 556static ssize_t sticky_key_show(struct device *dev, struct device_attribute *attr, 557 char *buf) 558{ 559 struct acpi_device *acpi = to_acpi_device(dev); 560 struct pcc_acpi *pcc = acpi_driver_data(acpi); 561 562 if (!acpi_pcc_retrieve_biosdata(pcc)) 563 return -EIO; 564 565 return sysfs_emit(buf, "%u\n", pcc->sticky_key); 566} 567 568static ssize_t sticky_key_store(struct device *dev, struct device_attribute *attr, 569 const char *buf, size_t count) 570{ 571 struct acpi_device *acpi = to_acpi_device(dev); 572 struct pcc_acpi *pcc = acpi_driver_data(acpi); 573 int err, val; 574 575 err = kstrtoint(buf, 0, &val); 576 if (err) 577 return err; 578 if (val == 0 || val == 1) { 579 acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, val); 580 pcc->sticky_key = val; 581 } 582 583 return count; 584} 585 586static ssize_t eco_mode_show(struct device *dev, struct device_attribute *attr, 587 char *buf) 588{ 589 struct acpi_device *acpi = to_acpi_device(dev); 590 struct pcc_acpi *pcc = acpi_driver_data(acpi); 591 int result; 592 593 if (!acpi_pcc_retrieve_biosdata(pcc)) 594 return -EIO; 595 596 switch (pcc->sinf[SINF_ECO_MODE]) { 597 case (ECO_MODE_OFF + 3): 598 result = 0; 599 break; 600 case (ECO_MODE_ON + 3): 601 result = 1; 602 break; 603 default: 604 result = -EIO; 605 break; 606 } 607 return sysfs_emit(buf, "%u\n", result); 608} 609 610static ssize_t eco_mode_store(struct device *dev, struct device_attribute *attr, 611 const char *buf, size_t count) 612{ 613 struct acpi_device *acpi = to_acpi_device(dev); 614 struct pcc_acpi *pcc = acpi_driver_data(acpi); 615 int err, state; 616 617 union acpi_object param[2]; 618 struct acpi_object_list input; 619 acpi_status status; 620 621 param[0].type = ACPI_TYPE_INTEGER; 622 param[0].integer.value = 0x15; 623 param[1].type = ACPI_TYPE_INTEGER; 624 input.count = 2; 625 input.pointer = param; 626 627 err = kstrtoint(buf, 0, &state); 628 if (err) 629 return err; 630 631 switch (state) { 632 case 0: 633 param[1].integer.value = ECO_MODE_OFF; 634 pcc->sinf[SINF_ECO_MODE] = 0; 635 pcc->eco_mode = 0; 636 break; 637 case 1: 638 param[1].integer.value = ECO_MODE_ON; 639 pcc->sinf[SINF_ECO_MODE] = 1; 640 pcc->eco_mode = 1; 641 break; 642 default: 643 /* nothing to do */ 644 return count; 645 } 646 647 status = acpi_evaluate_object(NULL, METHOD_ECWR, 648 &input, NULL); 649 if (ACPI_FAILURE(status)) { 650 pr_err("%s evaluation failed\n", METHOD_ECWR); 651 return -EINVAL; 652 } 653 654 return count; 655} 656 657static ssize_t ac_brightness_show(struct device *dev, struct device_attribute *attr, 658 char *buf) 659{ 660 struct acpi_device *acpi = to_acpi_device(dev); 661 struct pcc_acpi *pcc = acpi_driver_data(acpi); 662 663 if (!acpi_pcc_retrieve_biosdata(pcc)) 664 return -EIO; 665 666 return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_AC_CUR_BRIGHT]); 667} 668 669static ssize_t ac_brightness_store(struct device *dev, struct device_attribute *attr, 670 const char *buf, size_t count) 671{ 672 struct acpi_device *acpi = to_acpi_device(dev); 673 struct pcc_acpi *pcc = acpi_driver_data(acpi); 674 int err, val; 675 676 err = kstrtoint(buf, 0, &val); 677 if (err) 678 return err; 679 if (val >= 0 && val <= 255) { 680 acpi_pcc_write_sset(pcc, SINF_AC_CUR_BRIGHT, val); 681 pcc->ac_brightness = val; 682 } 683 684 return count; 685} 686 687static ssize_t dc_brightness_show(struct device *dev, struct device_attribute *attr, 688 char *buf) 689{ 690 struct acpi_device *acpi = to_acpi_device(dev); 691 struct pcc_acpi *pcc = acpi_driver_data(acpi); 692 693 if (!acpi_pcc_retrieve_biosdata(pcc)) 694 return -EIO; 695 696 return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_DC_CUR_BRIGHT]); 697} 698 699static ssize_t dc_brightness_store(struct device *dev, struct device_attribute *attr, 700 const char *buf, size_t count) 701{ 702 struct acpi_device *acpi = to_acpi_device(dev); 703 struct pcc_acpi *pcc = acpi_driver_data(acpi); 704 int err, val; 705 706 err = kstrtoint(buf, 0, &val); 707 if (err) 708 return err; 709 if (val >= 0 && val <= 255) { 710 acpi_pcc_write_sset(pcc, SINF_DC_CUR_BRIGHT, val); 711 pcc->dc_brightness = val; 712 } 713 714 return count; 715} 716 717static ssize_t current_brightness_show(struct device *dev, struct device_attribute *attr, 718 char *buf) 719{ 720 struct acpi_device *acpi = to_acpi_device(dev); 721 struct pcc_acpi *pcc = acpi_driver_data(acpi); 722 723 if (!acpi_pcc_retrieve_biosdata(pcc)) 724 return -EIO; 725 726 return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_CUR_BRIGHT]); 727} 728 729static ssize_t current_brightness_store(struct device *dev, struct device_attribute *attr, 730 const char *buf, size_t count) 731{ 732 struct acpi_device *acpi = to_acpi_device(dev); 733 struct pcc_acpi *pcc = acpi_driver_data(acpi); 734 int err, val; 735 736 err = kstrtoint(buf, 0, &val); 737 if (err) 738 return err; 739 740 if (val >= 0 && val <= 255) { 741 err = acpi_pcc_write_sset(pcc, SINF_CUR_BRIGHT, val); 742 pcc->current_brightness = val; 743 } 744 745 return count; 746} 747 748static ssize_t cdpower_show(struct device *dev, struct device_attribute *attr, 749 char *buf) 750{ 751 return sysfs_emit(buf, "%d\n", get_optd_power_state()); 752} 753 754static ssize_t cdpower_store(struct device *dev, struct device_attribute *attr, 755 const char *buf, size_t count) 756{ 757 int err, val; 758 759 err = kstrtoint(buf, 10, &val); 760 if (err) 761 return err; 762 set_optd_power_state(val); 763 return count; 764} 765 766static DEVICE_ATTR_RO(numbatt); 767static DEVICE_ATTR_RO(lcdtype); 768static DEVICE_ATTR_RW(mute); 769static DEVICE_ATTR_RW(sticky_key); 770static DEVICE_ATTR_RW(eco_mode); 771static DEVICE_ATTR_RW(ac_brightness); 772static DEVICE_ATTR_RW(dc_brightness); 773static DEVICE_ATTR_RW(current_brightness); 774static DEVICE_ATTR_RW(cdpower); 775 776static struct attribute *pcc_sysfs_entries[] = { 777 &dev_attr_numbatt.attr, 778 &dev_attr_lcdtype.attr, 779 &dev_attr_mute.attr, 780 &dev_attr_sticky_key.attr, 781 &dev_attr_eco_mode.attr, 782 &dev_attr_ac_brightness.attr, 783 &dev_attr_dc_brightness.attr, 784 &dev_attr_current_brightness.attr, 785 &dev_attr_cdpower.attr, 786 NULL, 787}; 788 789static const struct attribute_group pcc_attr_group = { 790 .name = NULL, /* put in device directory */ 791 .attrs = pcc_sysfs_entries, 792}; 793 794 795/* hotkey input device driver */ 796 797static int sleep_keydown_seen; 798static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc) 799{ 800 struct input_dev *hotk_input_dev = pcc->input_dev; 801 int rc; 802 unsigned long long result; 803 unsigned int key; 804 unsigned int updown; 805 806 rc = acpi_evaluate_integer(pcc->handle, METHOD_HKEY_QUERY, 807 NULL, &result); 808 if (ACPI_FAILURE(rc)) { 809 pr_err("error getting hotkey status\n"); 810 return; 811 } 812 813 key = result & 0xf; 814 updown = result & 0x80; /* 0x80 == key down; 0x00 = key up */ 815 816 /* hack: some firmware sends no key down for sleep / hibernate */ 817 if (key == 7 || key == 10) { 818 if (updown) 819 sleep_keydown_seen = 1; 820 if (!sleep_keydown_seen) 821 sparse_keymap_report_event(hotk_input_dev, 822 key, 0x80, false); 823 } 824 825 /* 826 * Don't report brightness key-presses if they are also reported 827 * by the ACPI video bus. 828 */ 829 if ((key == 1 || key == 2) && acpi_video_handles_brightness_key_presses()) 830 return; 831 832 if (!sparse_keymap_report_event(hotk_input_dev, key, updown, false)) 833 pr_err("Unknown hotkey event: 0x%04llx\n", result); 834} 835 836static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event) 837{ 838 struct pcc_acpi *pcc = acpi_driver_data(device); 839 840 switch (event) { 841 case HKEY_NOTIFY: 842 acpi_pcc_generate_keyinput(pcc); 843 break; 844 default: 845 /* nothing to do */ 846 break; 847 } 848} 849 850static void pcc_optd_notify(acpi_handle handle, u32 event, void *data) 851{ 852 if (event != ACPI_NOTIFY_EJECT_REQUEST) 853 return; 854 855 set_optd_power_state(0); 856} 857 858static int pcc_register_optd_notifier(struct pcc_acpi *pcc, char *node) 859{ 860 acpi_status status; 861 acpi_handle handle; 862 863 status = acpi_get_handle(NULL, node, &handle); 864 865 if (ACPI_SUCCESS(status)) { 866 status = acpi_install_notify_handler(handle, 867 ACPI_SYSTEM_NOTIFY, 868 pcc_optd_notify, pcc); 869 if (ACPI_FAILURE(status)) 870 pr_err("Failed to register notify on %s\n", node); 871 } else 872 return -ENODEV; 873 874 return 0; 875} 876 877static void pcc_unregister_optd_notifier(struct pcc_acpi *pcc, char *node) 878{ 879 acpi_status status = AE_OK; 880 acpi_handle handle; 881 882 status = acpi_get_handle(NULL, node, &handle); 883 884 if (ACPI_SUCCESS(status)) { 885 status = acpi_remove_notify_handler(handle, 886 ACPI_SYSTEM_NOTIFY, 887 pcc_optd_notify); 888 if (ACPI_FAILURE(status)) 889 pr_err("Error removing optd notify handler %s\n", 890 node); 891 } 892} 893 894static int acpi_pcc_init_input(struct pcc_acpi *pcc) 895{ 896 struct input_dev *input_dev; 897 int error; 898 899 input_dev = input_allocate_device(); 900 if (!input_dev) 901 return -ENOMEM; 902 903 input_dev->name = ACPI_PCC_DRIVER_NAME; 904 input_dev->phys = ACPI_PCC_INPUT_PHYS; 905 input_dev->id.bustype = BUS_HOST; 906 input_dev->id.vendor = 0x0001; 907 input_dev->id.product = 0x0001; 908 input_dev->id.version = 0x0100; 909 910 error = sparse_keymap_setup(input_dev, panasonic_keymap, NULL); 911 if (error) { 912 pr_err("Unable to setup input device keymap\n"); 913 goto err_free_dev; 914 } 915 916 error = input_register_device(input_dev); 917 if (error) { 918 pr_err("Unable to register input device\n"); 919 goto err_free_dev; 920 } 921 922 pcc->input_dev = input_dev; 923 return 0; 924 925 err_free_dev: 926 input_free_device(input_dev); 927 return error; 928} 929 930/* kernel module interface */ 931 932#ifdef CONFIG_PM_SLEEP 933static int acpi_pcc_hotkey_resume(struct device *dev) 934{ 935 struct pcc_acpi *pcc; 936 937 if (!dev) 938 return -EINVAL; 939 940 pcc = acpi_driver_data(to_acpi_device(dev)); 941 if (!pcc) 942 return -EINVAL; 943 944 acpi_pcc_write_sset(pcc, SINF_MUTE, pcc->mute); 945 acpi_pcc_write_sset(pcc, SINF_ECO_MODE, pcc->eco_mode); 946 acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, pcc->sticky_key); 947 acpi_pcc_write_sset(pcc, SINF_AC_CUR_BRIGHT, pcc->ac_brightness); 948 acpi_pcc_write_sset(pcc, SINF_DC_CUR_BRIGHT, pcc->dc_brightness); 949 acpi_pcc_write_sset(pcc, SINF_CUR_BRIGHT, pcc->current_brightness); 950 951 return 0; 952} 953#endif 954 955static int acpi_pcc_hotkey_add(struct acpi_device *device) 956{ 957 struct backlight_properties props; 958 struct pcc_acpi *pcc; 959 int num_sifr, result; 960 961 if (!device) 962 return -EINVAL; 963 964 num_sifr = acpi_pcc_get_sqty(device); 965 966 if (num_sifr < 0 || num_sifr > 255) { 967 pr_err("num_sifr out of range"); 968 return -ENODEV; 969 } 970 971 pcc = kzalloc(sizeof(struct pcc_acpi), GFP_KERNEL); 972 if (!pcc) { 973 pr_err("Couldn't allocate mem for pcc"); 974 return -ENOMEM; 975 } 976 977 pcc->sinf = kcalloc(num_sifr + 1, sizeof(u32), GFP_KERNEL); 978 if (!pcc->sinf) { 979 result = -ENOMEM; 980 goto out_hotkey; 981 } 982 983 pcc->device = device; 984 pcc->handle = device->handle; 985 pcc->num_sifr = num_sifr; 986 device->driver_data = pcc; 987 strcpy(acpi_device_name(device), ACPI_PCC_DEVICE_NAME); 988 strcpy(acpi_device_class(device), ACPI_PCC_CLASS); 989 990 result = acpi_pcc_init_input(pcc); 991 if (result) { 992 pr_err("Error installing keyinput handler\n"); 993 goto out_sinf; 994 } 995 996 if (!acpi_pcc_retrieve_biosdata(pcc)) { 997 result = -EIO; 998 pr_err("Couldn't retrieve BIOS data\n"); 999 goto out_input; 1000 } 1001 /* initialize backlight */ 1002 memset(&props, 0, sizeof(struct backlight_properties)); 1003 props.type = BACKLIGHT_PLATFORM; 1004 props.max_brightness = pcc->sinf[SINF_AC_MAX_BRIGHT]; 1005 pcc->backlight = backlight_device_register("panasonic", NULL, pcc, 1006 &pcc_backlight_ops, &props); 1007 if (IS_ERR(pcc->backlight)) { 1008 result = PTR_ERR(pcc->backlight); 1009 goto out_input; 1010 } 1011 1012 /* read the initial brightness setting from the hardware */ 1013 pcc->backlight->props.brightness = pcc->sinf[SINF_AC_CUR_BRIGHT]; 1014 1015 /* Reset initial sticky key mode since the hardware register state is not consistent */ 1016 acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, 0); 1017 pcc->sticky_key = 0; 1018 1019 pcc->eco_mode = pcc->sinf[SINF_ECO_MODE]; 1020 pcc->mute = pcc->sinf[SINF_MUTE]; 1021 pcc->ac_brightness = pcc->sinf[SINF_AC_CUR_BRIGHT]; 1022 pcc->dc_brightness = pcc->sinf[SINF_DC_CUR_BRIGHT]; 1023 pcc->current_brightness = pcc->sinf[SINF_CUR_BRIGHT]; 1024 1025 /* add sysfs attributes */ 1026 result = sysfs_create_group(&device->dev.kobj, &pcc_attr_group); 1027 if (result) 1028 goto out_backlight; 1029 1030 /* optical drive initialization */ 1031 if (ACPI_SUCCESS(check_optd_present())) { 1032 pcc->platform = platform_device_register_simple("panasonic", 1033 -1, NULL, 0); 1034 if (IS_ERR(pcc->platform)) { 1035 result = PTR_ERR(pcc->platform); 1036 goto out_backlight; 1037 } 1038 result = device_create_file(&pcc->platform->dev, 1039 &dev_attr_cdpower); 1040 pcc_register_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); 1041 if (result) 1042 goto out_platform; 1043 } else { 1044 pcc->platform = NULL; 1045 } 1046 1047 i8042_install_filter(panasonic_i8042_filter); 1048 return 0; 1049 1050out_platform: 1051 platform_device_unregister(pcc->platform); 1052out_backlight: 1053 backlight_device_unregister(pcc->backlight); 1054out_input: 1055 input_unregister_device(pcc->input_dev); 1056out_sinf: 1057 kfree(pcc->sinf); 1058out_hotkey: 1059 kfree(pcc); 1060 1061 return result; 1062} 1063 1064static int acpi_pcc_hotkey_remove(struct acpi_device *device) 1065{ 1066 struct pcc_acpi *pcc = acpi_driver_data(device); 1067 1068 if (!device || !pcc) 1069 return -EINVAL; 1070 1071 i8042_remove_filter(panasonic_i8042_filter); 1072 1073 if (pcc->platform) { 1074 device_remove_file(&pcc->platform->dev, &dev_attr_cdpower); 1075 platform_device_unregister(pcc->platform); 1076 } 1077 pcc_unregister_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); 1078 1079 sysfs_remove_group(&device->dev.kobj, &pcc_attr_group); 1080 1081 backlight_device_unregister(pcc->backlight); 1082 1083 input_unregister_device(pcc->input_dev); 1084 1085 kfree(pcc->sinf); 1086 kfree(pcc); 1087 1088 return 0; 1089} 1090 1091module_acpi_driver(acpi_pcc_driver);