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