Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  Panasonic HotKey and LCD brightness control driver
0004  *  (C) 2004 Hiroshi Miura <miura@da-cha.org>
0005  *  (C) 2004 NTT DATA Intellilink Co. http://www.intellilink.co.jp/
0006  *  (C) YOKOTA Hiroshi <yokota (at) netlab. is. tsukuba. ac. jp>
0007  *  (C) 2004 David Bronaugh <dbronaugh>
0008  *  (C) 2006-2008 Harald Welte <laforge@gnumonks.org>
0009  *
0010  *  derived from toshiba_acpi.c, Copyright (C) 2002-2004 John Belmonte
0011  *
0012  *---------------------------------------------------------------------------
0013  *
0014  * ChangeLog:
0015  *  Aug.18, 2020    Kenneth Chan <kenneth.t.chan@gmail.com>
0016  *      -v0.98  add platform devices for firmware brightness registers
0017  *          add support for battery charging threshold (eco mode)
0018  *          resolve hotkey double trigger
0019  *          add write support to mute
0020  *          fix sticky_key init bug
0021  *          fix naming of platform files for consistency with other
0022  *          modules
0023  *          split MODULE_AUTHOR() by one author per macro call
0024  *          replace ACPI prints with pr_*() macros
0025  *      -v0.97  add support for cdpower hardware switch
0026  *      -v0.96  merge Lucina's enhancement
0027  *          Jan.13, 2009 Martin Lucina <mato@kotelna.sk>
0028  *              - add support for optical driver power in
0029  *                Y and W series
0030  *
0031  *  Sep.23, 2008    Harald Welte <laforge@gnumonks.org>
0032  *      -v0.95  rename driver from drivers/acpi/pcc_acpi.c to
0033  *          drivers/misc/panasonic-laptop.c
0034  *
0035  *  Jul.04, 2008    Harald Welte <laforge@gnumonks.org>
0036  *      -v0.94  replace /proc interface with device attributes
0037  *          support {set,get}keycode on th input device
0038  *
0039  *      Jun.27, 2008    Harald Welte <laforge@gnumonks.org>
0040  *          -v0.92  merge with 2.6.26-rc6 input API changes
0041  *              remove broken <= 2.6.15 kernel support
0042  *              resolve all compiler warnings
0043  *              various coding style fixes (checkpatch.pl)
0044  *              add support for backlight api
0045  *              major code restructuring
0046  *
0047  *  Dac.28, 2007    Harald Welte <laforge@gnumonks.org>
0048  *      -v0.91  merge with 2.6.24-rc6 ACPI changes
0049  *
0050  *  Nov.04, 2006    Hiroshi Miura <miura@da-cha.org>
0051  *      -v0.9   remove warning about section reference.
0052  *          remove acpi_os_free
0053  *          add /proc/acpi/pcc/brightness interface for HAL access
0054  *          merge dbronaugh's enhancement
0055  *          Aug.17, 2004 David Bronaugh (dbronaugh)
0056  *                  - Added screen brightness setting interface
0057  *                Thanks to FreeBSD crew (acpi_panasonic.c)
0058  *                for the ideas I needed to accomplish it
0059  *
0060  *  May.29, 2006    Hiroshi Miura <miura@da-cha.org>
0061  *      -v0.8.4 follow to change keyinput structure
0062  *          thanks Fabian Yamaguchi <fabs@cs.tu-berlin.de>,
0063  *          Jacob Bower <jacob.bower@ic.ac.uk> and
0064  *          Hiroshi Yokota for providing solutions.
0065  *
0066  *  Oct.02, 2004    Hiroshi Miura <miura@da-cha.org>
0067  *      -v0.8.2 merge code of YOKOTA Hiroshi
0068  *                  <yokota@netlab.is.tsukuba.ac.jp>.
0069  *          Add sticky key mode interface.
0070  *          Refactoring acpi_pcc_generate_keyinput().
0071  *
0072  *  Sep.15, 2004    Hiroshi Miura <miura@da-cha.org>
0073  *      -v0.8   Generate key input event on input subsystem.
0074  *          This is based on yet another driver written by
0075  *                          Ryuta Nakanishi.
0076  *
0077  *  Sep.10, 2004    Hiroshi Miura <miura@da-cha.org>
0078  *      -v0.7   Change proc interface functions using seq_file
0079  *          facility as same as other ACPI drivers.
0080  *
0081  *  Aug.28, 2004    Hiroshi Miura <miura@da-cha.org>
0082  *      -v0.6.4 Fix a silly error with status checking
0083  *
0084  *  Aug.25, 2004    Hiroshi Miura <miura@da-cha.org>
0085  *      -v0.6.3 replace read_acpi_int by standard function
0086  *                          acpi_evaluate_integer
0087  *          some clean up and make smart copyright notice.
0088  *          fix return value of pcc_acpi_get_key()
0089  *          fix checking return value of acpi_bus_register_driver()
0090  *
0091  *      Aug.22, 2004    David Bronaugh <dbronaugh@linuxboxen.org>
0092  *              -v0.6.2 Add check on ACPI data (num_sifr)
0093  *                      Coding style cleanups, better error messages/handling
0094  *          Fixed an off-by-one error in memory allocation
0095  *
0096  *      Aug.21, 2004    David Bronaugh <dbronaugh@linuxboxen.org>
0097  *              -v0.6.1 Fix a silly error with status checking
0098  *
0099  *      Aug.20, 2004    David Bronaugh <dbronaugh@linuxboxen.org>
0100  *              - v0.6  Correct brightness controls to reflect reality
0101  *                      based on information gleaned by Hiroshi Miura
0102  *                      and discussions with Hiroshi Miura
0103  *
0104  *  Aug.10, 2004    Hiroshi Miura <miura@da-cha.org>
0105  *      - v0.5  support LCD brightness control
0106  *          based on the disclosed information by MEI.
0107  *
0108  *  Jul.25, 2004    Hiroshi Miura <miura@da-cha.org>
0109  *      - v0.4  first post version
0110  *              add function to retrive SIFR
0111  *
0112  *  Jul.24, 2004    Hiroshi Miura <miura@da-cha.org>
0113  *      - v0.3  get proper status of hotkey
0114  *
0115  *      Jul.22, 2004    Hiroshi Miura <miura@da-cha.org>
0116  *      - v0.2  add HotKey handler
0117  *
0118  *      Jul.17, 2004    Hiroshi Miura <miura@da-cha.org>
0119  *      - v0.1  start from toshiba_acpi driver written by John Belmonte
0120  */
0121 
0122 #include <linux/acpi.h>
0123 #include <linux/backlight.h>
0124 #include <linux/ctype.h>
0125 #include <linux/i8042.h>
0126 #include <linux/init.h>
0127 #include <linux/input.h>
0128 #include <linux/input/sparse-keymap.h>
0129 #include <linux/kernel.h>
0130 #include <linux/module.h>
0131 #include <linux/platform_device.h>
0132 #include <linux/seq_file.h>
0133 #include <linux/serio.h>
0134 #include <linux/slab.h>
0135 #include <linux/types.h>
0136 #include <linux/uaccess.h>
0137 #include <acpi/video.h>
0138 
0139 MODULE_AUTHOR("Hiroshi Miura <miura@da-cha.org>");
0140 MODULE_AUTHOR("David Bronaugh <dbronaugh@linuxboxen.org>");
0141 MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
0142 MODULE_AUTHOR("Martin Lucina <mato@kotelna.sk>");
0143 MODULE_AUTHOR("Kenneth Chan <kenneth.t.chan@gmail.com>");
0144 MODULE_DESCRIPTION("ACPI HotKey driver for Panasonic Let's Note laptops");
0145 MODULE_LICENSE("GPL");
0146 
0147 #define LOGPREFIX "pcc_acpi: "
0148 
0149 /* Define ACPI PATHs */
0150 /* Lets note hotkeys */
0151 #define METHOD_HKEY_QUERY   "HINF"
0152 #define METHOD_HKEY_SQTY    "SQTY"
0153 #define METHOD_HKEY_SINF    "SINF"
0154 #define METHOD_HKEY_SSET    "SSET"
0155 #define METHOD_ECWR     "\\_SB.ECWR"
0156 #define HKEY_NOTIFY     0x80
0157 #define ECO_MODE_OFF        0x00
0158 #define ECO_MODE_ON     0x80
0159 
0160 #define ACPI_PCC_DRIVER_NAME    "Panasonic Laptop Support"
0161 #define ACPI_PCC_DEVICE_NAME    "Hotkey"
0162 #define ACPI_PCC_CLASS      "pcc"
0163 
0164 #define ACPI_PCC_INPUT_PHYS "panasonic/hkey0"
0165 
0166 /* LCD_TYPEs: 0 = Normal, 1 = Semi-transparent
0167    ECO_MODEs: 0x03 = off, 0x83 = on
0168 */
0169 enum SINF_BITS { SINF_NUM_BATTERIES = 0,
0170          SINF_LCD_TYPE,
0171          SINF_AC_MAX_BRIGHT,
0172          SINF_AC_MIN_BRIGHT,
0173          SINF_AC_CUR_BRIGHT,
0174          SINF_DC_MAX_BRIGHT,
0175          SINF_DC_MIN_BRIGHT,
0176          SINF_DC_CUR_BRIGHT,
0177          SINF_MUTE,
0178          SINF_RESERVED,
0179          SINF_ECO_MODE = 0x0A,
0180          SINF_CUR_BRIGHT = 0x0D,
0181          SINF_STICKY_KEY = 0x80,
0182     };
0183 /* R1 handles SINF_AC_CUR_BRIGHT as SINF_CUR_BRIGHT, doesn't know AC state */
0184 
0185 static int acpi_pcc_hotkey_add(struct acpi_device *device);
0186 static int acpi_pcc_hotkey_remove(struct acpi_device *device);
0187 static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event);
0188 
0189 static const struct acpi_device_id pcc_device_ids[] = {
0190     { "MAT0012", 0},
0191     { "MAT0013", 0},
0192     { "MAT0018", 0},
0193     { "MAT0019", 0},
0194     { "", 0},
0195 };
0196 MODULE_DEVICE_TABLE(acpi, pcc_device_ids);
0197 
0198 #ifdef CONFIG_PM_SLEEP
0199 static int acpi_pcc_hotkey_resume(struct device *dev);
0200 #endif
0201 static SIMPLE_DEV_PM_OPS(acpi_pcc_hotkey_pm, NULL, acpi_pcc_hotkey_resume);
0202 
0203 static struct acpi_driver acpi_pcc_driver = {
0204     .name =     ACPI_PCC_DRIVER_NAME,
0205     .class =    ACPI_PCC_CLASS,
0206     .ids =      pcc_device_ids,
0207     .ops =      {
0208                 .add =      acpi_pcc_hotkey_add,
0209                 .remove =   acpi_pcc_hotkey_remove,
0210                 .notify =   acpi_pcc_hotkey_notify,
0211             },
0212     .drv.pm =   &acpi_pcc_hotkey_pm,
0213 };
0214 
0215 static const struct key_entry panasonic_keymap[] = {
0216     { KE_KEY, 0, { KEY_RESERVED } },
0217     { KE_KEY, 1, { KEY_BRIGHTNESSDOWN } },
0218     { KE_KEY, 2, { KEY_BRIGHTNESSUP } },
0219     { KE_KEY, 3, { KEY_DISPLAYTOGGLE } },
0220     { KE_KEY, 4, { KEY_MUTE } },
0221     { KE_KEY, 5, { KEY_VOLUMEDOWN } },
0222     { KE_KEY, 6, { KEY_VOLUMEUP } },
0223     { KE_KEY, 7, { KEY_SLEEP } },
0224     { KE_KEY, 8, { KEY_PROG1 } }, /* Change CPU boost */
0225     { KE_KEY, 9, { KEY_BATTERY } },
0226     { KE_KEY, 10, { KEY_SUSPEND } },
0227     { KE_END, 0 }
0228 };
0229 
0230 struct pcc_acpi {
0231     acpi_handle     handle;
0232     unsigned long       num_sifr;
0233     int         sticky_key;
0234     int         eco_mode;
0235     int         mute;
0236     int         ac_brightness;
0237     int         dc_brightness;
0238     int         current_brightness;
0239     u32         *sinf;
0240     struct acpi_device  *device;
0241     struct input_dev    *input_dev;
0242     struct backlight_device *backlight;
0243     struct platform_device  *platform;
0244 };
0245 
0246 /*
0247  * On some Panasonic models the volume up / down / mute keys send duplicate
0248  * keypress events over the PS/2 kbd interface, filter these out.
0249  */
0250 static bool panasonic_i8042_filter(unsigned char data, unsigned char str,
0251                    struct serio *port)
0252 {
0253     static bool extended;
0254 
0255     if (str & I8042_STR_AUXDATA)
0256         return false;
0257 
0258     if (data == 0xe0) {
0259         extended = true;
0260         return true;
0261     } else if (extended) {
0262         extended = false;
0263 
0264         switch (data & 0x7f) {
0265         case 0x20: /* e0 20 / e0 a0, Volume Mute press / release */
0266         case 0x2e: /* e0 2e / e0 ae, Volume Down press / release */
0267         case 0x30: /* e0 30 / e0 b0, Volume Up press / release */
0268             return true;
0269         default:
0270             /*
0271              * Report the previously filtered e0 before continuing
0272              * with the next non-filtered byte.
0273              */
0274             serio_interrupt(port, 0xe0, 0);
0275             return false;
0276         }
0277     }
0278 
0279     return false;
0280 }
0281 
0282 /* method access functions */
0283 static int acpi_pcc_write_sset(struct pcc_acpi *pcc, int func, int val)
0284 {
0285     union acpi_object in_objs[] = {
0286         { .integer.type  = ACPI_TYPE_INTEGER,
0287           .integer.value = func, },
0288         { .integer.type  = ACPI_TYPE_INTEGER,
0289           .integer.value = val, },
0290     };
0291     struct acpi_object_list params = {
0292         .count   = ARRAY_SIZE(in_objs),
0293         .pointer = in_objs,
0294     };
0295     acpi_status status = AE_OK;
0296 
0297     status = acpi_evaluate_object(pcc->handle, METHOD_HKEY_SSET,
0298                       &params, NULL);
0299 
0300     return (status == AE_OK) ? 0 : -EIO;
0301 }
0302 
0303 static inline int acpi_pcc_get_sqty(struct acpi_device *device)
0304 {
0305     unsigned long long s;
0306     acpi_status status;
0307 
0308     status = acpi_evaluate_integer(device->handle, METHOD_HKEY_SQTY,
0309                        NULL, &s);
0310     if (ACPI_SUCCESS(status))
0311         return s;
0312     else {
0313         pr_err("evaluation error HKEY.SQTY\n");
0314         return -EINVAL;
0315     }
0316 }
0317 
0318 static int acpi_pcc_retrieve_biosdata(struct pcc_acpi *pcc)
0319 {
0320     acpi_status status;
0321     struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
0322     union acpi_object *hkey = NULL;
0323     int i;
0324 
0325     status = acpi_evaluate_object(pcc->handle, METHOD_HKEY_SINF, NULL,
0326                       &buffer);
0327     if (ACPI_FAILURE(status)) {
0328         pr_err("evaluation error HKEY.SINF\n");
0329         return 0;
0330     }
0331 
0332     hkey = buffer.pointer;
0333     if (!hkey || (hkey->type != ACPI_TYPE_PACKAGE)) {
0334         pr_err("Invalid HKEY.SINF\n");
0335         status = AE_ERROR;
0336         goto end;
0337     }
0338 
0339     if (pcc->num_sifr < hkey->package.count) {
0340         pr_err("SQTY reports bad SINF length\n");
0341         status = AE_ERROR;
0342         goto end;
0343     }
0344 
0345     for (i = 0; i < hkey->package.count; i++) {
0346         union acpi_object *element = &(hkey->package.elements[i]);
0347         if (likely(element->type == ACPI_TYPE_INTEGER)) {
0348             pcc->sinf[i] = element->integer.value;
0349         } else
0350             pr_err("Invalid HKEY.SINF data\n");
0351     }
0352     pcc->sinf[hkey->package.count] = -1;
0353 
0354 end:
0355     kfree(buffer.pointer);
0356     return status == AE_OK;
0357 }
0358 
0359 /* backlight API interface functions */
0360 
0361 /* This driver currently treats AC and DC brightness identical,
0362  * since we don't need to invent an interface to the core ACPI
0363  * logic to receive events in case a power supply is plugged in
0364  * or removed */
0365 
0366 static int bl_get(struct backlight_device *bd)
0367 {
0368     struct pcc_acpi *pcc = bl_get_data(bd);
0369 
0370     if (!acpi_pcc_retrieve_biosdata(pcc))
0371         return -EIO;
0372 
0373     return pcc->sinf[SINF_AC_CUR_BRIGHT];
0374 }
0375 
0376 static int bl_set_status(struct backlight_device *bd)
0377 {
0378     struct pcc_acpi *pcc = bl_get_data(bd);
0379     int bright = bd->props.brightness;
0380     int rc;
0381 
0382     if (!acpi_pcc_retrieve_biosdata(pcc))
0383         return -EIO;
0384 
0385     if (bright < pcc->sinf[SINF_AC_MIN_BRIGHT])
0386         bright = pcc->sinf[SINF_AC_MIN_BRIGHT];
0387 
0388     if (bright < pcc->sinf[SINF_DC_MIN_BRIGHT])
0389         bright = pcc->sinf[SINF_DC_MIN_BRIGHT];
0390 
0391     if (bright < pcc->sinf[SINF_AC_MIN_BRIGHT] ||
0392         bright > pcc->sinf[SINF_AC_MAX_BRIGHT])
0393         return -EINVAL;
0394 
0395     rc = acpi_pcc_write_sset(pcc, SINF_AC_CUR_BRIGHT, bright);
0396     if (rc < 0)
0397         return rc;
0398 
0399     return acpi_pcc_write_sset(pcc, SINF_DC_CUR_BRIGHT, bright);
0400 }
0401 
0402 static const struct backlight_ops pcc_backlight_ops = {
0403     .get_brightness = bl_get,
0404     .update_status  = bl_set_status,
0405 };
0406 
0407 
0408 /* returns ACPI_SUCCESS if methods to control optical drive are present */
0409 
0410 static acpi_status check_optd_present(void)
0411 {
0412     acpi_status status = AE_OK;
0413     acpi_handle handle;
0414 
0415     status = acpi_get_handle(NULL, "\\_SB.STAT", &handle);
0416     if (ACPI_FAILURE(status))
0417         goto out;
0418     status = acpi_get_handle(NULL, "\\_SB.FBAY", &handle);
0419     if (ACPI_FAILURE(status))
0420         goto out;
0421     status = acpi_get_handle(NULL, "\\_SB.CDDI", &handle);
0422     if (ACPI_FAILURE(status))
0423         goto out;
0424 
0425 out:
0426     return status;
0427 }
0428 
0429 /* get optical driver power state */
0430 
0431 static int get_optd_power_state(void)
0432 {
0433     acpi_status status;
0434     unsigned long long state;
0435     int result;
0436 
0437     status = acpi_evaluate_integer(NULL, "\\_SB.STAT", NULL, &state);
0438     if (ACPI_FAILURE(status)) {
0439         pr_err("evaluation error _SB.STAT\n");
0440         result = -EIO;
0441         goto out;
0442     }
0443     switch (state) {
0444     case 0: /* power off */
0445         result = 0;
0446         break;
0447     case 0x0f: /* power on */
0448         result = 1;
0449         break;
0450     default:
0451         result = -EIO;
0452         break;
0453     }
0454 
0455 out:
0456     return result;
0457 }
0458 
0459 /* set optical drive power state */
0460 
0461 static int set_optd_power_state(int new_state)
0462 {
0463     int result;
0464     acpi_status status;
0465 
0466     result = get_optd_power_state();
0467     if (result < 0)
0468         goto out;
0469     if (new_state == result)
0470         goto out;
0471 
0472     switch (new_state) {
0473     case 0: /* power off */
0474         /* Call CDDR instead, since they both call the same method
0475          * while CDDI takes 1 arg and we are not quite sure what it is.
0476          */
0477         status = acpi_evaluate_object(NULL, "\\_SB.CDDR", NULL, NULL);
0478         if (ACPI_FAILURE(status)) {
0479             pr_err("evaluation error _SB.CDDR\n");
0480             result = -EIO;
0481         }
0482         break;
0483     case 1: /* power on */
0484         status = acpi_evaluate_object(NULL, "\\_SB.FBAY", NULL, NULL);
0485         if (ACPI_FAILURE(status)) {
0486             pr_err("evaluation error _SB.FBAY\n");
0487             result = -EIO;
0488         }
0489         break;
0490     default:
0491         result = -EINVAL;
0492         break;
0493     }
0494 
0495 out:
0496     return result;
0497 }
0498 
0499 
0500 /* sysfs user interface functions */
0501 
0502 static ssize_t numbatt_show(struct device *dev, struct device_attribute *attr,
0503                 char *buf)
0504 {
0505     struct acpi_device *acpi = to_acpi_device(dev);
0506     struct pcc_acpi *pcc = acpi_driver_data(acpi);
0507 
0508     if (!acpi_pcc_retrieve_biosdata(pcc))
0509         return -EIO;
0510 
0511     return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_NUM_BATTERIES]);
0512 }
0513 
0514 static ssize_t lcdtype_show(struct device *dev, struct device_attribute *attr,
0515                 char *buf)
0516 {
0517     struct acpi_device *acpi = to_acpi_device(dev);
0518     struct pcc_acpi *pcc = acpi_driver_data(acpi);
0519 
0520     if (!acpi_pcc_retrieve_biosdata(pcc))
0521         return -EIO;
0522 
0523     return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_LCD_TYPE]);
0524 }
0525 
0526 static ssize_t mute_show(struct device *dev, struct device_attribute *attr,
0527              char *buf)
0528 {
0529     struct acpi_device *acpi = to_acpi_device(dev);
0530     struct pcc_acpi *pcc = acpi_driver_data(acpi);
0531 
0532     if (!acpi_pcc_retrieve_biosdata(pcc))
0533         return -EIO;
0534 
0535     return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_MUTE]);
0536 }
0537 
0538 static ssize_t mute_store(struct device *dev, struct device_attribute *attr,
0539               const char *buf, size_t count)
0540 {
0541     struct acpi_device *acpi = to_acpi_device(dev);
0542     struct pcc_acpi *pcc = acpi_driver_data(acpi);
0543     int err, val;
0544 
0545     err = kstrtoint(buf, 0, &val);
0546     if (err)
0547         return err;
0548     if (val == 0 || val == 1) {
0549         acpi_pcc_write_sset(pcc, SINF_MUTE, val);
0550         pcc->mute = val;
0551     }
0552 
0553     return count;
0554 }
0555 
0556 static ssize_t sticky_key_show(struct device *dev, struct device_attribute *attr,
0557                char *buf)
0558 {
0559     struct acpi_device *acpi = to_acpi_device(dev);
0560     struct pcc_acpi *pcc = acpi_driver_data(acpi);
0561 
0562     if (!acpi_pcc_retrieve_biosdata(pcc))
0563         return -EIO;
0564 
0565     return sysfs_emit(buf, "%u\n", pcc->sticky_key);
0566 }
0567 
0568 static ssize_t sticky_key_store(struct device *dev, struct device_attribute *attr,
0569               const char *buf, size_t count)
0570 {
0571     struct acpi_device *acpi = to_acpi_device(dev);
0572     struct pcc_acpi *pcc = acpi_driver_data(acpi);
0573     int err, val;
0574 
0575     err = kstrtoint(buf, 0, &val);
0576     if (err)
0577         return err;
0578     if (val == 0 || val == 1) {
0579         acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, val);
0580         pcc->sticky_key = val;
0581     }
0582 
0583     return count;
0584 }
0585 
0586 static ssize_t eco_mode_show(struct device *dev, struct device_attribute *attr,
0587                 char *buf)
0588 {
0589     struct acpi_device *acpi = to_acpi_device(dev);
0590     struct pcc_acpi *pcc = acpi_driver_data(acpi);
0591     int result;
0592 
0593     if (!acpi_pcc_retrieve_biosdata(pcc))
0594         return -EIO;
0595 
0596     switch (pcc->sinf[SINF_ECO_MODE]) {
0597     case (ECO_MODE_OFF + 3):
0598         result = 0;
0599         break;
0600     case (ECO_MODE_ON + 3):
0601         result = 1;
0602         break;
0603     default:
0604         result = -EIO;
0605         break;
0606     }
0607     return sysfs_emit(buf, "%u\n", result);
0608 }
0609 
0610 static ssize_t eco_mode_store(struct device *dev, struct device_attribute *attr,
0611               const char *buf, size_t count)
0612 {
0613     struct acpi_device *acpi = to_acpi_device(dev);
0614     struct pcc_acpi *pcc = acpi_driver_data(acpi);
0615     int err, state;
0616 
0617     union acpi_object param[2];
0618     struct acpi_object_list input;
0619     acpi_status status;
0620 
0621     param[0].type = ACPI_TYPE_INTEGER;
0622     param[0].integer.value = 0x15;
0623     param[1].type = ACPI_TYPE_INTEGER;
0624     input.count = 2;
0625     input.pointer = param;
0626 
0627     err = kstrtoint(buf, 0, &state);
0628     if (err)
0629         return err;
0630 
0631     switch (state) {
0632     case 0:
0633         param[1].integer.value = ECO_MODE_OFF;
0634         pcc->sinf[SINF_ECO_MODE] = 0;
0635         pcc->eco_mode = 0;
0636         break;
0637     case 1:
0638         param[1].integer.value = ECO_MODE_ON;
0639         pcc->sinf[SINF_ECO_MODE] = 1;
0640         pcc->eco_mode = 1;
0641         break;
0642     default:
0643         /* nothing to do */
0644         return count;
0645     }
0646 
0647     status = acpi_evaluate_object(NULL, METHOD_ECWR,
0648                        &input, NULL);
0649     if (ACPI_FAILURE(status)) {
0650         pr_err("%s evaluation failed\n", METHOD_ECWR);
0651         return -EINVAL;
0652     }
0653 
0654     return count;
0655 }
0656 
0657 static ssize_t ac_brightness_show(struct device *dev, struct device_attribute *attr,
0658                   char *buf)
0659 {
0660     struct acpi_device *acpi = to_acpi_device(dev);
0661     struct pcc_acpi *pcc = acpi_driver_data(acpi);
0662 
0663     if (!acpi_pcc_retrieve_biosdata(pcc))
0664         return -EIO;
0665 
0666     return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_AC_CUR_BRIGHT]);
0667 }
0668 
0669 static ssize_t ac_brightness_store(struct device *dev, struct device_attribute *attr,
0670                    const char *buf, size_t count)
0671 {
0672     struct acpi_device *acpi = to_acpi_device(dev);
0673     struct pcc_acpi *pcc = acpi_driver_data(acpi);
0674     int err, val;
0675 
0676     err = kstrtoint(buf, 0, &val);
0677     if (err)
0678         return err;
0679     if (val >= 0 && val <= 255) {
0680         acpi_pcc_write_sset(pcc, SINF_AC_CUR_BRIGHT, val);
0681         pcc->ac_brightness = val;
0682     }
0683 
0684     return count;
0685 }
0686 
0687 static ssize_t dc_brightness_show(struct device *dev, struct device_attribute *attr,
0688                   char *buf)
0689 {
0690     struct acpi_device *acpi = to_acpi_device(dev);
0691     struct pcc_acpi *pcc = acpi_driver_data(acpi);
0692 
0693     if (!acpi_pcc_retrieve_biosdata(pcc))
0694         return -EIO;
0695 
0696     return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_DC_CUR_BRIGHT]);
0697 }
0698 
0699 static ssize_t dc_brightness_store(struct device *dev, struct device_attribute *attr,
0700                    const char *buf, size_t count)
0701 {
0702     struct acpi_device *acpi = to_acpi_device(dev);
0703     struct pcc_acpi *pcc = acpi_driver_data(acpi);
0704     int err, val;
0705 
0706     err = kstrtoint(buf, 0, &val);
0707     if (err)
0708         return err;
0709     if (val >= 0 && val <= 255) {
0710         acpi_pcc_write_sset(pcc, SINF_DC_CUR_BRIGHT, val);
0711         pcc->dc_brightness = val;
0712     }
0713 
0714     return count;
0715 }
0716 
0717 static ssize_t current_brightness_show(struct device *dev, struct device_attribute *attr,
0718                        char *buf)
0719 {
0720     struct acpi_device *acpi = to_acpi_device(dev);
0721     struct pcc_acpi *pcc = acpi_driver_data(acpi);
0722 
0723     if (!acpi_pcc_retrieve_biosdata(pcc))
0724         return -EIO;
0725 
0726     return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_CUR_BRIGHT]);
0727 }
0728 
0729 static ssize_t current_brightness_store(struct device *dev, struct device_attribute *attr,
0730                     const char *buf, size_t count)
0731 {
0732     struct acpi_device *acpi = to_acpi_device(dev);
0733     struct pcc_acpi *pcc = acpi_driver_data(acpi);
0734     int err, val;
0735 
0736     err = kstrtoint(buf, 0, &val);
0737     if (err)
0738         return err;
0739 
0740     if (val >= 0 && val <= 255) {
0741         err = acpi_pcc_write_sset(pcc, SINF_CUR_BRIGHT, val);
0742         pcc->current_brightness = val;
0743     }
0744 
0745     return count;
0746 }
0747 
0748 static ssize_t cdpower_show(struct device *dev, struct device_attribute *attr,
0749                 char *buf)
0750 {
0751     return sysfs_emit(buf, "%d\n", get_optd_power_state());
0752 }
0753 
0754 static ssize_t cdpower_store(struct device *dev, struct device_attribute *attr,
0755                const char *buf, size_t count)
0756 {
0757     int err, val;
0758 
0759     err = kstrtoint(buf, 10, &val);
0760     if (err)
0761         return err;
0762     set_optd_power_state(val);
0763     return count;
0764 }
0765 
0766 static DEVICE_ATTR_RO(numbatt);
0767 static DEVICE_ATTR_RO(lcdtype);
0768 static DEVICE_ATTR_RW(mute);
0769 static DEVICE_ATTR_RW(sticky_key);
0770 static DEVICE_ATTR_RW(eco_mode);
0771 static DEVICE_ATTR_RW(ac_brightness);
0772 static DEVICE_ATTR_RW(dc_brightness);
0773 static DEVICE_ATTR_RW(current_brightness);
0774 static DEVICE_ATTR_RW(cdpower);
0775 
0776 static struct attribute *pcc_sysfs_entries[] = {
0777     &dev_attr_numbatt.attr,
0778     &dev_attr_lcdtype.attr,
0779     &dev_attr_mute.attr,
0780     &dev_attr_sticky_key.attr,
0781     &dev_attr_eco_mode.attr,
0782     &dev_attr_ac_brightness.attr,
0783     &dev_attr_dc_brightness.attr,
0784     &dev_attr_current_brightness.attr,
0785     &dev_attr_cdpower.attr,
0786     NULL,
0787 };
0788 
0789 static const struct attribute_group pcc_attr_group = {
0790     .name   = NULL,     /* put in device directory */
0791     .attrs  = pcc_sysfs_entries,
0792 };
0793 
0794 
0795 /* hotkey input device driver */
0796 
0797 static int sleep_keydown_seen;
0798 static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
0799 {
0800     struct input_dev *hotk_input_dev = pcc->input_dev;
0801     int rc;
0802     unsigned long long result;
0803     unsigned int key;
0804     unsigned int updown;
0805 
0806     rc = acpi_evaluate_integer(pcc->handle, METHOD_HKEY_QUERY,
0807                    NULL, &result);
0808     if (ACPI_FAILURE(rc)) {
0809         pr_err("error getting hotkey status\n");
0810         return;
0811     }
0812 
0813     key = result & 0xf;
0814     updown = result & 0x80; /* 0x80 == key down; 0x00 = key up */
0815 
0816     /* hack: some firmware sends no key down for sleep / hibernate */
0817     if (key == 7 || key == 10) {
0818         if (updown)
0819             sleep_keydown_seen = 1;
0820         if (!sleep_keydown_seen)
0821             sparse_keymap_report_event(hotk_input_dev,
0822                     key, 0x80, false);
0823     }
0824 
0825     /*
0826      * Don't report brightness key-presses if they are also reported
0827      * by the ACPI video bus.
0828      */
0829     if ((key == 1 || key == 2) && acpi_video_handles_brightness_key_presses())
0830         return;
0831 
0832     if (!sparse_keymap_report_event(hotk_input_dev, key, updown, false))
0833         pr_err("Unknown hotkey event: 0x%04llx\n", result);
0834 }
0835 
0836 static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event)
0837 {
0838     struct pcc_acpi *pcc = acpi_driver_data(device);
0839 
0840     switch (event) {
0841     case HKEY_NOTIFY:
0842         acpi_pcc_generate_keyinput(pcc);
0843         break;
0844     default:
0845         /* nothing to do */
0846         break;
0847     }
0848 }
0849 
0850 static void pcc_optd_notify(acpi_handle handle, u32 event, void *data)
0851 {
0852     if (event != ACPI_NOTIFY_EJECT_REQUEST)
0853         return;
0854 
0855     set_optd_power_state(0);
0856 }
0857 
0858 static int pcc_register_optd_notifier(struct pcc_acpi *pcc, char *node)
0859 {
0860     acpi_status status;
0861     acpi_handle handle;
0862 
0863     status = acpi_get_handle(NULL, node, &handle);
0864 
0865     if (ACPI_SUCCESS(status)) {
0866         status = acpi_install_notify_handler(handle,
0867                 ACPI_SYSTEM_NOTIFY,
0868                 pcc_optd_notify, pcc);
0869         if (ACPI_FAILURE(status))
0870             pr_err("Failed to register notify on %s\n", node);
0871     } else
0872         return -ENODEV;
0873 
0874     return 0;
0875 }
0876 
0877 static void pcc_unregister_optd_notifier(struct pcc_acpi *pcc, char *node)
0878 {
0879     acpi_status status = AE_OK;
0880     acpi_handle handle;
0881 
0882     status = acpi_get_handle(NULL, node, &handle);
0883 
0884     if (ACPI_SUCCESS(status)) {
0885         status = acpi_remove_notify_handler(handle,
0886                 ACPI_SYSTEM_NOTIFY,
0887                 pcc_optd_notify);
0888         if (ACPI_FAILURE(status))
0889             pr_err("Error removing optd notify handler %s\n",
0890                     node);
0891     }
0892 }
0893 
0894 static int acpi_pcc_init_input(struct pcc_acpi *pcc)
0895 {
0896     struct input_dev *input_dev;
0897     int error;
0898 
0899     input_dev = input_allocate_device();
0900     if (!input_dev)
0901         return -ENOMEM;
0902 
0903     input_dev->name = ACPI_PCC_DRIVER_NAME;
0904     input_dev->phys = ACPI_PCC_INPUT_PHYS;
0905     input_dev->id.bustype = BUS_HOST;
0906     input_dev->id.vendor = 0x0001;
0907     input_dev->id.product = 0x0001;
0908     input_dev->id.version = 0x0100;
0909 
0910     error = sparse_keymap_setup(input_dev, panasonic_keymap, NULL);
0911     if (error) {
0912         pr_err("Unable to setup input device keymap\n");
0913         goto err_free_dev;
0914     }
0915 
0916     error = input_register_device(input_dev);
0917     if (error) {
0918         pr_err("Unable to register input device\n");
0919         goto err_free_dev;
0920     }
0921 
0922     pcc->input_dev = input_dev;
0923     return 0;
0924 
0925  err_free_dev:
0926     input_free_device(input_dev);
0927     return error;
0928 }
0929 
0930 /* kernel module interface */
0931 
0932 #ifdef CONFIG_PM_SLEEP
0933 static int acpi_pcc_hotkey_resume(struct device *dev)
0934 {
0935     struct pcc_acpi *pcc;
0936 
0937     if (!dev)
0938         return -EINVAL;
0939 
0940     pcc = acpi_driver_data(to_acpi_device(dev));
0941     if (!pcc)
0942         return -EINVAL;
0943 
0944     acpi_pcc_write_sset(pcc, SINF_MUTE, pcc->mute);
0945     acpi_pcc_write_sset(pcc, SINF_ECO_MODE, pcc->eco_mode);
0946     acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, pcc->sticky_key);
0947     acpi_pcc_write_sset(pcc, SINF_AC_CUR_BRIGHT, pcc->ac_brightness);
0948     acpi_pcc_write_sset(pcc, SINF_DC_CUR_BRIGHT, pcc->dc_brightness);
0949     acpi_pcc_write_sset(pcc, SINF_CUR_BRIGHT, pcc->current_brightness);
0950 
0951     return 0;
0952 }
0953 #endif
0954 
0955 static int acpi_pcc_hotkey_add(struct acpi_device *device)
0956 {
0957     struct backlight_properties props;
0958     struct pcc_acpi *pcc;
0959     int num_sifr, result;
0960 
0961     if (!device)
0962         return -EINVAL;
0963 
0964     num_sifr = acpi_pcc_get_sqty(device);
0965 
0966     if (num_sifr < 0 || num_sifr > 255) {
0967         pr_err("num_sifr out of range");
0968         return -ENODEV;
0969     }
0970 
0971     pcc = kzalloc(sizeof(struct pcc_acpi), GFP_KERNEL);
0972     if (!pcc) {
0973         pr_err("Couldn't allocate mem for pcc");
0974         return -ENOMEM;
0975     }
0976 
0977     pcc->sinf = kcalloc(num_sifr + 1, sizeof(u32), GFP_KERNEL);
0978     if (!pcc->sinf) {
0979         result = -ENOMEM;
0980         goto out_hotkey;
0981     }
0982 
0983     pcc->device = device;
0984     pcc->handle = device->handle;
0985     pcc->num_sifr = num_sifr;
0986     device->driver_data = pcc;
0987     strcpy(acpi_device_name(device), ACPI_PCC_DEVICE_NAME);
0988     strcpy(acpi_device_class(device), ACPI_PCC_CLASS);
0989 
0990     result = acpi_pcc_init_input(pcc);
0991     if (result) {
0992         pr_err("Error installing keyinput handler\n");
0993         goto out_sinf;
0994     }
0995 
0996     if (!acpi_pcc_retrieve_biosdata(pcc)) {
0997         result = -EIO;
0998         pr_err("Couldn't retrieve BIOS data\n");
0999         goto out_input;
1000     }
1001 
1002     if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
1003         /* initialize backlight */
1004         memset(&props, 0, sizeof(struct backlight_properties));
1005         props.type = BACKLIGHT_PLATFORM;
1006         props.max_brightness = pcc->sinf[SINF_AC_MAX_BRIGHT];
1007 
1008         pcc->backlight = backlight_device_register("panasonic", NULL, pcc,
1009                                &pcc_backlight_ops, &props);
1010         if (IS_ERR(pcc->backlight)) {
1011             result = PTR_ERR(pcc->backlight);
1012             goto out_input;
1013         }
1014 
1015         /* read the initial brightness setting from the hardware */
1016         pcc->backlight->props.brightness = pcc->sinf[SINF_AC_CUR_BRIGHT];
1017     }
1018 
1019     /* Reset initial sticky key mode since the hardware register state is not consistent */
1020     acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, 0);
1021     pcc->sticky_key = 0;
1022 
1023     pcc->eco_mode = pcc->sinf[SINF_ECO_MODE];
1024     pcc->mute = pcc->sinf[SINF_MUTE];
1025     pcc->ac_brightness = pcc->sinf[SINF_AC_CUR_BRIGHT];
1026     pcc->dc_brightness = pcc->sinf[SINF_DC_CUR_BRIGHT];
1027     pcc->current_brightness = pcc->sinf[SINF_CUR_BRIGHT];
1028 
1029     /* add sysfs attributes */
1030     result = sysfs_create_group(&device->dev.kobj, &pcc_attr_group);
1031     if (result)
1032         goto out_backlight;
1033 
1034     /* optical drive initialization */
1035     if (ACPI_SUCCESS(check_optd_present())) {
1036         pcc->platform = platform_device_register_simple("panasonic",
1037             -1, NULL, 0);
1038         if (IS_ERR(pcc->platform)) {
1039             result = PTR_ERR(pcc->platform);
1040             goto out_backlight;
1041         }
1042         result = device_create_file(&pcc->platform->dev,
1043             &dev_attr_cdpower);
1044         pcc_register_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD");
1045         if (result)
1046             goto out_platform;
1047     } else {
1048         pcc->platform = NULL;
1049     }
1050 
1051     i8042_install_filter(panasonic_i8042_filter);
1052     return 0;
1053 
1054 out_platform:
1055     platform_device_unregister(pcc->platform);
1056 out_backlight:
1057     backlight_device_unregister(pcc->backlight);
1058 out_input:
1059     input_unregister_device(pcc->input_dev);
1060 out_sinf:
1061     kfree(pcc->sinf);
1062 out_hotkey:
1063     kfree(pcc);
1064 
1065     return result;
1066 }
1067 
1068 static int acpi_pcc_hotkey_remove(struct acpi_device *device)
1069 {
1070     struct pcc_acpi *pcc = acpi_driver_data(device);
1071 
1072     if (!device || !pcc)
1073         return -EINVAL;
1074 
1075     i8042_remove_filter(panasonic_i8042_filter);
1076 
1077     if (pcc->platform) {
1078         device_remove_file(&pcc->platform->dev, &dev_attr_cdpower);
1079         platform_device_unregister(pcc->platform);
1080     }
1081     pcc_unregister_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD");
1082 
1083     sysfs_remove_group(&device->dev.kobj, &pcc_attr_group);
1084 
1085     backlight_device_unregister(pcc->backlight);
1086 
1087     input_unregister_device(pcc->input_dev);
1088 
1089     kfree(pcc->sinf);
1090     kfree(pcc);
1091 
1092     return 0;
1093 }
1094 
1095 module_acpi_driver(acpi_pcc_driver);