linux/drivers/platform/x86/sony-laptop.c
<<
>>
Prefs
   1/*
   2 * ACPI Sony Notebook Control Driver (SNC and SPIC)
   3 *
   4 * Copyright (C) 2004-2005 Stelian Pop <stelian@popies.net>
   5 * Copyright (C) 2007-2009 Mattia Dongili <malattia@linux.it>
   6 *
   7 * Parts of this driver inspired from asus_acpi.c and ibm_acpi.c
   8 * which are copyrighted by their respective authors.
   9 *
  10 * The SNY6001 driver part is based on the sonypi driver which includes
  11 * material from:
  12 *
  13 * Copyright (C) 2001-2005 Stelian Pop <stelian@popies.net>
  14 *
  15 * Copyright (C) 2005 Narayanan R S <nars@kadamba.org>
  16 *
  17 * Copyright (C) 2001-2002 AlcĂ´ve <www.alcove.com>
  18 *
  19 * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
  20 *
  21 * Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
  22 *
  23 * Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp>
  24 *
  25 * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
  26 *
  27 * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras.
  28 *
  29 * This program is free software; you can redistribute it and/or modify
  30 * it under the terms of the GNU General Public License as published by
  31 * the Free Software Foundation; either version 2 of the License, or
  32 * (at your option) any later version.
  33 *
  34 * This program is distributed in the hope that it will be useful,
  35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  37 * GNU General Public License for more details.
  38 *
  39 * You should have received a copy of the GNU General Public License
  40 * along with this program; if not, write to the Free Software
  41 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  42 *
  43 */
  44
  45#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  46
  47#include <linux/kernel.h>
  48#include <linux/module.h>
  49#include <linux/moduleparam.h>
  50#include <linux/init.h>
  51#include <linux/types.h>
  52#include <linux/backlight.h>
  53#include <linux/platform_device.h>
  54#include <linux/err.h>
  55#include <linux/dmi.h>
  56#include <linux/pci.h>
  57#include <linux/interrupt.h>
  58#include <linux/delay.h>
  59#include <linux/input.h>
  60#include <linux/kfifo.h>
  61#include <linux/workqueue.h>
  62#include <linux/acpi.h>
  63#include <linux/slab.h>
  64#include <linux/sonypi.h>
  65#include <linux/sony-laptop.h>
  66#include <linux/rfkill.h>
  67#ifdef CONFIG_SONYPI_COMPAT
  68#include <linux/poll.h>
  69#include <linux/miscdevice.h>
  70#endif
  71#include <asm/uaccess.h>
  72
  73#define dprintk(fmt, ...)                       \
  74do {                                            \
  75        if (debug)                              \
  76                pr_warn(fmt, ##__VA_ARGS__);    \
  77} while (0)
  78
  79#define SONY_NC_CLASS           "sony-nc"
  80#define SONY_NC_HID             "SNY5001"
  81#define SONY_NC_DRIVER_NAME     "Sony Notebook Control Driver"
  82
  83#define SONY_PIC_CLASS          "sony-pic"
  84#define SONY_PIC_HID            "SNY6001"
  85#define SONY_PIC_DRIVER_NAME    "Sony Programmable IO Control Driver"
  86
  87MODULE_AUTHOR("Stelian Pop, Mattia Dongili");
  88MODULE_DESCRIPTION("Sony laptop extras driver (SPIC and SNC ACPI device)");
  89MODULE_LICENSE("GPL");
  90
  91static int debug;
  92module_param(debug, int, 0);
  93MODULE_PARM_DESC(debug, "set this to 1 (and RTFM) if you want to help "
  94                 "the development of this driver");
  95
  96static int no_spic;             /* = 0 */
  97module_param(no_spic, int, 0444);
  98MODULE_PARM_DESC(no_spic,
  99                 "set this if you don't want to enable the SPIC device");
 100
 101static int compat;              /* = 0 */
 102module_param(compat, int, 0444);
 103MODULE_PARM_DESC(compat,
 104                 "set this if you want to enable backward compatibility mode");
 105
 106static unsigned long mask = 0xffffffff;
 107module_param(mask, ulong, 0644);
 108MODULE_PARM_DESC(mask,
 109                 "set this to the mask of event you want to enable (see doc)");
 110
 111static int camera;              /* = 0 */
 112module_param(camera, int, 0444);
 113MODULE_PARM_DESC(camera,
 114                 "set this to 1 to enable Motion Eye camera controls "
 115                 "(only use it if you have a C1VE or C1VN model)");
 116
 117#ifdef CONFIG_SONYPI_COMPAT
 118static int minor = -1;
 119module_param(minor, int, 0);
 120MODULE_PARM_DESC(minor,
 121                 "minor number of the misc device for the SPIC compatibility code, "
 122                 "default is -1 (automatic)");
 123#endif
 124
 125static int kbd_backlight = -1;
 126module_param(kbd_backlight, int, 0444);
 127MODULE_PARM_DESC(kbd_backlight,
 128                 "set this to 0 to disable keyboard backlight, "
 129                 "1 to enable it with automatic control and 2 to have it always "
 130                 "on (default: no change from current value)");
 131
 132static int kbd_backlight_timeout = -1;
 133module_param(kbd_backlight_timeout, int, 0444);
 134MODULE_PARM_DESC(kbd_backlight_timeout,
 135                 "meaningful values vary from 0 to 3 and their meaning depends "
 136                 "on the model (default: no change from current value)");
 137
 138#ifdef CONFIG_PM_SLEEP
 139static void sony_nc_thermal_resume(void);
 140#endif
 141static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
 142                unsigned int handle);
 143static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd,
 144                unsigned int handle);
 145
 146static int sony_nc_battery_care_setup(struct platform_device *pd,
 147                unsigned int handle);
 148static void sony_nc_battery_care_cleanup(struct platform_device *pd);
 149
 150static int sony_nc_thermal_setup(struct platform_device *pd);
 151static void sony_nc_thermal_cleanup(struct platform_device *pd);
 152
 153static int sony_nc_lid_resume_setup(struct platform_device *pd,
 154                                    unsigned int handle);
 155static void sony_nc_lid_resume_cleanup(struct platform_device *pd);
 156
 157static int sony_nc_gfx_switch_setup(struct platform_device *pd,
 158                unsigned int handle);
 159static void sony_nc_gfx_switch_cleanup(struct platform_device *pd);
 160static int __sony_nc_gfx_switch_status_get(void);
 161
 162static int sony_nc_highspeed_charging_setup(struct platform_device *pd);
 163static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd);
 164
 165static int sony_nc_lowbatt_setup(struct platform_device *pd);
 166static void sony_nc_lowbatt_cleanup(struct platform_device *pd);
 167
 168static int sony_nc_fanspeed_setup(struct platform_device *pd);
 169static void sony_nc_fanspeed_cleanup(struct platform_device *pd);
 170
 171static int sony_nc_usb_charge_setup(struct platform_device *pd);
 172static void sony_nc_usb_charge_cleanup(struct platform_device *pd);
 173
 174static int sony_nc_panelid_setup(struct platform_device *pd);
 175static void sony_nc_panelid_cleanup(struct platform_device *pd);
 176
 177static int sony_nc_smart_conn_setup(struct platform_device *pd);
 178static void sony_nc_smart_conn_cleanup(struct platform_device *pd);
 179
 180static int sony_nc_touchpad_setup(struct platform_device *pd,
 181                                  unsigned int handle);
 182static void sony_nc_touchpad_cleanup(struct platform_device *pd);
 183
 184enum sony_nc_rfkill {
 185        SONY_WIFI,
 186        SONY_BLUETOOTH,
 187        SONY_WWAN,
 188        SONY_WIMAX,
 189        N_SONY_RFKILL,
 190};
 191
 192static int sony_rfkill_handle;
 193static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL];
 194static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900};
 195static int sony_nc_rfkill_setup(struct acpi_device *device,
 196                unsigned int handle);
 197static void sony_nc_rfkill_cleanup(void);
 198static void sony_nc_rfkill_update(void);
 199
 200/*********** Input Devices ***********/
 201
 202#define SONY_LAPTOP_BUF_SIZE    128
 203struct sony_laptop_input_s {
 204        atomic_t                users;
 205        struct input_dev        *jog_dev;
 206        struct input_dev        *key_dev;
 207        struct kfifo            fifo;
 208        spinlock_t              fifo_lock;
 209        struct timer_list       release_key_timer;
 210};
 211
 212static struct sony_laptop_input_s sony_laptop_input = {
 213        .users = ATOMIC_INIT(0),
 214};
 215
 216struct sony_laptop_keypress {
 217        struct input_dev *dev;
 218        int key;
 219};
 220
 221/* Correspondance table between sonypi events
 222 * and input layer indexes in the keymap
 223 */
 224static int sony_laptop_input_index[] = {
 225        -1,     /*  0 no event */
 226        -1,     /*  1 SONYPI_EVENT_JOGDIAL_DOWN */
 227        -1,     /*  2 SONYPI_EVENT_JOGDIAL_UP */
 228        -1,     /*  3 SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */
 229        -1,     /*  4 SONYPI_EVENT_JOGDIAL_UP_PRESSED */
 230        -1,     /*  5 SONYPI_EVENT_JOGDIAL_PRESSED */
 231        -1,     /*  6 SONYPI_EVENT_JOGDIAL_RELEASED */
 232         0,     /*  7 SONYPI_EVENT_CAPTURE_PRESSED */
 233         1,     /*  8 SONYPI_EVENT_CAPTURE_RELEASED */
 234         2,     /*  9 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
 235         3,     /* 10 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
 236         4,     /* 11 SONYPI_EVENT_FNKEY_ESC */
 237         5,     /* 12 SONYPI_EVENT_FNKEY_F1 */
 238         6,     /* 13 SONYPI_EVENT_FNKEY_F2 */
 239         7,     /* 14 SONYPI_EVENT_FNKEY_F3 */
 240         8,     /* 15 SONYPI_EVENT_FNKEY_F4 */
 241         9,     /* 16 SONYPI_EVENT_FNKEY_F5 */
 242        10,     /* 17 SONYPI_EVENT_FNKEY_F6 */
 243        11,     /* 18 SONYPI_EVENT_FNKEY_F7 */
 244        12,     /* 19 SONYPI_EVENT_FNKEY_F8 */
 245        13,     /* 20 SONYPI_EVENT_FNKEY_F9 */
 246        14,     /* 21 SONYPI_EVENT_FNKEY_F10 */
 247        15,     /* 22 SONYPI_EVENT_FNKEY_F11 */
 248        16,     /* 23 SONYPI_EVENT_FNKEY_F12 */
 249        17,     /* 24 SONYPI_EVENT_FNKEY_1 */
 250        18,     /* 25 SONYPI_EVENT_FNKEY_2 */
 251        19,     /* 26 SONYPI_EVENT_FNKEY_D */
 252        20,     /* 27 SONYPI_EVENT_FNKEY_E */
 253        21,     /* 28 SONYPI_EVENT_FNKEY_F */
 254        22,     /* 29 SONYPI_EVENT_FNKEY_S */
 255        23,     /* 30 SONYPI_EVENT_FNKEY_B */
 256        24,     /* 31 SONYPI_EVENT_BLUETOOTH_PRESSED */
 257        25,     /* 32 SONYPI_EVENT_PKEY_P1 */
 258        26,     /* 33 SONYPI_EVENT_PKEY_P2 */
 259        27,     /* 34 SONYPI_EVENT_PKEY_P3 */
 260        28,     /* 35 SONYPI_EVENT_BACK_PRESSED */
 261        -1,     /* 36 SONYPI_EVENT_LID_CLOSED */
 262        -1,     /* 37 SONYPI_EVENT_LID_OPENED */
 263        29,     /* 38 SONYPI_EVENT_BLUETOOTH_ON */
 264        30,     /* 39 SONYPI_EVENT_BLUETOOTH_OFF */
 265        31,     /* 40 SONYPI_EVENT_HELP_PRESSED */
 266        32,     /* 41 SONYPI_EVENT_FNKEY_ONLY */
 267        33,     /* 42 SONYPI_EVENT_JOGDIAL_FAST_DOWN */
 268        34,     /* 43 SONYPI_EVENT_JOGDIAL_FAST_UP */
 269        35,     /* 44 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
 270        36,     /* 45 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
 271        37,     /* 46 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
 272        38,     /* 47 SONYPI_EVENT_JOGDIAL_VFAST_UP */
 273        39,     /* 48 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
 274        40,     /* 49 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
 275        41,     /* 50 SONYPI_EVENT_ZOOM_PRESSED */
 276        42,     /* 51 SONYPI_EVENT_THUMBPHRASE_PRESSED */
 277        43,     /* 52 SONYPI_EVENT_MEYE_FACE */
 278        44,     /* 53 SONYPI_EVENT_MEYE_OPPOSITE */
 279        45,     /* 54 SONYPI_EVENT_MEMORYSTICK_INSERT */
 280        46,     /* 55 SONYPI_EVENT_MEMORYSTICK_EJECT */
 281        -1,     /* 56 SONYPI_EVENT_ANYBUTTON_RELEASED */
 282        -1,     /* 57 SONYPI_EVENT_BATTERY_INSERT */
 283        -1,     /* 58 SONYPI_EVENT_BATTERY_REMOVE */
 284        -1,     /* 59 SONYPI_EVENT_FNKEY_RELEASED */
 285        47,     /* 60 SONYPI_EVENT_WIRELESS_ON */
 286        48,     /* 61 SONYPI_EVENT_WIRELESS_OFF */
 287        49,     /* 62 SONYPI_EVENT_ZOOM_IN_PRESSED */
 288        50,     /* 63 SONYPI_EVENT_ZOOM_OUT_PRESSED */
 289        51,     /* 64 SONYPI_EVENT_CD_EJECT_PRESSED */
 290        52,     /* 65 SONYPI_EVENT_MODEKEY_PRESSED */
 291        53,     /* 66 SONYPI_EVENT_PKEY_P4 */
 292        54,     /* 67 SONYPI_EVENT_PKEY_P5 */
 293        55,     /* 68 SONYPI_EVENT_SETTINGKEY_PRESSED */
 294        56,     /* 69 SONYPI_EVENT_VOLUME_INC_PRESSED */
 295        57,     /* 70 SONYPI_EVENT_VOLUME_DEC_PRESSED */
 296        -1,     /* 71 SONYPI_EVENT_BRIGHTNESS_PRESSED */
 297        58,     /* 72 SONYPI_EVENT_MEDIA_PRESSED */
 298        59,     /* 72 SONYPI_EVENT_VENDOR_PRESSED */
 299};
 300
 301static int sony_laptop_input_keycode_map[] = {
 302        KEY_CAMERA,     /*  0 SONYPI_EVENT_CAPTURE_PRESSED */
 303        KEY_RESERVED,   /*  1 SONYPI_EVENT_CAPTURE_RELEASED */
 304        KEY_RESERVED,   /*  2 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
 305        KEY_RESERVED,   /*  3 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
 306        KEY_FN_ESC,     /*  4 SONYPI_EVENT_FNKEY_ESC */
 307        KEY_FN_F1,      /*  5 SONYPI_EVENT_FNKEY_F1 */
 308        KEY_FN_F2,      /*  6 SONYPI_EVENT_FNKEY_F2 */
 309        KEY_FN_F3,      /*  7 SONYPI_EVENT_FNKEY_F3 */
 310        KEY_FN_F4,      /*  8 SONYPI_EVENT_FNKEY_F4 */
 311        KEY_FN_F5,      /*  9 SONYPI_EVENT_FNKEY_F5 */
 312        KEY_FN_F6,      /* 10 SONYPI_EVENT_FNKEY_F6 */
 313        KEY_FN_F7,      /* 11 SONYPI_EVENT_FNKEY_F7 */
 314        KEY_FN_F8,      /* 12 SONYPI_EVENT_FNKEY_F8 */
 315        KEY_FN_F9,      /* 13 SONYPI_EVENT_FNKEY_F9 */
 316        KEY_FN_F10,     /* 14 SONYPI_EVENT_FNKEY_F10 */
 317        KEY_FN_F11,     /* 15 SONYPI_EVENT_FNKEY_F11 */
 318        KEY_FN_F12,     /* 16 SONYPI_EVENT_FNKEY_F12 */
 319        KEY_FN_1,       /* 17 SONYPI_EVENT_FNKEY_1 */
 320        KEY_FN_2,       /* 18 SONYPI_EVENT_FNKEY_2 */
 321        KEY_FN_D,       /* 19 SONYPI_EVENT_FNKEY_D */
 322        KEY_FN_E,       /* 20 SONYPI_EVENT_FNKEY_E */
 323        KEY_FN_F,       /* 21 SONYPI_EVENT_FNKEY_F */
 324        KEY_FN_S,       /* 22 SONYPI_EVENT_FNKEY_S */
 325        KEY_FN_B,       /* 23 SONYPI_EVENT_FNKEY_B */
 326        KEY_BLUETOOTH,  /* 24 SONYPI_EVENT_BLUETOOTH_PRESSED */
 327        KEY_PROG1,      /* 25 SONYPI_EVENT_PKEY_P1 */
 328        KEY_PROG2,      /* 26 SONYPI_EVENT_PKEY_P2 */
 329        KEY_PROG3,      /* 27 SONYPI_EVENT_PKEY_P3 */
 330        KEY_BACK,       /* 28 SONYPI_EVENT_BACK_PRESSED */
 331        KEY_BLUETOOTH,  /* 29 SONYPI_EVENT_BLUETOOTH_ON */
 332        KEY_BLUETOOTH,  /* 30 SONYPI_EVENT_BLUETOOTH_OFF */
 333        KEY_HELP,       /* 31 SONYPI_EVENT_HELP_PRESSED */
 334        KEY_FN,         /* 32 SONYPI_EVENT_FNKEY_ONLY */
 335        KEY_RESERVED,   /* 33 SONYPI_EVENT_JOGDIAL_FAST_DOWN */
 336        KEY_RESERVED,   /* 34 SONYPI_EVENT_JOGDIAL_FAST_UP */
 337        KEY_RESERVED,   /* 35 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
 338        KEY_RESERVED,   /* 36 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
 339        KEY_RESERVED,   /* 37 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
 340        KEY_RESERVED,   /* 38 SONYPI_EVENT_JOGDIAL_VFAST_UP */
 341        KEY_RESERVED,   /* 39 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
 342        KEY_RESERVED,   /* 40 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
 343        KEY_ZOOM,       /* 41 SONYPI_EVENT_ZOOM_PRESSED */
 344        BTN_THUMB,      /* 42 SONYPI_EVENT_THUMBPHRASE_PRESSED */
 345        KEY_RESERVED,   /* 43 SONYPI_EVENT_MEYE_FACE */
 346        KEY_RESERVED,   /* 44 SONYPI_EVENT_MEYE_OPPOSITE */
 347        KEY_RESERVED,   /* 45 SONYPI_EVENT_MEMORYSTICK_INSERT */
 348        KEY_RESERVED,   /* 46 SONYPI_EVENT_MEMORYSTICK_EJECT */
 349        KEY_WLAN,       /* 47 SONYPI_EVENT_WIRELESS_ON */
 350        KEY_WLAN,       /* 48 SONYPI_EVENT_WIRELESS_OFF */
 351        KEY_ZOOMIN,     /* 49 SONYPI_EVENT_ZOOM_IN_PRESSED */
 352        KEY_ZOOMOUT,    /* 50 SONYPI_EVENT_ZOOM_OUT_PRESSED */
 353        KEY_EJECTCD,    /* 51 SONYPI_EVENT_CD_EJECT_PRESSED */
 354        KEY_F13,        /* 52 SONYPI_EVENT_MODEKEY_PRESSED */
 355        KEY_PROG4,      /* 53 SONYPI_EVENT_PKEY_P4 */
 356        KEY_F14,        /* 54 SONYPI_EVENT_PKEY_P5 */
 357        KEY_F15,        /* 55 SONYPI_EVENT_SETTINGKEY_PRESSED */
 358        KEY_VOLUMEUP,   /* 56 SONYPI_EVENT_VOLUME_INC_PRESSED */
 359        KEY_VOLUMEDOWN, /* 57 SONYPI_EVENT_VOLUME_DEC_PRESSED */
 360        KEY_MEDIA,      /* 58 SONYPI_EVENT_MEDIA_PRESSED */
 361        KEY_VENDOR,     /* 59 SONYPI_EVENT_VENDOR_PRESSED */
 362};
 363
 364/* release buttons after a short delay if pressed */
 365static void do_sony_laptop_release_key(unsigned long unused)
 366{
 367        struct sony_laptop_keypress kp;
 368        unsigned long flags;
 369
 370        spin_lock_irqsave(&sony_laptop_input.fifo_lock, flags);
 371
 372        if (kfifo_out(&sony_laptop_input.fifo,
 373                      (unsigned char *)&kp, sizeof(kp)) == sizeof(kp)) {
 374                input_report_key(kp.dev, kp.key, 0);
 375                input_sync(kp.dev);
 376        }
 377
 378        /* If there is something in the fifo schedule next release. */
 379        if (kfifo_len(&sony_laptop_input.fifo) != 0)
 380                mod_timer(&sony_laptop_input.release_key_timer,
 381                          jiffies + msecs_to_jiffies(10));
 382
 383        spin_unlock_irqrestore(&sony_laptop_input.fifo_lock, flags);
 384}
 385
 386/* forward event to the input subsystem */
 387static void sony_laptop_report_input_event(u8 event)
 388{
 389        struct input_dev *jog_dev = sony_laptop_input.jog_dev;
 390        struct input_dev *key_dev = sony_laptop_input.key_dev;
 391        struct sony_laptop_keypress kp = { NULL };
 392        int scancode = -1;
 393
 394        if (event == SONYPI_EVENT_FNKEY_RELEASED ||
 395                        event == SONYPI_EVENT_ANYBUTTON_RELEASED) {
 396                /* Nothing, not all VAIOs generate this event */
 397                return;
 398        }
 399
 400        /* report events */
 401        switch (event) {
 402        /* jog_dev events */
 403        case SONYPI_EVENT_JOGDIAL_UP:
 404        case SONYPI_EVENT_JOGDIAL_UP_PRESSED:
 405                input_report_rel(jog_dev, REL_WHEEL, 1);
 406                input_sync(jog_dev);
 407                return;
 408
 409        case SONYPI_EVENT_JOGDIAL_DOWN:
 410        case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED:
 411                input_report_rel(jog_dev, REL_WHEEL, -1);
 412                input_sync(jog_dev);
 413                return;
 414
 415        /* key_dev events */
 416        case SONYPI_EVENT_JOGDIAL_PRESSED:
 417                kp.key = BTN_MIDDLE;
 418                kp.dev = jog_dev;
 419                break;
 420
 421        default:
 422                if (event >= ARRAY_SIZE(sony_laptop_input_index)) {
 423                        dprintk("sony_laptop_report_input_event, event not known: %d\n", event);
 424                        break;
 425                }
 426                if ((scancode = sony_laptop_input_index[event]) != -1) {
 427                        kp.key = sony_laptop_input_keycode_map[scancode];
 428                        if (kp.key != KEY_UNKNOWN)
 429                                kp.dev = key_dev;
 430                }
 431                break;
 432        }
 433
 434        if (kp.dev) {
 435                /* if we have a scancode we emit it so we can always
 436                    remap the key */
 437                if (scancode != -1)
 438                        input_event(kp.dev, EV_MSC, MSC_SCAN, scancode);
 439                input_report_key(kp.dev, kp.key, 1);
 440                input_sync(kp.dev);
 441
 442                /* schedule key release */
 443                kfifo_in_locked(&sony_laptop_input.fifo,
 444                                (unsigned char *)&kp, sizeof(kp),
 445                                &sony_laptop_input.fifo_lock);
 446                mod_timer(&sony_laptop_input.release_key_timer,
 447                          jiffies + msecs_to_jiffies(10));
 448        } else
 449                dprintk("unknown input event %.2x\n", event);
 450}
 451
 452static int sony_laptop_setup_input(struct acpi_device *acpi_device)
 453{
 454        struct input_dev *jog_dev;
 455        struct input_dev *key_dev;
 456        int i;
 457        int error;
 458
 459        /* don't run again if already initialized */
 460        if (atomic_add_return(1, &sony_laptop_input.users) > 1)
 461                return 0;
 462
 463        /* kfifo */
 464        spin_lock_init(&sony_laptop_input.fifo_lock);
 465        error = kfifo_alloc(&sony_laptop_input.fifo,
 466                            SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
 467        if (error) {
 468                pr_err("kfifo_alloc failed\n");
 469                goto err_dec_users;
 470        }
 471
 472        setup_timer(&sony_laptop_input.release_key_timer,
 473                    do_sony_laptop_release_key, 0);
 474
 475        /* input keys */
 476        key_dev = input_allocate_device();
 477        if (!key_dev) {
 478                error = -ENOMEM;
 479                goto err_free_kfifo;
 480        }
 481
 482        key_dev->name = "Sony Vaio Keys";
 483        key_dev->id.bustype = BUS_ISA;
 484        key_dev->id.vendor = PCI_VENDOR_ID_SONY;
 485        key_dev->dev.parent = &acpi_device->dev;
 486
 487        /* Initialize the Input Drivers: special keys */
 488        input_set_capability(key_dev, EV_MSC, MSC_SCAN);
 489
 490        __set_bit(EV_KEY, key_dev->evbit);
 491        key_dev->keycodesize = sizeof(sony_laptop_input_keycode_map[0]);
 492        key_dev->keycodemax = ARRAY_SIZE(sony_laptop_input_keycode_map);
 493        key_dev->keycode = &sony_laptop_input_keycode_map;
 494        for (i = 0; i < ARRAY_SIZE(sony_laptop_input_keycode_map); i++)
 495                __set_bit(sony_laptop_input_keycode_map[i], key_dev->keybit);
 496        __clear_bit(KEY_RESERVED, key_dev->keybit);
 497
 498        error = input_register_device(key_dev);
 499        if (error)
 500                goto err_free_keydev;
 501
 502        sony_laptop_input.key_dev = key_dev;
 503
 504        /* jogdial */
 505        jog_dev = input_allocate_device();
 506        if (!jog_dev) {
 507                error = -ENOMEM;
 508                goto err_unregister_keydev;
 509        }
 510
 511        jog_dev->name = "Sony Vaio Jogdial";
 512        jog_dev->id.bustype = BUS_ISA;
 513        jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
 514        jog_dev->dev.parent = &acpi_device->dev;
 515
 516        input_set_capability(jog_dev, EV_KEY, BTN_MIDDLE);
 517        input_set_capability(jog_dev, EV_REL, REL_WHEEL);
 518
 519        error = input_register_device(jog_dev);
 520        if (error)
 521                goto err_free_jogdev;
 522
 523        sony_laptop_input.jog_dev = jog_dev;
 524
 525        return 0;
 526
 527err_free_jogdev:
 528        input_free_device(jog_dev);
 529
 530err_unregister_keydev:
 531        input_unregister_device(key_dev);
 532        /* to avoid kref underflow below at input_free_device */
 533        key_dev = NULL;
 534
 535err_free_keydev:
 536        input_free_device(key_dev);
 537
 538err_free_kfifo:
 539        kfifo_free(&sony_laptop_input.fifo);
 540
 541err_dec_users:
 542        atomic_dec(&sony_laptop_input.users);
 543        return error;
 544}
 545
 546static void sony_laptop_remove_input(void)
 547{
 548        struct sony_laptop_keypress kp = { NULL };
 549
 550        /* Cleanup only after the last user has gone */
 551        if (!atomic_dec_and_test(&sony_laptop_input.users))
 552                return;
 553
 554        del_timer_sync(&sony_laptop_input.release_key_timer);
 555
 556        /*
 557         * Generate key-up events for remaining keys. Note that we don't
 558         * need locking since nobody is adding new events to the kfifo.
 559         */
 560        while (kfifo_out(&sony_laptop_input.fifo,
 561                         (unsigned char *)&kp, sizeof(kp)) == sizeof(kp)) {
 562                input_report_key(kp.dev, kp.key, 0);
 563                input_sync(kp.dev);
 564        }
 565
 566        /* destroy input devs */
 567        input_unregister_device(sony_laptop_input.key_dev);
 568        sony_laptop_input.key_dev = NULL;
 569
 570        if (sony_laptop_input.jog_dev) {
 571                input_unregister_device(sony_laptop_input.jog_dev);
 572                sony_laptop_input.jog_dev = NULL;
 573        }
 574
 575        kfifo_free(&sony_laptop_input.fifo);
 576}
 577
 578/*********** Platform Device ***********/
 579
 580static atomic_t sony_pf_users = ATOMIC_INIT(0);
 581static struct platform_driver sony_pf_driver = {
 582        .driver = {
 583                   .name = "sony-laptop",
 584                   .owner = THIS_MODULE,
 585                   }
 586};
 587static struct platform_device *sony_pf_device;
 588
 589static int sony_pf_add(void)
 590{
 591        int ret = 0;
 592
 593        /* don't run again if already initialized */
 594        if (atomic_add_return(1, &sony_pf_users) > 1)
 595                return 0;
 596
 597        ret = platform_driver_register(&sony_pf_driver);
 598        if (ret)
 599                goto out;
 600
 601        sony_pf_device = platform_device_alloc("sony-laptop", -1);
 602        if (!sony_pf_device) {
 603                ret = -ENOMEM;
 604                goto out_platform_registered;
 605        }
 606
 607        ret = platform_device_add(sony_pf_device);
 608        if (ret)
 609                goto out_platform_alloced;
 610
 611        return 0;
 612
 613      out_platform_alloced:
 614        platform_device_put(sony_pf_device);
 615        sony_pf_device = NULL;
 616      out_platform_registered:
 617        platform_driver_unregister(&sony_pf_driver);
 618      out:
 619        atomic_dec(&sony_pf_users);
 620        return ret;
 621}
 622
 623static void sony_pf_remove(void)
 624{
 625        /* deregister only after the last user has gone */
 626        if (!atomic_dec_and_test(&sony_pf_users))
 627                return;
 628
 629        platform_device_unregister(sony_pf_device);
 630        platform_driver_unregister(&sony_pf_driver);
 631}
 632
 633/*********** SNC (SNY5001) Device ***********/
 634
 635/* the device uses 1-based values, while the backlight subsystem uses
 636   0-based values */
 637#define SONY_MAX_BRIGHTNESS     8
 638
 639#define SNC_VALIDATE_IN         0
 640#define SNC_VALIDATE_OUT        1
 641
 642static ssize_t sony_nc_sysfs_show(struct device *, struct device_attribute *,
 643                              char *);
 644static ssize_t sony_nc_sysfs_store(struct device *, struct device_attribute *,
 645                               const char *, size_t);
 646static int boolean_validate(const int, const int);
 647static int brightness_default_validate(const int, const int);
 648
 649struct sony_nc_value {
 650        char *name;             /* name of the entry */
 651        char **acpiget;         /* names of the ACPI get function */
 652        char **acpiset;         /* names of the ACPI set function */
 653        int (*validate)(const int, const int);  /* input/output validation */
 654        int value;              /* current setting */
 655        int valid;              /* Has ever been set */
 656        int debug;              /* active only in debug mode ? */
 657        struct device_attribute devattr;        /* sysfs attribute */
 658};
 659
 660#define SNC_HANDLE_NAMES(_name, _values...) \
 661        static char *snc_##_name[] = { _values, NULL }
 662
 663#define SNC_HANDLE(_name, _getters, _setters, _validate, _debug) \
 664        { \
 665                .name           = __stringify(_name), \
 666                .acpiget        = _getters, \
 667                .acpiset        = _setters, \
 668                .validate       = _validate, \
 669                .debug          = _debug, \
 670                .devattr        = __ATTR(_name, 0, sony_nc_sysfs_show, sony_nc_sysfs_store), \
 671        }
 672
 673#define SNC_HANDLE_NULL { .name = NULL }
 674
 675SNC_HANDLE_NAMES(fnkey_get, "GHKE");
 676
 677SNC_HANDLE_NAMES(brightness_def_get, "GPBR");
 678SNC_HANDLE_NAMES(brightness_def_set, "SPBR");
 679
 680SNC_HANDLE_NAMES(cdpower_get, "GCDP");
 681SNC_HANDLE_NAMES(cdpower_set, "SCDP", "CDPW");
 682
 683SNC_HANDLE_NAMES(audiopower_get, "GAZP");
 684SNC_HANDLE_NAMES(audiopower_set, "AZPW");
 685
 686SNC_HANDLE_NAMES(lanpower_get, "GLNP");
 687SNC_HANDLE_NAMES(lanpower_set, "LNPW");
 688
 689SNC_HANDLE_NAMES(lidstate_get, "GLID");
 690
 691SNC_HANDLE_NAMES(indicatorlamp_get, "GILS");
 692SNC_HANDLE_NAMES(indicatorlamp_set, "SILS");
 693
 694SNC_HANDLE_NAMES(gainbass_get, "GMGB");
 695SNC_HANDLE_NAMES(gainbass_set, "CMGB");
 696
 697SNC_HANDLE_NAMES(PID_get, "GPID");
 698
 699SNC_HANDLE_NAMES(CTR_get, "GCTR");
 700SNC_HANDLE_NAMES(CTR_set, "SCTR");
 701
 702SNC_HANDLE_NAMES(PCR_get, "GPCR");
 703SNC_HANDLE_NAMES(PCR_set, "SPCR");
 704
 705SNC_HANDLE_NAMES(CMI_get, "GCMI");
 706SNC_HANDLE_NAMES(CMI_set, "SCMI");
 707
 708static struct sony_nc_value sony_nc_values[] = {
 709        SNC_HANDLE(brightness_default, snc_brightness_def_get,
 710                        snc_brightness_def_set, brightness_default_validate, 0),
 711        SNC_HANDLE(fnkey, snc_fnkey_get, NULL, NULL, 0),
 712        SNC_HANDLE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0),
 713        SNC_HANDLE(audiopower, snc_audiopower_get, snc_audiopower_set,
 714                        boolean_validate, 0),
 715        SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set,
 716                        boolean_validate, 1),
 717        SNC_HANDLE(lidstate, snc_lidstate_get, NULL,
 718                        boolean_validate, 0),
 719        SNC_HANDLE(indicatorlamp, snc_indicatorlamp_get, snc_indicatorlamp_set,
 720                        boolean_validate, 0),
 721        SNC_HANDLE(gainbass, snc_gainbass_get, snc_gainbass_set,
 722                        boolean_validate, 0),
 723        /* unknown methods */
 724        SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1),
 725        SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1),
 726        SNC_HANDLE(PCR, snc_PCR_get, snc_PCR_set, NULL, 1),
 727        SNC_HANDLE(CMI, snc_CMI_get, snc_CMI_set, NULL, 1),
 728        SNC_HANDLE_NULL
 729};
 730
 731static acpi_handle sony_nc_acpi_handle;
 732static struct acpi_device *sony_nc_acpi_device = NULL;
 733
 734/*
 735 * acpi_evaluate_object wrappers
 736 * all useful calls into SNC methods take one or zero parameters and return
 737 * integers or arrays.
 738 */
 739static union acpi_object *__call_snc_method(acpi_handle handle, char *method,
 740                u64 *value)
 741{
 742        union acpi_object *result = NULL;
 743        struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
 744        acpi_status status;
 745
 746        if (value) {
 747                struct acpi_object_list params;
 748                union acpi_object in;
 749                in.type = ACPI_TYPE_INTEGER;
 750                in.integer.value = *value;
 751                params.count = 1;
 752                params.pointer = &in;
 753                status = acpi_evaluate_object(handle, method, &params, &output);
 754                dprintk("__call_snc_method: [%s:0x%.8x%.8x]\n", method,
 755                                (unsigned int)(*value >> 32),
 756                                (unsigned int)*value & 0xffffffff);
 757        } else {
 758                status = acpi_evaluate_object(handle, method, NULL, &output);
 759                dprintk("__call_snc_method: [%s]\n", method);
 760        }
 761
 762        if (ACPI_FAILURE(status)) {
 763                pr_err("Failed to evaluate [%s]\n", method);
 764                return NULL;
 765        }
 766
 767        result = (union acpi_object *) output.pointer;
 768        if (!result)
 769                dprintk("No return object [%s]\n", method);
 770
 771        return result;
 772}
 773
 774static int sony_nc_int_call(acpi_handle handle, char *name, int *value,
 775                int *result)
 776{
 777        union acpi_object *object = NULL;
 778        if (value) {
 779                u64 v = *value;
 780                object = __call_snc_method(handle, name, &v);
 781        } else
 782                object = __call_snc_method(handle, name, NULL);
 783
 784        if (!object)
 785                return -EINVAL;
 786
 787        if (object->type != ACPI_TYPE_INTEGER) {
 788                pr_warn("Invalid acpi_object: expected 0x%x got 0x%x\n",
 789                                ACPI_TYPE_INTEGER, object->type);
 790                kfree(object);
 791                return -EINVAL;
 792        }
 793
 794        if (result)
 795                *result = object->integer.value;
 796
 797        kfree(object);
 798        return 0;
 799}
 800
 801#define MIN(a, b)       (a > b ? b : a)
 802static int sony_nc_buffer_call(acpi_handle handle, char *name, u64 *value,
 803                void *buffer, size_t buflen)
 804{
 805        int ret = 0;
 806        size_t len;
 807        union acpi_object *object = __call_snc_method(handle, name, value);
 808
 809        if (!object)
 810                return -EINVAL;
 811
 812        if (object->type == ACPI_TYPE_BUFFER) {
 813                len = MIN(buflen, object->buffer.length);
 814                memcpy(buffer, object->buffer.pointer, len);
 815
 816        } else if (object->type == ACPI_TYPE_INTEGER) {
 817                len = MIN(buflen, sizeof(object->integer.value));
 818                memcpy(buffer, &object->integer.value, len);
 819
 820        } else {
 821                pr_warn("Invalid acpi_object: expected 0x%x got 0x%x\n",
 822                                ACPI_TYPE_BUFFER, object->type);
 823                ret = -EINVAL;
 824        }
 825
 826        kfree(object);
 827        return ret;
 828}
 829
 830struct sony_nc_handles {
 831        u16 cap[0x10];
 832        struct device_attribute devattr;
 833};
 834
 835static struct sony_nc_handles *handles;
 836
 837static ssize_t sony_nc_handles_show(struct device *dev,
 838                struct device_attribute *attr, char *buffer)
 839{
 840        ssize_t len = 0;
 841        int i;
 842
 843        for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
 844                len += snprintf(buffer + len, PAGE_SIZE - len, "0x%.4x ",
 845                                handles->cap[i]);
 846        }
 847        len += snprintf(buffer + len, PAGE_SIZE - len, "\n");
 848
 849        return len;
 850}
 851
 852static int sony_nc_handles_setup(struct platform_device *pd)
 853{
 854        int i, r, result, arg;
 855
 856        handles = kzalloc(sizeof(*handles), GFP_KERNEL);
 857        if (!handles)
 858                return -ENOMEM;
 859
 860        for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
 861                arg = i + 0x20;
 862                r = sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg,
 863                                        &result);
 864                if (!r) {
 865                        dprintk("caching handle 0x%.4x (offset: 0x%.2x)\n",
 866                                        result, i);
 867                        handles->cap[i] = result;
 868                }
 869        }
 870
 871        if (debug) {
 872                sysfs_attr_init(&handles->devattr.attr);
 873                handles->devattr.attr.name = "handles";
 874                handles->devattr.attr.mode = S_IRUGO;
 875                handles->devattr.show = sony_nc_handles_show;
 876
 877                /* allow reading capabilities via sysfs */
 878                if (device_create_file(&pd->dev, &handles->devattr)) {
 879                        kfree(handles);
 880                        handles = NULL;
 881                        return -1;
 882                }
 883        }
 884
 885        return 0;
 886}
 887
 888static int sony_nc_handles_cleanup(struct platform_device *pd)
 889{
 890        if (handles) {
 891                if (debug)
 892                        device_remove_file(&pd->dev, &handles->devattr);
 893                kfree(handles);
 894                handles = NULL;
 895        }
 896        return 0;
 897}
 898
 899static int sony_find_snc_handle(int handle)
 900{
 901        int i;
 902
 903        /* not initialized yet, return early */
 904        if (!handles || !handle)
 905                return -EINVAL;
 906
 907        for (i = 0; i < 0x10; i++) {
 908                if (handles->cap[i] == handle) {
 909                        dprintk("found handle 0x%.4x (offset: 0x%.2x)\n",
 910                                        handle, i);
 911                        return i;
 912                }
 913        }
 914        dprintk("handle 0x%.4x not found\n", handle);
 915        return -EINVAL;
 916}
 917
 918static int sony_call_snc_handle(int handle, int argument, int *result)
 919{
 920        int arg, ret = 0;
 921        int offset = sony_find_snc_handle(handle);
 922
 923        if (offset < 0)
 924                return offset;
 925
 926        arg = offset | argument;
 927        ret = sony_nc_int_call(sony_nc_acpi_handle, "SN07", &arg, result);
 928        dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n", arg, *result);
 929        return ret;
 930}
 931
 932/*
 933 * sony_nc_values input/output validate functions
 934 */
 935
 936/* brightness_default_validate:
 937 *
 938 * manipulate input output values to keep consistency with the
 939 * backlight framework for which brightness values are 0-based.
 940 */
 941static int brightness_default_validate(const int direction, const int value)
 942{
 943        switch (direction) {
 944                case SNC_VALIDATE_OUT:
 945                        return value - 1;
 946                case SNC_VALIDATE_IN:
 947                        if (value >= 0 && value < SONY_MAX_BRIGHTNESS)
 948                                return value + 1;
 949        }
 950        return -EINVAL;
 951}
 952
 953/* boolean_validate:
 954 *
 955 * on input validate boolean values 0/1, on output just pass the
 956 * received value.
 957 */
 958static int boolean_validate(const int direction, const int value)
 959{
 960        if (direction == SNC_VALIDATE_IN) {
 961                if (value != 0 && value != 1)
 962                        return -EINVAL;
 963        }
 964        return value;
 965}
 966
 967/*
 968 * Sysfs show/store common to all sony_nc_values
 969 */
 970static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr,
 971                              char *buffer)
 972{
 973        int value, ret = 0;
 974        struct sony_nc_value *item =
 975            container_of(attr, struct sony_nc_value, devattr);
 976
 977        if (!*item->acpiget)
 978                return -EIO;
 979
 980        ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiget, NULL,
 981                                &value);
 982        if (ret < 0)
 983                return -EIO;
 984
 985        if (item->validate)
 986                value = item->validate(SNC_VALIDATE_OUT, value);
 987
 988        return snprintf(buffer, PAGE_SIZE, "%d\n", value);
 989}
 990
 991static ssize_t sony_nc_sysfs_store(struct device *dev,
 992                               struct device_attribute *attr,
 993                               const char *buffer, size_t count)
 994{
 995        int value;
 996        int ret = 0;
 997        struct sony_nc_value *item =
 998            container_of(attr, struct sony_nc_value, devattr);
 999
1000        if (!item->acpiset)
1001                return -EIO;
1002
1003        if (count > 31)
1004                return -EINVAL;
1005
1006        if (kstrtoint(buffer, 10, &value))
1007                return -EINVAL;
1008
1009        if (item->validate)
1010                value = item->validate(SNC_VALIDATE_IN, value);
1011
1012        if (value < 0)
1013                return value;
1014
1015        ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiset,
1016                               &value, NULL);
1017        if (ret < 0)
1018                return -EIO;
1019
1020        item->value = value;
1021        item->valid = 1;
1022        return count;
1023}
1024
1025
1026/*
1027 * Backlight device
1028 */
1029struct sony_backlight_props {
1030        struct backlight_device *dev;
1031        int                     handle;
1032        int                     cmd_base;
1033        u8                      offset;
1034        u8                      maxlvl;
1035};
1036struct sony_backlight_props sony_bl_props;
1037
1038static int sony_backlight_update_status(struct backlight_device *bd)
1039{
1040        int arg = bd->props.brightness + 1;
1041        return sony_nc_int_call(sony_nc_acpi_handle, "SBRT", &arg, NULL);
1042}
1043
1044static int sony_backlight_get_brightness(struct backlight_device *bd)
1045{
1046        int value;
1047
1048        if (sony_nc_int_call(sony_nc_acpi_handle, "GBRT", NULL, &value))
1049                return 0;
1050        /* brightness levels are 1-based, while backlight ones are 0-based */
1051        return value - 1;
1052}
1053
1054static int sony_nc_get_brightness_ng(struct backlight_device *bd)
1055{
1056        int result;
1057        struct sony_backlight_props *sdev =
1058                (struct sony_backlight_props *)bl_get_data(bd);
1059
1060        sony_call_snc_handle(sdev->handle, sdev->cmd_base + 0x100, &result);
1061
1062        return (result & 0xff) - sdev->offset;
1063}
1064
1065static int sony_nc_update_status_ng(struct backlight_device *bd)
1066{
1067        int value, result;
1068        struct sony_backlight_props *sdev =
1069                (struct sony_backlight_props *)bl_get_data(bd);
1070
1071        value = bd->props.brightness + sdev->offset;
1072        if (sony_call_snc_handle(sdev->handle, sdev->cmd_base | (value << 0x10),
1073                                &result))
1074                return -EIO;
1075
1076        return value;
1077}
1078
1079static const struct backlight_ops sony_backlight_ops = {
1080        .options = BL_CORE_SUSPENDRESUME,
1081        .update_status = sony_backlight_update_status,
1082        .get_brightness = sony_backlight_get_brightness,
1083};
1084static const struct backlight_ops sony_backlight_ng_ops = {
1085        .options = BL_CORE_SUSPENDRESUME,
1086        .update_status = sony_nc_update_status_ng,
1087        .get_brightness = sony_nc_get_brightness_ng,
1088};
1089
1090/*
1091 * New SNC-only Vaios event mapping to driver known keys
1092 */
1093struct sony_nc_event {
1094        u8      data;
1095        u8      event;
1096};
1097
1098static struct sony_nc_event sony_100_events[] = {
1099        { 0x90, SONYPI_EVENT_PKEY_P1 },
1100        { 0x10, SONYPI_EVENT_ANYBUTTON_RELEASED },
1101        { 0x91, SONYPI_EVENT_PKEY_P2 },
1102        { 0x11, SONYPI_EVENT_ANYBUTTON_RELEASED },
1103        { 0x81, SONYPI_EVENT_FNKEY_F1 },
1104        { 0x01, SONYPI_EVENT_FNKEY_RELEASED },
1105        { 0x82, SONYPI_EVENT_FNKEY_F2 },
1106        { 0x02, SONYPI_EVENT_FNKEY_RELEASED },
1107        { 0x83, SONYPI_EVENT_FNKEY_F3 },
1108        { 0x03, SONYPI_EVENT_FNKEY_RELEASED },
1109        { 0x84, SONYPI_EVENT_FNKEY_F4 },
1110        { 0x04, SONYPI_EVENT_FNKEY_RELEASED },
1111        { 0x85, SONYPI_EVENT_FNKEY_F5 },
1112        { 0x05, SONYPI_EVENT_FNKEY_RELEASED },
1113        { 0x86, SONYPI_EVENT_FNKEY_F6 },
1114        { 0x06, SONYPI_EVENT_FNKEY_RELEASED },
1115        { 0x87, SONYPI_EVENT_FNKEY_F7 },
1116        { 0x07, SONYPI_EVENT_FNKEY_RELEASED },
1117        { 0x88, SONYPI_EVENT_FNKEY_F8 },
1118        { 0x08, SONYPI_EVENT_FNKEY_RELEASED },
1119        { 0x89, SONYPI_EVENT_FNKEY_F9 },
1120        { 0x09, SONYPI_EVENT_FNKEY_RELEASED },
1121        { 0x8A, SONYPI_EVENT_FNKEY_F10 },
1122        { 0x0A, SONYPI_EVENT_FNKEY_RELEASED },
1123        { 0x8B, SONYPI_EVENT_FNKEY_F11 },
1124        { 0x0B, SONYPI_EVENT_FNKEY_RELEASED },
1125        { 0x8C, SONYPI_EVENT_FNKEY_F12 },
1126        { 0x0C, SONYPI_EVENT_FNKEY_RELEASED },
1127        { 0x9d, SONYPI_EVENT_ZOOM_PRESSED },
1128        { 0x1d, SONYPI_EVENT_ANYBUTTON_RELEASED },
1129        { 0x9f, SONYPI_EVENT_CD_EJECT_PRESSED },
1130        { 0x1f, SONYPI_EVENT_ANYBUTTON_RELEASED },
1131        { 0xa1, SONYPI_EVENT_MEDIA_PRESSED },
1132        { 0x21, SONYPI_EVENT_ANYBUTTON_RELEASED },
1133        { 0xa4, SONYPI_EVENT_CD_EJECT_PRESSED },
1134        { 0x24, SONYPI_EVENT_ANYBUTTON_RELEASED },
1135        { 0xa5, SONYPI_EVENT_VENDOR_PRESSED },
1136        { 0x25, SONYPI_EVENT_ANYBUTTON_RELEASED },
1137        { 0xa6, SONYPI_EVENT_HELP_PRESSED },
1138        { 0x26, SONYPI_EVENT_ANYBUTTON_RELEASED },
1139        { 0xa8, SONYPI_EVENT_FNKEY_1 },
1140        { 0x28, SONYPI_EVENT_ANYBUTTON_RELEASED },
1141        { 0, 0 },
1142};
1143
1144static struct sony_nc_event sony_127_events[] = {
1145        { 0x81, SONYPI_EVENT_MODEKEY_PRESSED },
1146        { 0x01, SONYPI_EVENT_ANYBUTTON_RELEASED },
1147        { 0x82, SONYPI_EVENT_PKEY_P1 },
1148        { 0x02, SONYPI_EVENT_ANYBUTTON_RELEASED },
1149        { 0x83, SONYPI_EVENT_PKEY_P2 },
1150        { 0x03, SONYPI_EVENT_ANYBUTTON_RELEASED },
1151        { 0x84, SONYPI_EVENT_PKEY_P3 },
1152        { 0x04, SONYPI_EVENT_ANYBUTTON_RELEASED },
1153        { 0x85, SONYPI_EVENT_PKEY_P4 },
1154        { 0x05, SONYPI_EVENT_ANYBUTTON_RELEASED },
1155        { 0x86, SONYPI_EVENT_PKEY_P5 },
1156        { 0x06, SONYPI_EVENT_ANYBUTTON_RELEASED },
1157        { 0x87, SONYPI_EVENT_SETTINGKEY_PRESSED },
1158        { 0x07, SONYPI_EVENT_ANYBUTTON_RELEASED },
1159        { 0, 0 },
1160};
1161
1162static int sony_nc_hotkeys_decode(u32 event, unsigned int handle)
1163{
1164        int ret = -EINVAL;
1165        unsigned int result = 0;
1166        struct sony_nc_event *key_event;
1167
1168        if (sony_call_snc_handle(handle, 0x200, &result)) {
1169                dprintk("Unable to decode event 0x%.2x 0x%.2x\n", handle,
1170                                event);
1171                return -EINVAL;
1172        }
1173
1174        result &= 0xFF;
1175
1176        if (handle == 0x0100)
1177                key_event = sony_100_events;
1178        else
1179                key_event = sony_127_events;
1180
1181        for (; key_event->data; key_event++) {
1182                if (key_event->data == result) {
1183                        ret = key_event->event;
1184                        break;
1185                }
1186        }
1187
1188        if (!key_event->data)
1189                pr_info("Unknown hotkey 0x%.2x/0x%.2x (handle 0x%.2x)\n",
1190                                event, result, handle);
1191
1192        return ret;
1193}
1194
1195/*
1196 * ACPI callbacks
1197 */
1198enum event_types {
1199        HOTKEY = 1,
1200        KILLSWITCH,
1201        GFX_SWITCH
1202};
1203static void sony_nc_notify(struct acpi_device *device, u32 event)
1204{
1205        u32 real_ev = event;
1206        u8 ev_type = 0;
1207        dprintk("sony_nc_notify, event: 0x%.2x\n", event);
1208
1209        if (event >= 0x90) {
1210                unsigned int result = 0;
1211                unsigned int arg = 0;
1212                unsigned int handle = 0;
1213                unsigned int offset = event - 0x90;
1214
1215                if (offset >= ARRAY_SIZE(handles->cap)) {
1216                        pr_err("Event 0x%x outside of capabilities list\n",
1217                                        event);
1218                        return;
1219                }
1220                handle = handles->cap[offset];
1221
1222                /* list of handles known for generating events */
1223                switch (handle) {
1224                /* hotkey event */
1225                case 0x0100:
1226                case 0x0127:
1227                        ev_type = HOTKEY;
1228                        real_ev = sony_nc_hotkeys_decode(event, handle);
1229
1230                        if (real_ev > 0)
1231                                sony_laptop_report_input_event(real_ev);
1232                        else
1233                                /* restore the original event for reporting */
1234                                real_ev = event;
1235
1236                        break;
1237
1238                /* wlan switch */
1239                case 0x0124:
1240                case 0x0135:
1241                        /* events on this handle are reported when the
1242                         * switch changes position or for battery
1243                         * events. We'll notify both of them but only
1244                         * update the rfkill device status when the
1245                         * switch is moved.
1246                         */
1247                        ev_type = KILLSWITCH;
1248                        sony_call_snc_handle(handle, 0x0100, &result);
1249                        real_ev = result & 0x03;
1250
1251                        /* hw switch event */
1252                        if (real_ev == 1)
1253                                sony_nc_rfkill_update();
1254
1255                        break;
1256
1257                case 0x0128:
1258                case 0x0146:
1259                        /* Hybrid GFX switching */
1260                        sony_call_snc_handle(handle, 0x0000, &result);
1261                        dprintk("GFX switch event received (reason: %s)\n",
1262                                        (result == 0x1) ? "switch change" :
1263                                        (result == 0x2) ? "output switch" :
1264                                        (result == 0x3) ? "output switch" :
1265                                        "");
1266
1267                        ev_type = GFX_SWITCH;
1268                        real_ev = __sony_nc_gfx_switch_status_get();
1269                        break;
1270
1271                case 0x015B:
1272                        /* Hybrid GFX switching SVS151290S */
1273                        ev_type = GFX_SWITCH;
1274                        real_ev = __sony_nc_gfx_switch_status_get();
1275                        break;
1276                default:
1277                        dprintk("Unknown event 0x%x for handle 0x%x\n",
1278                                        event, handle);
1279                        break;
1280                }
1281
1282                /* clear the event (and the event reason when present) */
1283                arg = 1 << offset;
1284                sony_nc_int_call(sony_nc_acpi_handle, "SN05", &arg, &result);
1285
1286        } else {
1287                /* old style event */
1288                ev_type = HOTKEY;
1289                sony_laptop_report_input_event(real_ev);
1290        }
1291        acpi_bus_generate_netlink_event(sony_nc_acpi_device->pnp.device_class,
1292                        dev_name(&sony_nc_acpi_device->dev), ev_type, real_ev);
1293}
1294
1295static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
1296                                      void *context, void **return_value)
1297{
1298        struct acpi_device_info *info;
1299
1300        if (ACPI_SUCCESS(acpi_get_object_info(handle, &info))) {
1301                pr_warn("method: name: %4.4s, args %X\n",
1302                        (char *)&info->name, info->param_count);
1303
1304                kfree(info);
1305        }
1306
1307        return AE_OK;
1308}
1309
1310/*
1311 * ACPI device
1312 */
1313static void sony_nc_function_setup(struct acpi_device *device,
1314                struct platform_device *pf_device)
1315{
1316        unsigned int i, result, bitmask, arg;
1317
1318        if (!handles)
1319                return;
1320
1321        /* setup found handles here */
1322        for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
1323                unsigned int handle = handles->cap[i];
1324
1325                if (!handle)
1326                        continue;
1327
1328                dprintk("setting up handle 0x%.4x\n", handle);
1329
1330                switch (handle) {
1331                case 0x0100:
1332                case 0x0101:
1333                case 0x0127:
1334                        /* setup hotkeys */
1335                        sony_call_snc_handle(handle, 0, &result);
1336                        break;
1337                case 0x0102:
1338                        /* setup hotkeys */
1339                        sony_call_snc_handle(handle, 0x100, &result);
1340                        break;
1341                case 0x0105:
1342                case 0x0148:
1343                        /* touchpad enable/disable */
1344                        result = sony_nc_touchpad_setup(pf_device, handle);
1345                        if (result)
1346                                pr_err("couldn't set up touchpad control function (%d)\n",
1347                                                result);
1348                        break;
1349                case 0x0115:
1350                case 0x0136:
1351                case 0x013f:
1352                        result = sony_nc_battery_care_setup(pf_device, handle);
1353                        if (result)
1354                                pr_err("couldn't set up battery care function (%d)\n",
1355                                                result);
1356                        break;
1357                case 0x0119:
1358                case 0x015D:
1359                        result = sony_nc_lid_resume_setup(pf_device, handle);
1360                        if (result)
1361                                pr_err("couldn't set up lid resume function (%d)\n",
1362                                                result);
1363                        break;
1364                case 0x0122:
1365                        result = sony_nc_thermal_setup(pf_device);
1366                        if (result)
1367                                pr_err("couldn't set up thermal profile function (%d)\n",
1368                                                result);
1369                        break;
1370                case 0x0128:
1371                case 0x0146:
1372                case 0x015B:
1373                        result = sony_nc_gfx_switch_setup(pf_device, handle);
1374                        if (result)
1375                                pr_err("couldn't set up GFX Switch status (%d)\n",
1376                                                result);
1377                        break;
1378                case 0x0131:
1379                        result = sony_nc_highspeed_charging_setup(pf_device);
1380                        if (result)
1381                                pr_err("couldn't set up high speed charging function (%d)\n",
1382                                       result);
1383                        break;
1384                case 0x0124:
1385                case 0x0135:
1386                        result = sony_nc_rfkill_setup(device, handle);
1387                        if (result)
1388                                pr_err("couldn't set up rfkill support (%d)\n",
1389                                                result);
1390                        break;
1391                case 0x0137:
1392                case 0x0143:
1393                case 0x014b:
1394                case 0x014c:
1395                case 0x0163:
1396                        result = sony_nc_kbd_backlight_setup(pf_device, handle);
1397                        if (result)
1398                                pr_err("couldn't set up keyboard backlight function (%d)\n",
1399                                                result);
1400                        break;
1401                case 0x0121:
1402                        result = sony_nc_lowbatt_setup(pf_device);
1403                        if (result)
1404                                pr_err("couldn't set up low battery function (%d)\n",
1405                                       result);
1406                        break;
1407                case 0x0149:
1408                        result = sony_nc_fanspeed_setup(pf_device);
1409                        if (result)
1410                                pr_err("couldn't set up fan speed function (%d)\n",
1411                                       result);
1412                        break;
1413                case 0x0155:
1414                        result = sony_nc_usb_charge_setup(pf_device);
1415                        if (result)
1416                                pr_err("couldn't set up USB charge support (%d)\n",
1417                                                result);
1418                        break;
1419                case 0x011D:
1420                        result = sony_nc_panelid_setup(pf_device);
1421                        if (result)
1422                                pr_err("couldn't set up panel ID function (%d)\n",
1423                                       result);
1424                        break;
1425                case 0x0168:
1426                        result = sony_nc_smart_conn_setup(pf_device);
1427                        if (result)
1428                                pr_err("couldn't set up smart connect support (%d)\n",
1429                                                result);
1430                        break;
1431                default:
1432                        continue;
1433                }
1434        }
1435
1436        /* Enable all events */
1437        arg = 0x10;
1438        if (!sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg, &bitmask))
1439                sony_nc_int_call(sony_nc_acpi_handle, "SN02", &bitmask,
1440                                &result);
1441}
1442
1443static void sony_nc_function_cleanup(struct platform_device *pd)
1444{
1445        unsigned int i, result, bitmask, handle;
1446
1447        /* get enabled events and disable them */
1448        sony_nc_int_call(sony_nc_acpi_handle, "SN01", NULL, &bitmask);
1449        sony_nc_int_call(sony_nc_acpi_handle, "SN03", &bitmask, &result);
1450
1451        /* cleanup handles here */
1452        for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
1453
1454                handle = handles->cap[i];
1455
1456                if (!handle)
1457                        continue;
1458
1459                switch (handle) {
1460                case 0x0105:
1461                case 0x0148:
1462                        sony_nc_touchpad_cleanup(pd);
1463                        break;
1464                case 0x0115:
1465                case 0x0136:
1466                case 0x013f:
1467                        sony_nc_battery_care_cleanup(pd);
1468                        break;
1469                case 0x0119:
1470                case 0x015D:
1471                        sony_nc_lid_resume_cleanup(pd);
1472                        break;
1473                case 0x0122:
1474                        sony_nc_thermal_cleanup(pd);
1475                        break;
1476                case 0x0128:
1477                case 0x0146:
1478                case 0x015B:
1479                        sony_nc_gfx_switch_cleanup(pd);
1480                        break;
1481                case 0x0131:
1482                        sony_nc_highspeed_charging_cleanup(pd);
1483                        break;
1484                case 0x0124:
1485                case 0x0135:
1486                        sony_nc_rfkill_cleanup();
1487                        break;
1488                case 0x0137:
1489                case 0x0143:
1490                case 0x014b:
1491                case 0x014c:
1492                case 0x0163:
1493                        sony_nc_kbd_backlight_cleanup(pd, handle);
1494                        break;
1495                case 0x0121:
1496                        sony_nc_lowbatt_cleanup(pd);
1497                        break;
1498                case 0x0149:
1499                        sony_nc_fanspeed_cleanup(pd);
1500                        break;
1501                case 0x0155:
1502                        sony_nc_usb_charge_cleanup(pd);
1503                        break;
1504                case 0x011D:
1505                        sony_nc_panelid_cleanup(pd);
1506                        break;
1507                case 0x0168:
1508                        sony_nc_smart_conn_cleanup(pd);
1509                        break;
1510                default:
1511                        continue;
1512                }
1513        }
1514
1515        /* finally cleanup the handles list */
1516        sony_nc_handles_cleanup(pd);
1517}
1518
1519#ifdef CONFIG_PM_SLEEP
1520static void sony_nc_function_resume(void)
1521{
1522        unsigned int i, result, bitmask, arg;
1523
1524        dprintk("Resuming SNC device\n");
1525
1526        for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
1527                unsigned int handle = handles->cap[i];
1528
1529                if (!handle)
1530                        continue;
1531
1532                switch (handle) {
1533                case 0x0100:
1534                case 0x0101:
1535                case 0x0127:
1536                        /* re-enable hotkeys */
1537                        sony_call_snc_handle(handle, 0, &result);
1538                        break;
1539                case 0x0102:
1540                        /* re-enable hotkeys */
1541                        sony_call_snc_handle(handle, 0x100, &result);
1542                        break;
1543                case 0x0122:
1544                        sony_nc_thermal_resume();
1545                        break;
1546                case 0x0124:
1547                case 0x0135:
1548                        sony_nc_rfkill_update();
1549                        break;
1550                default:
1551                        continue;
1552                }
1553        }
1554
1555        /* Enable all events */
1556        arg = 0x10;
1557        if (!sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg, &bitmask))
1558                sony_nc_int_call(sony_nc_acpi_handle, "SN02", &bitmask,
1559                                &result);
1560}
1561
1562static int sony_nc_resume(struct device *dev)
1563{
1564        struct sony_nc_value *item;
1565
1566        for (item = sony_nc_values; item->name; item++) {
1567                int ret;
1568
1569                if (!item->valid)
1570                        continue;
1571                ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiset,
1572                                       &item->value, NULL);
1573                if (ret < 0) {
1574                        pr_err("%s: %d\n", __func__, ret);
1575                        break;
1576                }
1577        }
1578
1579        if (acpi_has_method(sony_nc_acpi_handle, "ECON")) {
1580                int arg = 1;
1581                if (sony_nc_int_call(sony_nc_acpi_handle, "ECON", &arg, NULL))
1582                        dprintk("ECON Method failed\n");
1583        }
1584
1585        if (acpi_has_method(sony_nc_acpi_handle, "SN00"))
1586                sony_nc_function_resume();
1587
1588        return 0;
1589}
1590#endif
1591
1592static SIMPLE_DEV_PM_OPS(sony_nc_pm, NULL, sony_nc_resume);
1593
1594static void sony_nc_rfkill_cleanup(void)
1595{
1596        int i;
1597
1598        for (i = 0; i < N_SONY_RFKILL; i++) {
1599                if (sony_rfkill_devices[i]) {
1600                        rfkill_unregister(sony_rfkill_devices[i]);
1601                        rfkill_destroy(sony_rfkill_devices[i]);
1602                }
1603        }
1604}
1605
1606static int sony_nc_rfkill_set(void *data, bool blocked)
1607{
1608        int result;
1609        int argument = sony_rfkill_address[(long) data] + 0x100;
1610
1611        if (!blocked)
1612                argument |= 0x070000;
1613
1614        return sony_call_snc_handle(sony_rfkill_handle, argument, &result);
1615}
1616
1617static const struct rfkill_ops sony_rfkill_ops = {
1618        .set_block = sony_nc_rfkill_set,
1619};
1620
1621static int sony_nc_setup_rfkill(struct acpi_device *device,
1622                                enum sony_nc_rfkill nc_type)
1623{
1624        int err = 0;
1625        struct rfkill *rfk;
1626        enum rfkill_type type;
1627        const char *name;
1628        int result;
1629        bool hwblock, swblock;
1630
1631        switch (nc_type) {
1632        case SONY_WIFI:
1633                type = RFKILL_TYPE_WLAN;
1634                name = "sony-wifi";
1635                break;
1636        case SONY_BLUETOOTH:
1637                type = RFKILL_TYPE_BLUETOOTH;
1638                name = "sony-bluetooth";
1639                break;
1640        case SONY_WWAN:
1641                type = RFKILL_TYPE_WWAN;
1642                name = "sony-wwan";
1643                break;
1644        case SONY_WIMAX:
1645                type = RFKILL_TYPE_WIMAX;
1646                name = "sony-wimax";
1647                break;
1648        default:
1649                return -EINVAL;
1650        }
1651
1652        rfk = rfkill_alloc(name, &device->dev, type,
1653                           &sony_rfkill_ops, (void *)nc_type);
1654        if (!rfk)
1655                return -ENOMEM;
1656
1657        if (sony_call_snc_handle(sony_rfkill_handle, 0x200, &result) < 0) {
1658                rfkill_destroy(rfk);
1659                return -1;
1660        }
1661        hwblock = !(result & 0x1);
1662
1663        if (sony_call_snc_handle(sony_rfkill_handle,
1664                                sony_rfkill_address[nc_type],
1665                                &result) < 0) {
1666                rfkill_destroy(rfk);
1667                return -1;
1668        }
1669        swblock = !(result & 0x2);
1670
1671        rfkill_init_sw_state(rfk, swblock);
1672        rfkill_set_hw_state(rfk, hwblock);
1673
1674        err = rfkill_register(rfk);
1675        if (err) {
1676                rfkill_destroy(rfk);
1677                return err;
1678        }
1679        sony_rfkill_devices[nc_type] = rfk;
1680        return err;
1681}
1682
1683static void sony_nc_rfkill_update(void)
1684{
1685        enum sony_nc_rfkill i;
1686        int result;
1687        bool hwblock;
1688
1689        sony_call_snc_handle(sony_rfkill_handle, 0x200, &result);
1690        hwblock = !(result & 0x1);
1691
1692        for (i = 0; i < N_SONY_RFKILL; i++) {
1693                int argument = sony_rfkill_address[i];
1694
1695                if (!sony_rfkill_devices[i])
1696                        continue;
1697
1698                if (hwblock) {
1699                        if (rfkill_set_hw_state(sony_rfkill_devices[i], true)) {
1700                                /* we already know we're blocked */
1701                        }
1702                        continue;
1703                }
1704
1705                sony_call_snc_handle(sony_rfkill_handle, argument, &result);
1706                rfkill_set_states(sony_rfkill_devices[i],
1707                                  !(result & 0x2), false);
1708        }
1709}
1710
1711static int sony_nc_rfkill_setup(struct acpi_device *device,
1712                unsigned int handle)
1713{
1714        u64 offset;
1715        int i;
1716        unsigned char buffer[32] = { 0 };
1717
1718        offset = sony_find_snc_handle(handle);
1719        sony_rfkill_handle = handle;
1720
1721        i = sony_nc_buffer_call(sony_nc_acpi_handle, "SN06", &offset, buffer,
1722                        32);
1723        if (i < 0)
1724                return i;
1725
1726        /* The buffer is filled with magic numbers describing the devices
1727         * available, 0xff terminates the enumeration.
1728         * Known codes:
1729         *      0x00 WLAN
1730         *      0x10 BLUETOOTH
1731         *      0x20 WWAN GPRS-EDGE
1732         *      0x21 WWAN HSDPA
1733         *      0x22 WWAN EV-DO
1734         *      0x23 WWAN GPS
1735         *      0x25 Gobi WWAN no GPS
1736         *      0x26 Gobi WWAN + GPS
1737         *      0x28 Gobi WWAN no GPS
1738         *      0x29 Gobi WWAN + GPS
1739         *      0x30 WIMAX
1740         *      0x50 Gobi WWAN no GPS
1741         *      0x51 Gobi WWAN + GPS
1742         *      0x70 no SIM card slot
1743         *      0x71 SIM card slot
1744         */
1745        for (i = 0; i < ARRAY_SIZE(buffer); i++) {
1746
1747                if (buffer[i] == 0xff)
1748                        break;
1749
1750                dprintk("Radio devices, found 0x%.2x\n", buffer[i]);
1751
1752                if (buffer[i] == 0 && !sony_rfkill_devices[SONY_WIFI])
1753                        sony_nc_setup_rfkill(device, SONY_WIFI);
1754
1755                if (buffer[i] == 0x10 && !sony_rfkill_devices[SONY_BLUETOOTH])
1756                        sony_nc_setup_rfkill(device, SONY_BLUETOOTH);
1757
1758                if (((0xf0 & buffer[i]) == 0x20 ||
1759                                        (0xf0 & buffer[i]) == 0x50) &&
1760                                !sony_rfkill_devices[SONY_WWAN])
1761                        sony_nc_setup_rfkill(device, SONY_WWAN);
1762
1763                if (buffer[i] == 0x30 && !sony_rfkill_devices[SONY_WIMAX])
1764                        sony_nc_setup_rfkill(device, SONY_WIMAX);
1765        }
1766        return 0;
1767}
1768
1769/* Keyboard backlight feature */
1770struct kbd_backlight {
1771        unsigned int handle;
1772        unsigned int base;
1773        unsigned int mode;
1774        unsigned int timeout;
1775        struct device_attribute mode_attr;
1776        struct device_attribute timeout_attr;
1777};
1778
1779static struct kbd_backlight *kbdbl_ctl;
1780
1781static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value)
1782{
1783        int result;
1784
1785        if (value > 2)
1786                return -EINVAL;
1787
1788        if (sony_call_snc_handle(kbdbl_ctl->handle,
1789                                (value << 0x10) | (kbdbl_ctl->base), &result))
1790                return -EIO;
1791
1792        /* Try to turn the light on/off immediately */
1793        if (value != 1)
1794                sony_call_snc_handle(kbdbl_ctl->handle,
1795                                (value << 0x0f) | (kbdbl_ctl->base + 0x100),
1796                                &result);
1797
1798        kbdbl_ctl->mode = value;
1799
1800        return 0;
1801}
1802
1803static ssize_t sony_nc_kbd_backlight_mode_store(struct device *dev,
1804                struct device_attribute *attr,
1805                const char *buffer, size_t count)
1806{
1807        int ret = 0;
1808        unsigned long value;
1809
1810        if (count > 31)
1811                return -EINVAL;
1812
1813        if (kstrtoul(buffer, 10, &value))
1814                return -EINVAL;
1815
1816        ret = __sony_nc_kbd_backlight_mode_set(value);
1817        if (ret < 0)
1818                return ret;
1819
1820        return count;
1821}
1822
1823static ssize_t sony_nc_kbd_backlight_mode_show(struct device *dev,
1824                struct device_attribute *attr, char *buffer)
1825{
1826        ssize_t count = 0;
1827        count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_ctl->mode);
1828        return count;
1829}
1830
1831static int __sony_nc_kbd_backlight_timeout_set(u8 value)
1832{
1833        int result;
1834
1835        if (value > 3)
1836                return -EINVAL;
1837
1838        if (sony_call_snc_handle(kbdbl_ctl->handle, (value << 0x10) |
1839                                (kbdbl_ctl->base + 0x200), &result))
1840                return -EIO;
1841
1842        kbdbl_ctl->timeout = value;
1843
1844        return 0;
1845}
1846
1847static ssize_t sony_nc_kbd_backlight_timeout_store(struct device *dev,
1848                struct device_attribute *attr,
1849                const char *buffer, size_t count)
1850{
1851        int ret = 0;
1852        unsigned long value;
1853
1854        if (count > 31)
1855                return -EINVAL;
1856
1857        if (kstrtoul(buffer, 10, &value))
1858                return -EINVAL;
1859
1860        ret = __sony_nc_kbd_backlight_timeout_set(value);
1861        if (ret < 0)
1862                return ret;
1863
1864        return count;
1865}
1866
1867static ssize_t sony_nc_kbd_backlight_timeout_show(struct device *dev,
1868                struct device_attribute *attr, char *buffer)
1869{
1870        ssize_t count = 0;
1871        count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_ctl->timeout);
1872        return count;
1873}
1874
1875static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
1876                unsigned int handle)
1877{
1878        int result;
1879        int ret = 0;
1880
1881        if (kbdbl_ctl) {
1882                pr_warn("handle 0x%.4x: keyboard backlight setup already done for 0x%.4x\n",
1883                                handle, kbdbl_ctl->handle);
1884                return -EBUSY;
1885        }
1886
1887        /* verify the kbd backlight presence, these handles are not used for
1888         * keyboard backlight only
1889         */
1890        ret = sony_call_snc_handle(handle, handle == 0x0137 ? 0x0B00 : 0x0100,
1891                        &result);
1892        if (ret)
1893                return ret;
1894
1895        if ((handle == 0x0137 && !(result & 0x02)) ||
1896                        !(result & 0x01)) {
1897                dprintk("no backlight keyboard found\n");
1898                return 0;
1899        }
1900
1901        kbdbl_ctl = kzalloc(sizeof(*kbdbl_ctl), GFP_KERNEL);
1902        if (!kbdbl_ctl)
1903                return -ENOMEM;
1904
1905        kbdbl_ctl->mode = kbd_backlight;
1906        kbdbl_ctl->timeout = kbd_backlight_timeout;
1907        kbdbl_ctl->handle = handle;
1908        if (handle == 0x0137)
1909                kbdbl_ctl->base = 0x0C00;
1910        else
1911                kbdbl_ctl->base = 0x4000;
1912
1913        sysfs_attr_init(&kbdbl_ctl->mode_attr.attr);
1914        kbdbl_ctl->mode_attr.attr.name = "kbd_backlight";
1915        kbdbl_ctl->mode_attr.attr.mode = S_IRUGO | S_IWUSR;
1916        kbdbl_ctl->mode_attr.show = sony_nc_kbd_backlight_mode_show;
1917        kbdbl_ctl->mode_attr.store = sony_nc_kbd_backlight_mode_store;
1918
1919        sysfs_attr_init(&kbdbl_ctl->timeout_attr.attr);
1920        kbdbl_ctl->timeout_attr.attr.name = "kbd_backlight_timeout";
1921        kbdbl_ctl->timeout_attr.attr.mode = S_IRUGO | S_IWUSR;
1922        kbdbl_ctl->timeout_attr.show = sony_nc_kbd_backlight_timeout_show;
1923        kbdbl_ctl->timeout_attr.store = sony_nc_kbd_backlight_timeout_store;
1924
1925        ret = device_create_file(&pd->dev, &kbdbl_ctl->mode_attr);
1926        if (ret)
1927                goto outkzalloc;
1928
1929        ret = device_create_file(&pd->dev, &kbdbl_ctl->timeout_attr);
1930        if (ret)
1931                goto outmode;
1932
1933        __sony_nc_kbd_backlight_mode_set(kbdbl_ctl->mode);
1934        __sony_nc_kbd_backlight_timeout_set(kbdbl_ctl->timeout);
1935
1936        return 0;
1937
1938outmode:
1939        device_remove_file(&pd->dev, &kbdbl_ctl->mode_attr);
1940outkzalloc:
1941        kfree(kbdbl_ctl);
1942        kbdbl_ctl = NULL;
1943        return ret;
1944}
1945
1946static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd,
1947                unsigned int handle)
1948{
1949        if (kbdbl_ctl && handle == kbdbl_ctl->handle) {
1950                device_remove_file(&pd->dev, &kbdbl_ctl->mode_attr);
1951                device_remove_file(&pd->dev, &kbdbl_ctl->timeout_attr);
1952                kfree(kbdbl_ctl);
1953                kbdbl_ctl = NULL;
1954        }
1955}
1956
1957struct battery_care_control {
1958        struct device_attribute attrs[2];
1959        unsigned int handle;
1960};
1961static struct battery_care_control *bcare_ctl;
1962
1963static ssize_t sony_nc_battery_care_limit_store(struct device *dev,
1964                struct device_attribute *attr,
1965                const char *buffer, size_t count)
1966{
1967        unsigned int result, cmd;
1968        unsigned long value;
1969
1970        if (count > 31)
1971                return -EINVAL;
1972
1973        if (kstrtoul(buffer, 10, &value))
1974                return -EINVAL;
1975
1976        /*  limit values (2 bits):
1977         *  00 - none
1978         *  01 - 80%
1979         *  10 - 50%
1980         *  11 - 100%
1981         *
1982         *  bit 0: 0 disable BCL, 1 enable BCL
1983         *  bit 1: 1 tell to store the battery limit (see bits 6,7) too
1984         *  bits 2,3: reserved
1985         *  bits 4,5: store the limit into the EC
1986         *  bits 6,7: store the limit into the battery
1987         */
1988        cmd = 0;
1989
1990        if (value > 0) {
1991                if (value <= 50)
1992                        cmd = 0x20;
1993
1994                else if (value <= 80)
1995                        cmd = 0x10;
1996
1997                else if (value <= 100)
1998                        cmd = 0x30;
1999
2000                else
2001                        return -EINVAL;
2002
2003                /*
2004                 * handle 0x0115 should allow storing on battery too;
2005                 * handle 0x0136 same as 0x0115 + health status;
2006                 * handle 0x013f, same as 0x0136 but no storing on the battery
2007                 */
2008                if (bcare_ctl->handle != 0x013f)
2009                        cmd = cmd | (cmd << 2);
2010
2011                cmd = (cmd | 0x1) << 0x10;
2012        }
2013
2014        if (sony_call_snc_handle(bcare_ctl->handle, cmd | 0x0100, &result))
2015                return -EIO;
2016
2017        return count;
2018}
2019
2020static ssize_t sony_nc_battery_care_limit_show(struct device *dev,
2021                struct device_attribute *attr, char *buffer)
2022{
2023        unsigned int result, status;
2024
2025        if (sony_call_snc_handle(bcare_ctl->handle, 0x0000, &result))
2026                return -EIO;
2027
2028        status = (result & 0x01) ? ((result & 0x30) >> 0x04) : 0;
2029        switch (status) {
2030        case 1:
2031                status = 80;
2032                break;
2033        case 2:
2034                status = 50;
2035                break;
2036        case 3:
2037                status = 100;
2038                break;
2039        default:
2040                status = 0;
2041                break;
2042        }
2043
2044        return snprintf(buffer, PAGE_SIZE, "%d\n", status);
2045}
2046
2047static ssize_t sony_nc_battery_care_health_show(struct device *dev,
2048                struct device_attribute *attr, char *buffer)
2049{
2050        ssize_t count = 0;
2051        unsigned int health;
2052
2053        if (sony_call_snc_handle(bcare_ctl->handle, 0x0200, &health))
2054                return -EIO;
2055
2056        count = snprintf(buffer, PAGE_SIZE, "%d\n", health & 0xff);
2057
2058        return count;
2059}
2060
2061static int sony_nc_battery_care_setup(struct platform_device *pd,
2062                unsigned int handle)
2063{
2064        int ret = 0;
2065
2066        bcare_ctl = kzalloc(sizeof(struct battery_care_control), GFP_KERNEL);
2067        if (!bcare_ctl)
2068                return -ENOMEM;
2069
2070        bcare_ctl->handle = handle;
2071
2072        sysfs_attr_init(&bcare_ctl->attrs[0].attr);
2073        bcare_ctl->attrs[0].attr.name = "battery_care_limiter";
2074        bcare_ctl->attrs[0].attr.mode = S_IRUGO | S_IWUSR;
2075        bcare_ctl->attrs[0].show = sony_nc_battery_care_limit_show;
2076        bcare_ctl->attrs[0].store = sony_nc_battery_care_limit_store;
2077
2078        ret = device_create_file(&pd->dev, &bcare_ctl->attrs[0]);
2079        if (ret)
2080                goto outkzalloc;
2081
2082        /* 0x0115 is for models with no health reporting capability */
2083        if (handle == 0x0115)
2084                return 0;
2085
2086        sysfs_attr_init(&bcare_ctl->attrs[1].attr);
2087        bcare_ctl->attrs[1].attr.name = "battery_care_health";
2088        bcare_ctl->attrs[1].attr.mode = S_IRUGO;
2089        bcare_ctl->attrs[1].show = sony_nc_battery_care_health_show;
2090
2091        ret = device_create_file(&pd->dev, &bcare_ctl->attrs[1]);
2092        if (ret)
2093                goto outlimiter;
2094
2095        return 0;
2096
2097outlimiter:
2098        device_remove_file(&pd->dev, &bcare_ctl->attrs[0]);
2099
2100outkzalloc:
2101        kfree(bcare_ctl);
2102        bcare_ctl = NULL;
2103
2104        return ret;
2105}
2106
2107static void sony_nc_battery_care_cleanup(struct platform_device *pd)
2108{
2109        if (bcare_ctl) {
2110                device_remove_file(&pd->dev, &bcare_ctl->attrs[0]);
2111                if (bcare_ctl->handle != 0x0115)
2112                        device_remove_file(&pd->dev, &bcare_ctl->attrs[1]);
2113
2114                kfree(bcare_ctl);
2115                bcare_ctl = NULL;
2116        }
2117}
2118
2119struct snc_thermal_ctrl {
2120        unsigned int mode;
2121        unsigned int profiles;
2122        struct device_attribute mode_attr;
2123        struct device_attribute profiles_attr;
2124};
2125static struct snc_thermal_ctrl *th_handle;
2126
2127#define THM_PROFILE_MAX 3
2128static const char * const snc_thermal_profiles[] = {
2129        "balanced",
2130        "silent",
2131        "performance"
2132};
2133
2134static int sony_nc_thermal_mode_set(unsigned short mode)
2135{
2136        unsigned int result;
2137
2138        /* the thermal profile seems to be a two bit bitmask:
2139         * lsb -> silent
2140         * msb -> performance
2141         * no bit set is the normal operation and is always valid
2142         * Some vaio models only have "balanced" and "performance"
2143         */
2144        if ((mode && !(th_handle->profiles & mode)) || mode >= THM_PROFILE_MAX)
2145                return -EINVAL;
2146
2147        if (sony_call_snc_handle(0x0122, mode << 0x10 | 0x0200, &result))
2148                return -EIO;
2149
2150        th_handle->mode = mode;
2151
2152        return 0;
2153}
2154
2155static int sony_nc_thermal_mode_get(void)
2156{
2157        unsigned int result;
2158
2159        if (sony_call_snc_handle(0x0122, 0x0100, &result))
2160                return -EIO;
2161
2162        return result & 0xff;
2163}
2164
2165static ssize_t sony_nc_thermal_profiles_show(struct device *dev,
2166                struct device_attribute *attr, char *buffer)
2167{
2168        short cnt;
2169        size_t idx = 0;
2170
2171        for (cnt = 0; cnt < THM_PROFILE_MAX; cnt++) {
2172                if (!cnt || (th_handle->profiles & cnt))
2173                        idx += snprintf(buffer + idx, PAGE_SIZE - idx, "%s ",
2174                                        snc_thermal_profiles[cnt]);
2175        }
2176        idx += snprintf(buffer + idx, PAGE_SIZE - idx, "\n");
2177
2178        return idx;
2179}
2180
2181static ssize_t sony_nc_thermal_mode_store(struct device *dev,
2182                struct device_attribute *attr,
2183                const char *buffer, size_t count)
2184{
2185        unsigned short cmd;
2186        size_t len = count;
2187
2188        if (count == 0)
2189                return -EINVAL;
2190
2191        /* skip the newline if present */
2192        if (buffer[len - 1] == '\n')
2193                len--;
2194
2195        for (cmd = 0; cmd < THM_PROFILE_MAX; cmd++)
2196                if (strncmp(buffer, snc_thermal_profiles[cmd], len) == 0)
2197                        break;
2198
2199        if (sony_nc_thermal_mode_set(cmd))
2200                return -EIO;
2201
2202        return count;
2203}
2204
2205static ssize_t sony_nc_thermal_mode_show(struct device *dev,
2206                struct device_attribute *attr, char *buffer)
2207{
2208        ssize_t count = 0;
2209        int mode = sony_nc_thermal_mode_get();
2210
2211        if (mode < 0)
2212                return mode;
2213
2214        count = snprintf(buffer, PAGE_SIZE, "%s\n", snc_thermal_profiles[mode]);
2215
2216        return count;
2217}
2218
2219static int sony_nc_thermal_setup(struct platform_device *pd)
2220{
2221        int ret = 0;
2222        th_handle = kzalloc(sizeof(struct snc_thermal_ctrl), GFP_KERNEL);
2223        if (!th_handle)
2224                return -ENOMEM;
2225
2226        ret = sony_call_snc_handle(0x0122, 0x0000, &th_handle->profiles);
2227        if (ret) {
2228                pr_warn("couldn't to read the thermal profiles\n");
2229                goto outkzalloc;
2230        }
2231
2232        ret = sony_nc_thermal_mode_get();
2233        if (ret < 0) {
2234                pr_warn("couldn't to read the current thermal profile");
2235                goto outkzalloc;
2236        }
2237        th_handle->mode = ret;
2238
2239        sysfs_attr_init(&th_handle->profiles_attr.attr);
2240        th_handle->profiles_attr.attr.name = "thermal_profiles";
2241        th_handle->profiles_attr.attr.mode = S_IRUGO;
2242        th_handle->profiles_attr.show = sony_nc_thermal_profiles_show;
2243
2244        sysfs_attr_init(&th_handle->mode_attr.attr);
2245        th_handle->mode_attr.attr.name = "thermal_control";
2246        th_handle->mode_attr.attr.mode = S_IRUGO | S_IWUSR;
2247        th_handle->mode_attr.show = sony_nc_thermal_mode_show;
2248        th_handle->mode_attr.store = sony_nc_thermal_mode_store;
2249
2250        ret = device_create_file(&pd->dev, &th_handle->profiles_attr);
2251        if (ret)
2252                goto outkzalloc;
2253
2254        ret = device_create_file(&pd->dev, &th_handle->mode_attr);
2255        if (ret)
2256                goto outprofiles;
2257
2258        return 0;
2259
2260outprofiles:
2261        device_remove_file(&pd->dev, &th_handle->profiles_attr);
2262outkzalloc:
2263        kfree(th_handle);
2264        th_handle = NULL;
2265        return ret;
2266}
2267
2268static void sony_nc_thermal_cleanup(struct platform_device *pd)
2269{
2270        if (th_handle) {
2271                device_remove_file(&pd->dev, &th_handle->profiles_attr);
2272                device_remove_file(&pd->dev, &th_handle->mode_attr);
2273                kfree(th_handle);
2274                th_handle = NULL;
2275        }
2276}
2277
2278#ifdef CONFIG_PM_SLEEP
2279static void sony_nc_thermal_resume(void)
2280{
2281        unsigned int status = sony_nc_thermal_mode_get();
2282
2283        if (status != th_handle->mode)
2284                sony_nc_thermal_mode_set(th_handle->mode);
2285}
2286#endif
2287
2288/* resume on LID open */
2289#define LID_RESUME_S5   0
2290#define LID_RESUME_S4   1
2291#define LID_RESUME_S3   2
2292#define LID_RESUME_MAX  3
2293struct snc_lid_resume_control {
2294        struct device_attribute attrs[LID_RESUME_MAX];
2295        unsigned int status;
2296        int handle;
2297};
2298static struct snc_lid_resume_control *lid_ctl;
2299
2300static ssize_t sony_nc_lid_resume_store(struct device *dev,
2301                                        struct device_attribute *attr,
2302                                        const char *buffer, size_t count)
2303{
2304        unsigned int result;
2305        unsigned long value;
2306        unsigned int pos = LID_RESUME_S5;
2307        if (count > 31)
2308                return -EINVAL;
2309
2310        if (kstrtoul(buffer, 10, &value) || value > 1)
2311                return -EINVAL;
2312
2313        /* the value we have to write to SNC is a bitmask:
2314         * +--------------+
2315         * | S3 | S4 | S5 |
2316         * +--------------+
2317         *   2    1    0
2318         */
2319        while (pos < LID_RESUME_MAX) {
2320                if (&lid_ctl->attrs[pos].attr == &attr->attr)
2321                        break;
2322                pos++;
2323        }
2324        if (pos == LID_RESUME_MAX)
2325                return -EINVAL;
2326
2327        if (value)
2328                value = lid_ctl->status | (1 << pos);
2329        else
2330                value = lid_ctl->status & ~(1 << pos);
2331
2332        if (sony_call_snc_handle(lid_ctl->handle, value << 0x10 | 0x0100,
2333                                &result))
2334                return -EIO;
2335
2336        lid_ctl->status = value;
2337
2338        return count;
2339}
2340
2341static ssize_t sony_nc_lid_resume_show(struct device *dev,
2342                                        struct device_attribute *attr,
2343                                        char *buffer)
2344{
2345        unsigned int pos = LID_RESUME_S5;
2346
2347        while (pos < LID_RESUME_MAX) {
2348                if (&lid_ctl->attrs[pos].attr == &attr->attr)
2349                        return snprintf(buffer, PAGE_SIZE, "%d\n",
2350                                        (lid_ctl->status >> pos) & 0x01);
2351                pos++;
2352        }
2353        return -EINVAL;
2354}
2355
2356static int sony_nc_lid_resume_setup(struct platform_device *pd,
2357                                        unsigned int handle)
2358{
2359        unsigned int result;
2360        int i;
2361
2362        if (sony_call_snc_handle(handle, 0x0000, &result))
2363                return -EIO;
2364
2365        lid_ctl = kzalloc(sizeof(struct snc_lid_resume_control), GFP_KERNEL);
2366        if (!lid_ctl)
2367                return -ENOMEM;
2368
2369        lid_ctl->status = result & 0x7;
2370        lid_ctl->handle = handle;
2371
2372        sysfs_attr_init(&lid_ctl->attrs[0].attr);
2373        lid_ctl->attrs[LID_RESUME_S5].attr.name = "lid_resume_S5";
2374        lid_ctl->attrs[LID_RESUME_S5].attr.mode = S_IRUGO | S_IWUSR;
2375        lid_ctl->attrs[LID_RESUME_S5].show = sony_nc_lid_resume_show;
2376        lid_ctl->attrs[LID_RESUME_S5].store = sony_nc_lid_resume_store;
2377
2378        if (handle == 0x0119) {
2379                sysfs_attr_init(&lid_ctl->attrs[1].attr);
2380                lid_ctl->attrs[LID_RESUME_S4].attr.name = "lid_resume_S4";
2381                lid_ctl->attrs[LID_RESUME_S4].attr.mode = S_IRUGO | S_IWUSR;
2382                lid_ctl->attrs[LID_RESUME_S4].show = sony_nc_lid_resume_show;
2383                lid_ctl->attrs[LID_RESUME_S4].store = sony_nc_lid_resume_store;
2384
2385                sysfs_attr_init(&lid_ctl->attrs[2].attr);
2386                lid_ctl->attrs[LID_RESUME_S3].attr.name = "lid_resume_S3";
2387                lid_ctl->attrs[LID_RESUME_S3].attr.mode = S_IRUGO | S_IWUSR;
2388                lid_ctl->attrs[LID_RESUME_S3].show = sony_nc_lid_resume_show;
2389                lid_ctl->attrs[LID_RESUME_S3].store = sony_nc_lid_resume_store;
2390        }
2391        for (i = 0; i < LID_RESUME_MAX &&
2392                        lid_ctl->attrs[LID_RESUME_S3].attr.name; i++) {
2393                result = device_create_file(&pd->dev, &lid_ctl->attrs[i]);
2394                if (result)
2395                        goto liderror;
2396        }
2397
2398        return 0;
2399
2400liderror:
2401        for (i--; i >= 0; i--)
2402                device_remove_file(&pd->dev, &lid_ctl->attrs[i]);
2403
2404        kfree(lid_ctl);
2405        lid_ctl = NULL;
2406
2407        return result;
2408}
2409
2410static void sony_nc_lid_resume_cleanup(struct platform_device *pd)
2411{
2412        int i;
2413
2414        if (lid_ctl) {
2415                for (i = 0; i < LID_RESUME_MAX; i++) {
2416                        if (!lid_ctl->attrs[i].attr.name)
2417                                break;
2418
2419                        device_remove_file(&pd->dev, &lid_ctl->attrs[i]);
2420                }
2421
2422                kfree(lid_ctl);
2423                lid_ctl = NULL;
2424        }
2425}
2426
2427/* GFX Switch position */
2428enum gfx_switch {
2429        SPEED,
2430        STAMINA,
2431        AUTO
2432};
2433struct snc_gfx_switch_control {
2434        struct device_attribute attr;
2435        unsigned int handle;
2436};
2437static struct snc_gfx_switch_control *gfxs_ctl;
2438
2439/* returns 0 for speed, 1 for stamina */
2440static int __sony_nc_gfx_switch_status_get(void)
2441{
2442        unsigned int result;
2443
2444        if (sony_call_snc_handle(gfxs_ctl->handle,
2445                                gfxs_ctl->handle == 0x015B ? 0x0000 : 0x0100,
2446                                &result))
2447                return -EIO;
2448
2449        switch (gfxs_ctl->handle) {
2450        case 0x0146:
2451                /* 1: discrete GFX (speed)
2452                 * 0: integrated GFX (stamina)
2453                 */
2454                return result & 0x1 ? SPEED : STAMINA;
2455                break;
2456        case 0x015B:
2457                /* 0: discrete GFX (speed)
2458                 * 1: integrated GFX (stamina)
2459                 */
2460                return result & 0x1 ? STAMINA : SPEED;
2461                break;
2462        case 0x0128:
2463                /* it's a more elaborated bitmask, for now:
2464                 * 2: integrated GFX (stamina)
2465                 * 0: discrete GFX (speed)
2466                 */
2467                dprintk("GFX Status: 0x%x\n", result);
2468                return result & 0x80 ? AUTO :
2469                        result & 0x02 ? STAMINA : SPEED;
2470                break;
2471        }
2472        return -EINVAL;
2473}
2474
2475static ssize_t sony_nc_gfx_switch_status_show(struct device *dev,
2476                                       struct device_attribute *attr,
2477                                       char *buffer)
2478{
2479        int pos = __sony_nc_gfx_switch_status_get();
2480
2481        if (pos < 0)
2482                return pos;
2483
2484        return snprintf(buffer, PAGE_SIZE, "%s\n",
2485                                        pos == SPEED ? "speed" :
2486                                        pos == STAMINA ? "stamina" :
2487                                        pos == AUTO ? "auto" : "unknown");
2488}
2489
2490static int sony_nc_gfx_switch_setup(struct platform_device *pd,
2491                unsigned int handle)
2492{
2493        unsigned int result;
2494
2495        gfxs_ctl = kzalloc(sizeof(struct snc_gfx_switch_control), GFP_KERNEL);
2496        if (!gfxs_ctl)
2497                return -ENOMEM;
2498
2499        gfxs_ctl->handle = handle;
2500
2501        sysfs_attr_init(&gfxs_ctl->attr.attr);
2502        gfxs_ctl->attr.attr.name = "gfx_switch_status";
2503        gfxs_ctl->attr.attr.mode = S_IRUGO;
2504        gfxs_ctl->attr.show = sony_nc_gfx_switch_status_show;
2505
2506        result = device_create_file(&pd->dev, &gfxs_ctl->attr);
2507        if (result)
2508                goto gfxerror;
2509
2510        return 0;
2511
2512gfxerror:
2513        kfree(gfxs_ctl);
2514        gfxs_ctl = NULL;
2515
2516        return result;
2517}
2518
2519static void sony_nc_gfx_switch_cleanup(struct platform_device *pd)
2520{
2521        if (gfxs_ctl) {
2522                device_remove_file(&pd->dev, &gfxs_ctl->attr);
2523
2524                kfree(gfxs_ctl);
2525                gfxs_ctl = NULL;
2526        }
2527}
2528
2529/* High speed charging function */
2530static struct device_attribute *hsc_handle;
2531
2532static ssize_t sony_nc_highspeed_charging_store(struct device *dev,
2533                struct device_attribute *attr,
2534                const char *buffer, size_t count)
2535{
2536        unsigned int result;
2537        unsigned long value;
2538
2539        if (count > 31)
2540                return -EINVAL;
2541
2542        if (kstrtoul(buffer, 10, &value) || value > 1)
2543                return -EINVAL;
2544
2545        if (sony_call_snc_handle(0x0131, value << 0x10 | 0x0200, &result))
2546                return -EIO;
2547
2548        return count;
2549}
2550
2551static ssize_t sony_nc_highspeed_charging_show(struct device *dev,
2552                struct device_attribute *attr, char *buffer)
2553{
2554        unsigned int result;
2555
2556        if (sony_call_snc_handle(0x0131, 0x0100, &result))
2557                return -EIO;
2558
2559        return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01);
2560}
2561
2562static int sony_nc_highspeed_charging_setup(struct platform_device *pd)
2563{
2564        unsigned int result;
2565
2566        if (sony_call_snc_handle(0x0131, 0x0000, &result) || !(result & 0x01)) {
2567                /* some models advertise the handle but have no implementation
2568                 * for it
2569                 */
2570                pr_info("No High Speed Charging capability found\n");
2571                return 0;
2572        }
2573
2574        hsc_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2575        if (!hsc_handle)
2576                return -ENOMEM;
2577
2578        sysfs_attr_init(&hsc_handle->attr);
2579        hsc_handle->attr.name = "battery_highspeed_charging";
2580        hsc_handle->attr.mode = S_IRUGO | S_IWUSR;
2581        hsc_handle->show = sony_nc_highspeed_charging_show;
2582        hsc_handle->store = sony_nc_highspeed_charging_store;
2583
2584        result = device_create_file(&pd->dev, hsc_handle);
2585        if (result) {
2586                kfree(hsc_handle);
2587                hsc_handle = NULL;
2588                return result;
2589        }
2590
2591        return 0;
2592}
2593
2594static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd)
2595{
2596        if (hsc_handle) {
2597                device_remove_file(&pd->dev, hsc_handle);
2598                kfree(hsc_handle);
2599                hsc_handle = NULL;
2600        }
2601}
2602
2603/* low battery function */
2604static struct device_attribute *lowbatt_handle;
2605
2606static ssize_t sony_nc_lowbatt_store(struct device *dev,
2607                struct device_attribute *attr,
2608                const char *buffer, size_t count)
2609{
2610        unsigned int result;
2611        unsigned long value;
2612
2613        if (count > 31)
2614                return -EINVAL;
2615
2616        if (kstrtoul(buffer, 10, &value) || value > 1)
2617                return -EINVAL;
2618
2619        if (sony_call_snc_handle(0x0121, value << 8, &result))
2620                return -EIO;
2621
2622        return count;
2623}
2624
2625static ssize_t sony_nc_lowbatt_show(struct device *dev,
2626                struct device_attribute *attr, char *buffer)
2627{
2628        unsigned int result;
2629
2630        if (sony_call_snc_handle(0x0121, 0x0200, &result))
2631                return -EIO;
2632
2633        return snprintf(buffer, PAGE_SIZE, "%d\n", result & 1);
2634}
2635
2636static int sony_nc_lowbatt_setup(struct platform_device *pd)
2637{
2638        unsigned int result;
2639
2640        lowbatt_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2641        if (!lowbatt_handle)
2642                return -ENOMEM;
2643
2644        sysfs_attr_init(&lowbatt_handle->attr);
2645        lowbatt_handle->attr.name = "lowbatt_hibernate";
2646        lowbatt_handle->attr.mode = S_IRUGO | S_IWUSR;
2647        lowbatt_handle->show = sony_nc_lowbatt_show;
2648        lowbatt_handle->store = sony_nc_lowbatt_store;
2649
2650        result = device_create_file(&pd->dev, lowbatt_handle);
2651        if (result) {
2652                kfree(lowbatt_handle);
2653                lowbatt_handle = NULL;
2654                return result;
2655        }
2656
2657        return 0;
2658}
2659
2660static void sony_nc_lowbatt_cleanup(struct platform_device *pd)
2661{
2662        if (lowbatt_handle) {
2663                device_remove_file(&pd->dev, lowbatt_handle);
2664                kfree(lowbatt_handle);
2665                lowbatt_handle = NULL;
2666        }
2667}
2668
2669/* fan speed function */
2670static struct device_attribute *fan_handle, *hsf_handle;
2671
2672static ssize_t sony_nc_hsfan_store(struct device *dev,
2673                struct device_attribute *attr,
2674                const char *buffer, size_t count)
2675{
2676        unsigned int result;
2677        unsigned long value;
2678
2679        if (count > 31)
2680                return -EINVAL;
2681
2682        if (kstrtoul(buffer, 10, &value) || value > 1)
2683                return -EINVAL;
2684
2685        if (sony_call_snc_handle(0x0149, value << 0x10 | 0x0200, &result))
2686                return -EIO;
2687
2688        return count;
2689}
2690
2691static ssize_t sony_nc_hsfan_show(struct device *dev,
2692                struct device_attribute *attr, char *buffer)
2693{
2694        unsigned int result;
2695
2696        if (sony_call_snc_handle(0x0149, 0x0100, &result))
2697                return -EIO;
2698
2699        return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01);
2700}
2701
2702static ssize_t sony_nc_fanspeed_show(struct device *dev,
2703                struct device_attribute *attr, char *buffer)
2704{
2705        unsigned int result;
2706
2707        if (sony_call_snc_handle(0x0149, 0x0300, &result))
2708                return -EIO;
2709
2710        return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0xff);
2711}
2712
2713static int sony_nc_fanspeed_setup(struct platform_device *pd)
2714{
2715        unsigned int result;
2716
2717        fan_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2718        if (!fan_handle)
2719                return -ENOMEM;
2720
2721        hsf_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2722        if (!hsf_handle) {
2723                result = -ENOMEM;
2724                goto out_hsf_handle_alloc;
2725        }
2726
2727        sysfs_attr_init(&fan_handle->attr);
2728        fan_handle->attr.name = "fanspeed";
2729        fan_handle->attr.mode = S_IRUGO;
2730        fan_handle->show = sony_nc_fanspeed_show;
2731        fan_handle->store = NULL;
2732
2733        sysfs_attr_init(&hsf_handle->attr);
2734        hsf_handle->attr.name = "fan_forced";
2735        hsf_handle->attr.mode = S_IRUGO | S_IWUSR;
2736        hsf_handle->show = sony_nc_hsfan_show;
2737        hsf_handle->store = sony_nc_hsfan_store;
2738
2739        result = device_create_file(&pd->dev, fan_handle);
2740        if (result)
2741                goto out_fan_handle;
2742
2743        result = device_create_file(&pd->dev, hsf_handle);
2744        if (result)
2745                goto out_hsf_handle;
2746
2747        return 0;
2748
2749out_hsf_handle:
2750        device_remove_file(&pd->dev, fan_handle);
2751
2752out_fan_handle:
2753        kfree(hsf_handle);
2754        hsf_handle = NULL;
2755
2756out_hsf_handle_alloc:
2757        kfree(fan_handle);
2758        fan_handle = NULL;
2759        return result;
2760}
2761
2762static void sony_nc_fanspeed_cleanup(struct platform_device *pd)
2763{
2764        if (fan_handle) {
2765                device_remove_file(&pd->dev, fan_handle);
2766                kfree(fan_handle);
2767                fan_handle = NULL;
2768        }
2769        if (hsf_handle) {
2770                device_remove_file(&pd->dev, hsf_handle);
2771                kfree(hsf_handle);
2772                hsf_handle = NULL;
2773        }
2774}
2775
2776/* USB charge function */
2777static struct device_attribute *uc_handle;
2778
2779static ssize_t sony_nc_usb_charge_store(struct device *dev,
2780                struct device_attribute *attr,
2781                const char *buffer, size_t count)
2782{
2783        unsigned int result;
2784        unsigned long value;
2785
2786        if (count > 31)
2787                return -EINVAL;
2788
2789        if (kstrtoul(buffer, 10, &value) || value > 1)
2790                return -EINVAL;
2791
2792        if (sony_call_snc_handle(0x0155, value << 0x10 | 0x0100, &result))
2793                return -EIO;
2794
2795        return count;
2796}
2797
2798static ssize_t sony_nc_usb_charge_show(struct device *dev,
2799                struct device_attribute *attr, char *buffer)
2800{
2801        unsigned int result;
2802
2803        if (sony_call_snc_handle(0x0155, 0x0000, &result))
2804                return -EIO;
2805
2806        return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01);
2807}
2808
2809static int sony_nc_usb_charge_setup(struct platform_device *pd)
2810{
2811        unsigned int result;
2812
2813        if (sony_call_snc_handle(0x0155, 0x0000, &result) || !(result & 0x01)) {
2814                /* some models advertise the handle but have no implementation
2815                 * for it
2816                 */
2817                pr_info("No USB Charge capability found\n");
2818                return 0;
2819        }
2820
2821        uc_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2822        if (!uc_handle)
2823                return -ENOMEM;
2824
2825        sysfs_attr_init(&uc_handle->attr);
2826        uc_handle->attr.name = "usb_charge";
2827        uc_handle->attr.mode = S_IRUGO | S_IWUSR;
2828        uc_handle->show = sony_nc_usb_charge_show;
2829        uc_handle->store = sony_nc_usb_charge_store;
2830
2831        result = device_create_file(&pd->dev, uc_handle);
2832        if (result) {
2833                kfree(uc_handle);
2834                uc_handle = NULL;
2835                return result;
2836        }
2837
2838        return 0;
2839}
2840
2841static void sony_nc_usb_charge_cleanup(struct platform_device *pd)
2842{
2843        if (uc_handle) {
2844                device_remove_file(&pd->dev, uc_handle);
2845                kfree(uc_handle);
2846                uc_handle = NULL;
2847        }
2848}
2849
2850/* Panel ID function */
2851static struct device_attribute *panel_handle;
2852
2853static ssize_t sony_nc_panelid_show(struct device *dev,
2854                struct device_attribute *attr, char *buffer)
2855{
2856        unsigned int result;
2857
2858        if (sony_call_snc_handle(0x011D, 0x0000, &result))
2859                return -EIO;
2860
2861        return snprintf(buffer, PAGE_SIZE, "%d\n", result);
2862}
2863
2864static int sony_nc_panelid_setup(struct platform_device *pd)
2865{
2866        unsigned int result;
2867
2868        panel_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2869        if (!panel_handle)
2870                return -ENOMEM;
2871
2872        sysfs_attr_init(&panel_handle->attr);
2873        panel_handle->attr.name = "panel_id";
2874        panel_handle->attr.mode = S_IRUGO;
2875        panel_handle->show = sony_nc_panelid_show;
2876        panel_handle->store = NULL;
2877
2878        result = device_create_file(&pd->dev, panel_handle);
2879        if (result) {
2880                kfree(panel_handle);
2881                panel_handle = NULL;
2882                return result;
2883        }
2884
2885        return 0;
2886}
2887
2888static void sony_nc_panelid_cleanup(struct platform_device *pd)
2889{
2890        if (panel_handle) {
2891                device_remove_file(&pd->dev, panel_handle);
2892                kfree(panel_handle);
2893                panel_handle = NULL;
2894        }
2895}
2896
2897/* smart connect function */
2898static struct device_attribute *sc_handle;
2899
2900static ssize_t sony_nc_smart_conn_store(struct device *dev,
2901                struct device_attribute *attr,
2902                const char *buffer, size_t count)
2903{
2904        unsigned int result;
2905        unsigned long value;
2906
2907        if (count > 31)
2908                return -EINVAL;
2909
2910        if (kstrtoul(buffer, 10, &value) || value > 1)
2911                return -EINVAL;
2912
2913        if (sony_call_snc_handle(0x0168, value << 0x10, &result))
2914                return -EIO;
2915
2916        return count;
2917}
2918
2919static int sony_nc_smart_conn_setup(struct platform_device *pd)
2920{
2921        unsigned int result;
2922
2923        sc_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2924        if (!sc_handle)
2925                return -ENOMEM;
2926
2927        sysfs_attr_init(&sc_handle->attr);
2928        sc_handle->attr.name = "smart_connect";
2929        sc_handle->attr.mode = S_IWUSR;
2930        sc_handle->show = NULL;
2931        sc_handle->store = sony_nc_smart_conn_store;
2932
2933        result = device_create_file(&pd->dev, sc_handle);
2934        if (result) {
2935                kfree(sc_handle);
2936                sc_handle = NULL;
2937                return result;
2938        }
2939
2940        return 0;
2941}
2942
2943static void sony_nc_smart_conn_cleanup(struct platform_device *pd)
2944{
2945        if (sc_handle) {
2946                device_remove_file(&pd->dev, sc_handle);
2947                kfree(sc_handle);
2948                sc_handle = NULL;
2949        }
2950}
2951
2952/* Touchpad enable/disable */
2953struct touchpad_control {
2954        struct device_attribute attr;
2955        int handle;
2956};
2957static struct touchpad_control *tp_ctl;
2958
2959static ssize_t sony_nc_touchpad_store(struct device *dev,
2960                struct device_attribute *attr, const char *buffer, size_t count)
2961{
2962        unsigned int result;
2963        unsigned long value;
2964
2965        if (count > 31)
2966                return -EINVAL;
2967
2968        if (kstrtoul(buffer, 10, &value) || value > 1)
2969                return -EINVAL;
2970
2971        /* sysfs: 0 disabled, 1 enabled
2972         * EC: 0 enabled, 1 disabled
2973         */
2974        if (sony_call_snc_handle(tp_ctl->handle,
2975                                (!value << 0x10) | 0x100, &result))
2976                return -EIO;
2977
2978        return count;
2979}
2980
2981static ssize_t sony_nc_touchpad_show(struct device *dev,
2982                struct device_attribute *attr, char *buffer)
2983{
2984        unsigned int result;
2985
2986        if (sony_call_snc_handle(tp_ctl->handle, 0x000, &result))
2987                return -EINVAL;
2988
2989        return snprintf(buffer, PAGE_SIZE, "%d\n", !(result & 0x01));
2990}
2991
2992static int sony_nc_touchpad_setup(struct platform_device *pd,
2993                unsigned int handle)
2994{
2995        int ret = 0;
2996
2997        tp_ctl = kzalloc(sizeof(struct touchpad_control), GFP_KERNEL);
2998        if (!tp_ctl)
2999                return -ENOMEM;
3000
3001        tp_ctl->handle = handle;
3002
3003        sysfs_attr_init(&tp_ctl->attr.attr);
3004        tp_ctl->attr.attr.name = "touchpad";
3005        tp_ctl->attr.attr.mode = S_IRUGO | S_IWUSR;
3006        tp_ctl->attr.show = sony_nc_touchpad_show;
3007        tp_ctl->attr.store = sony_nc_touchpad_store;
3008
3009        ret = device_create_file(&pd->dev, &tp_ctl->attr);
3010        if (ret) {
3011                kfree(tp_ctl);
3012                tp_ctl = NULL;
3013        }
3014
3015        return ret;
3016}
3017
3018static void sony_nc_touchpad_cleanup(struct platform_device *pd)
3019{
3020        if (tp_ctl) {
3021                device_remove_file(&pd->dev, &tp_ctl->attr);
3022                kfree(tp_ctl);
3023                tp_ctl = NULL;
3024        }
3025}
3026
3027static void sony_nc_backlight_ng_read_limits(int handle,
3028                struct sony_backlight_props *props)
3029{
3030        u64 offset;
3031        int i;
3032        int lvl_table_len = 0;
3033        u8 min = 0xff, max = 0x00;
3034        unsigned char buffer[32] = { 0 };
3035
3036        props->handle = handle;
3037        props->offset = 0;
3038        props->maxlvl = 0xff;
3039
3040        offset = sony_find_snc_handle(handle);
3041
3042        /* try to read the boundaries from ACPI tables, if we fail the above
3043         * defaults should be reasonable
3044         */
3045        i = sony_nc_buffer_call(sony_nc_acpi_handle, "SN06", &offset, buffer,
3046                        32);
3047        if (i < 0)
3048                return;
3049
3050        switch (handle) {
3051        case 0x012f:
3052        case 0x0137:
3053                lvl_table_len = 9;
3054                break;
3055        case 0x143:
3056        case 0x14b:
3057        case 0x14c:
3058                lvl_table_len = 16;
3059                break;
3060        }
3061
3062        /* the buffer lists brightness levels available, brightness levels are
3063         * from position 0 to 8 in the array, other values are used by ALS
3064         * control.
3065         */
3066        for (i = 0; i < lvl_table_len && i < ARRAY_SIZE(buffer); i++) {
3067
3068                dprintk("Brightness level: %d\n", buffer[i]);
3069
3070                if (!buffer[i])
3071                        break;
3072
3073                if (buffer[i] > max)
3074                        max = buffer[i];
3075                if (buffer[i] < min)
3076                        min = buffer[i];
3077        }
3078        props->offset = min;
3079        props->maxlvl = max;
3080        dprintk("Brightness levels: min=%d max=%d\n", props->offset,
3081                        props->maxlvl);
3082}
3083
3084static void sony_nc_backlight_setup(void)
3085{
3086        int max_brightness = 0;
3087        const struct backlight_ops *ops = NULL;
3088        struct backlight_properties props;
3089
3090        if (sony_find_snc_handle(0x12f) >= 0) {
3091                ops = &sony_backlight_ng_ops;
3092                sony_bl_props.cmd_base = 0x0100;
3093                sony_nc_backlight_ng_read_limits(0x12f, &sony_bl_props);
3094                max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
3095
3096        } else if (sony_find_snc_handle(0x137) >= 0) {
3097                ops = &sony_backlight_ng_ops;
3098                sony_bl_props.cmd_base = 0x0100;
3099                sony_nc_backlight_ng_read_limits(0x137, &sony_bl_props);
3100                max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
3101
3102        } else if (sony_find_snc_handle(0x143) >= 0) {
3103                ops = &sony_backlight_ng_ops;
3104                sony_bl_props.cmd_base = 0x3000;
3105                sony_nc_backlight_ng_read_limits(0x143, &sony_bl_props);
3106                max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
3107
3108        } else if (sony_find_snc_handle(0x14b) >= 0) {
3109                ops = &sony_backlight_ng_ops;
3110                sony_bl_props.cmd_base = 0x3000;
3111                sony_nc_backlight_ng_read_limits(0x14b, &sony_bl_props);
3112                max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
3113
3114        } else if (sony_find_snc_handle(0x14c) >= 0) {
3115                ops = &sony_backlight_ng_ops;
3116                sony_bl_props.cmd_base = 0x3000;
3117                sony_nc_backlight_ng_read_limits(0x14c, &sony_bl_props);
3118                max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
3119
3120        } else if (acpi_has_method(sony_nc_acpi_handle, "GBRT")) {
3121                ops = &sony_backlight_ops;
3122                max_brightness = SONY_MAX_BRIGHTNESS - 1;
3123
3124        } else
3125                return;
3126
3127        memset(&props, 0, sizeof(struct backlight_properties));
3128        props.type = BACKLIGHT_PLATFORM;
3129        props.max_brightness = max_brightness;
3130        sony_bl_props.dev = backlight_device_register("sony", NULL,
3131                                                      &sony_bl_props,
3132                                                      ops, &props);
3133
3134        if (IS_ERR(sony_bl_props.dev)) {
3135                pr_warn("unable to register backlight device\n");
3136                sony_bl_props.dev = NULL;
3137        } else
3138                sony_bl_props.dev->props.brightness =
3139                        ops->get_brightness(sony_bl_props.dev);
3140}
3141
3142static void sony_nc_backlight_cleanup(void)
3143{
3144        if (sony_bl_props.dev)
3145                backlight_device_unregister(sony_bl_props.dev);
3146}
3147
3148static int sony_nc_add(struct acpi_device *device)
3149{
3150        acpi_status status;
3151        int result = 0;
3152        struct sony_nc_value *item;
3153
3154        sony_nc_acpi_device = device;
3155        strcpy(acpi_device_class(device), "sony/hotkey");
3156
3157        sony_nc_acpi_handle = device->handle;
3158
3159        /* read device status */
3160        result = acpi_bus_get_status(device);
3161        /* bail IFF the above call was successful and the device is not present */
3162        if (!result && !device->status.present) {
3163                dprintk("Device not present\n");
3164                result = -ENODEV;
3165                goto outwalk;
3166        }
3167
3168        result = sony_pf_add();
3169        if (result)
3170                goto outpresent;
3171
3172        if (debug) {
3173                status = acpi_walk_namespace(ACPI_TYPE_METHOD,
3174                                sony_nc_acpi_handle, 1, sony_walk_callback,
3175                                NULL, NULL, NULL);
3176                if (ACPI_FAILURE(status)) {
3177                        pr_warn("unable to walk acpi resources\n");
3178                        result = -ENODEV;
3179                        goto outpresent;
3180                }
3181        }
3182
3183        result = sony_laptop_setup_input(device);
3184        if (result) {
3185                pr_err("Unable to create input devices\n");
3186                goto outplatform;
3187        }
3188
3189        if (acpi_has_method(sony_nc_acpi_handle, "ECON")) {
3190                int arg = 1;
3191                if (sony_nc_int_call(sony_nc_acpi_handle, "ECON", &arg, NULL))
3192                        dprintk("ECON Method failed\n");
3193        }
3194
3195        if (acpi_has_method(sony_nc_acpi_handle, "SN00")) {
3196                dprintk("Doing SNC setup\n");
3197                /* retrieve the available handles */
3198                result = sony_nc_handles_setup(sony_pf_device);
3199                if (!result)
3200                        sony_nc_function_setup(device, sony_pf_device);
3201        }
3202
3203        /* setup input devices and helper fifo */
3204        if (acpi_video_backlight_support()) {
3205                pr_info("brightness ignored, must be controlled by ACPI video driver\n");
3206        } else {
3207                sony_nc_backlight_setup();
3208        }
3209
3210        /* create sony_pf sysfs attributes related to the SNC device */
3211        for (item = sony_nc_values; item->name; ++item) {
3212
3213                if (!debug && item->debug)
3214                        continue;
3215
3216                /* find the available acpiget as described in the DSDT */
3217                for (; item->acpiget && *item->acpiget; ++item->acpiget) {
3218                        if (acpi_has_method(sony_nc_acpi_handle,
3219                                                        *item->acpiget)) {
3220                                dprintk("Found %s getter: %s\n",
3221                                                item->name, *item->acpiget);
3222                                item->devattr.attr.mode |= S_IRUGO;
3223                                break;
3224                        }
3225                }
3226
3227                /* find the available acpiset as described in the DSDT */
3228                for (; item->acpiset && *item->acpiset; ++item->acpiset) {
3229                        if (acpi_has_method(sony_nc_acpi_handle,
3230                                                        *item->acpiset)) {
3231                                dprintk("Found %s setter: %s\n",
3232                                                item->name, *item->acpiset);
3233                                item->devattr.attr.mode |= S_IWUSR;
3234                                break;
3235                        }
3236                }
3237
3238                if (item->devattr.attr.mode != 0) {
3239                        result =
3240                            device_create_file(&sony_pf_device->dev,
3241                                               &item->devattr);
3242                        if (result)
3243                                goto out_sysfs;
3244                }
3245        }
3246
3247        pr_info("SNC setup done.\n");
3248        return 0;
3249
3250out_sysfs:
3251        for (item = sony_nc_values; item->name; ++item) {
3252                device_remove_file(&sony_pf_device->dev, &item->devattr);
3253        }
3254        sony_nc_backlight_cleanup();
3255        sony_nc_function_cleanup(sony_pf_device);
3256        sony_nc_handles_cleanup(sony_pf_device);
3257
3258outplatform:
3259        sony_laptop_remove_input();
3260
3261outpresent:
3262        sony_pf_remove();
3263
3264outwalk:
3265        sony_nc_rfkill_cleanup();
3266        return result;
3267}
3268
3269static int sony_nc_remove(struct acpi_device *device)
3270{
3271        struct sony_nc_value *item;
3272
3273        sony_nc_backlight_cleanup();
3274
3275        sony_nc_acpi_device = NULL;
3276
3277        for (item = sony_nc_values; item->name; ++item) {
3278                device_remove_file(&sony_pf_device->dev, &item->devattr);
3279        }
3280
3281        sony_nc_function_cleanup(sony_pf_device);
3282        sony_nc_handles_cleanup(sony_pf_device);
3283        sony_pf_remove();
3284        sony_laptop_remove_input();
3285        dprintk(SONY_NC_DRIVER_NAME " removed.\n");
3286
3287        return 0;
3288}
3289
3290static const struct acpi_device_id sony_device_ids[] = {
3291        {SONY_NC_HID, 0},
3292        {SONY_PIC_HID, 0},
3293        {"", 0},
3294};
3295MODULE_DEVICE_TABLE(acpi, sony_device_ids);
3296
3297static const struct acpi_device_id sony_nc_device_ids[] = {
3298        {SONY_NC_HID, 0},
3299        {"", 0},
3300};
3301
3302static struct acpi_driver sony_nc_driver = {
3303        .name = SONY_NC_DRIVER_NAME,
3304        .class = SONY_NC_CLASS,
3305        .ids = sony_nc_device_ids,
3306        .owner = THIS_MODULE,
3307        .ops = {
3308                .add = sony_nc_add,
3309                .remove = sony_nc_remove,
3310                .notify = sony_nc_notify,
3311                },
3312        .drv.pm = &sony_nc_pm,
3313};
3314
3315/*********** SPIC (SNY6001) Device ***********/
3316
3317#define SONYPI_DEVICE_TYPE1     0x00000001
3318#define SONYPI_DEVICE_TYPE2     0x00000002
3319#define SONYPI_DEVICE_TYPE3     0x00000004
3320
3321#define SONYPI_TYPE1_OFFSET     0x04
3322#define SONYPI_TYPE2_OFFSET     0x12
3323#define SONYPI_TYPE3_OFFSET     0x12
3324
3325struct sony_pic_ioport {
3326        struct acpi_resource_io io1;
3327        struct acpi_resource_io io2;
3328        struct list_head        list;
3329};
3330
3331struct sony_pic_irq {
3332        struct acpi_resource_irq        irq;
3333        struct list_head                list;
3334};
3335
3336struct sonypi_eventtypes {
3337        u8                      data;
3338        unsigned long           mask;
3339        struct sonypi_event     *events;
3340};
3341
3342struct sony_pic_dev {
3343        struct acpi_device              *acpi_dev;
3344        struct sony_pic_irq             *cur_irq;
3345        struct sony_pic_ioport          *cur_ioport;
3346        struct list_head                interrupts;
3347        struct list_head                ioports;
3348        struct mutex                    lock;
3349        struct sonypi_eventtypes        *event_types;
3350        int                             (*handle_irq)(const u8, const u8);
3351        int                             model;
3352        u16                             evport_offset;
3353        u8                              camera_power;
3354        u8                              bluetooth_power;
3355        u8                              wwan_power;
3356};
3357
3358static struct sony_pic_dev spic_dev = {
3359        .interrupts     = LIST_HEAD_INIT(spic_dev.interrupts),
3360        .ioports        = LIST_HEAD_INIT(spic_dev.ioports),
3361};
3362
3363static int spic_drv_registered;
3364
3365/* Event masks */
3366#define SONYPI_JOGGER_MASK                      0x00000001
3367#define SONYPI_CAPTURE_MASK                     0x00000002
3368#define SONYPI_FNKEY_MASK                       0x00000004
3369#define SONYPI_BLUETOOTH_MASK                   0x00000008
3370#define SONYPI_PKEY_MASK                        0x00000010
3371#define SONYPI_BACK_MASK                        0x00000020
3372#define SONYPI_HELP_MASK                        0x00000040
3373#define SONYPI_LID_MASK                         0x00000080
3374#define SONYPI_ZOOM_MASK                        0x00000100
3375#define SONYPI_THUMBPHRASE_MASK                 0x00000200
3376#define SONYPI_MEYE_MASK                        0x00000400
3377#define SONYPI_MEMORYSTICK_MASK                 0x00000800
3378#define SONYPI_BATTERY_MASK                     0x00001000
3379#define SONYPI_WIRELESS_MASK                    0x00002000
3380
3381struct sonypi_event {
3382        u8      data;
3383        u8      event;
3384};
3385
3386/* The set of possible button release events */
3387static struct sonypi_event sonypi_releaseev[] = {
3388        { 0x00, SONYPI_EVENT_ANYBUTTON_RELEASED },
3389        { 0, 0 }
3390};
3391
3392/* The set of possible jogger events  */
3393static struct sonypi_event sonypi_joggerev[] = {
3394        { 0x1f, SONYPI_EVENT_JOGDIAL_UP },
3395        { 0x01, SONYPI_EVENT_JOGDIAL_DOWN },
3396        { 0x5f, SONYPI_EVENT_JOGDIAL_UP_PRESSED },
3397        { 0x41, SONYPI_EVENT_JOGDIAL_DOWN_PRESSED },
3398        { 0x1e, SONYPI_EVENT_JOGDIAL_FAST_UP },
3399        { 0x02, SONYPI_EVENT_JOGDIAL_FAST_DOWN },
3400        { 0x5e, SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED },
3401        { 0x42, SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED },
3402        { 0x1d, SONYPI_EVENT_JOGDIAL_VFAST_UP },
3403        { 0x03, SONYPI_EVENT_JOGDIAL_VFAST_DOWN },
3404        { 0x5d, SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED },
3405        { 0x43, SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED },
3406        { 0x40, SONYPI_EVENT_JOGDIAL_PRESSED },
3407        { 0, 0 }
3408};
3409
3410/* The set of possible capture button events */
3411static struct sonypi_event sonypi_captureev[] = {
3412        { 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED },
3413        { 0x07, SONYPI_EVENT_CAPTURE_PRESSED },
3414        { 0x40, SONYPI_EVENT_CAPTURE_PRESSED },
3415        { 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED },
3416        { 0, 0 }
3417};
3418
3419/* The set of possible fnkeys events */
3420static struct sonypi_event sonypi_fnkeyev[] = {
3421        { 0x10, SONYPI_EVENT_FNKEY_ESC },
3422        { 0x11, SONYPI_EVENT_FNKEY_F1 },
3423        { 0x12, SONYPI_EVENT_FNKEY_F2 },
3424        { 0x13, SONYPI_EVENT_FNKEY_F3 },
3425        { 0x14, SONYPI_EVENT_FNKEY_F4 },
3426        { 0x15, SONYPI_EVENT_FNKEY_F5 },
3427        { 0x16, SONYPI_EVENT_FNKEY_F6 },
3428        { 0x17, SONYPI_EVENT_FNKEY_F7 },
3429        { 0x18, SONYPI_EVENT_FNKEY_F8 },
3430        { 0x19, SONYPI_EVENT_FNKEY_F9 },
3431        { 0x1a, SONYPI_EVENT_FNKEY_F10 },
3432        { 0x1b, SONYPI_EVENT_FNKEY_F11 },
3433        { 0x1c, SONYPI_EVENT_FNKEY_F12 },
3434        { 0x1f, SONYPI_EVENT_FNKEY_RELEASED },
3435        { 0x21, SONYPI_EVENT_FNKEY_1 },
3436        { 0x22, SONYPI_EVENT_FNKEY_2 },
3437        { 0x31, SONYPI_EVENT_FNKEY_D },
3438        { 0x32, SONYPI_EVENT_FNKEY_E },
3439        { 0x33, SONYPI_EVENT_FNKEY_F },
3440        { 0x34, SONYPI_EVENT_FNKEY_S },
3441        { 0x35, SONYPI_EVENT_FNKEY_B },
3442        { 0x36, SONYPI_EVENT_FNKEY_ONLY },
3443        { 0, 0 }
3444};
3445
3446/* The set of possible program key events */
3447static struct sonypi_event sonypi_pkeyev[] = {
3448        { 0x01, SONYPI_EVENT_PKEY_P1 },
3449        { 0x02, SONYPI_EVENT_PKEY_P2 },
3450        { 0x04, SONYPI_EVENT_PKEY_P3 },
3451        { 0x20, SONYPI_EVENT_PKEY_P1 },
3452        { 0, 0 }
3453};
3454
3455/* The set of possible bluetooth events */
3456static struct sonypi_event sonypi_blueev[] = {
3457        { 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED },
3458        { 0x59, SONYPI_EVENT_BLUETOOTH_ON },
3459        { 0x5a, SONYPI_EVENT_BLUETOOTH_OFF },
3460        { 0, 0 }
3461};
3462
3463/* The set of possible wireless events */
3464static struct sonypi_event sonypi_wlessev[] = {
3465        { 0x59, SONYPI_EVENT_IGNORE },
3466        { 0x5a, SONYPI_EVENT_IGNORE },
3467        { 0, 0 }
3468};
3469
3470/* The set of possible back button events */
3471static struct sonypi_event sonypi_backev[] = {
3472        { 0x20, SONYPI_EVENT_BACK_PRESSED },
3473        { 0, 0 }
3474};
3475
3476/* The set of possible help button events */
3477static struct sonypi_event sonypi_helpev[] = {
3478        { 0x3b, SONYPI_EVENT_HELP_PRESSED },
3479        { 0, 0 }
3480};
3481
3482
3483/* The set of possible lid events */
3484static struct sonypi_event sonypi_lidev[] = {
3485        { 0x51, SONYPI_EVENT_LID_CLOSED },
3486        { 0x50, SONYPI_EVENT_LID_OPENED },
3487        { 0, 0 }
3488};
3489
3490/* The set of possible zoom events */
3491static struct sonypi_event sonypi_zoomev[] = {
3492        { 0x39, SONYPI_EVENT_ZOOM_PRESSED },
3493        { 0x10, SONYPI_EVENT_ZOOM_IN_PRESSED },
3494        { 0x20, SONYPI_EVENT_ZOOM_OUT_PRESSED },
3495        { 0x04, SONYPI_EVENT_ZOOM_PRESSED },
3496        { 0, 0 }
3497};
3498
3499/* The set of possible thumbphrase events */
3500static struct sonypi_event sonypi_thumbphraseev[] = {
3501        { 0x3a, SONYPI_EVENT_THUMBPHRASE_PRESSED },
3502        { 0, 0 }
3503};
3504
3505/* The set of possible motioneye camera events */
3506static struct sonypi_event sonypi_meyeev[] = {
3507        { 0x00, SONYPI_EVENT_MEYE_FACE },
3508        { 0x01, SONYPI_EVENT_MEYE_OPPOSITE },
3509        { 0, 0 }
3510};
3511
3512/* The set of possible memorystick events */
3513static struct sonypi_event sonypi_memorystickev[] = {
3514        { 0x53, SONYPI_EVENT_MEMORYSTICK_INSERT },
3515        { 0x54, SONYPI_EVENT_MEMORYSTICK_EJECT },
3516        { 0, 0 }
3517};
3518
3519/* The set of possible battery events */
3520static struct sonypi_event sonypi_batteryev[] = {
3521        { 0x20, SONYPI_EVENT_BATTERY_INSERT },
3522        { 0x30, SONYPI_EVENT_BATTERY_REMOVE },
3523        { 0, 0 }
3524};
3525
3526/* The set of possible volume events */
3527static struct sonypi_event sonypi_volumeev[] = {
3528        { 0x01, SONYPI_EVENT_VOLUME_INC_PRESSED },
3529        { 0x02, SONYPI_EVENT_VOLUME_DEC_PRESSED },
3530        { 0, 0 }
3531};
3532
3533/* The set of possible brightness events */
3534static struct sonypi_event sonypi_brightnessev[] = {
3535        { 0x80, SONYPI_EVENT_BRIGHTNESS_PRESSED },
3536        { 0, 0 }
3537};
3538
3539static struct sonypi_eventtypes type1_events[] = {
3540        { 0, 0xffffffff, sonypi_releaseev },
3541        { 0x70, SONYPI_MEYE_MASK, sonypi_meyeev },
3542        { 0x30, SONYPI_LID_MASK, sonypi_lidev },
3543        { 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev },
3544        { 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev },
3545        { 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
3546        { 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
3547        { 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
3548        { 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
3549        { 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev },
3550        { 0 },
3551};
3552static struct sonypi_eventtypes type2_events[] = {
3553        { 0, 0xffffffff, sonypi_releaseev },
3554        { 0x38, SONYPI_LID_MASK, sonypi_lidev },
3555        { 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev },
3556        { 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev },
3557        { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
3558        { 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
3559        { 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
3560        { 0x11, SONYPI_BACK_MASK, sonypi_backev },
3561        { 0x21, SONYPI_HELP_MASK, sonypi_helpev },
3562        { 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev },
3563        { 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
3564        { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
3565        { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
3566        { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
3567        { 0 },
3568};
3569static struct sonypi_eventtypes type3_events[] = {
3570        { 0, 0xffffffff, sonypi_releaseev },
3571        { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
3572        { 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
3573        { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
3574        { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
3575        { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
3576        { 0x05, SONYPI_PKEY_MASK, sonypi_pkeyev },
3577        { 0x05, SONYPI_ZOOM_MASK, sonypi_zoomev },
3578        { 0x05, SONYPI_CAPTURE_MASK, sonypi_captureev },
3579        { 0x05, SONYPI_PKEY_MASK, sonypi_volumeev },
3580        { 0x05, SONYPI_PKEY_MASK, sonypi_brightnessev },
3581        { 0 },
3582};
3583
3584/* low level spic calls */
3585#define ITERATIONS_LONG         10000
3586#define ITERATIONS_SHORT        10
3587#define wait_on_command(command, iterations) {                          \
3588        unsigned int n = iterations;                                    \
3589        while (--n && (command))                                        \
3590                udelay(1);                                              \
3591        if (!n)                                                         \
3592                dprintk("command failed at %s : %s (line %d)\n",        \
3593                                __FILE__, __func__, __LINE__);  \
3594}
3595
3596static u8 sony_pic_call1(u8 dev)
3597{
3598        u8 v1, v2;
3599
3600        wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
3601                        ITERATIONS_LONG);
3602        outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
3603        v1 = inb_p(spic_dev.cur_ioport->io1.minimum + 4);
3604        v2 = inb_p(spic_dev.cur_ioport->io1.minimum);
3605        dprintk("sony_pic_call1(0x%.2x): 0x%.4x\n", dev, (v2 << 8) | v1);
3606        return v2;
3607}
3608
3609static u8 sony_pic_call2(u8 dev, u8 fn)
3610{
3611        u8 v1;
3612
3613        wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
3614                        ITERATIONS_LONG);
3615        outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
3616        wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
3617                        ITERATIONS_LONG);
3618        outb(fn, spic_dev.cur_ioport->io1.minimum);
3619        v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
3620        dprintk("sony_pic_call2(0x%.2x - 0x%.2x): 0x%.4x\n", dev, fn, v1);
3621        return v1;
3622}
3623
3624static u8 sony_pic_call3(u8 dev, u8 fn, u8 v)
3625{
3626        u8 v1;
3627
3628        wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
3629        outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
3630        wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
3631        outb(fn, spic_dev.cur_ioport->io1.minimum);
3632        wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
3633        outb(v, spic_dev.cur_ioport->io1.minimum);
3634        v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
3635        dprintk("sony_pic_call3(0x%.2x - 0x%.2x - 0x%.2x): 0x%.4x\n",
3636                        dev, fn, v, v1);
3637        return v1;
3638}
3639
3640/*
3641 * minidrivers for SPIC models
3642 */
3643static int type3_handle_irq(const u8 data_mask, const u8 ev)
3644{
3645        /*
3646         * 0x31 could mean we have to take some extra action and wait for
3647         * the next irq for some Type3 models, it will generate a new
3648         * irq and we can read new data from the device:
3649         *  - 0x5c and 0x5f requires 0xA0
3650         *  - 0x61 requires 0xB3
3651         */
3652        if (data_mask == 0x31) {
3653                if (ev == 0x5c || ev == 0x5f)
3654                        sony_pic_call1(0xA0);
3655                else if (ev == 0x61)
3656                        sony_pic_call1(0xB3);
3657                return 0;
3658        }
3659        return 1;
3660}
3661
3662static void sony_pic_detect_device_type(struct sony_pic_dev *dev)
3663{
3664        struct pci_dev *pcidev;
3665
3666        pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
3667                        PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
3668        if (pcidev) {
3669                dev->model = SONYPI_DEVICE_TYPE1;
3670                dev->evport_offset = SONYPI_TYPE1_OFFSET;
3671                dev->event_types = type1_events;
3672                goto out;
3673        }
3674
3675        pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
3676                        PCI_DEVICE_ID_INTEL_ICH6_1, NULL);
3677        if (pcidev) {
3678                dev->model = SONYPI_DEVICE_TYPE2;
3679                dev->evport_offset = SONYPI_TYPE2_OFFSET;
3680                dev->event_types = type2_events;
3681                goto out;
3682        }
3683
3684        pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
3685                        PCI_DEVICE_ID_INTEL_ICH7_1, NULL);
3686        if (pcidev) {
3687                dev->model = SONYPI_DEVICE_TYPE3;
3688                dev->handle_irq = type3_handle_irq;
3689                dev->evport_offset = SONYPI_TYPE3_OFFSET;
3690                dev->event_types = type3_events;
3691                goto out;
3692        }
3693
3694        pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
3695                        PCI_DEVICE_ID_INTEL_ICH8_4, NULL);
3696        if (pcidev) {
3697                dev->model = SONYPI_DEVICE_TYPE3;
3698                dev->handle_irq = type3_handle_irq;
3699                dev->evport_offset = SONYPI_TYPE3_OFFSET;
3700                dev->event_types = type3_events;
3701                goto out;
3702        }
3703
3704        pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
3705                        PCI_DEVICE_ID_INTEL_ICH9_1, NULL);
3706        if (pcidev) {
3707                dev->model = SONYPI_DEVICE_TYPE3;
3708                dev->handle_irq = type3_handle_irq;
3709                dev->evport_offset = SONYPI_TYPE3_OFFSET;
3710                dev->event_types = type3_events;
3711                goto out;
3712        }
3713
3714        /* default */
3715        dev->model = SONYPI_DEVICE_TYPE2;
3716        dev->evport_offset = SONYPI_TYPE2_OFFSET;
3717        dev->event_types = type2_events;
3718
3719out:
3720        if (pcidev)
3721                pci_dev_put(pcidev);
3722
3723        pr_info("detected Type%d model\n",
3724                dev->model == SONYPI_DEVICE_TYPE1 ? 1 :
3725                dev->model == SONYPI_DEVICE_TYPE2 ? 2 : 3);
3726}
3727
3728/* camera tests and poweron/poweroff */
3729#define SONYPI_CAMERA_PICTURE           5
3730#define SONYPI_CAMERA_CONTROL           0x10
3731
3732#define SONYPI_CAMERA_BRIGHTNESS                0
3733#define SONYPI_CAMERA_CONTRAST                  1
3734#define SONYPI_CAMERA_HUE                       2
3735#define SONYPI_CAMERA_COLOR                     3
3736#define SONYPI_CAMERA_SHARPNESS                 4
3737
3738#define SONYPI_CAMERA_EXPOSURE_MASK             0xC
3739#define SONYPI_CAMERA_WHITE_BALANCE_MASK        0x3
3740#define SONYPI_CAMERA_PICTURE_MODE_MASK         0x30
3741#define SONYPI_CAMERA_MUTE_MASK                 0x40
3742
3743/* the rest don't need a loop until not 0xff */
3744#define SONYPI_CAMERA_AGC                       6
3745#define SONYPI_CAMERA_AGC_MASK                  0x30
3746#define SONYPI_CAMERA_SHUTTER_MASK              0x7
3747
3748#define SONYPI_CAMERA_SHUTDOWN_REQUEST          7
3749#define SONYPI_CAMERA_CONTROL                   0x10
3750
3751#define SONYPI_CAMERA_STATUS                    7
3752#define SONYPI_CAMERA_STATUS_READY              0x2
3753#define SONYPI_CAMERA_STATUS_POSITION           0x4
3754
3755#define SONYPI_DIRECTION_BACKWARDS              0x4
3756
3757#define SONYPI_CAMERA_REVISION                  8
3758#define SONYPI_CAMERA_ROMVERSION                9
3759
3760static int __sony_pic_camera_ready(void)
3761{
3762        u8 v;
3763
3764        v = sony_pic_call2(0x8f, SONYPI_CAMERA_STATUS);
3765        return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY));
3766}
3767
3768static int __sony_pic_camera_off(void)
3769{
3770        if (!camera) {
3771                pr_warn("camera control not enabled\n");
3772                return -ENODEV;
3773        }
3774
3775        wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE,
3776                                SONYPI_CAMERA_MUTE_MASK),
3777                        ITERATIONS_SHORT);
3778
3779        if (spic_dev.camera_power) {
3780                sony_pic_call2(0x91, 0);
3781                spic_dev.camera_power = 0;
3782        }
3783        return 0;
3784}
3785
3786static int __sony_pic_camera_on(void)
3787{
3788        int i, j, x;
3789
3790        if (!camera) {
3791                pr_warn("camera control not enabled\n");
3792                return -ENODEV;
3793        }
3794
3795        if (spic_dev.camera_power)
3796                return 0;
3797
3798        for (j = 5; j > 0; j--) {
3799
3800                for (x = 0; x < 100 && sony_pic_call2(0x91, 0x1); x++)
3801                        msleep(10);
3802                sony_pic_call1(0x93);
3803
3804                for (i = 400; i > 0; i--) {
3805                        if (__sony_pic_camera_ready())
3806                                break;
3807                        msleep(10);
3808                }
3809                if (i)
3810                        break;
3811        }
3812
3813        if (j == 0) {
3814                pr_warn("failed to power on camera\n");
3815                return -ENODEV;
3816        }
3817
3818        wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTROL,
3819                                0x5a),
3820                        ITERATIONS_SHORT);
3821
3822        spic_dev.camera_power = 1;
3823        return 0;
3824}
3825
3826/* External camera command (exported to the motion eye v4l driver) */
3827int sony_pic_camera_command(int command, u8 value)
3828{
3829        if (!camera)
3830                return -EIO;
3831
3832        mutex_lock(&spic_dev.lock);
3833
3834        switch (command) {
3835        case SONY_PIC_COMMAND_SETCAMERA:
3836                if (value)
3837                        __sony_pic_camera_on();
3838                else
3839                        __sony_pic_camera_off();
3840                break;
3841        case SONY_PIC_COMMAND_SETCAMERABRIGHTNESS:
3842                wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_BRIGHTNESS, value),
3843                                ITERATIONS_SHORT);
3844                break;
3845        case SONY_PIC_COMMAND_SETCAMERACONTRAST:
3846                wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTRAST, value),
3847                                ITERATIONS_SHORT);
3848                break;
3849        case SONY_PIC_COMMAND_SETCAMERAHUE:
3850                wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_HUE, value),
3851                                ITERATIONS_SHORT);
3852                break;
3853        case SONY_PIC_COMMAND_SETCAMERACOLOR:
3854                wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_COLOR, value),
3855                                ITERATIONS_SHORT);
3856                break;
3857        case SONY_PIC_COMMAND_SETCAMERASHARPNESS:
3858                wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_SHARPNESS, value),
3859                                ITERATIONS_SHORT);
3860                break;
3861        case SONY_PIC_COMMAND_SETCAMERAPICTURE:
3862                wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE, value),
3863                                ITERATIONS_SHORT);
3864                break;
3865        case SONY_PIC_COMMAND_SETCAMERAAGC:
3866                wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_AGC, value),
3867                                ITERATIONS_SHORT);
3868                break;
3869        default:
3870                pr_err("sony_pic_camera_command invalid: %d\n", command);
3871                break;
3872        }
3873        mutex_unlock(&spic_dev.lock);
3874        return 0;
3875}
3876EXPORT_SYMBOL(sony_pic_camera_command);
3877
3878/* gprs/edge modem (SZ460N and SZ210P), thanks to Joshua Wise */
3879static void __sony_pic_set_wwanpower(u8 state)
3880{
3881        state = !!state;
3882        if (spic_dev.wwan_power == state)
3883                return;
3884        sony_pic_call2(0xB0, state);
3885        sony_pic_call1(0x82);
3886        spic_dev.wwan_power = state;
3887}
3888
3889static ssize_t sony_pic_wwanpower_store(struct device *dev,
3890                struct device_attribute *attr,
3891                const char *buffer, size_t count)
3892{
3893        unsigned long value;
3894        if (count > 31)
3895                return -EINVAL;
3896
3897        if (kstrtoul(buffer, 10, &value))
3898                return -EINVAL;
3899
3900        mutex_lock(&spic_dev.lock);
3901        __sony_pic_set_wwanpower(value);
3902        mutex_unlock(&spic_dev.lock);
3903
3904        return count;
3905}
3906
3907static ssize_t sony_pic_wwanpower_show(struct device *dev,
3908                struct device_attribute *attr, char *buffer)
3909{
3910        ssize_t count;
3911        mutex_lock(&spic_dev.lock);
3912        count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.wwan_power);
3913        mutex_unlock(&spic_dev.lock);
3914        return count;
3915}
3916
3917/* bluetooth subsystem power state */
3918static void __sony_pic_set_bluetoothpower(u8 state)
3919{
3920        state = !!state;
3921        if (spic_dev.bluetooth_power == state)
3922                return;
3923        sony_pic_call2(0x96, state);
3924        sony_pic_call1(0x82);
3925        spic_dev.bluetooth_power = state;
3926}
3927
3928static ssize_t sony_pic_bluetoothpower_store(struct device *dev,
3929                struct device_attribute *attr,
3930                const char *buffer, size_t count)
3931{
3932        unsigned long value;
3933        if (count > 31)
3934                return -EINVAL;
3935
3936        if (kstrtoul(buffer, 10, &value))
3937                return -EINVAL;
3938
3939        mutex_lock(&spic_dev.lock);
3940        __sony_pic_set_bluetoothpower(value);
3941        mutex_unlock(&spic_dev.lock);
3942
3943        return count;
3944}
3945
3946static ssize_t sony_pic_bluetoothpower_show(struct device *dev,
3947                struct device_attribute *attr, char *buffer)
3948{
3949        ssize_t count = 0;
3950        mutex_lock(&spic_dev.lock);
3951        count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.bluetooth_power);
3952        mutex_unlock(&spic_dev.lock);
3953        return count;
3954}
3955
3956/* fan speed */
3957/* FAN0 information (reverse engineered from ACPI tables) */
3958#define SONY_PIC_FAN0_STATUS    0x93
3959static int sony_pic_set_fanspeed(unsigned long value)
3960{
3961        return ec_write(SONY_PIC_FAN0_STATUS, value);
3962}
3963
3964static int sony_pic_get_fanspeed(u8 *value)
3965{
3966        return ec_read(SONY_PIC_FAN0_STATUS, value);
3967}
3968
3969static ssize_t sony_pic_fanspeed_store(struct device *dev,
3970                struct device_attribute *attr,
3971                const char *buffer, size_t count)
3972{
3973        unsigned long value;
3974        if (count > 31)
3975                return -EINVAL;
3976
3977        if (kstrtoul(buffer, 10, &value))
3978                return -EINVAL;
3979
3980        if (sony_pic_set_fanspeed(value))
3981                return -EIO;
3982
3983        return count;
3984}
3985
3986static ssize_t sony_pic_fanspeed_show(struct device *dev,
3987                struct device_attribute *attr, char *buffer)
3988{
3989        u8 value = 0;
3990        if (sony_pic_get_fanspeed(&value))
3991                return -EIO;
3992
3993        return snprintf(buffer, PAGE_SIZE, "%d\n", value);
3994}
3995
3996#define SPIC_ATTR(_name, _mode)                                 \
3997struct device_attribute spic_attr_##_name = __ATTR(_name,       \
3998                _mode, sony_pic_## _name ##_show,               \
3999                sony_pic_## _name ##_store)
4000
4001static SPIC_ATTR(bluetoothpower, 0644);
4002static SPIC_ATTR(wwanpower, 0644);
4003static SPIC_ATTR(fanspeed, 0644);
4004
4005static struct attribute *spic_attributes[] = {
4006        &spic_attr_bluetoothpower.attr,
4007        &spic_attr_wwanpower.attr,
4008        &spic_attr_fanspeed.attr,
4009        NULL
4010};
4011
4012static struct attribute_group spic_attribute_group = {
4013        .attrs = spic_attributes
4014};
4015
4016/******** SONYPI compatibility **********/
4017#ifdef CONFIG_SONYPI_COMPAT
4018
4019/* battery / brightness / temperature  addresses */
4020#define SONYPI_BAT_FLAGS        0x81
4021#define SONYPI_LCD_LIGHT        0x96
4022#define SONYPI_BAT1_PCTRM       0xa0
4023#define SONYPI_BAT1_LEFT        0xa2
4024#define SONYPI_BAT1_MAXRT       0xa4
4025#define SONYPI_BAT2_PCTRM       0xa8
4026#define SONYPI_BAT2_LEFT        0xaa
4027#define SONYPI_BAT2_MAXRT       0xac
4028#define SONYPI_BAT1_MAXTK       0xb0
4029#define SONYPI_BAT1_FULL        0xb2
4030#define SONYPI_BAT2_MAXTK       0xb8
4031#define SONYPI_BAT2_FULL        0xba
4032#define SONYPI_TEMP_STATUS      0xC1
4033
4034struct sonypi_compat_s {
4035        struct fasync_struct    *fifo_async;
4036        struct kfifo            fifo;
4037        spinlock_t              fifo_lock;
4038        wait_queue_head_t       fifo_proc_list;
4039        atomic_t                open_count;
4040};
4041static struct sonypi_compat_s sonypi_compat = {
4042        .open_count = ATOMIC_INIT(0),
4043};
4044
4045static int sonypi_misc_fasync(int fd, struct file *filp, int on)
4046{
4047        return fasync_helper(fd, filp, on, &sonypi_compat.fifo_async);
4048}
4049
4050static int sonypi_misc_release(struct inode *inode, struct file *file)
4051{
4052        atomic_dec(&sonypi_compat.open_count);
4053        return 0;
4054}
4055
4056static int sonypi_misc_open(struct inode *inode, struct file *file)
4057{
4058        /* Flush input queue on first open */
4059        unsigned long flags;
4060
4061        spin_lock_irqsave(&sonypi_compat.fifo_lock, flags);
4062
4063        if (atomic_inc_return(&sonypi_compat.open_count) == 1)
4064                kfifo_reset(&sonypi_compat.fifo);
4065
4066        spin_unlock_irqrestore(&sonypi_compat.fifo_lock, flags);
4067
4068        return 0;
4069}
4070
4071static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
4072                                size_t count, loff_t *pos)
4073{
4074        ssize_t ret;
4075        unsigned char c;
4076
4077        if ((kfifo_len(&sonypi_compat.fifo) == 0) &&
4078            (file->f_flags & O_NONBLOCK))
4079                return -EAGAIN;
4080
4081        ret = wait_event_interruptible(sonypi_compat.fifo_proc_list,
4082                                       kfifo_len(&sonypi_compat.fifo) != 0);
4083        if (ret)
4084                return ret;
4085
4086        while (ret < count &&
4087               (kfifo_out_locked(&sonypi_compat.fifo, &c, sizeof(c),
4088                          &sonypi_compat.fifo_lock) == sizeof(c))) {
4089                if (put_user(c, buf++))
4090                        return -EFAULT;
4091                ret++;
4092        }
4093
4094        if (ret > 0) {
4095                struct inode *inode = file_inode(file);
4096                inode->i_atime = current_fs_time(inode->i_sb);
4097        }
4098
4099        return ret;
4100}
4101
4102static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait)
4103{
4104        poll_wait(file, &sonypi_compat.fifo_proc_list, wait);
4105        if (kfifo_len(&sonypi_compat.fifo))
4106                return POLLIN | POLLRDNORM;
4107        return 0;
4108}
4109
4110static int ec_read16(u8 addr, u16 *value)
4111{
4112        u8 val_lb, val_hb;
4113        if (ec_read(addr, &val_lb))
4114                return -1;
4115        if (ec_read(addr + 1, &val_hb))
4116                return -1;
4117        *value = val_lb | (val_hb << 8);
4118        return 0;
4119}
4120
4121static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd,
4122                                                        unsigned long arg)
4123{
4124        int ret = 0;
4125        void __user *argp = (void __user *)arg;
4126        u8 val8;
4127        u16 val16;
4128        int value;
4129
4130        mutex_lock(&spic_dev.lock);
4131        switch (cmd) {
4132        case SONYPI_IOCGBRT:
4133                if (sony_bl_props.dev == NULL) {
4134                        ret = -EIO;
4135                        break;
4136                }
4137                if (sony_nc_int_call(sony_nc_acpi_handle, "GBRT", NULL,
4138                                        &value)) {
4139                        ret = -EIO;
4140                        break;
4141                }
4142                val8 = ((value & 0xff) - 1) << 5;
4143                if (copy_to_user(argp, &val8, sizeof(val8)))
4144                                ret = -EFAULT;
4145                break;
4146        case SONYPI_IOCSBRT:
4147                if (sony_bl_props.dev == NULL) {
4148                        ret = -EIO;
4149                        break;
4150                }
4151                if (copy_from_user(&val8, argp, sizeof(val8))) {
4152                        ret = -EFAULT;
4153                        break;
4154                }
4155                value = (val8 >> 5) + 1;
4156                if (sony_nc_int_call(sony_nc_acpi_handle, "SBRT", &value,
4157                                        NULL)) {
4158                        ret = -EIO;
4159                        break;
4160                }
4161                /* sync the backlight device status */
4162                sony_bl_props.dev->props.brightness =
4163                    sony_backlight_get_brightness(sony_bl_props.dev);
4164                break;
4165        case SONYPI_IOCGBAT1CAP:
4166                if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
4167                        ret = -EIO;
4168                        break;
4169                }
4170                if (copy_to_user(argp, &val16, sizeof(val16)))
4171                        ret = -EFAULT;
4172                break;
4173        case SONYPI_IOCGBAT1REM:
4174                if (ec_read16(SONYPI_BAT1_LEFT, &val16)) {
4175                        ret = -EIO;
4176                        break;
4177                }
4178                if (copy_to_user(argp, &val16, sizeof(val16)))
4179                        ret = -EFAULT;
4180                break;
4181        case SONYPI_IOCGBAT2CAP:
4182                if (ec_read16(SONYPI_BAT2_FULL, &val16)) {
4183                        ret = -EIO;
4184                        break;
4185                }
4186                if (copy_to_user(argp, &val16, sizeof(val16)))
4187                        ret = -EFAULT;
4188                break;
4189        case SONYPI_IOCGBAT2REM:
4190                if (ec_read16(SONYPI_BAT2_LEFT, &val16)) {
4191                        ret = -EIO;
4192                        break;
4193                }
4194                if (copy_to_user(argp, &val16, sizeof(val16)))
4195                        ret = -EFAULT;
4196                break;
4197        case SONYPI_IOCGBATFLAGS:
4198                if (ec_read(SONYPI_BAT_FLAGS, &val8)) {
4199                        ret = -EIO;
4200                        break;
4201                }
4202                val8 &= 0x07;
4203                if (copy_to_user(argp, &val8, sizeof(val8)))
4204                        ret = -EFAULT;
4205                break;
4206        case SONYPI_IOCGBLUE:
4207                val8 = spic_dev.bluetooth_power;
4208                if (copy_to_user(argp, &val8, sizeof(val8)))
4209                        ret = -EFAULT;
4210                break;
4211        case SONYPI_IOCSBLUE:
4212                if (copy_from_user(&val8, argp, sizeof(val8))) {
4213                        ret = -EFAULT;
4214                        break;
4215                }
4216                __sony_pic_set_bluetoothpower(val8);
4217                break;
4218        /* FAN Controls */
4219        case SONYPI_IOCGFAN:
4220                if (sony_pic_get_fanspeed(&val8)) {
4221                        ret = -EIO;
4222                        break;
4223                }
4224                if (copy_to_user(argp, &val8, sizeof(val8)))
4225                        ret = -EFAULT;
4226                break;
4227        case SONYPI_IOCSFAN:
4228                if (copy_from_user(&val8, argp, sizeof(val8))) {
4229                        ret = -EFAULT;
4230                        break;
4231                }
4232                if (sony_pic_set_fanspeed(val8))
4233                        ret = -EIO;
4234                break;
4235        /* GET Temperature (useful under APM) */
4236        case SONYPI_IOCGTEMP:
4237                if (ec_read(SONYPI_TEMP_STATUS, &val8)) {
4238                        ret = -EIO;
4239                        break;
4240                }
4241                if (copy_to_user(argp, &val8, sizeof(val8)))
4242                        ret = -EFAULT;
4243                break;
4244        default:
4245                ret = -EINVAL;
4246        }
4247        mutex_unlock(&spic_dev.lock);
4248        return ret;
4249}
4250
4251static const struct file_operations sonypi_misc_fops = {
4252        .owner          = THIS_MODULE,
4253        .read           = sonypi_misc_read,
4254        .poll           = sonypi_misc_poll,
4255        .open           = sonypi_misc_open,
4256        .release        = sonypi_misc_release,
4257        .fasync         = sonypi_misc_fasync,
4258        .unlocked_ioctl = sonypi_misc_ioctl,
4259        .llseek         = noop_llseek,
4260};
4261
4262static struct miscdevice sonypi_misc_device = {
4263        .minor          = MISC_DYNAMIC_MINOR,
4264        .name           = "sonypi",
4265        .fops           = &sonypi_misc_fops,
4266};
4267
4268static void sonypi_compat_report_event(u8 event)
4269{
4270        kfifo_in_locked(&sonypi_compat.fifo, (unsigned char *)&event,
4271                        sizeof(event), &sonypi_compat.fifo_lock);
4272        kill_fasync(&sonypi_compat.fifo_async, SIGIO, POLL_IN);
4273        wake_up_interruptible(&sonypi_compat.fifo_proc_list);
4274}
4275
4276static int sonypi_compat_init(void)
4277{
4278        int error;
4279
4280        spin_lock_init(&sonypi_compat.fifo_lock);
4281        error =
4282         kfifo_alloc(&sonypi_compat.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
4283        if (error) {
4284                pr_err("kfifo_alloc failed\n");
4285                return error;
4286        }
4287
4288        init_waitqueue_head(&sonypi_compat.fifo_proc_list);
4289
4290        if (minor != -1)
4291                sonypi_misc_device.minor = minor;
4292        error = misc_register(&sonypi_misc_device);
4293        if (error) {
4294                pr_err("misc_register failed\n");
4295                goto err_free_kfifo;
4296        }
4297        if (minor == -1)
4298                pr_info("device allocated minor is %d\n",
4299                        sonypi_misc_device.minor);
4300
4301        return 0;
4302
4303err_free_kfifo:
4304        kfifo_free(&sonypi_compat.fifo);
4305        return error;
4306}
4307
4308static void sonypi_compat_exit(void)
4309{
4310        misc_deregister(&sonypi_misc_device);
4311        kfifo_free(&sonypi_compat.fifo);
4312}
4313#else
4314static int sonypi_compat_init(void) { return 0; }
4315static void sonypi_compat_exit(void) { }
4316static void sonypi_compat_report_event(u8 event) { }
4317#endif /* CONFIG_SONYPI_COMPAT */
4318
4319/*
4320 * ACPI callbacks
4321 */
4322static acpi_status
4323sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
4324{
4325        u32 i;
4326        struct sony_pic_dev *dev = (struct sony_pic_dev *)context;
4327
4328        switch (resource->type) {
4329        case ACPI_RESOURCE_TYPE_START_DEPENDENT:
4330                {
4331                        /* start IO enumeration */
4332                        struct sony_pic_ioport *ioport = kzalloc(sizeof(*ioport), GFP_KERNEL);
4333                        if (!ioport)
4334                                return AE_ERROR;
4335
4336                        list_add(&ioport->list, &dev->ioports);
4337                        return AE_OK;
4338                }
4339
4340        case ACPI_RESOURCE_TYPE_END_DEPENDENT:
4341                /* end IO enumeration */
4342                return AE_OK;
4343
4344        case ACPI_RESOURCE_TYPE_IRQ:
4345                {
4346                        struct acpi_resource_irq *p = &resource->data.irq;
4347                        struct sony_pic_irq *interrupt = NULL;
4348                        if (!p || !p->interrupt_count) {
4349                                /*
4350                                 * IRQ descriptors may have no IRQ# bits set,
4351                                 * particularly those those w/ _STA disabled
4352                                 */
4353                                dprintk("Blank IRQ resource\n");
4354                                return AE_OK;
4355                        }
4356                        for (i = 0; i < p->interrupt_count; i++) {
4357                                if (!p->interrupts[i]) {
4358                                        pr_warn("Invalid IRQ %d\n",
4359                                                p->interrupts[i]);
4360                                        continue;
4361                                }
4362                                interrupt = kzalloc(sizeof(*interrupt),
4363                                                GFP_KERNEL);
4364                                if (!interrupt)
4365                                        return AE_ERROR;
4366
4367                                list_add(&interrupt->list, &dev->interrupts);
4368                                interrupt->irq.triggering = p->triggering;
4369                                interrupt->irq.polarity = p->polarity;
4370                                interrupt->irq.sharable = p->sharable;
4371                                interrupt->irq.interrupt_count = 1;
4372                                interrupt->irq.interrupts[0] = p->interrupts[i];
4373                        }
4374                        return AE_OK;
4375                }
4376        case ACPI_RESOURCE_TYPE_IO:
4377                {
4378                        struct acpi_resource_io *io = &resource->data.io;
4379                        struct sony_pic_ioport *ioport =
4380                                list_first_entry(&dev->ioports, struct sony_pic_ioport, list);
4381                        if (!io) {
4382                                dprintk("Blank IO resource\n");
4383                                return AE_OK;
4384                        }
4385
4386                        if (!ioport->io1.minimum) {
4387                                memcpy(&ioport->io1, io, sizeof(*io));
4388                                dprintk("IO1 at 0x%.4x (0x%.2x)\n", ioport->io1.minimum,
4389                                                ioport->io1.address_length);
4390                        }
4391                        else if (!ioport->io2.minimum) {
4392                                memcpy(&ioport->io2, io, sizeof(*io));
4393                                dprintk("IO2 at 0x%.4x (0x%.2x)\n", ioport->io2.minimum,
4394                                                ioport->io2.address_length);
4395                        }
4396                        else {
4397                                pr_err("Unknown SPIC Type, more than 2 IO Ports\n");
4398                                return AE_ERROR;
4399                        }
4400                        return AE_OK;
4401                }
4402        default:
4403                dprintk("Resource %d isn't an IRQ nor an IO port\n",
4404                        resource->type);
4405
4406        case ACPI_RESOURCE_TYPE_END_TAG:
4407                return AE_OK;
4408        }
4409        return AE_CTRL_TERMINATE;
4410}
4411
4412static int sony_pic_possible_resources(struct acpi_device *device)
4413{
4414        int result = 0;
4415        acpi_status status = AE_OK;
4416
4417        if (!device)
4418                return -EINVAL;
4419
4420        /* get device status */
4421        /* see acpi_pci_link_get_current acpi_pci_link_get_possible */
4422        dprintk("Evaluating _STA\n");
4423        result = acpi_bus_get_status(device);
4424        if (result) {
4425                pr_warn("Unable to read status\n");
4426                goto end;
4427        }
4428
4429        if (!device->status.enabled)
4430                dprintk("Device disabled\n");
4431        else
4432                dprintk("Device enabled\n");
4433
4434        /*
4435         * Query and parse 'method'
4436         */
4437        dprintk("Evaluating %s\n", METHOD_NAME__PRS);
4438        status = acpi_walk_resources(device->handle, METHOD_NAME__PRS,
4439                        sony_pic_read_possible_resource, &spic_dev);
4440        if (ACPI_FAILURE(status)) {
4441                pr_warn("Failure evaluating %s\n", METHOD_NAME__PRS);
4442                result = -ENODEV;
4443        }
4444end:
4445        return result;
4446}
4447
4448/*
4449 *  Disable the spic device by calling its _DIS method
4450 */
4451static int sony_pic_disable(struct acpi_device *device)
4452{
4453        acpi_status ret = acpi_evaluate_object(device->handle, "_DIS", NULL,
4454                                               NULL);
4455
4456        if (ACPI_FAILURE(ret) && ret != AE_NOT_FOUND)
4457                return -ENXIO;
4458
4459        dprintk("Device disabled\n");
4460        return 0;
4461}
4462
4463
4464/*
4465 *  Based on drivers/acpi/pci_link.c:acpi_pci_link_set
4466 *
4467 *  Call _SRS to set current resources
4468 */
4469static int sony_pic_enable(struct acpi_device *device,
4470                struct sony_pic_ioport *ioport, struct sony_pic_irq *irq)
4471{
4472        acpi_status status;
4473        int result = 0;
4474        /* Type 1 resource layout is:
4475         *    IO
4476         *    IO
4477         *    IRQNoFlags
4478         *    End
4479         *
4480         * Type 2 and 3 resource layout is:
4481         *    IO
4482         *    IRQNoFlags
4483         *    End
4484         */
4485        struct {
4486                struct acpi_resource res1;
4487                struct acpi_resource res2;
4488                struct acpi_resource res3;
4489                struct acpi_resource res4;
4490        } *resource;
4491        struct acpi_buffer buffer = { 0, NULL };
4492
4493        if (!ioport || !irq)
4494                return -EINVAL;
4495
4496        /* init acpi_buffer */
4497        resource = kzalloc(sizeof(*resource) + 1, GFP_KERNEL);
4498        if (!resource)
4499                return -ENOMEM;
4500
4501        buffer.length = sizeof(*resource) + 1;
4502        buffer.pointer = resource;
4503
4504        /* setup Type 1 resources */
4505        if (spic_dev.model == SONYPI_DEVICE_TYPE1) {
4506
4507                /* setup io resources */
4508                resource->res1.type = ACPI_RESOURCE_TYPE_IO;
4509                resource->res1.length = sizeof(struct acpi_resource);
4510                memcpy(&resource->res1.data.io, &ioport->io1,
4511                                sizeof(struct acpi_resource_io));
4512
4513                resource->res2.type = ACPI_RESOURCE_TYPE_IO;
4514                resource->res2.length = sizeof(struct acpi_resource);
4515                memcpy(&resource->res2.data.io, &ioport->io2,
4516                                sizeof(struct acpi_resource_io));
4517
4518                /* setup irq resource */
4519                resource->res3.type = ACPI_RESOURCE_TYPE_IRQ;
4520                resource->res3.length = sizeof(struct acpi_resource);
4521                memcpy(&resource->res3.data.irq, &irq->irq,
4522                                sizeof(struct acpi_resource_irq));
4523                /* we requested a shared irq */
4524                resource->res3.data.irq.sharable = ACPI_SHARED;
4525
4526                resource->res4.type = ACPI_RESOURCE_TYPE_END_TAG;
4527                resource->res4.length = sizeof(struct acpi_resource);
4528        }
4529        /* setup Type 2/3 resources */
4530        else {
4531                /* setup io resource */
4532                resource->res1.type = ACPI_RESOURCE_TYPE_IO;
4533                resource->res1.length = sizeof(struct acpi_resource);
4534                memcpy(&resource->res1.data.io, &ioport->io1,
4535                                sizeof(struct acpi_resource_io));
4536
4537                /* setup irq resource */
4538                resource->res2.type = ACPI_RESOURCE_TYPE_IRQ;
4539                resource->res2.length = sizeof(struct acpi_resource);
4540                memcpy(&resource->res2.data.irq, &irq->irq,
4541                                sizeof(struct acpi_resource_irq));
4542                /* we requested a shared irq */
4543                resource->res2.data.irq.sharable = ACPI_SHARED;
4544
4545                resource->res3.type = ACPI_RESOURCE_TYPE_END_TAG;
4546                resource->res3.length = sizeof(struct acpi_resource);
4547        }
4548
4549        /* Attempt to set the resource */
4550        dprintk("Evaluating _SRS\n");
4551        status = acpi_set_current_resources(device->handle, &buffer);
4552
4553        /* check for total failure */
4554        if (ACPI_FAILURE(status)) {
4555                pr_err("Error evaluating _SRS\n");
4556                result = -ENODEV;
4557                goto end;
4558        }
4559
4560        /* Necessary device initializations calls (from sonypi) */
4561        sony_pic_call1(0x82);
4562        sony_pic_call2(0x81, 0xff);
4563        sony_pic_call1(compat ? 0x92 : 0x82);
4564
4565end:
4566        kfree(resource);
4567        return result;
4568}
4569
4570/*****************
4571 *
4572 * ISR: some event is available
4573 *
4574 *****************/
4575static irqreturn_t sony_pic_irq(int irq, void *dev_id)
4576{
4577        int i, j;
4578        u8 ev = 0;
4579        u8 data_mask = 0;
4580        u8 device_event = 0;
4581
4582        struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id;
4583
4584        ev = inb_p(dev->cur_ioport->io1.minimum);
4585        if (dev->cur_ioport->io2.minimum)
4586                data_mask = inb_p(dev->cur_ioport->io2.minimum);
4587        else
4588                data_mask = inb_p(dev->cur_ioport->io1.minimum +
4589                                dev->evport_offset);
4590
4591        dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
4592                        ev, data_mask, dev->cur_ioport->io1.minimum,
4593                        dev->evport_offset);
4594
4595        if (ev == 0x00 || ev == 0xff)
4596                return IRQ_HANDLED;
4597
4598        for (i = 0; dev->event_types[i].mask; i++) {
4599
4600                if ((data_mask & dev->event_types[i].data) !=
4601                    dev->event_types[i].data)
4602                        continue;
4603
4604                if (!(mask & dev->event_types[i].mask))
4605                        continue;
4606
4607                for (j = 0; dev->event_types[i].events[j].event; j++) {
4608                        if (ev == dev->event_types[i].events[j].data) {
4609                                device_event =
4610                                        dev->event_types[i].events[j].event;
4611                                /* some events may require ignoring */
4612                                if (!device_event)
4613                                        return IRQ_HANDLED;
4614                                goto found;
4615                        }
4616                }
4617        }
4618        /* Still not able to decode the event try to pass
4619         * it over to the minidriver
4620         */
4621        if (dev->handle_irq && dev->handle_irq(data_mask, ev) == 0)
4622                return IRQ_HANDLED;
4623
4624        dprintk("unknown event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
4625                        ev, data_mask, dev->cur_ioport->io1.minimum,
4626                        dev->evport_offset);
4627        return IRQ_HANDLED;
4628
4629found:
4630        sony_laptop_report_input_event(device_event);
4631        sonypi_compat_report_event(device_event);
4632        return IRQ_HANDLED;
4633}
4634
4635/*****************
4636 *
4637 *  ACPI driver
4638 *
4639 *****************/
4640static int sony_pic_remove(struct acpi_device *device)
4641{
4642        struct sony_pic_ioport *io, *tmp_io;
4643        struct sony_pic_irq *irq, *tmp_irq;
4644
4645        if (sony_pic_disable(device)) {
4646                pr_err("Couldn't disable device\n");
4647                return -ENXIO;
4648        }
4649
4650        free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
4651        release_region(spic_dev.cur_ioport->io1.minimum,
4652                        spic_dev.cur_ioport->io1.address_length);
4653        if (spic_dev.cur_ioport->io2.minimum)
4654                release_region(spic_dev.cur_ioport->io2.minimum,
4655                                spic_dev.cur_ioport->io2.address_length);
4656
4657        sonypi_compat_exit();
4658
4659        sony_laptop_remove_input();
4660
4661        /* pf attrs */
4662        sysfs_remove_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
4663        sony_pf_remove();
4664
4665        list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
4666                list_del(&io->list);
4667                kfree(io);
4668        }
4669        list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
4670                list_del(&irq->list);
4671                kfree(irq);
4672        }
4673        spic_dev.cur_ioport = NULL;
4674        spic_dev.cur_irq = NULL;
4675
4676        dprintk(SONY_PIC_DRIVER_NAME " removed.\n");
4677        return 0;
4678}
4679
4680static int sony_pic_add(struct acpi_device *device)
4681{
4682        int result;
4683        struct sony_pic_ioport *io, *tmp_io;
4684        struct sony_pic_irq *irq, *tmp_irq;
4685
4686        spic_dev.acpi_dev = device;
4687        strcpy(acpi_device_class(device), "sony/hotkey");
4688        sony_pic_detect_device_type(&spic_dev);
4689        mutex_init(&spic_dev.lock);
4690
4691        /* read _PRS resources */
4692        result = sony_pic_possible_resources(device);
4693        if (result) {
4694                pr_err("Unable to read possible resources\n");
4695                goto err_free_resources;
4696        }
4697
4698        /* setup input devices and helper fifo */
4699        result = sony_laptop_setup_input(device);
4700        if (result) {
4701                pr_err("Unable to create input devices\n");
4702                goto err_free_resources;
4703        }
4704
4705        result = sonypi_compat_init();
4706        if (result)
4707                goto err_remove_input;
4708
4709        /* request io port */
4710        list_for_each_entry_reverse(io, &spic_dev.ioports, list) {
4711                if (request_region(io->io1.minimum, io->io1.address_length,
4712                                        "Sony Programmable I/O Device")) {
4713                        dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n",
4714                                        io->io1.minimum, io->io1.maximum,
4715                                        io->io1.address_length);
4716                        /* Type 1 have 2 ioports */
4717                        if (io->io2.minimum) {
4718                                if (request_region(io->io2.minimum,
4719                                                io->io2.address_length,
4720                                                "Sony Programmable I/O Device")) {
4721                                        dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n",
4722                                                        io->io2.minimum, io->io2.maximum,
4723                                                        io->io2.address_length);
4724                                        spic_dev.cur_ioport = io;
4725                                        break;
4726                                }
4727                                else {
4728                                        dprintk("Unable to get I/O port2: "
4729                                                        "0x%.4x (0x%.4x) + 0x%.2x\n",
4730                                                        io->io2.minimum, io->io2.maximum,
4731                                                        io->io2.address_length);
4732                                        release_region(io->io1.minimum,
4733                                                        io->io1.address_length);
4734                                }
4735                        }
4736                        else {
4737                                spic_dev.cur_ioport = io;
4738                                break;
4739                        }
4740                }
4741        }
4742        if (!spic_dev.cur_ioport) {
4743                pr_err("Failed to request_region\n");
4744                result = -ENODEV;
4745                goto err_remove_compat;
4746        }
4747
4748        /* request IRQ */
4749        list_for_each_entry_reverse(irq, &spic_dev.interrupts, list) {
4750                if (!request_irq(irq->irq.interrupts[0], sony_pic_irq,
4751                                        0, "sony-laptop", &spic_dev)) {
4752                        dprintk("IRQ: %d - triggering: %d - "
4753                                        "polarity: %d - shr: %d\n",
4754                                        irq->irq.interrupts[0],
4755                                        irq->irq.triggering,
4756                                        irq->irq.polarity,
4757                                        irq->irq.sharable);
4758                        spic_dev.cur_irq = irq;
4759                        break;
4760                }
4761        }
4762        if (!spic_dev.cur_irq) {
4763                pr_err("Failed to request_irq\n");
4764                result = -ENODEV;
4765                goto err_release_region;
4766        }
4767
4768        /* set resource status _SRS */
4769        result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
4770        if (result) {
4771                pr_err("Couldn't enable device\n");
4772                goto err_free_irq;
4773        }
4774
4775        spic_dev.bluetooth_power = -1;
4776        /* create device attributes */
4777        result = sony_pf_add();
4778        if (result)
4779                goto err_disable_device;
4780
4781        result = sysfs_create_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
4782        if (result)
4783                goto err_remove_pf;
4784
4785        pr_info("SPIC setup done.\n");
4786        return 0;
4787
4788err_remove_pf:
4789        sony_pf_remove();
4790
4791err_disable_device:
4792        sony_pic_disable(device);
4793
4794err_free_irq:
4795        free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
4796
4797err_release_region:
4798        release_region(spic_dev.cur_ioport->io1.minimum,
4799                        spic_dev.cur_ioport->io1.address_length);
4800        if (spic_dev.cur_ioport->io2.minimum)
4801                release_region(spic_dev.cur_ioport->io2.minimum,
4802                                spic_dev.cur_ioport->io2.address_length);
4803
4804err_remove_compat:
4805        sonypi_compat_exit();
4806
4807err_remove_input:
4808        sony_laptop_remove_input();
4809
4810err_free_resources:
4811        list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
4812                list_del(&io->list);
4813                kfree(io);
4814        }
4815        list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
4816                list_del(&irq->list);
4817                kfree(irq);
4818        }
4819        spic_dev.cur_ioport = NULL;
4820        spic_dev.cur_irq = NULL;
4821
4822        return result;
4823}
4824
4825#ifdef CONFIG_PM_SLEEP
4826static int sony_pic_suspend(struct device *dev)
4827{
4828        if (sony_pic_disable(to_acpi_device(dev)))
4829                return -ENXIO;
4830        return 0;
4831}
4832
4833static int sony_pic_resume(struct device *dev)
4834{
4835        sony_pic_enable(to_acpi_device(dev),
4836                        spic_dev.cur_ioport, spic_dev.cur_irq);
4837        return 0;
4838}
4839#endif
4840
4841static SIMPLE_DEV_PM_OPS(sony_pic_pm, sony_pic_suspend, sony_pic_resume);
4842
4843static const struct acpi_device_id sony_pic_device_ids[] = {
4844        {SONY_PIC_HID, 0},
4845        {"", 0},
4846};
4847
4848static struct acpi_driver sony_pic_driver = {
4849        .name = SONY_PIC_DRIVER_NAME,
4850        .class = SONY_PIC_CLASS,
4851        .ids = sony_pic_device_ids,
4852        .owner = THIS_MODULE,
4853        .ops = {
4854                .add = sony_pic_add,
4855                .remove = sony_pic_remove,
4856                },
4857        .drv.pm = &sony_pic_pm,
4858};
4859
4860static struct dmi_system_id __initdata sonypi_dmi_table[] = {
4861        {
4862                .ident = "Sony Vaio",
4863                .matches = {
4864                        DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
4865                        DMI_MATCH(DMI_PRODUCT_NAME, "PCG-"),
4866                },
4867        },
4868        {
4869                .ident = "Sony Vaio",
4870                .matches = {
4871                        DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
4872                        DMI_MATCH(DMI_PRODUCT_NAME, "VGN-"),
4873                },
4874        },
4875        { }
4876};
4877
4878static int __init sony_laptop_init(void)
4879{
4880        int result;
4881
4882        if (!no_spic && dmi_check_system(sonypi_dmi_table)) {
4883                result = acpi_bus_register_driver(&sony_pic_driver);
4884                if (result) {
4885                        pr_err("Unable to register SPIC driver\n");
4886                        goto out;
4887                }
4888                spic_drv_registered = 1;
4889        }
4890
4891        result = acpi_bus_register_driver(&sony_nc_driver);
4892        if (result) {
4893                pr_err("Unable to register SNC driver\n");
4894                goto out_unregister_pic;
4895        }
4896
4897        return 0;
4898
4899out_unregister_pic:
4900        if (spic_drv_registered)
4901                acpi_bus_unregister_driver(&sony_pic_driver);
4902out:
4903        return result;
4904}
4905
4906static void __exit sony_laptop_exit(void)
4907{
4908        acpi_bus_unregister_driver(&sony_nc_driver);
4909        if (spic_drv_registered)
4910                acpi_bus_unregister_driver(&sony_pic_driver);
4911}
4912
4913module_init(sony_laptop_init);
4914module_exit(sony_laptop_exit);
4915