Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * ACPI Sony Notebook Control Driver (SNC and SPIC)
0004  *
0005  * Copyright (C) 2004-2005 Stelian Pop <stelian@popies.net>
0006  * Copyright (C) 2007-2009 Mattia Dongili <malattia@linux.it>
0007  *
0008  * Parts of this driver inspired from asus_acpi.c and ibm_acpi.c
0009  * which are copyrighted by their respective authors.
0010  *
0011  * The SNY6001 driver part is based on the sonypi driver which includes
0012  * material from:
0013  *
0014  * Copyright (C) 2001-2005 Stelian Pop <stelian@popies.net>
0015  *
0016  * Copyright (C) 2005 Narayanan R S <nars@kadamba.org>
0017  *
0018  * Copyright (C) 2001-2002 AlcĂ´ve <www.alcove.com>
0019  *
0020  * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
0021  *
0022  * Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
0023  *
0024  * Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp>
0025  *
0026  * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
0027  *
0028  * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras.
0029  */
0030 
0031 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0032 
0033 #include <linux/kernel.h>
0034 #include <linux/module.h>
0035 #include <linux/moduleparam.h>
0036 #include <linux/init.h>
0037 #include <linux/types.h>
0038 #include <linux/backlight.h>
0039 #include <linux/platform_device.h>
0040 #include <linux/err.h>
0041 #include <linux/dmi.h>
0042 #include <linux/pci.h>
0043 #include <linux/interrupt.h>
0044 #include <linux/delay.h>
0045 #include <linux/input.h>
0046 #include <linux/kfifo.h>
0047 #include <linux/workqueue.h>
0048 #include <linux/acpi.h>
0049 #include <linux/slab.h>
0050 #include <linux/sonypi.h>
0051 #include <linux/sony-laptop.h>
0052 #include <linux/rfkill.h>
0053 #ifdef CONFIG_SONYPI_COMPAT
0054 #include <linux/poll.h>
0055 #include <linux/miscdevice.h>
0056 #endif
0057 #include <linux/uaccess.h>
0058 #include <acpi/video.h>
0059 
0060 #define dprintk(fmt, ...)           \
0061 do {                        \
0062     if (debug)              \
0063         pr_warn(fmt, ##__VA_ARGS__);    \
0064 } while (0)
0065 
0066 #define SONY_NC_CLASS       "sony-nc"
0067 #define SONY_NC_HID     "SNY5001"
0068 #define SONY_NC_DRIVER_NAME "Sony Notebook Control Driver"
0069 
0070 #define SONY_PIC_CLASS      "sony-pic"
0071 #define SONY_PIC_HID        "SNY6001"
0072 #define SONY_PIC_DRIVER_NAME    "Sony Programmable IO Control Driver"
0073 
0074 MODULE_AUTHOR("Stelian Pop, Mattia Dongili");
0075 MODULE_DESCRIPTION("Sony laptop extras driver (SPIC and SNC ACPI device)");
0076 MODULE_LICENSE("GPL");
0077 
0078 static int debug;
0079 module_param(debug, int, 0);
0080 MODULE_PARM_DESC(debug, "set this to 1 (and RTFM) if you want to help "
0081          "the development of this driver");
0082 
0083 static int no_spic;     /* = 0 */
0084 module_param(no_spic, int, 0444);
0085 MODULE_PARM_DESC(no_spic,
0086          "set this if you don't want to enable the SPIC device");
0087 
0088 static int compat;      /* = 0 */
0089 module_param(compat, int, 0444);
0090 MODULE_PARM_DESC(compat,
0091          "set this if you want to enable backward compatibility mode");
0092 
0093 static unsigned long mask = 0xffffffff;
0094 module_param(mask, ulong, 0644);
0095 MODULE_PARM_DESC(mask,
0096          "set this to the mask of event you want to enable (see doc)");
0097 
0098 static int camera;      /* = 0 */
0099 module_param(camera, int, 0444);
0100 MODULE_PARM_DESC(camera,
0101          "set this to 1 to enable Motion Eye camera controls "
0102          "(only use it if you have a C1VE or C1VN model)");
0103 
0104 #ifdef CONFIG_SONYPI_COMPAT
0105 static int minor = -1;
0106 module_param(minor, int, 0);
0107 MODULE_PARM_DESC(minor,
0108          "minor number of the misc device for the SPIC compatibility code, "
0109          "default is -1 (automatic)");
0110 #endif
0111 
0112 static int kbd_backlight = -1;
0113 module_param(kbd_backlight, int, 0444);
0114 MODULE_PARM_DESC(kbd_backlight,
0115          "set this to 0 to disable keyboard backlight, "
0116          "1 to enable it with automatic control and 2 to have it always "
0117          "on (default: no change from current value)");
0118 
0119 static int kbd_backlight_timeout = -1;
0120 module_param(kbd_backlight_timeout, int, 0444);
0121 MODULE_PARM_DESC(kbd_backlight_timeout,
0122          "meaningful values vary from 0 to 3 and their meaning depends "
0123          "on the model (default: no change from current value)");
0124 
0125 #ifdef CONFIG_PM_SLEEP
0126 static void sony_nc_thermal_resume(void);
0127 #endif
0128 static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
0129         unsigned int handle);
0130 static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd,
0131         unsigned int handle);
0132 
0133 static int sony_nc_battery_care_setup(struct platform_device *pd,
0134         unsigned int handle);
0135 static void sony_nc_battery_care_cleanup(struct platform_device *pd);
0136 
0137 static int sony_nc_thermal_setup(struct platform_device *pd);
0138 static void sony_nc_thermal_cleanup(struct platform_device *pd);
0139 
0140 static int sony_nc_lid_resume_setup(struct platform_device *pd,
0141                     unsigned int handle);
0142 static void sony_nc_lid_resume_cleanup(struct platform_device *pd);
0143 
0144 static int sony_nc_gfx_switch_setup(struct platform_device *pd,
0145         unsigned int handle);
0146 static void sony_nc_gfx_switch_cleanup(struct platform_device *pd);
0147 static int __sony_nc_gfx_switch_status_get(void);
0148 
0149 static int sony_nc_highspeed_charging_setup(struct platform_device *pd);
0150 static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd);
0151 
0152 static int sony_nc_lowbatt_setup(struct platform_device *pd);
0153 static void sony_nc_lowbatt_cleanup(struct platform_device *pd);
0154 
0155 static int sony_nc_fanspeed_setup(struct platform_device *pd);
0156 static void sony_nc_fanspeed_cleanup(struct platform_device *pd);
0157 
0158 static int sony_nc_usb_charge_setup(struct platform_device *pd);
0159 static void sony_nc_usb_charge_cleanup(struct platform_device *pd);
0160 
0161 static int sony_nc_panelid_setup(struct platform_device *pd);
0162 static void sony_nc_panelid_cleanup(struct platform_device *pd);
0163 
0164 static int sony_nc_smart_conn_setup(struct platform_device *pd);
0165 static void sony_nc_smart_conn_cleanup(struct platform_device *pd);
0166 
0167 static int sony_nc_touchpad_setup(struct platform_device *pd,
0168                   unsigned int handle);
0169 static void sony_nc_touchpad_cleanup(struct platform_device *pd);
0170 
0171 enum sony_nc_rfkill {
0172     SONY_WIFI,
0173     SONY_BLUETOOTH,
0174     SONY_WWAN,
0175     SONY_WIMAX,
0176     N_SONY_RFKILL,
0177 };
0178 
0179 static int sony_rfkill_handle;
0180 static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL];
0181 static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900};
0182 static int sony_nc_rfkill_setup(struct acpi_device *device,
0183         unsigned int handle);
0184 static void sony_nc_rfkill_cleanup(void);
0185 static void sony_nc_rfkill_update(void);
0186 
0187 /*********** Input Devices ***********/
0188 
0189 #define SONY_LAPTOP_BUF_SIZE    128
0190 struct sony_laptop_input_s {
0191     atomic_t        users;
0192     struct input_dev    *jog_dev;
0193     struct input_dev    *key_dev;
0194     struct kfifo        fifo;
0195     spinlock_t      fifo_lock;
0196     struct timer_list   release_key_timer;
0197 };
0198 
0199 static struct sony_laptop_input_s sony_laptop_input = {
0200     .users = ATOMIC_INIT(0),
0201 };
0202 
0203 struct sony_laptop_keypress {
0204     struct input_dev *dev;
0205     int key;
0206 };
0207 
0208 /* Correspondance table between sonypi events
0209  * and input layer indexes in the keymap
0210  */
0211 static const int sony_laptop_input_index[] = {
0212     -1, /*  0 no event */
0213     -1, /*  1 SONYPI_EVENT_JOGDIAL_DOWN */
0214     -1, /*  2 SONYPI_EVENT_JOGDIAL_UP */
0215     -1, /*  3 SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */
0216     -1, /*  4 SONYPI_EVENT_JOGDIAL_UP_PRESSED */
0217     -1, /*  5 SONYPI_EVENT_JOGDIAL_PRESSED */
0218     -1, /*  6 SONYPI_EVENT_JOGDIAL_RELEASED */
0219      0, /*  7 SONYPI_EVENT_CAPTURE_PRESSED */
0220      1, /*  8 SONYPI_EVENT_CAPTURE_RELEASED */
0221      2, /*  9 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
0222      3, /* 10 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
0223      4, /* 11 SONYPI_EVENT_FNKEY_ESC */
0224      5, /* 12 SONYPI_EVENT_FNKEY_F1 */
0225      6, /* 13 SONYPI_EVENT_FNKEY_F2 */
0226      7, /* 14 SONYPI_EVENT_FNKEY_F3 */
0227      8, /* 15 SONYPI_EVENT_FNKEY_F4 */
0228      9, /* 16 SONYPI_EVENT_FNKEY_F5 */
0229     10, /* 17 SONYPI_EVENT_FNKEY_F6 */
0230     11, /* 18 SONYPI_EVENT_FNKEY_F7 */
0231     12, /* 19 SONYPI_EVENT_FNKEY_F8 */
0232     13, /* 20 SONYPI_EVENT_FNKEY_F9 */
0233     14, /* 21 SONYPI_EVENT_FNKEY_F10 */
0234     15, /* 22 SONYPI_EVENT_FNKEY_F11 */
0235     16, /* 23 SONYPI_EVENT_FNKEY_F12 */
0236     17, /* 24 SONYPI_EVENT_FNKEY_1 */
0237     18, /* 25 SONYPI_EVENT_FNKEY_2 */
0238     19, /* 26 SONYPI_EVENT_FNKEY_D */
0239     20, /* 27 SONYPI_EVENT_FNKEY_E */
0240     21, /* 28 SONYPI_EVENT_FNKEY_F */
0241     22, /* 29 SONYPI_EVENT_FNKEY_S */
0242     23, /* 30 SONYPI_EVENT_FNKEY_B */
0243     24, /* 31 SONYPI_EVENT_BLUETOOTH_PRESSED */
0244     25, /* 32 SONYPI_EVENT_PKEY_P1 */
0245     26, /* 33 SONYPI_EVENT_PKEY_P2 */
0246     27, /* 34 SONYPI_EVENT_PKEY_P3 */
0247     28, /* 35 SONYPI_EVENT_BACK_PRESSED */
0248     -1, /* 36 SONYPI_EVENT_LID_CLOSED */
0249     -1, /* 37 SONYPI_EVENT_LID_OPENED */
0250     29, /* 38 SONYPI_EVENT_BLUETOOTH_ON */
0251     30, /* 39 SONYPI_EVENT_BLUETOOTH_OFF */
0252     31, /* 40 SONYPI_EVENT_HELP_PRESSED */
0253     32, /* 41 SONYPI_EVENT_FNKEY_ONLY */
0254     33, /* 42 SONYPI_EVENT_JOGDIAL_FAST_DOWN */
0255     34, /* 43 SONYPI_EVENT_JOGDIAL_FAST_UP */
0256     35, /* 44 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
0257     36, /* 45 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
0258     37, /* 46 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
0259     38, /* 47 SONYPI_EVENT_JOGDIAL_VFAST_UP */
0260     39, /* 48 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
0261     40, /* 49 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
0262     41, /* 50 SONYPI_EVENT_ZOOM_PRESSED */
0263     42, /* 51 SONYPI_EVENT_THUMBPHRASE_PRESSED */
0264     43, /* 52 SONYPI_EVENT_MEYE_FACE */
0265     44, /* 53 SONYPI_EVENT_MEYE_OPPOSITE */
0266     45, /* 54 SONYPI_EVENT_MEMORYSTICK_INSERT */
0267     46, /* 55 SONYPI_EVENT_MEMORYSTICK_EJECT */
0268     -1, /* 56 SONYPI_EVENT_ANYBUTTON_RELEASED */
0269     -1, /* 57 SONYPI_EVENT_BATTERY_INSERT */
0270     -1, /* 58 SONYPI_EVENT_BATTERY_REMOVE */
0271     -1, /* 59 SONYPI_EVENT_FNKEY_RELEASED */
0272     47, /* 60 SONYPI_EVENT_WIRELESS_ON */
0273     48, /* 61 SONYPI_EVENT_WIRELESS_OFF */
0274     49, /* 62 SONYPI_EVENT_ZOOM_IN_PRESSED */
0275     50, /* 63 SONYPI_EVENT_ZOOM_OUT_PRESSED */
0276     51, /* 64 SONYPI_EVENT_CD_EJECT_PRESSED */
0277     52, /* 65 SONYPI_EVENT_MODEKEY_PRESSED */
0278     53, /* 66 SONYPI_EVENT_PKEY_P4 */
0279     54, /* 67 SONYPI_EVENT_PKEY_P5 */
0280     55, /* 68 SONYPI_EVENT_SETTINGKEY_PRESSED */
0281     56, /* 69 SONYPI_EVENT_VOLUME_INC_PRESSED */
0282     57, /* 70 SONYPI_EVENT_VOLUME_DEC_PRESSED */
0283     -1, /* 71 SONYPI_EVENT_BRIGHTNESS_PRESSED */
0284     58, /* 72 SONYPI_EVENT_MEDIA_PRESSED */
0285     59, /* 72 SONYPI_EVENT_VENDOR_PRESSED */
0286 };
0287 
0288 static int sony_laptop_input_keycode_map[] = {
0289     KEY_CAMERA, /*  0 SONYPI_EVENT_CAPTURE_PRESSED */
0290     KEY_RESERVED,   /*  1 SONYPI_EVENT_CAPTURE_RELEASED */
0291     KEY_RESERVED,   /*  2 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
0292     KEY_RESERVED,   /*  3 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
0293     KEY_FN_ESC, /*  4 SONYPI_EVENT_FNKEY_ESC */
0294     KEY_FN_F1,  /*  5 SONYPI_EVENT_FNKEY_F1 */
0295     KEY_FN_F2,  /*  6 SONYPI_EVENT_FNKEY_F2 */
0296     KEY_FN_F3,  /*  7 SONYPI_EVENT_FNKEY_F3 */
0297     KEY_FN_F4,  /*  8 SONYPI_EVENT_FNKEY_F4 */
0298     KEY_FN_F5,  /*  9 SONYPI_EVENT_FNKEY_F5 */
0299     KEY_FN_F6,  /* 10 SONYPI_EVENT_FNKEY_F6 */
0300     KEY_FN_F7,  /* 11 SONYPI_EVENT_FNKEY_F7 */
0301     KEY_FN_F8,  /* 12 SONYPI_EVENT_FNKEY_F8 */
0302     KEY_FN_F9,  /* 13 SONYPI_EVENT_FNKEY_F9 */
0303     KEY_FN_F10, /* 14 SONYPI_EVENT_FNKEY_F10 */
0304     KEY_FN_F11, /* 15 SONYPI_EVENT_FNKEY_F11 */
0305     KEY_FN_F12, /* 16 SONYPI_EVENT_FNKEY_F12 */
0306     KEY_FN_1,   /* 17 SONYPI_EVENT_FNKEY_1 */
0307     KEY_FN_2,   /* 18 SONYPI_EVENT_FNKEY_2 */
0308     KEY_FN_D,   /* 19 SONYPI_EVENT_FNKEY_D */
0309     KEY_FN_E,   /* 20 SONYPI_EVENT_FNKEY_E */
0310     KEY_FN_F,   /* 21 SONYPI_EVENT_FNKEY_F */
0311     KEY_FN_S,   /* 22 SONYPI_EVENT_FNKEY_S */
0312     KEY_FN_B,   /* 23 SONYPI_EVENT_FNKEY_B */
0313     KEY_BLUETOOTH,  /* 24 SONYPI_EVENT_BLUETOOTH_PRESSED */
0314     KEY_PROG1,  /* 25 SONYPI_EVENT_PKEY_P1 */
0315     KEY_PROG2,  /* 26 SONYPI_EVENT_PKEY_P2 */
0316     KEY_PROG3,  /* 27 SONYPI_EVENT_PKEY_P3 */
0317     KEY_BACK,   /* 28 SONYPI_EVENT_BACK_PRESSED */
0318     KEY_BLUETOOTH,  /* 29 SONYPI_EVENT_BLUETOOTH_ON */
0319     KEY_BLUETOOTH,  /* 30 SONYPI_EVENT_BLUETOOTH_OFF */
0320     KEY_HELP,   /* 31 SONYPI_EVENT_HELP_PRESSED */
0321     KEY_FN,     /* 32 SONYPI_EVENT_FNKEY_ONLY */
0322     KEY_RESERVED,   /* 33 SONYPI_EVENT_JOGDIAL_FAST_DOWN */
0323     KEY_RESERVED,   /* 34 SONYPI_EVENT_JOGDIAL_FAST_UP */
0324     KEY_RESERVED,   /* 35 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
0325     KEY_RESERVED,   /* 36 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
0326     KEY_RESERVED,   /* 37 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
0327     KEY_RESERVED,   /* 38 SONYPI_EVENT_JOGDIAL_VFAST_UP */
0328     KEY_RESERVED,   /* 39 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
0329     KEY_RESERVED,   /* 40 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
0330     KEY_ZOOM,   /* 41 SONYPI_EVENT_ZOOM_PRESSED */
0331     BTN_THUMB,  /* 42 SONYPI_EVENT_THUMBPHRASE_PRESSED */
0332     KEY_RESERVED,   /* 43 SONYPI_EVENT_MEYE_FACE */
0333     KEY_RESERVED,   /* 44 SONYPI_EVENT_MEYE_OPPOSITE */
0334     KEY_RESERVED,   /* 45 SONYPI_EVENT_MEMORYSTICK_INSERT */
0335     KEY_RESERVED,   /* 46 SONYPI_EVENT_MEMORYSTICK_EJECT */
0336     KEY_WLAN,   /* 47 SONYPI_EVENT_WIRELESS_ON */
0337     KEY_WLAN,   /* 48 SONYPI_EVENT_WIRELESS_OFF */
0338     KEY_ZOOMIN, /* 49 SONYPI_EVENT_ZOOM_IN_PRESSED */
0339     KEY_ZOOMOUT,    /* 50 SONYPI_EVENT_ZOOM_OUT_PRESSED */
0340     KEY_EJECTCD,    /* 51 SONYPI_EVENT_CD_EJECT_PRESSED */
0341     KEY_F13,    /* 52 SONYPI_EVENT_MODEKEY_PRESSED */
0342     KEY_PROG4,  /* 53 SONYPI_EVENT_PKEY_P4 */
0343     KEY_F14,    /* 54 SONYPI_EVENT_PKEY_P5 */
0344     KEY_F15,    /* 55 SONYPI_EVENT_SETTINGKEY_PRESSED */
0345     KEY_VOLUMEUP,   /* 56 SONYPI_EVENT_VOLUME_INC_PRESSED */
0346     KEY_VOLUMEDOWN, /* 57 SONYPI_EVENT_VOLUME_DEC_PRESSED */
0347     KEY_MEDIA,  /* 58 SONYPI_EVENT_MEDIA_PRESSED */
0348     KEY_VENDOR, /* 59 SONYPI_EVENT_VENDOR_PRESSED */
0349 };
0350 
0351 /* release buttons after a short delay if pressed */
0352 static void do_sony_laptop_release_key(struct timer_list *unused)
0353 {
0354     struct sony_laptop_keypress kp;
0355     unsigned long flags;
0356 
0357     spin_lock_irqsave(&sony_laptop_input.fifo_lock, flags);
0358 
0359     if (kfifo_out(&sony_laptop_input.fifo,
0360               (unsigned char *)&kp, sizeof(kp)) == sizeof(kp)) {
0361         input_report_key(kp.dev, kp.key, 0);
0362         input_sync(kp.dev);
0363     }
0364 
0365     /* If there is something in the fifo schedule next release. */
0366     if (kfifo_len(&sony_laptop_input.fifo) != 0)
0367         mod_timer(&sony_laptop_input.release_key_timer,
0368               jiffies + msecs_to_jiffies(10));
0369 
0370     spin_unlock_irqrestore(&sony_laptop_input.fifo_lock, flags);
0371 }
0372 
0373 /* forward event to the input subsystem */
0374 static void sony_laptop_report_input_event(u8 event)
0375 {
0376     struct input_dev *jog_dev = sony_laptop_input.jog_dev;
0377     struct input_dev *key_dev = sony_laptop_input.key_dev;
0378     struct sony_laptop_keypress kp = { NULL };
0379     int scancode = -1;
0380 
0381     if (event == SONYPI_EVENT_FNKEY_RELEASED ||
0382             event == SONYPI_EVENT_ANYBUTTON_RELEASED) {
0383         /* Nothing, not all VAIOs generate this event */
0384         return;
0385     }
0386 
0387     /* report events */
0388     switch (event) {
0389     /* jog_dev events */
0390     case SONYPI_EVENT_JOGDIAL_UP:
0391     case SONYPI_EVENT_JOGDIAL_UP_PRESSED:
0392         input_report_rel(jog_dev, REL_WHEEL, 1);
0393         input_sync(jog_dev);
0394         return;
0395 
0396     case SONYPI_EVENT_JOGDIAL_DOWN:
0397     case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED:
0398         input_report_rel(jog_dev, REL_WHEEL, -1);
0399         input_sync(jog_dev);
0400         return;
0401 
0402     /* key_dev events */
0403     case SONYPI_EVENT_JOGDIAL_PRESSED:
0404         kp.key = BTN_MIDDLE;
0405         kp.dev = jog_dev;
0406         break;
0407 
0408     default:
0409         if (event >= ARRAY_SIZE(sony_laptop_input_index)) {
0410             dprintk("sony_laptop_report_input_event, event not known: %d\n", event);
0411             break;
0412         }
0413         if ((scancode = sony_laptop_input_index[event]) != -1) {
0414             kp.key = sony_laptop_input_keycode_map[scancode];
0415             if (kp.key != KEY_UNKNOWN)
0416                 kp.dev = key_dev;
0417         }
0418         break;
0419     }
0420 
0421     if (kp.dev) {
0422         /* if we have a scancode we emit it so we can always
0423             remap the key */
0424         if (scancode != -1)
0425             input_event(kp.dev, EV_MSC, MSC_SCAN, scancode);
0426         input_report_key(kp.dev, kp.key, 1);
0427         input_sync(kp.dev);
0428 
0429         /* schedule key release */
0430         kfifo_in_locked(&sony_laptop_input.fifo,
0431                 (unsigned char *)&kp, sizeof(kp),
0432                 &sony_laptop_input.fifo_lock);
0433         mod_timer(&sony_laptop_input.release_key_timer,
0434               jiffies + msecs_to_jiffies(10));
0435     } else
0436         dprintk("unknown input event %.2x\n", event);
0437 }
0438 
0439 static int sony_laptop_setup_input(struct acpi_device *acpi_device)
0440 {
0441     struct input_dev *jog_dev;
0442     struct input_dev *key_dev;
0443     int i;
0444     int error;
0445 
0446     /* don't run again if already initialized */
0447     if (atomic_add_return(1, &sony_laptop_input.users) > 1)
0448         return 0;
0449 
0450     /* kfifo */
0451     spin_lock_init(&sony_laptop_input.fifo_lock);
0452     error = kfifo_alloc(&sony_laptop_input.fifo,
0453                 SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
0454     if (error) {
0455         pr_err("kfifo_alloc failed\n");
0456         goto err_dec_users;
0457     }
0458 
0459     timer_setup(&sony_laptop_input.release_key_timer,
0460             do_sony_laptop_release_key, 0);
0461 
0462     /* input keys */
0463     key_dev = input_allocate_device();
0464     if (!key_dev) {
0465         error = -ENOMEM;
0466         goto err_free_kfifo;
0467     }
0468 
0469     key_dev->name = "Sony Vaio Keys";
0470     key_dev->id.bustype = BUS_ISA;
0471     key_dev->id.vendor = PCI_VENDOR_ID_SONY;
0472     key_dev->dev.parent = &acpi_device->dev;
0473 
0474     /* Initialize the Input Drivers: special keys */
0475     input_set_capability(key_dev, EV_MSC, MSC_SCAN);
0476 
0477     __set_bit(EV_KEY, key_dev->evbit);
0478     key_dev->keycodesize = sizeof(sony_laptop_input_keycode_map[0]);
0479     key_dev->keycodemax = ARRAY_SIZE(sony_laptop_input_keycode_map);
0480     key_dev->keycode = &sony_laptop_input_keycode_map;
0481     for (i = 0; i < ARRAY_SIZE(sony_laptop_input_keycode_map); i++)
0482         __set_bit(sony_laptop_input_keycode_map[i], key_dev->keybit);
0483     __clear_bit(KEY_RESERVED, key_dev->keybit);
0484 
0485     error = input_register_device(key_dev);
0486     if (error)
0487         goto err_free_keydev;
0488 
0489     sony_laptop_input.key_dev = key_dev;
0490 
0491     /* jogdial */
0492     jog_dev = input_allocate_device();
0493     if (!jog_dev) {
0494         error = -ENOMEM;
0495         goto err_unregister_keydev;
0496     }
0497 
0498     jog_dev->name = "Sony Vaio Jogdial";
0499     jog_dev->id.bustype = BUS_ISA;
0500     jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
0501     jog_dev->dev.parent = &acpi_device->dev;
0502 
0503     input_set_capability(jog_dev, EV_KEY, BTN_MIDDLE);
0504     input_set_capability(jog_dev, EV_REL, REL_WHEEL);
0505 
0506     error = input_register_device(jog_dev);
0507     if (error)
0508         goto err_free_jogdev;
0509 
0510     sony_laptop_input.jog_dev = jog_dev;
0511 
0512     return 0;
0513 
0514 err_free_jogdev:
0515     input_free_device(jog_dev);
0516 
0517 err_unregister_keydev:
0518     input_unregister_device(key_dev);
0519     /* to avoid kref underflow below at input_free_device */
0520     key_dev = NULL;
0521 
0522 err_free_keydev:
0523     input_free_device(key_dev);
0524 
0525 err_free_kfifo:
0526     kfifo_free(&sony_laptop_input.fifo);
0527 
0528 err_dec_users:
0529     atomic_dec(&sony_laptop_input.users);
0530     return error;
0531 }
0532 
0533 static void sony_laptop_remove_input(void)
0534 {
0535     struct sony_laptop_keypress kp = { NULL };
0536 
0537     /* Cleanup only after the last user has gone */
0538     if (!atomic_dec_and_test(&sony_laptop_input.users))
0539         return;
0540 
0541     del_timer_sync(&sony_laptop_input.release_key_timer);
0542 
0543     /*
0544      * Generate key-up events for remaining keys. Note that we don't
0545      * need locking since nobody is adding new events to the kfifo.
0546      */
0547     while (kfifo_out(&sony_laptop_input.fifo,
0548              (unsigned char *)&kp, sizeof(kp)) == sizeof(kp)) {
0549         input_report_key(kp.dev, kp.key, 0);
0550         input_sync(kp.dev);
0551     }
0552 
0553     /* destroy input devs */
0554     input_unregister_device(sony_laptop_input.key_dev);
0555     sony_laptop_input.key_dev = NULL;
0556 
0557     if (sony_laptop_input.jog_dev) {
0558         input_unregister_device(sony_laptop_input.jog_dev);
0559         sony_laptop_input.jog_dev = NULL;
0560     }
0561 
0562     kfifo_free(&sony_laptop_input.fifo);
0563 }
0564 
0565 /*********** Platform Device ***********/
0566 
0567 static atomic_t sony_pf_users = ATOMIC_INIT(0);
0568 static struct platform_driver sony_pf_driver = {
0569     .driver = {
0570            .name = "sony-laptop",
0571            }
0572 };
0573 static struct platform_device *sony_pf_device;
0574 
0575 static int sony_pf_add(void)
0576 {
0577     int ret = 0;
0578 
0579     /* don't run again if already initialized */
0580     if (atomic_add_return(1, &sony_pf_users) > 1)
0581         return 0;
0582 
0583     ret = platform_driver_register(&sony_pf_driver);
0584     if (ret)
0585         goto out;
0586 
0587     sony_pf_device = platform_device_alloc("sony-laptop", -1);
0588     if (!sony_pf_device) {
0589         ret = -ENOMEM;
0590         goto out_platform_registered;
0591     }
0592 
0593     ret = platform_device_add(sony_pf_device);
0594     if (ret)
0595         goto out_platform_alloced;
0596 
0597     return 0;
0598 
0599       out_platform_alloced:
0600     platform_device_put(sony_pf_device);
0601     sony_pf_device = NULL;
0602       out_platform_registered:
0603     platform_driver_unregister(&sony_pf_driver);
0604       out:
0605     atomic_dec(&sony_pf_users);
0606     return ret;
0607 }
0608 
0609 static void sony_pf_remove(void)
0610 {
0611     /* deregister only after the last user has gone */
0612     if (!atomic_dec_and_test(&sony_pf_users))
0613         return;
0614 
0615     platform_device_unregister(sony_pf_device);
0616     platform_driver_unregister(&sony_pf_driver);
0617 }
0618 
0619 /*********** SNC (SNY5001) Device ***********/
0620 
0621 /* the device uses 1-based values, while the backlight subsystem uses
0622    0-based values */
0623 #define SONY_MAX_BRIGHTNESS 8
0624 
0625 #define SNC_VALIDATE_IN     0
0626 #define SNC_VALIDATE_OUT    1
0627 
0628 static ssize_t sony_nc_sysfs_show(struct device *, struct device_attribute *,
0629                   char *);
0630 static ssize_t sony_nc_sysfs_store(struct device *, struct device_attribute *,
0631                    const char *, size_t);
0632 static int boolean_validate(const int, const int);
0633 static int brightness_default_validate(const int, const int);
0634 
0635 struct sony_nc_value {
0636     char *name;     /* name of the entry */
0637     char **acpiget;     /* names of the ACPI get function */
0638     char **acpiset;     /* names of the ACPI set function */
0639     int (*validate)(const int, const int);  /* input/output validation */
0640     int value;      /* current setting */
0641     int valid;      /* Has ever been set */
0642     int debug;      /* active only in debug mode ? */
0643     struct device_attribute devattr;    /* sysfs attribute */
0644 };
0645 
0646 #define SNC_HANDLE_NAMES(_name, _values...) \
0647     static char *snc_##_name[] = { _values, NULL }
0648 
0649 #define SNC_HANDLE(_name, _getters, _setters, _validate, _debug) \
0650     { \
0651         .name       = __stringify(_name), \
0652         .acpiget    = _getters, \
0653         .acpiset    = _setters, \
0654         .validate   = _validate, \
0655         .debug      = _debug, \
0656         .devattr    = __ATTR(_name, 0, sony_nc_sysfs_show, sony_nc_sysfs_store), \
0657     }
0658 
0659 #define SNC_HANDLE_NULL { .name = NULL }
0660 
0661 SNC_HANDLE_NAMES(fnkey_get, "GHKE");
0662 
0663 SNC_HANDLE_NAMES(brightness_def_get, "GPBR");
0664 SNC_HANDLE_NAMES(brightness_def_set, "SPBR");
0665 
0666 SNC_HANDLE_NAMES(cdpower_get, "GCDP");
0667 SNC_HANDLE_NAMES(cdpower_set, "SCDP", "CDPW");
0668 
0669 SNC_HANDLE_NAMES(audiopower_get, "GAZP");
0670 SNC_HANDLE_NAMES(audiopower_set, "AZPW");
0671 
0672 SNC_HANDLE_NAMES(lanpower_get, "GLNP");
0673 SNC_HANDLE_NAMES(lanpower_set, "LNPW");
0674 
0675 SNC_HANDLE_NAMES(lidstate_get, "GLID");
0676 
0677 SNC_HANDLE_NAMES(indicatorlamp_get, "GILS");
0678 SNC_HANDLE_NAMES(indicatorlamp_set, "SILS");
0679 
0680 SNC_HANDLE_NAMES(gainbass_get, "GMGB");
0681 SNC_HANDLE_NAMES(gainbass_set, "CMGB");
0682 
0683 SNC_HANDLE_NAMES(PID_get, "GPID");
0684 
0685 SNC_HANDLE_NAMES(CTR_get, "GCTR");
0686 SNC_HANDLE_NAMES(CTR_set, "SCTR");
0687 
0688 SNC_HANDLE_NAMES(PCR_get, "GPCR");
0689 SNC_HANDLE_NAMES(PCR_set, "SPCR");
0690 
0691 SNC_HANDLE_NAMES(CMI_get, "GCMI");
0692 SNC_HANDLE_NAMES(CMI_set, "SCMI");
0693 
0694 static struct sony_nc_value sony_nc_values[] = {
0695     SNC_HANDLE(brightness_default, snc_brightness_def_get,
0696             snc_brightness_def_set, brightness_default_validate, 0),
0697     SNC_HANDLE(fnkey, snc_fnkey_get, NULL, NULL, 0),
0698     SNC_HANDLE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0),
0699     SNC_HANDLE(audiopower, snc_audiopower_get, snc_audiopower_set,
0700             boolean_validate, 0),
0701     SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set,
0702             boolean_validate, 1),
0703     SNC_HANDLE(lidstate, snc_lidstate_get, NULL,
0704             boolean_validate, 0),
0705     SNC_HANDLE(indicatorlamp, snc_indicatorlamp_get, snc_indicatorlamp_set,
0706             boolean_validate, 0),
0707     SNC_HANDLE(gainbass, snc_gainbass_get, snc_gainbass_set,
0708             boolean_validate, 0),
0709     /* unknown methods */
0710     SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1),
0711     SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1),
0712     SNC_HANDLE(PCR, snc_PCR_get, snc_PCR_set, NULL, 1),
0713     SNC_HANDLE(CMI, snc_CMI_get, snc_CMI_set, NULL, 1),
0714     SNC_HANDLE_NULL
0715 };
0716 
0717 static acpi_handle sony_nc_acpi_handle;
0718 static struct acpi_device *sony_nc_acpi_device = NULL;
0719 
0720 /*
0721  * acpi_evaluate_object wrappers
0722  * all useful calls into SNC methods take one or zero parameters and return
0723  * integers or arrays.
0724  */
0725 static union acpi_object *__call_snc_method(acpi_handle handle, char *method,
0726         u64 *value)
0727 {
0728     union acpi_object *result = NULL;
0729     struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
0730     acpi_status status;
0731 
0732     if (value) {
0733         struct acpi_object_list params;
0734         union acpi_object in;
0735         in.type = ACPI_TYPE_INTEGER;
0736         in.integer.value = *value;
0737         params.count = 1;
0738         params.pointer = &in;
0739         status = acpi_evaluate_object(handle, method, &params, &output);
0740         dprintk("__call_snc_method: [%s:0x%.8x%.8x]\n", method,
0741                 (unsigned int)(*value >> 32),
0742                 (unsigned int)*value & 0xffffffff);
0743     } else {
0744         status = acpi_evaluate_object(handle, method, NULL, &output);
0745         dprintk("__call_snc_method: [%s]\n", method);
0746     }
0747 
0748     if (ACPI_FAILURE(status)) {
0749         pr_err("Failed to evaluate [%s]\n", method);
0750         return NULL;
0751     }
0752 
0753     result = (union acpi_object *) output.pointer;
0754     if (!result)
0755         dprintk("No return object [%s]\n", method);
0756 
0757     return result;
0758 }
0759 
0760 #define MIN(a, b)   (a > b ? b : a)
0761 static int sony_nc_buffer_call(acpi_handle handle, char *name, u64 *value,
0762         void *buffer, size_t buflen)
0763 {
0764     int ret = 0;
0765     size_t len;
0766     union acpi_object *object = __call_snc_method(handle, name, value);
0767 
0768     if (!object)
0769         return -EINVAL;
0770 
0771     if (!buffer) {
0772         /* do nothing */
0773     } else if (object->type == ACPI_TYPE_BUFFER) {
0774         len = MIN(buflen, object->buffer.length);
0775         memset(buffer, 0, buflen);
0776         memcpy(buffer, object->buffer.pointer, len);
0777 
0778     } else if (object->type == ACPI_TYPE_INTEGER) {
0779         len = MIN(buflen, sizeof(object->integer.value));
0780         memset(buffer, 0, buflen);
0781         memcpy(buffer, &object->integer.value, len);
0782 
0783     } else {
0784         pr_warn("Unexpected acpi_object: 0x%x\n", object->type);
0785         ret = -EINVAL;
0786     }
0787 
0788     kfree(object);
0789     return ret;
0790 }
0791 
0792 static int sony_nc_int_call(acpi_handle handle, char *name, int *value, int
0793         *result)
0794 {
0795     int ret;
0796 
0797     if (value) {
0798         u64 v = *value;
0799 
0800         ret = sony_nc_buffer_call(handle, name, &v, result,
0801                 sizeof(*result));
0802     } else {
0803         ret =  sony_nc_buffer_call(handle, name, NULL, result,
0804                 sizeof(*result));
0805     }
0806     return ret;
0807 }
0808 
0809 struct sony_nc_handles {
0810     u16 cap[0x10];
0811     struct device_attribute devattr;
0812 };
0813 
0814 static struct sony_nc_handles *handles;
0815 
0816 static ssize_t sony_nc_handles_show(struct device *dev,
0817         struct device_attribute *attr, char *buffer)
0818 {
0819     ssize_t len = 0;
0820     int i;
0821 
0822     for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
0823         len += scnprintf(buffer + len, PAGE_SIZE - len, "0x%.4x ",
0824                 handles->cap[i]);
0825     }
0826     len += scnprintf(buffer + len, PAGE_SIZE - len, "\n");
0827 
0828     return len;
0829 }
0830 
0831 static int sony_nc_handles_setup(struct platform_device *pd)
0832 {
0833     int i, r, result, arg;
0834 
0835     handles = kzalloc(sizeof(*handles), GFP_KERNEL);
0836     if (!handles)
0837         return -ENOMEM;
0838 
0839     for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
0840         arg = i + 0x20;
0841         r = sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg,
0842                     &result);
0843         if (!r) {
0844             dprintk("caching handle 0x%.4x (offset: 0x%.2x)\n",
0845                     result, i);
0846             handles->cap[i] = result;
0847         }
0848     }
0849 
0850     if (debug) {
0851         sysfs_attr_init(&handles->devattr.attr);
0852         handles->devattr.attr.name = "handles";
0853         handles->devattr.attr.mode = S_IRUGO;
0854         handles->devattr.show = sony_nc_handles_show;
0855 
0856         /* allow reading capabilities via sysfs */
0857         if (device_create_file(&pd->dev, &handles->devattr)) {
0858             kfree(handles);
0859             handles = NULL;
0860             return -1;
0861         }
0862     }
0863 
0864     return 0;
0865 }
0866 
0867 static int sony_nc_handles_cleanup(struct platform_device *pd)
0868 {
0869     if (handles) {
0870         if (debug)
0871             device_remove_file(&pd->dev, &handles->devattr);
0872         kfree(handles);
0873         handles = NULL;
0874     }
0875     return 0;
0876 }
0877 
0878 static int sony_find_snc_handle(int handle)
0879 {
0880     int i;
0881 
0882     /* not initialized yet, return early */
0883     if (!handles || !handle)
0884         return -EINVAL;
0885 
0886     for (i = 0; i < 0x10; i++) {
0887         if (handles->cap[i] == handle) {
0888             dprintk("found handle 0x%.4x (offset: 0x%.2x)\n",
0889                     handle, i);
0890             return i;
0891         }
0892     }
0893     dprintk("handle 0x%.4x not found\n", handle);
0894     return -EINVAL;
0895 }
0896 
0897 static int sony_call_snc_handle(int handle, int argument, int *result)
0898 {
0899     int arg, ret = 0;
0900     int offset = sony_find_snc_handle(handle);
0901 
0902     if (offset < 0)
0903         return offset;
0904 
0905     arg = offset | argument;
0906     ret = sony_nc_int_call(sony_nc_acpi_handle, "SN07", &arg, result);
0907     dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n", arg, *result);
0908     return ret;
0909 }
0910 
0911 /*
0912  * sony_nc_values input/output validate functions
0913  */
0914 
0915 /* brightness_default_validate:
0916  *
0917  * manipulate input output values to keep consistency with the
0918  * backlight framework for which brightness values are 0-based.
0919  */
0920 static int brightness_default_validate(const int direction, const int value)
0921 {
0922     switch (direction) {
0923         case SNC_VALIDATE_OUT:
0924             return value - 1;
0925         case SNC_VALIDATE_IN:
0926             if (value >= 0 && value < SONY_MAX_BRIGHTNESS)
0927                 return value + 1;
0928     }
0929     return -EINVAL;
0930 }
0931 
0932 /* boolean_validate:
0933  *
0934  * on input validate boolean values 0/1, on output just pass the
0935  * received value.
0936  */
0937 static int boolean_validate(const int direction, const int value)
0938 {
0939     if (direction == SNC_VALIDATE_IN) {
0940         if (value != 0 && value != 1)
0941             return -EINVAL;
0942     }
0943     return value;
0944 }
0945 
0946 /*
0947  * Sysfs show/store common to all sony_nc_values
0948  */
0949 static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr,
0950                   char *buffer)
0951 {
0952     int value, ret = 0;
0953     struct sony_nc_value *item =
0954         container_of(attr, struct sony_nc_value, devattr);
0955 
0956     if (!*item->acpiget)
0957         return -EIO;
0958 
0959     ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiget, NULL,
0960                 &value);
0961     if (ret < 0)
0962         return -EIO;
0963 
0964     if (item->validate)
0965         value = item->validate(SNC_VALIDATE_OUT, value);
0966 
0967     return sysfs_emit(buffer, "%d\n", value);
0968 }
0969 
0970 static ssize_t sony_nc_sysfs_store(struct device *dev,
0971                    struct device_attribute *attr,
0972                    const char *buffer, size_t count)
0973 {
0974     int value;
0975     int ret = 0;
0976     struct sony_nc_value *item =
0977         container_of(attr, struct sony_nc_value, devattr);
0978 
0979     if (!item->acpiset)
0980         return -EIO;
0981 
0982     if (count > 31)
0983         return -EINVAL;
0984 
0985     if (kstrtoint(buffer, 10, &value))
0986         return -EINVAL;
0987 
0988     if (item->validate)
0989         value = item->validate(SNC_VALIDATE_IN, value);
0990 
0991     if (value < 0)
0992         return value;
0993 
0994     ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiset,
0995                    &value, NULL);
0996     if (ret < 0)
0997         return -EIO;
0998 
0999     item->value = value;
1000     item->valid = 1;
1001     return count;
1002 }
1003 
1004 
1005 /*
1006  * Backlight device
1007  */
1008 struct sony_backlight_props {
1009     struct backlight_device *dev;
1010     int         handle;
1011     int         cmd_base;
1012     u8          offset;
1013     u8          maxlvl;
1014 };
1015 static struct sony_backlight_props sony_bl_props;
1016 
1017 static int sony_backlight_update_status(struct backlight_device *bd)
1018 {
1019     int arg = bd->props.brightness + 1;
1020     return sony_nc_int_call(sony_nc_acpi_handle, "SBRT", &arg, NULL);
1021 }
1022 
1023 static int sony_backlight_get_brightness(struct backlight_device *bd)
1024 {
1025     int value;
1026 
1027     if (sony_nc_int_call(sony_nc_acpi_handle, "GBRT", NULL, &value))
1028         return 0;
1029     /* brightness levels are 1-based, while backlight ones are 0-based */
1030     return value - 1;
1031 }
1032 
1033 static int sony_nc_get_brightness_ng(struct backlight_device *bd)
1034 {
1035     int result;
1036     struct sony_backlight_props *sdev =
1037         (struct sony_backlight_props *)bl_get_data(bd);
1038 
1039     sony_call_snc_handle(sdev->handle, sdev->cmd_base + 0x100, &result);
1040 
1041     return (result & 0xff) - sdev->offset;
1042 }
1043 
1044 static int sony_nc_update_status_ng(struct backlight_device *bd)
1045 {
1046     int value, result;
1047     struct sony_backlight_props *sdev =
1048         (struct sony_backlight_props *)bl_get_data(bd);
1049 
1050     value = bd->props.brightness + sdev->offset;
1051     if (sony_call_snc_handle(sdev->handle, sdev->cmd_base | (value << 0x10),
1052                 &result))
1053         return -EIO;
1054 
1055     return value;
1056 }
1057 
1058 static const struct backlight_ops sony_backlight_ops = {
1059     .options = BL_CORE_SUSPENDRESUME,
1060     .update_status = sony_backlight_update_status,
1061     .get_brightness = sony_backlight_get_brightness,
1062 };
1063 static const struct backlight_ops sony_backlight_ng_ops = {
1064     .options = BL_CORE_SUSPENDRESUME,
1065     .update_status = sony_nc_update_status_ng,
1066     .get_brightness = sony_nc_get_brightness_ng,
1067 };
1068 
1069 /*
1070  * New SNC-only Vaios event mapping to driver known keys
1071  */
1072 struct sony_nc_event {
1073     u8  data;
1074     u8  event;
1075 };
1076 
1077 static struct sony_nc_event sony_100_events[] = {
1078     { 0x90, SONYPI_EVENT_PKEY_P1 },
1079     { 0x10, SONYPI_EVENT_ANYBUTTON_RELEASED },
1080     { 0x91, SONYPI_EVENT_PKEY_P2 },
1081     { 0x11, SONYPI_EVENT_ANYBUTTON_RELEASED },
1082     { 0x81, SONYPI_EVENT_FNKEY_F1 },
1083     { 0x01, SONYPI_EVENT_FNKEY_RELEASED },
1084     { 0x82, SONYPI_EVENT_FNKEY_F2 },
1085     { 0x02, SONYPI_EVENT_FNKEY_RELEASED },
1086     { 0x83, SONYPI_EVENT_FNKEY_F3 },
1087     { 0x03, SONYPI_EVENT_FNKEY_RELEASED },
1088     { 0x84, SONYPI_EVENT_FNKEY_F4 },
1089     { 0x04, SONYPI_EVENT_FNKEY_RELEASED },
1090     { 0x85, SONYPI_EVENT_FNKEY_F5 },
1091     { 0x05, SONYPI_EVENT_FNKEY_RELEASED },
1092     { 0x86, SONYPI_EVENT_FNKEY_F6 },
1093     { 0x06, SONYPI_EVENT_FNKEY_RELEASED },
1094     { 0x87, SONYPI_EVENT_FNKEY_F7 },
1095     { 0x07, SONYPI_EVENT_FNKEY_RELEASED },
1096     { 0x88, SONYPI_EVENT_FNKEY_F8 },
1097     { 0x08, SONYPI_EVENT_FNKEY_RELEASED },
1098     { 0x89, SONYPI_EVENT_FNKEY_F9 },
1099     { 0x09, SONYPI_EVENT_FNKEY_RELEASED },
1100     { 0x8A, SONYPI_EVENT_FNKEY_F10 },
1101     { 0x0A, SONYPI_EVENT_FNKEY_RELEASED },
1102     { 0x8B, SONYPI_EVENT_FNKEY_F11 },
1103     { 0x0B, SONYPI_EVENT_FNKEY_RELEASED },
1104     { 0x8C, SONYPI_EVENT_FNKEY_F12 },
1105     { 0x0C, SONYPI_EVENT_FNKEY_RELEASED },
1106     { 0x9d, SONYPI_EVENT_ZOOM_PRESSED },
1107     { 0x1d, SONYPI_EVENT_ANYBUTTON_RELEASED },
1108     { 0x9f, SONYPI_EVENT_CD_EJECT_PRESSED },
1109     { 0x1f, SONYPI_EVENT_ANYBUTTON_RELEASED },
1110     { 0xa1, SONYPI_EVENT_MEDIA_PRESSED },
1111     { 0x21, SONYPI_EVENT_ANYBUTTON_RELEASED },
1112     { 0xa4, SONYPI_EVENT_CD_EJECT_PRESSED },
1113     { 0x24, SONYPI_EVENT_ANYBUTTON_RELEASED },
1114     { 0xa5, SONYPI_EVENT_VENDOR_PRESSED },
1115     { 0x25, SONYPI_EVENT_ANYBUTTON_RELEASED },
1116     { 0xa6, SONYPI_EVENT_HELP_PRESSED },
1117     { 0x26, SONYPI_EVENT_ANYBUTTON_RELEASED },
1118     { 0xa8, SONYPI_EVENT_FNKEY_1 },
1119     { 0x28, SONYPI_EVENT_ANYBUTTON_RELEASED },
1120     { 0, 0 },
1121 };
1122 
1123 static struct sony_nc_event sony_127_events[] = {
1124     { 0x81, SONYPI_EVENT_MODEKEY_PRESSED },
1125     { 0x01, SONYPI_EVENT_ANYBUTTON_RELEASED },
1126     { 0x82, SONYPI_EVENT_PKEY_P1 },
1127     { 0x02, SONYPI_EVENT_ANYBUTTON_RELEASED },
1128     { 0x83, SONYPI_EVENT_PKEY_P2 },
1129     { 0x03, SONYPI_EVENT_ANYBUTTON_RELEASED },
1130     { 0x84, SONYPI_EVENT_PKEY_P3 },
1131     { 0x04, SONYPI_EVENT_ANYBUTTON_RELEASED },
1132     { 0x85, SONYPI_EVENT_PKEY_P4 },
1133     { 0x05, SONYPI_EVENT_ANYBUTTON_RELEASED },
1134     { 0x86, SONYPI_EVENT_PKEY_P5 },
1135     { 0x06, SONYPI_EVENT_ANYBUTTON_RELEASED },
1136     { 0x87, SONYPI_EVENT_SETTINGKEY_PRESSED },
1137     { 0x07, SONYPI_EVENT_ANYBUTTON_RELEASED },
1138     { 0, 0 },
1139 };
1140 
1141 static int sony_nc_hotkeys_decode(u32 event, unsigned int handle)
1142 {
1143     int ret = -EINVAL;
1144     unsigned int result = 0;
1145     struct sony_nc_event *key_event;
1146 
1147     if (sony_call_snc_handle(handle, 0x200, &result)) {
1148         dprintk("Unable to decode event 0x%.2x 0x%.2x\n", handle,
1149                 event);
1150         return -EINVAL;
1151     }
1152 
1153     result &= 0xFF;
1154 
1155     if (handle == 0x0100)
1156         key_event = sony_100_events;
1157     else
1158         key_event = sony_127_events;
1159 
1160     for (; key_event->data; key_event++) {
1161         if (key_event->data == result) {
1162             ret = key_event->event;
1163             break;
1164         }
1165     }
1166 
1167     if (!key_event->data)
1168         pr_info("Unknown hotkey 0x%.2x/0x%.2x (handle 0x%.2x)\n",
1169                 event, result, handle);
1170 
1171     return ret;
1172 }
1173 
1174 /*
1175  * ACPI callbacks
1176  */
1177 enum event_types {
1178     HOTKEY = 1,
1179     KILLSWITCH,
1180     GFX_SWITCH
1181 };
1182 static void sony_nc_notify(struct acpi_device *device, u32 event)
1183 {
1184     u32 real_ev = event;
1185     u8 ev_type = 0;
1186     int ret;
1187 
1188     dprintk("sony_nc_notify, event: 0x%.2x\n", event);
1189 
1190     if (event >= 0x90) {
1191         unsigned int result = 0;
1192         unsigned int arg = 0;
1193         unsigned int handle = 0;
1194         unsigned int offset = event - 0x90;
1195 
1196         if (offset >= ARRAY_SIZE(handles->cap)) {
1197             pr_err("Event 0x%x outside of capabilities list\n",
1198                     event);
1199             return;
1200         }
1201         handle = handles->cap[offset];
1202 
1203         /* list of handles known for generating events */
1204         switch (handle) {
1205         /* hotkey event */
1206         case 0x0100:
1207         case 0x0127:
1208             ev_type = HOTKEY;
1209             ret = sony_nc_hotkeys_decode(event, handle);
1210 
1211             if (ret > 0) {
1212                 sony_laptop_report_input_event(ret);
1213                 real_ev = ret;
1214             }
1215 
1216             break;
1217 
1218         /* wlan switch */
1219         case 0x0124:
1220         case 0x0135:
1221             /* events on this handle are reported when the
1222              * switch changes position or for battery
1223              * events. We'll notify both of them but only
1224              * update the rfkill device status when the
1225              * switch is moved.
1226              */
1227             ev_type = KILLSWITCH;
1228             sony_call_snc_handle(handle, 0x0100, &result);
1229             real_ev = result & 0x03;
1230 
1231             /* hw switch event */
1232             if (real_ev == 1)
1233                 sony_nc_rfkill_update();
1234 
1235             break;
1236 
1237         case 0x0128:
1238         case 0x0146:
1239             /* Hybrid GFX switching */
1240             sony_call_snc_handle(handle, 0x0000, &result);
1241             dprintk("GFX switch event received (reason: %s)\n",
1242                     (result == 0x1) ? "switch change" :
1243                     (result == 0x2) ? "output switch" :
1244                     (result == 0x3) ? "output switch" :
1245                     "");
1246 
1247             ev_type = GFX_SWITCH;
1248             real_ev = __sony_nc_gfx_switch_status_get();
1249             break;
1250 
1251         case 0x015B:
1252             /* Hybrid GFX switching SVS151290S */
1253             ev_type = GFX_SWITCH;
1254             real_ev = __sony_nc_gfx_switch_status_get();
1255             break;
1256         default:
1257             dprintk("Unknown event 0x%x for handle 0x%x\n",
1258                     event, handle);
1259             break;
1260         }
1261 
1262         /* clear the event (and the event reason when present) */
1263         arg = 1 << offset;
1264         sony_nc_int_call(sony_nc_acpi_handle, "SN05", &arg, &result);
1265 
1266     } else {
1267         /* old style event */
1268         ev_type = HOTKEY;
1269         sony_laptop_report_input_event(real_ev);
1270     }
1271     acpi_bus_generate_netlink_event(sony_nc_acpi_device->pnp.device_class,
1272             dev_name(&sony_nc_acpi_device->dev), ev_type, real_ev);
1273 }
1274 
1275 static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
1276                       void *context, void **return_value)
1277 {
1278     struct acpi_device_info *info;
1279 
1280     if (ACPI_SUCCESS(acpi_get_object_info(handle, &info))) {
1281         pr_warn("method: name: %4.4s, args %X\n",
1282             (char *)&info->name, info->param_count);
1283 
1284         kfree(info);
1285     }
1286 
1287     return AE_OK;
1288 }
1289 
1290 /*
1291  * ACPI device
1292  */
1293 static void sony_nc_function_setup(struct acpi_device *device,
1294         struct platform_device *pf_device)
1295 {
1296     unsigned int i, result, bitmask, arg;
1297 
1298     if (!handles)
1299         return;
1300 
1301     /* setup found handles here */
1302     for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
1303         unsigned int handle = handles->cap[i];
1304 
1305         if (!handle)
1306             continue;
1307 
1308         dprintk("setting up handle 0x%.4x\n", handle);
1309 
1310         switch (handle) {
1311         case 0x0100:
1312         case 0x0101:
1313         case 0x0127:
1314             /* setup hotkeys */
1315             sony_call_snc_handle(handle, 0, &result);
1316             break;
1317         case 0x0102:
1318             /* setup hotkeys */
1319             sony_call_snc_handle(handle, 0x100, &result);
1320             break;
1321         case 0x0105:
1322         case 0x0148:
1323             /* touchpad enable/disable */
1324             result = sony_nc_touchpad_setup(pf_device, handle);
1325             if (result)
1326                 pr_err("couldn't set up touchpad control function (%d)\n",
1327                         result);
1328             break;
1329         case 0x0115:
1330         case 0x0136:
1331         case 0x013f:
1332             result = sony_nc_battery_care_setup(pf_device, handle);
1333             if (result)
1334                 pr_err("couldn't set up battery care function (%d)\n",
1335                         result);
1336             break;
1337         case 0x0119:
1338         case 0x015D:
1339             result = sony_nc_lid_resume_setup(pf_device, handle);
1340             if (result)
1341                 pr_err("couldn't set up lid resume function (%d)\n",
1342                         result);
1343             break;
1344         case 0x0122:
1345             result = sony_nc_thermal_setup(pf_device);
1346             if (result)
1347                 pr_err("couldn't set up thermal profile function (%d)\n",
1348                         result);
1349             break;
1350         case 0x0128:
1351         case 0x0146:
1352         case 0x015B:
1353             result = sony_nc_gfx_switch_setup(pf_device, handle);
1354             if (result)
1355                 pr_err("couldn't set up GFX Switch status (%d)\n",
1356                         result);
1357             break;
1358         case 0x0131:
1359             result = sony_nc_highspeed_charging_setup(pf_device);
1360             if (result)
1361                 pr_err("couldn't set up high speed charging function (%d)\n",
1362                        result);
1363             break;
1364         case 0x0124:
1365         case 0x0135:
1366             result = sony_nc_rfkill_setup(device, handle);
1367             if (result)
1368                 pr_err("couldn't set up rfkill support (%d)\n",
1369                         result);
1370             break;
1371         case 0x0137:
1372         case 0x0143:
1373         case 0x014b:
1374         case 0x014c:
1375         case 0x0153:
1376         case 0x0163:
1377             result = sony_nc_kbd_backlight_setup(pf_device, handle);
1378             if (result)
1379                 pr_err("couldn't set up keyboard backlight function (%d)\n",
1380                         result);
1381             break;
1382         case 0x0121:
1383             result = sony_nc_lowbatt_setup(pf_device);
1384             if (result)
1385                 pr_err("couldn't set up low battery function (%d)\n",
1386                        result);
1387             break;
1388         case 0x0149:
1389             result = sony_nc_fanspeed_setup(pf_device);
1390             if (result)
1391                 pr_err("couldn't set up fan speed function (%d)\n",
1392                        result);
1393             break;
1394         case 0x0155:
1395             result = sony_nc_usb_charge_setup(pf_device);
1396             if (result)
1397                 pr_err("couldn't set up USB charge support (%d)\n",
1398                         result);
1399             break;
1400         case 0x011D:
1401             result = sony_nc_panelid_setup(pf_device);
1402             if (result)
1403                 pr_err("couldn't set up panel ID function (%d)\n",
1404                        result);
1405             break;
1406         case 0x0168:
1407             result = sony_nc_smart_conn_setup(pf_device);
1408             if (result)
1409                 pr_err("couldn't set up smart connect support (%d)\n",
1410                         result);
1411             break;
1412         default:
1413             continue;
1414         }
1415     }
1416 
1417     /* Enable all events */
1418     arg = 0x10;
1419     if (!sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg, &bitmask))
1420         sony_nc_int_call(sony_nc_acpi_handle, "SN02", &bitmask,
1421                 &result);
1422 }
1423 
1424 static void sony_nc_function_cleanup(struct platform_device *pd)
1425 {
1426     unsigned int i, result, bitmask, handle;
1427 
1428     if (!handles)
1429         return;
1430 
1431     /* get enabled events and disable them */
1432     sony_nc_int_call(sony_nc_acpi_handle, "SN01", NULL, &bitmask);
1433     sony_nc_int_call(sony_nc_acpi_handle, "SN03", &bitmask, &result);
1434 
1435     /* cleanup handles here */
1436     for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
1437 
1438         handle = handles->cap[i];
1439 
1440         if (!handle)
1441             continue;
1442 
1443         switch (handle) {
1444         case 0x0105:
1445         case 0x0148:
1446             sony_nc_touchpad_cleanup(pd);
1447             break;
1448         case 0x0115:
1449         case 0x0136:
1450         case 0x013f:
1451             sony_nc_battery_care_cleanup(pd);
1452             break;
1453         case 0x0119:
1454         case 0x015D:
1455             sony_nc_lid_resume_cleanup(pd);
1456             break;
1457         case 0x0122:
1458             sony_nc_thermal_cleanup(pd);
1459             break;
1460         case 0x0128:
1461         case 0x0146:
1462         case 0x015B:
1463             sony_nc_gfx_switch_cleanup(pd);
1464             break;
1465         case 0x0131:
1466             sony_nc_highspeed_charging_cleanup(pd);
1467             break;
1468         case 0x0124:
1469         case 0x0135:
1470             sony_nc_rfkill_cleanup();
1471             break;
1472         case 0x0137:
1473         case 0x0143:
1474         case 0x014b:
1475         case 0x014c:
1476         case 0x0153:
1477         case 0x0163:
1478             sony_nc_kbd_backlight_cleanup(pd, handle);
1479             break;
1480         case 0x0121:
1481             sony_nc_lowbatt_cleanup(pd);
1482             break;
1483         case 0x0149:
1484             sony_nc_fanspeed_cleanup(pd);
1485             break;
1486         case 0x0155:
1487             sony_nc_usb_charge_cleanup(pd);
1488             break;
1489         case 0x011D:
1490             sony_nc_panelid_cleanup(pd);
1491             break;
1492         case 0x0168:
1493             sony_nc_smart_conn_cleanup(pd);
1494             break;
1495         default:
1496             continue;
1497         }
1498     }
1499 
1500     /* finally cleanup the handles list */
1501     sony_nc_handles_cleanup(pd);
1502 }
1503 
1504 #ifdef CONFIG_PM_SLEEP
1505 static void sony_nc_function_resume(void)
1506 {
1507     unsigned int i, result, bitmask, arg;
1508 
1509     dprintk("Resuming SNC device\n");
1510 
1511     for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
1512         unsigned int handle = handles->cap[i];
1513 
1514         if (!handle)
1515             continue;
1516 
1517         switch (handle) {
1518         case 0x0100:
1519         case 0x0101:
1520         case 0x0127:
1521             /* re-enable hotkeys */
1522             sony_call_snc_handle(handle, 0, &result);
1523             break;
1524         case 0x0102:
1525             /* re-enable hotkeys */
1526             sony_call_snc_handle(handle, 0x100, &result);
1527             break;
1528         case 0x0122:
1529             sony_nc_thermal_resume();
1530             break;
1531         case 0x0124:
1532         case 0x0135:
1533             sony_nc_rfkill_update();
1534             break;
1535         default:
1536             continue;
1537         }
1538     }
1539 
1540     /* Enable all events */
1541     arg = 0x10;
1542     if (!sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg, &bitmask))
1543         sony_nc_int_call(sony_nc_acpi_handle, "SN02", &bitmask,
1544                 &result);
1545 }
1546 
1547 static int sony_nc_resume(struct device *dev)
1548 {
1549     struct sony_nc_value *item;
1550 
1551     for (item = sony_nc_values; item->name; item++) {
1552         int ret;
1553 
1554         if (!item->valid)
1555             continue;
1556         ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiset,
1557                        &item->value, NULL);
1558         if (ret < 0) {
1559             pr_err("%s: %d\n", __func__, ret);
1560             break;
1561         }
1562     }
1563 
1564     if (acpi_has_method(sony_nc_acpi_handle, "ECON")) {
1565         int arg = 1;
1566         if (sony_nc_int_call(sony_nc_acpi_handle, "ECON", &arg, NULL))
1567             dprintk("ECON Method failed\n");
1568     }
1569 
1570     if (acpi_has_method(sony_nc_acpi_handle, "SN00"))
1571         sony_nc_function_resume();
1572 
1573     return 0;
1574 }
1575 #endif
1576 
1577 static SIMPLE_DEV_PM_OPS(sony_nc_pm, NULL, sony_nc_resume);
1578 
1579 static void sony_nc_rfkill_cleanup(void)
1580 {
1581     int i;
1582 
1583     for (i = 0; i < N_SONY_RFKILL; i++) {
1584         if (sony_rfkill_devices[i]) {
1585             rfkill_unregister(sony_rfkill_devices[i]);
1586             rfkill_destroy(sony_rfkill_devices[i]);
1587         }
1588     }
1589 }
1590 
1591 static int sony_nc_rfkill_set(void *data, bool blocked)
1592 {
1593     int result;
1594     int argument = sony_rfkill_address[(long) data] + 0x100;
1595 
1596     if (!blocked)
1597         argument |= 0x070000;
1598 
1599     return sony_call_snc_handle(sony_rfkill_handle, argument, &result);
1600 }
1601 
1602 static const struct rfkill_ops sony_rfkill_ops = {
1603     .set_block = sony_nc_rfkill_set,
1604 };
1605 
1606 static int sony_nc_setup_rfkill(struct acpi_device *device,
1607                 enum sony_nc_rfkill nc_type)
1608 {
1609     int err;
1610     struct rfkill *rfk;
1611     enum rfkill_type type;
1612     const char *name;
1613     int result;
1614     bool hwblock, swblock;
1615 
1616     switch (nc_type) {
1617     case SONY_WIFI:
1618         type = RFKILL_TYPE_WLAN;
1619         name = "sony-wifi";
1620         break;
1621     case SONY_BLUETOOTH:
1622         type = RFKILL_TYPE_BLUETOOTH;
1623         name = "sony-bluetooth";
1624         break;
1625     case SONY_WWAN:
1626         type = RFKILL_TYPE_WWAN;
1627         name = "sony-wwan";
1628         break;
1629     case SONY_WIMAX:
1630         type = RFKILL_TYPE_WIMAX;
1631         name = "sony-wimax";
1632         break;
1633     default:
1634         return -EINVAL;
1635     }
1636 
1637     rfk = rfkill_alloc(name, &device->dev, type,
1638                &sony_rfkill_ops, (void *)nc_type);
1639     if (!rfk)
1640         return -ENOMEM;
1641 
1642     err = sony_call_snc_handle(sony_rfkill_handle, 0x200, &result);
1643     if (err < 0) {
1644         rfkill_destroy(rfk);
1645         return err;
1646     }
1647     hwblock = !(result & 0x1);
1648 
1649     err = sony_call_snc_handle(sony_rfkill_handle,
1650                    sony_rfkill_address[nc_type],
1651                    &result);
1652     if (err < 0) {
1653         rfkill_destroy(rfk);
1654         return err;
1655     }
1656     swblock = !(result & 0x2);
1657 
1658     rfkill_init_sw_state(rfk, swblock);
1659     rfkill_set_hw_state(rfk, hwblock);
1660 
1661     err = rfkill_register(rfk);
1662     if (err) {
1663         rfkill_destroy(rfk);
1664         return err;
1665     }
1666     sony_rfkill_devices[nc_type] = rfk;
1667     return err;
1668 }
1669 
1670 static void sony_nc_rfkill_update(void)
1671 {
1672     enum sony_nc_rfkill i;
1673     int result;
1674     bool hwblock;
1675 
1676     sony_call_snc_handle(sony_rfkill_handle, 0x200, &result);
1677     hwblock = !(result & 0x1);
1678 
1679     for (i = 0; i < N_SONY_RFKILL; i++) {
1680         int argument = sony_rfkill_address[i];
1681 
1682         if (!sony_rfkill_devices[i])
1683             continue;
1684 
1685         if (hwblock) {
1686             if (rfkill_set_hw_state(sony_rfkill_devices[i], true)) {
1687                 /* we already know we're blocked */
1688             }
1689             continue;
1690         }
1691 
1692         sony_call_snc_handle(sony_rfkill_handle, argument, &result);
1693         rfkill_set_states(sony_rfkill_devices[i],
1694                   !(result & 0x2), false);
1695     }
1696 }
1697 
1698 static int sony_nc_rfkill_setup(struct acpi_device *device,
1699         unsigned int handle)
1700 {
1701     u64 offset;
1702     int i;
1703     unsigned char buffer[32] = { 0 };
1704 
1705     offset = sony_find_snc_handle(handle);
1706     sony_rfkill_handle = handle;
1707 
1708     i = sony_nc_buffer_call(sony_nc_acpi_handle, "SN06", &offset, buffer,
1709             32);
1710     if (i < 0)
1711         return i;
1712 
1713     /* The buffer is filled with magic numbers describing the devices
1714      * available, 0xff terminates the enumeration.
1715      * Known codes:
1716      *  0x00 WLAN
1717      *  0x10 BLUETOOTH
1718      *  0x20 WWAN GPRS-EDGE
1719      *  0x21 WWAN HSDPA
1720      *  0x22 WWAN EV-DO
1721      *  0x23 WWAN GPS
1722      *  0x25 Gobi WWAN no GPS
1723      *  0x26 Gobi WWAN + GPS
1724      *  0x28 Gobi WWAN no GPS
1725      *  0x29 Gobi WWAN + GPS
1726      *  0x30 WIMAX
1727      *  0x50 Gobi WWAN no GPS
1728      *  0x51 Gobi WWAN + GPS
1729      *  0x70 no SIM card slot
1730      *  0x71 SIM card slot
1731      */
1732     for (i = 0; i < ARRAY_SIZE(buffer); i++) {
1733 
1734         if (buffer[i] == 0xff)
1735             break;
1736 
1737         dprintk("Radio devices, found 0x%.2x\n", buffer[i]);
1738 
1739         if (buffer[i] == 0 && !sony_rfkill_devices[SONY_WIFI])
1740             sony_nc_setup_rfkill(device, SONY_WIFI);
1741 
1742         if (buffer[i] == 0x10 && !sony_rfkill_devices[SONY_BLUETOOTH])
1743             sony_nc_setup_rfkill(device, SONY_BLUETOOTH);
1744 
1745         if (((0xf0 & buffer[i]) == 0x20 ||
1746                     (0xf0 & buffer[i]) == 0x50) &&
1747                 !sony_rfkill_devices[SONY_WWAN])
1748             sony_nc_setup_rfkill(device, SONY_WWAN);
1749 
1750         if (buffer[i] == 0x30 && !sony_rfkill_devices[SONY_WIMAX])
1751             sony_nc_setup_rfkill(device, SONY_WIMAX);
1752     }
1753     return 0;
1754 }
1755 
1756 /* Keyboard backlight feature */
1757 struct kbd_backlight {
1758     unsigned int handle;
1759     unsigned int base;
1760     unsigned int mode;
1761     unsigned int timeout;
1762     unsigned int has_timeout;
1763     struct device_attribute mode_attr;
1764     struct device_attribute timeout_attr;
1765 };
1766 
1767 static struct kbd_backlight *kbdbl_ctl;
1768 
1769 static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value)
1770 {
1771     int result;
1772 
1773     if (value > 2)
1774         return -EINVAL;
1775 
1776     if (sony_call_snc_handle(kbdbl_ctl->handle,
1777                 (value << 0x10) | (kbdbl_ctl->base), &result))
1778         return -EIO;
1779 
1780     /* Try to turn the light on/off immediately */
1781     if (value != 1)
1782         sony_call_snc_handle(kbdbl_ctl->handle,
1783                 (value << 0x0f) | (kbdbl_ctl->base + 0x100),
1784                 &result);
1785 
1786     kbdbl_ctl->mode = value;
1787 
1788     return 0;
1789 }
1790 
1791 static ssize_t sony_nc_kbd_backlight_mode_store(struct device *dev,
1792         struct device_attribute *attr,
1793         const char *buffer, size_t count)
1794 {
1795     int ret = 0;
1796     unsigned long value;
1797 
1798     if (count > 31)
1799         return -EINVAL;
1800 
1801     if (kstrtoul(buffer, 10, &value))
1802         return -EINVAL;
1803 
1804     ret = __sony_nc_kbd_backlight_mode_set(value);
1805     if (ret < 0)
1806         return ret;
1807 
1808     return count;
1809 }
1810 
1811 static ssize_t sony_nc_kbd_backlight_mode_show(struct device *dev,
1812         struct device_attribute *attr, char *buffer)
1813 {
1814     return sysfs_emit(buffer, "%d\n", kbdbl_ctl->mode);
1815 }
1816 
1817 static int __sony_nc_kbd_backlight_timeout_set(u8 value)
1818 {
1819     int result;
1820 
1821     if (value > 3)
1822         return -EINVAL;
1823 
1824     if (sony_call_snc_handle(kbdbl_ctl->handle, (value << 0x10) |
1825                 (kbdbl_ctl->base + 0x200), &result))
1826         return -EIO;
1827 
1828     kbdbl_ctl->timeout = value;
1829 
1830     return 0;
1831 }
1832 
1833 static ssize_t sony_nc_kbd_backlight_timeout_store(struct device *dev,
1834         struct device_attribute *attr,
1835         const char *buffer, size_t count)
1836 {
1837     int ret = 0;
1838     unsigned long value;
1839 
1840     if (count > 31)
1841         return -EINVAL;
1842 
1843     if (kstrtoul(buffer, 10, &value))
1844         return -EINVAL;
1845 
1846     ret = __sony_nc_kbd_backlight_timeout_set(value);
1847     if (ret < 0)
1848         return ret;
1849 
1850     return count;
1851 }
1852 
1853 static ssize_t sony_nc_kbd_backlight_timeout_show(struct device *dev,
1854         struct device_attribute *attr, char *buffer)
1855 {
1856     return sysfs_emit(buffer, "%d\n", kbdbl_ctl->timeout);
1857 }
1858 
1859 static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
1860         unsigned int handle)
1861 {
1862     int result;
1863     int probe_base = 0;
1864     int ctl_base = 0;
1865     int ret = 0;
1866 
1867     if (kbdbl_ctl) {
1868         pr_warn("handle 0x%.4x: keyboard backlight setup already done for 0x%.4x\n",
1869                 handle, kbdbl_ctl->handle);
1870         return -EBUSY;
1871     }
1872 
1873     /* verify the kbd backlight presence, some of these handles are not used
1874      * for keyboard backlight only
1875      */
1876     switch (handle) {
1877     case 0x0153:
1878         probe_base = 0x0;
1879         ctl_base = 0x0;
1880         break;
1881     case 0x0137:
1882         probe_base = 0x0B00;
1883         ctl_base = 0x0C00;
1884         break;
1885     default:
1886         probe_base = 0x0100;
1887         ctl_base = 0x4000;
1888         break;
1889     }
1890 
1891     ret = sony_call_snc_handle(handle, probe_base, &result);
1892     if (ret)
1893         return ret;
1894 
1895     if ((handle == 0x0137 && !(result & 0x02)) ||
1896             !(result & 0x01)) {
1897         dprintk("no backlight keyboard found\n");
1898         return 0;
1899     }
1900 
1901     kbdbl_ctl = kzalloc(sizeof(*kbdbl_ctl), GFP_KERNEL);
1902     if (!kbdbl_ctl)
1903         return -ENOMEM;
1904 
1905     kbdbl_ctl->mode = kbd_backlight;
1906     kbdbl_ctl->timeout = kbd_backlight_timeout;
1907     kbdbl_ctl->handle = handle;
1908     kbdbl_ctl->base = ctl_base;
1909     /* Some models do not allow timeout control */
1910     kbdbl_ctl->has_timeout = handle != 0x0153;
1911 
1912     sysfs_attr_init(&kbdbl_ctl->mode_attr.attr);
1913     kbdbl_ctl->mode_attr.attr.name = "kbd_backlight";
1914     kbdbl_ctl->mode_attr.attr.mode = S_IRUGO | S_IWUSR;
1915     kbdbl_ctl->mode_attr.show = sony_nc_kbd_backlight_mode_show;
1916     kbdbl_ctl->mode_attr.store = sony_nc_kbd_backlight_mode_store;
1917 
1918     ret = device_create_file(&pd->dev, &kbdbl_ctl->mode_attr);
1919     if (ret)
1920         goto outkzalloc;
1921 
1922     __sony_nc_kbd_backlight_mode_set(kbdbl_ctl->mode);
1923 
1924     if (kbdbl_ctl->has_timeout) {
1925         sysfs_attr_init(&kbdbl_ctl->timeout_attr.attr);
1926         kbdbl_ctl->timeout_attr.attr.name = "kbd_backlight_timeout";
1927         kbdbl_ctl->timeout_attr.attr.mode = S_IRUGO | S_IWUSR;
1928         kbdbl_ctl->timeout_attr.show =
1929             sony_nc_kbd_backlight_timeout_show;
1930         kbdbl_ctl->timeout_attr.store =
1931             sony_nc_kbd_backlight_timeout_store;
1932 
1933         ret = device_create_file(&pd->dev, &kbdbl_ctl->timeout_attr);
1934         if (ret)
1935             goto outmode;
1936 
1937         __sony_nc_kbd_backlight_timeout_set(kbdbl_ctl->timeout);
1938     }
1939 
1940 
1941     return 0;
1942 
1943 outmode:
1944     device_remove_file(&pd->dev, &kbdbl_ctl->mode_attr);
1945 outkzalloc:
1946     kfree(kbdbl_ctl);
1947     kbdbl_ctl = NULL;
1948     return ret;
1949 }
1950 
1951 static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd,
1952         unsigned int handle)
1953 {
1954     if (kbdbl_ctl && handle == kbdbl_ctl->handle) {
1955         device_remove_file(&pd->dev, &kbdbl_ctl->mode_attr);
1956         if (kbdbl_ctl->has_timeout)
1957             device_remove_file(&pd->dev, &kbdbl_ctl->timeout_attr);
1958         kfree(kbdbl_ctl);
1959         kbdbl_ctl = NULL;
1960     }
1961 }
1962 
1963 struct battery_care_control {
1964     struct device_attribute attrs[2];
1965     unsigned int handle;
1966 };
1967 static struct battery_care_control *bcare_ctl;
1968 
1969 static ssize_t sony_nc_battery_care_limit_store(struct device *dev,
1970         struct device_attribute *attr,
1971         const char *buffer, size_t count)
1972 {
1973     unsigned int result, cmd;
1974     unsigned long value;
1975 
1976     if (count > 31)
1977         return -EINVAL;
1978 
1979     if (kstrtoul(buffer, 10, &value))
1980         return -EINVAL;
1981 
1982     /*  limit values (2 bits):
1983      *  00 - none
1984      *  01 - 80%
1985      *  10 - 50%
1986      *  11 - 100%
1987      *
1988      *  bit 0: 0 disable BCL, 1 enable BCL
1989      *  bit 1: 1 tell to store the battery limit (see bits 6,7) too
1990      *  bits 2,3: reserved
1991      *  bits 4,5: store the limit into the EC
1992      *  bits 6,7: store the limit into the battery
1993      */
1994     cmd = 0;
1995 
1996     if (value > 0) {
1997         if (value <= 50)
1998             cmd = 0x20;
1999 
2000         else if (value <= 80)
2001             cmd = 0x10;
2002 
2003         else if (value <= 100)
2004             cmd = 0x30;
2005 
2006         else
2007             return -EINVAL;
2008 
2009         /*
2010          * handle 0x0115 should allow storing on battery too;
2011          * handle 0x0136 same as 0x0115 + health status;
2012          * handle 0x013f, same as 0x0136 but no storing on the battery
2013          */
2014         if (bcare_ctl->handle != 0x013f)
2015             cmd = cmd | (cmd << 2);
2016 
2017         cmd = (cmd | 0x1) << 0x10;
2018     }
2019 
2020     if (sony_call_snc_handle(bcare_ctl->handle, cmd | 0x0100, &result))
2021         return -EIO;
2022 
2023     return count;
2024 }
2025 
2026 static ssize_t sony_nc_battery_care_limit_show(struct device *dev,
2027         struct device_attribute *attr, char *buffer)
2028 {
2029     unsigned int result, status;
2030 
2031     if (sony_call_snc_handle(bcare_ctl->handle, 0x0000, &result))
2032         return -EIO;
2033 
2034     status = (result & 0x01) ? ((result & 0x30) >> 0x04) : 0;
2035     switch (status) {
2036     case 1:
2037         status = 80;
2038         break;
2039     case 2:
2040         status = 50;
2041         break;
2042     case 3:
2043         status = 100;
2044         break;
2045     default:
2046         status = 0;
2047         break;
2048     }
2049 
2050     return sysfs_emit(buffer, "%d\n", status);
2051 }
2052 
2053 static ssize_t sony_nc_battery_care_health_show(struct device *dev,
2054         struct device_attribute *attr, char *buffer)
2055 {
2056     unsigned int health;
2057 
2058     if (sony_call_snc_handle(bcare_ctl->handle, 0x0200, &health))
2059         return -EIO;
2060 
2061     return sysfs_emit(buffer, "%d\n", health & 0xff);
2062 }
2063 
2064 static int sony_nc_battery_care_setup(struct platform_device *pd,
2065         unsigned int handle)
2066 {
2067     int ret = 0;
2068 
2069     bcare_ctl = kzalloc(sizeof(struct battery_care_control), GFP_KERNEL);
2070     if (!bcare_ctl)
2071         return -ENOMEM;
2072 
2073     bcare_ctl->handle = handle;
2074 
2075     sysfs_attr_init(&bcare_ctl->attrs[0].attr);
2076     bcare_ctl->attrs[0].attr.name = "battery_care_limiter";
2077     bcare_ctl->attrs[0].attr.mode = S_IRUGO | S_IWUSR;
2078     bcare_ctl->attrs[0].show = sony_nc_battery_care_limit_show;
2079     bcare_ctl->attrs[0].store = sony_nc_battery_care_limit_store;
2080 
2081     ret = device_create_file(&pd->dev, &bcare_ctl->attrs[0]);
2082     if (ret)
2083         goto outkzalloc;
2084 
2085     /* 0x0115 is for models with no health reporting capability */
2086     if (handle == 0x0115)
2087         return 0;
2088 
2089     sysfs_attr_init(&bcare_ctl->attrs[1].attr);
2090     bcare_ctl->attrs[1].attr.name = "battery_care_health";
2091     bcare_ctl->attrs[1].attr.mode = S_IRUGO;
2092     bcare_ctl->attrs[1].show = sony_nc_battery_care_health_show;
2093 
2094     ret = device_create_file(&pd->dev, &bcare_ctl->attrs[1]);
2095     if (ret)
2096         goto outlimiter;
2097 
2098     return 0;
2099 
2100 outlimiter:
2101     device_remove_file(&pd->dev, &bcare_ctl->attrs[0]);
2102 
2103 outkzalloc:
2104     kfree(bcare_ctl);
2105     bcare_ctl = NULL;
2106 
2107     return ret;
2108 }
2109 
2110 static void sony_nc_battery_care_cleanup(struct platform_device *pd)
2111 {
2112     if (bcare_ctl) {
2113         device_remove_file(&pd->dev, &bcare_ctl->attrs[0]);
2114         if (bcare_ctl->handle != 0x0115)
2115             device_remove_file(&pd->dev, &bcare_ctl->attrs[1]);
2116 
2117         kfree(bcare_ctl);
2118         bcare_ctl = NULL;
2119     }
2120 }
2121 
2122 struct snc_thermal_ctrl {
2123     unsigned int mode;
2124     unsigned int profiles;
2125     struct device_attribute mode_attr;
2126     struct device_attribute profiles_attr;
2127 };
2128 static struct snc_thermal_ctrl *th_handle;
2129 
2130 #define THM_PROFILE_MAX 3
2131 static const char * const snc_thermal_profiles[] = {
2132     "balanced",
2133     "silent",
2134     "performance"
2135 };
2136 
2137 static int sony_nc_thermal_mode_set(unsigned short mode)
2138 {
2139     unsigned int result;
2140 
2141     /* the thermal profile seems to be a two bit bitmask:
2142      * lsb -> silent
2143      * msb -> performance
2144      * no bit set is the normal operation and is always valid
2145      * Some vaio models only have "balanced" and "performance"
2146      */
2147     if ((mode && !(th_handle->profiles & mode)) || mode >= THM_PROFILE_MAX)
2148         return -EINVAL;
2149 
2150     if (sony_call_snc_handle(0x0122, mode << 0x10 | 0x0200, &result))
2151         return -EIO;
2152 
2153     th_handle->mode = mode;
2154 
2155     return 0;
2156 }
2157 
2158 static int sony_nc_thermal_mode_get(void)
2159 {
2160     unsigned int result;
2161 
2162     if (sony_call_snc_handle(0x0122, 0x0100, &result))
2163         return -EIO;
2164 
2165     return result & 0xff;
2166 }
2167 
2168 static ssize_t sony_nc_thermal_profiles_show(struct device *dev,
2169         struct device_attribute *attr, char *buffer)
2170 {
2171     short cnt;
2172     size_t idx = 0;
2173 
2174     for (cnt = 0; cnt < THM_PROFILE_MAX; cnt++) {
2175         if (!cnt || (th_handle->profiles & cnt))
2176             idx += scnprintf(buffer + idx, PAGE_SIZE - idx, "%s ",
2177                     snc_thermal_profiles[cnt]);
2178     }
2179     idx += scnprintf(buffer + idx, PAGE_SIZE - idx, "\n");
2180 
2181     return idx;
2182 }
2183 
2184 static ssize_t sony_nc_thermal_mode_store(struct device *dev,
2185         struct device_attribute *attr,
2186         const char *buffer, size_t count)
2187 {
2188     unsigned short cmd;
2189     size_t len = count;
2190 
2191     if (count == 0)
2192         return -EINVAL;
2193 
2194     /* skip the newline if present */
2195     if (buffer[len - 1] == '\n')
2196         len--;
2197 
2198     for (cmd = 0; cmd < THM_PROFILE_MAX; cmd++)
2199         if (strncmp(buffer, snc_thermal_profiles[cmd], len) == 0)
2200             break;
2201 
2202     if (sony_nc_thermal_mode_set(cmd))
2203         return -EIO;
2204 
2205     return count;
2206 }
2207 
2208 static ssize_t sony_nc_thermal_mode_show(struct device *dev,
2209         struct device_attribute *attr, char *buffer)
2210 {
2211     int mode = sony_nc_thermal_mode_get();
2212 
2213     if (mode < 0)
2214         return mode;
2215 
2216     return sysfs_emit(buffer, "%s\n", snc_thermal_profiles[mode]);
2217 }
2218 
2219 static int sony_nc_thermal_setup(struct platform_device *pd)
2220 {
2221     int ret = 0;
2222     th_handle = kzalloc(sizeof(struct snc_thermal_ctrl), GFP_KERNEL);
2223     if (!th_handle)
2224         return -ENOMEM;
2225 
2226     ret = sony_call_snc_handle(0x0122, 0x0000, &th_handle->profiles);
2227     if (ret) {
2228         pr_warn("couldn't to read the thermal profiles\n");
2229         goto outkzalloc;
2230     }
2231 
2232     ret = sony_nc_thermal_mode_get();
2233     if (ret < 0) {
2234         pr_warn("couldn't to read the current thermal profile");
2235         goto outkzalloc;
2236     }
2237     th_handle->mode = ret;
2238 
2239     sysfs_attr_init(&th_handle->profiles_attr.attr);
2240     th_handle->profiles_attr.attr.name = "thermal_profiles";
2241     th_handle->profiles_attr.attr.mode = S_IRUGO;
2242     th_handle->profiles_attr.show = sony_nc_thermal_profiles_show;
2243 
2244     sysfs_attr_init(&th_handle->mode_attr.attr);
2245     th_handle->mode_attr.attr.name = "thermal_control";
2246     th_handle->mode_attr.attr.mode = S_IRUGO | S_IWUSR;
2247     th_handle->mode_attr.show = sony_nc_thermal_mode_show;
2248     th_handle->mode_attr.store = sony_nc_thermal_mode_store;
2249 
2250     ret = device_create_file(&pd->dev, &th_handle->profiles_attr);
2251     if (ret)
2252         goto outkzalloc;
2253 
2254     ret = device_create_file(&pd->dev, &th_handle->mode_attr);
2255     if (ret)
2256         goto outprofiles;
2257 
2258     return 0;
2259 
2260 outprofiles:
2261     device_remove_file(&pd->dev, &th_handle->profiles_attr);
2262 outkzalloc:
2263     kfree(th_handle);
2264     th_handle = NULL;
2265     return ret;
2266 }
2267 
2268 static void sony_nc_thermal_cleanup(struct platform_device *pd)
2269 {
2270     if (th_handle) {
2271         device_remove_file(&pd->dev, &th_handle->profiles_attr);
2272         device_remove_file(&pd->dev, &th_handle->mode_attr);
2273         kfree(th_handle);
2274         th_handle = NULL;
2275     }
2276 }
2277 
2278 #ifdef CONFIG_PM_SLEEP
2279 static void sony_nc_thermal_resume(void)
2280 {
2281     int status;
2282 
2283     if (!th_handle)
2284         return;
2285 
2286     status = sony_nc_thermal_mode_get();
2287 
2288     if (status != th_handle->mode)
2289         sony_nc_thermal_mode_set(th_handle->mode);
2290 }
2291 #endif
2292 
2293 /* resume on LID open */
2294 #define LID_RESUME_S5   0
2295 #define LID_RESUME_S4   1
2296 #define LID_RESUME_S3   2
2297 #define LID_RESUME_MAX  3
2298 struct snc_lid_resume_control {
2299     struct device_attribute attrs[LID_RESUME_MAX];
2300     unsigned int status;
2301     int handle;
2302 };
2303 static struct snc_lid_resume_control *lid_ctl;
2304 
2305 static ssize_t sony_nc_lid_resume_store(struct device *dev,
2306                     struct device_attribute *attr,
2307                     const char *buffer, size_t count)
2308 {
2309     unsigned int result;
2310     unsigned long value;
2311     unsigned int pos = LID_RESUME_S5;
2312     if (count > 31)
2313         return -EINVAL;
2314 
2315     if (kstrtoul(buffer, 10, &value) || value > 1)
2316         return -EINVAL;
2317 
2318     /* the value we have to write to SNC is a bitmask:
2319      * +--------------+
2320      * | S3 | S4 | S5 |
2321      * +--------------+
2322      *   2    1    0
2323      */
2324     while (pos < LID_RESUME_MAX) {
2325         if (&lid_ctl->attrs[pos].attr == &attr->attr)
2326             break;
2327         pos++;
2328     }
2329     if (pos == LID_RESUME_MAX)
2330         return -EINVAL;
2331 
2332     if (value)
2333         value = lid_ctl->status | (1 << pos);
2334     else
2335         value = lid_ctl->status & ~(1 << pos);
2336 
2337     if (sony_call_snc_handle(lid_ctl->handle, value << 0x10 | 0x0100,
2338                 &result))
2339         return -EIO;
2340 
2341     lid_ctl->status = value;
2342 
2343     return count;
2344 }
2345 
2346 static ssize_t sony_nc_lid_resume_show(struct device *dev,
2347                     struct device_attribute *attr,
2348                     char *buffer)
2349 {
2350     unsigned int pos = LID_RESUME_S5;
2351 
2352     while (pos < LID_RESUME_MAX) {
2353         if (&lid_ctl->attrs[pos].attr == &attr->attr)
2354             return sysfs_emit(buffer, "%d\n",
2355                     (lid_ctl->status >> pos) & 0x01);
2356         pos++;
2357     }
2358     return -EINVAL;
2359 }
2360 
2361 static int sony_nc_lid_resume_setup(struct platform_device *pd,
2362                     unsigned int handle)
2363 {
2364     unsigned int result;
2365     int i;
2366 
2367     if (sony_call_snc_handle(handle, 0x0000, &result))
2368         return -EIO;
2369 
2370     lid_ctl = kzalloc(sizeof(struct snc_lid_resume_control), GFP_KERNEL);
2371     if (!lid_ctl)
2372         return -ENOMEM;
2373 
2374     lid_ctl->status = result & 0x7;
2375     lid_ctl->handle = handle;
2376 
2377     sysfs_attr_init(&lid_ctl->attrs[0].attr);
2378     lid_ctl->attrs[LID_RESUME_S5].attr.name = "lid_resume_S5";
2379     lid_ctl->attrs[LID_RESUME_S5].attr.mode = S_IRUGO | S_IWUSR;
2380     lid_ctl->attrs[LID_RESUME_S5].show = sony_nc_lid_resume_show;
2381     lid_ctl->attrs[LID_RESUME_S5].store = sony_nc_lid_resume_store;
2382 
2383     if (handle == 0x0119) {
2384         sysfs_attr_init(&lid_ctl->attrs[1].attr);
2385         lid_ctl->attrs[LID_RESUME_S4].attr.name = "lid_resume_S4";
2386         lid_ctl->attrs[LID_RESUME_S4].attr.mode = S_IRUGO | S_IWUSR;
2387         lid_ctl->attrs[LID_RESUME_S4].show = sony_nc_lid_resume_show;
2388         lid_ctl->attrs[LID_RESUME_S4].store = sony_nc_lid_resume_store;
2389 
2390         sysfs_attr_init(&lid_ctl->attrs[2].attr);
2391         lid_ctl->attrs[LID_RESUME_S3].attr.name = "lid_resume_S3";
2392         lid_ctl->attrs[LID_RESUME_S3].attr.mode = S_IRUGO | S_IWUSR;
2393         lid_ctl->attrs[LID_RESUME_S3].show = sony_nc_lid_resume_show;
2394         lid_ctl->attrs[LID_RESUME_S3].store = sony_nc_lid_resume_store;
2395     }
2396     for (i = 0; i < LID_RESUME_MAX &&
2397             lid_ctl->attrs[i].attr.name; i++) {
2398         result = device_create_file(&pd->dev, &lid_ctl->attrs[i]);
2399         if (result)
2400             goto liderror;
2401     }
2402 
2403     return 0;
2404 
2405 liderror:
2406     for (i--; i >= 0; i--)
2407         device_remove_file(&pd->dev, &lid_ctl->attrs[i]);
2408 
2409     kfree(lid_ctl);
2410     lid_ctl = NULL;
2411 
2412     return result;
2413 }
2414 
2415 static void sony_nc_lid_resume_cleanup(struct platform_device *pd)
2416 {
2417     int i;
2418 
2419     if (lid_ctl) {
2420         for (i = 0; i < LID_RESUME_MAX; i++) {
2421             if (!lid_ctl->attrs[i].attr.name)
2422                 break;
2423 
2424             device_remove_file(&pd->dev, &lid_ctl->attrs[i]);
2425         }
2426 
2427         kfree(lid_ctl);
2428         lid_ctl = NULL;
2429     }
2430 }
2431 
2432 /* GFX Switch position */
2433 enum gfx_switch {
2434     SPEED,
2435     STAMINA,
2436     AUTO
2437 };
2438 struct snc_gfx_switch_control {
2439     struct device_attribute attr;
2440     unsigned int handle;
2441 };
2442 static struct snc_gfx_switch_control *gfxs_ctl;
2443 
2444 /* returns 0 for speed, 1 for stamina */
2445 static int __sony_nc_gfx_switch_status_get(void)
2446 {
2447     unsigned int result;
2448 
2449     if (sony_call_snc_handle(gfxs_ctl->handle,
2450                 gfxs_ctl->handle == 0x015B ? 0x0000 : 0x0100,
2451                 &result))
2452         return -EIO;
2453 
2454     switch (gfxs_ctl->handle) {
2455     case 0x0146:
2456         /* 1: discrete GFX (speed)
2457          * 0: integrated GFX (stamina)
2458          */
2459         return result & 0x1 ? SPEED : STAMINA;
2460     case 0x015B:
2461         /* 0: discrete GFX (speed)
2462          * 1: integrated GFX (stamina)
2463          */
2464         return result & 0x1 ? STAMINA : SPEED;
2465     case 0x0128:
2466         /* it's a more elaborated bitmask, for now:
2467          * 2: integrated GFX (stamina)
2468          * 0: discrete GFX (speed)
2469          */
2470         dprintk("GFX Status: 0x%x\n", result);
2471         return result & 0x80 ? AUTO :
2472             result & 0x02 ? STAMINA : SPEED;
2473     }
2474     return -EINVAL;
2475 }
2476 
2477 static ssize_t sony_nc_gfx_switch_status_show(struct device *dev,
2478                        struct device_attribute *attr,
2479                        char *buffer)
2480 {
2481     int pos = __sony_nc_gfx_switch_status_get();
2482 
2483     if (pos < 0)
2484         return pos;
2485 
2486     return sysfs_emit(buffer, "%s\n",
2487                     pos == SPEED ? "speed" :
2488                     pos == STAMINA ? "stamina" :
2489                     pos == AUTO ? "auto" : "unknown");
2490 }
2491 
2492 static int sony_nc_gfx_switch_setup(struct platform_device *pd,
2493         unsigned int handle)
2494 {
2495     unsigned int result;
2496 
2497     gfxs_ctl = kzalloc(sizeof(struct snc_gfx_switch_control), GFP_KERNEL);
2498     if (!gfxs_ctl)
2499         return -ENOMEM;
2500 
2501     gfxs_ctl->handle = handle;
2502 
2503     sysfs_attr_init(&gfxs_ctl->attr.attr);
2504     gfxs_ctl->attr.attr.name = "gfx_switch_status";
2505     gfxs_ctl->attr.attr.mode = S_IRUGO;
2506     gfxs_ctl->attr.show = sony_nc_gfx_switch_status_show;
2507 
2508     result = device_create_file(&pd->dev, &gfxs_ctl->attr);
2509     if (result)
2510         goto gfxerror;
2511 
2512     return 0;
2513 
2514 gfxerror:
2515     kfree(gfxs_ctl);
2516     gfxs_ctl = NULL;
2517 
2518     return result;
2519 }
2520 
2521 static void sony_nc_gfx_switch_cleanup(struct platform_device *pd)
2522 {
2523     if (gfxs_ctl) {
2524         device_remove_file(&pd->dev, &gfxs_ctl->attr);
2525 
2526         kfree(gfxs_ctl);
2527         gfxs_ctl = NULL;
2528     }
2529 }
2530 
2531 /* High speed charging function */
2532 static struct device_attribute *hsc_handle;
2533 
2534 static ssize_t sony_nc_highspeed_charging_store(struct device *dev,
2535         struct device_attribute *attr,
2536         const char *buffer, size_t count)
2537 {
2538     unsigned int result;
2539     unsigned long value;
2540 
2541     if (count > 31)
2542         return -EINVAL;
2543 
2544     if (kstrtoul(buffer, 10, &value) || value > 1)
2545         return -EINVAL;
2546 
2547     if (sony_call_snc_handle(0x0131, value << 0x10 | 0x0200, &result))
2548         return -EIO;
2549 
2550     return count;
2551 }
2552 
2553 static ssize_t sony_nc_highspeed_charging_show(struct device *dev,
2554         struct device_attribute *attr, char *buffer)
2555 {
2556     unsigned int result;
2557 
2558     if (sony_call_snc_handle(0x0131, 0x0100, &result))
2559         return -EIO;
2560 
2561     return sysfs_emit(buffer, "%d\n", result & 0x01);
2562 }
2563 
2564 static int sony_nc_highspeed_charging_setup(struct platform_device *pd)
2565 {
2566     unsigned int result;
2567 
2568     if (sony_call_snc_handle(0x0131, 0x0000, &result) || !(result & 0x01)) {
2569         /* some models advertise the handle but have no implementation
2570          * for it
2571          */
2572         pr_info("No High Speed Charging capability found\n");
2573         return 0;
2574     }
2575 
2576     hsc_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2577     if (!hsc_handle)
2578         return -ENOMEM;
2579 
2580     sysfs_attr_init(&hsc_handle->attr);
2581     hsc_handle->attr.name = "battery_highspeed_charging";
2582     hsc_handle->attr.mode = S_IRUGO | S_IWUSR;
2583     hsc_handle->show = sony_nc_highspeed_charging_show;
2584     hsc_handle->store = sony_nc_highspeed_charging_store;
2585 
2586     result = device_create_file(&pd->dev, hsc_handle);
2587     if (result) {
2588         kfree(hsc_handle);
2589         hsc_handle = NULL;
2590         return result;
2591     }
2592 
2593     return 0;
2594 }
2595 
2596 static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd)
2597 {
2598     if (hsc_handle) {
2599         device_remove_file(&pd->dev, hsc_handle);
2600         kfree(hsc_handle);
2601         hsc_handle = NULL;
2602     }
2603 }
2604 
2605 /* low battery function */
2606 static struct device_attribute *lowbatt_handle;
2607 
2608 static ssize_t sony_nc_lowbatt_store(struct device *dev,
2609         struct device_attribute *attr,
2610         const char *buffer, size_t count)
2611 {
2612     unsigned int result;
2613     unsigned long value;
2614 
2615     if (count > 31)
2616         return -EINVAL;
2617 
2618     if (kstrtoul(buffer, 10, &value) || value > 1)
2619         return -EINVAL;
2620 
2621     if (sony_call_snc_handle(0x0121, value << 8, &result))
2622         return -EIO;
2623 
2624     return count;
2625 }
2626 
2627 static ssize_t sony_nc_lowbatt_show(struct device *dev,
2628         struct device_attribute *attr, char *buffer)
2629 {
2630     unsigned int result;
2631 
2632     if (sony_call_snc_handle(0x0121, 0x0200, &result))
2633         return -EIO;
2634 
2635     return sysfs_emit(buffer, "%d\n", result & 1);
2636 }
2637 
2638 static int sony_nc_lowbatt_setup(struct platform_device *pd)
2639 {
2640     unsigned int result;
2641 
2642     lowbatt_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2643     if (!lowbatt_handle)
2644         return -ENOMEM;
2645 
2646     sysfs_attr_init(&lowbatt_handle->attr);
2647     lowbatt_handle->attr.name = "lowbatt_hibernate";
2648     lowbatt_handle->attr.mode = S_IRUGO | S_IWUSR;
2649     lowbatt_handle->show = sony_nc_lowbatt_show;
2650     lowbatt_handle->store = sony_nc_lowbatt_store;
2651 
2652     result = device_create_file(&pd->dev, lowbatt_handle);
2653     if (result) {
2654         kfree(lowbatt_handle);
2655         lowbatt_handle = NULL;
2656         return result;
2657     }
2658 
2659     return 0;
2660 }
2661 
2662 static void sony_nc_lowbatt_cleanup(struct platform_device *pd)
2663 {
2664     if (lowbatt_handle) {
2665         device_remove_file(&pd->dev, lowbatt_handle);
2666         kfree(lowbatt_handle);
2667         lowbatt_handle = NULL;
2668     }
2669 }
2670 
2671 /* fan speed function */
2672 static struct device_attribute *fan_handle, *hsf_handle;
2673 
2674 static ssize_t sony_nc_hsfan_store(struct device *dev,
2675         struct device_attribute *attr,
2676         const char *buffer, size_t count)
2677 {
2678     unsigned int result;
2679     unsigned long value;
2680 
2681     if (count > 31)
2682         return -EINVAL;
2683 
2684     if (kstrtoul(buffer, 10, &value) || value > 1)
2685         return -EINVAL;
2686 
2687     if (sony_call_snc_handle(0x0149, value << 0x10 | 0x0200, &result))
2688         return -EIO;
2689 
2690     return count;
2691 }
2692 
2693 static ssize_t sony_nc_hsfan_show(struct device *dev,
2694         struct device_attribute *attr, char *buffer)
2695 {
2696     unsigned int result;
2697 
2698     if (sony_call_snc_handle(0x0149, 0x0100, &result))
2699         return -EIO;
2700 
2701     return sysfs_emit(buffer, "%d\n", result & 0x01);
2702 }
2703 
2704 static ssize_t sony_nc_fanspeed_show(struct device *dev,
2705         struct device_attribute *attr, char *buffer)
2706 {
2707     unsigned int result;
2708 
2709     if (sony_call_snc_handle(0x0149, 0x0300, &result))
2710         return -EIO;
2711 
2712     return sysfs_emit(buffer, "%d\n", result & 0xff);
2713 }
2714 
2715 static int sony_nc_fanspeed_setup(struct platform_device *pd)
2716 {
2717     unsigned int result;
2718 
2719     fan_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2720     if (!fan_handle)
2721         return -ENOMEM;
2722 
2723     hsf_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2724     if (!hsf_handle) {
2725         result = -ENOMEM;
2726         goto out_hsf_handle_alloc;
2727     }
2728 
2729     sysfs_attr_init(&fan_handle->attr);
2730     fan_handle->attr.name = "fanspeed";
2731     fan_handle->attr.mode = S_IRUGO;
2732     fan_handle->show = sony_nc_fanspeed_show;
2733     fan_handle->store = NULL;
2734 
2735     sysfs_attr_init(&hsf_handle->attr);
2736     hsf_handle->attr.name = "fan_forced";
2737     hsf_handle->attr.mode = S_IRUGO | S_IWUSR;
2738     hsf_handle->show = sony_nc_hsfan_show;
2739     hsf_handle->store = sony_nc_hsfan_store;
2740 
2741     result = device_create_file(&pd->dev, fan_handle);
2742     if (result)
2743         goto out_fan_handle;
2744 
2745     result = device_create_file(&pd->dev, hsf_handle);
2746     if (result)
2747         goto out_hsf_handle;
2748 
2749     return 0;
2750 
2751 out_hsf_handle:
2752     device_remove_file(&pd->dev, fan_handle);
2753 
2754 out_fan_handle:
2755     kfree(hsf_handle);
2756     hsf_handle = NULL;
2757 
2758 out_hsf_handle_alloc:
2759     kfree(fan_handle);
2760     fan_handle = NULL;
2761     return result;
2762 }
2763 
2764 static void sony_nc_fanspeed_cleanup(struct platform_device *pd)
2765 {
2766     if (fan_handle) {
2767         device_remove_file(&pd->dev, fan_handle);
2768         kfree(fan_handle);
2769         fan_handle = NULL;
2770     }
2771     if (hsf_handle) {
2772         device_remove_file(&pd->dev, hsf_handle);
2773         kfree(hsf_handle);
2774         hsf_handle = NULL;
2775     }
2776 }
2777 
2778 /* USB charge function */
2779 static struct device_attribute *uc_handle;
2780 
2781 static ssize_t sony_nc_usb_charge_store(struct device *dev,
2782         struct device_attribute *attr,
2783         const char *buffer, size_t count)
2784 {
2785     unsigned int result;
2786     unsigned long value;
2787 
2788     if (count > 31)
2789         return -EINVAL;
2790 
2791     if (kstrtoul(buffer, 10, &value) || value > 1)
2792         return -EINVAL;
2793 
2794     if (sony_call_snc_handle(0x0155, value << 0x10 | 0x0100, &result))
2795         return -EIO;
2796 
2797     return count;
2798 }
2799 
2800 static ssize_t sony_nc_usb_charge_show(struct device *dev,
2801         struct device_attribute *attr, char *buffer)
2802 {
2803     unsigned int result;
2804 
2805     if (sony_call_snc_handle(0x0155, 0x0000, &result))
2806         return -EIO;
2807 
2808     return sysfs_emit(buffer, "%d\n", result & 0x01);
2809 }
2810 
2811 static int sony_nc_usb_charge_setup(struct platform_device *pd)
2812 {
2813     unsigned int result;
2814 
2815     if (sony_call_snc_handle(0x0155, 0x0000, &result) || !(result & 0x01)) {
2816         /* some models advertise the handle but have no implementation
2817          * for it
2818          */
2819         pr_info("No USB Charge capability found\n");
2820         return 0;
2821     }
2822 
2823     uc_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2824     if (!uc_handle)
2825         return -ENOMEM;
2826 
2827     sysfs_attr_init(&uc_handle->attr);
2828     uc_handle->attr.name = "usb_charge";
2829     uc_handle->attr.mode = S_IRUGO | S_IWUSR;
2830     uc_handle->show = sony_nc_usb_charge_show;
2831     uc_handle->store = sony_nc_usb_charge_store;
2832 
2833     result = device_create_file(&pd->dev, uc_handle);
2834     if (result) {
2835         kfree(uc_handle);
2836         uc_handle = NULL;
2837         return result;
2838     }
2839 
2840     return 0;
2841 }
2842 
2843 static void sony_nc_usb_charge_cleanup(struct platform_device *pd)
2844 {
2845     if (uc_handle) {
2846         device_remove_file(&pd->dev, uc_handle);
2847         kfree(uc_handle);
2848         uc_handle = NULL;
2849     }
2850 }
2851 
2852 /* Panel ID function */
2853 static struct device_attribute *panel_handle;
2854 
2855 static ssize_t sony_nc_panelid_show(struct device *dev,
2856         struct device_attribute *attr, char *buffer)
2857 {
2858     unsigned int result;
2859 
2860     if (sony_call_snc_handle(0x011D, 0x0000, &result))
2861         return -EIO;
2862 
2863     return sysfs_emit(buffer, "%d\n", result);
2864 }
2865 
2866 static int sony_nc_panelid_setup(struct platform_device *pd)
2867 {
2868     unsigned int result;
2869 
2870     panel_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2871     if (!panel_handle)
2872         return -ENOMEM;
2873 
2874     sysfs_attr_init(&panel_handle->attr);
2875     panel_handle->attr.name = "panel_id";
2876     panel_handle->attr.mode = S_IRUGO;
2877     panel_handle->show = sony_nc_panelid_show;
2878     panel_handle->store = NULL;
2879 
2880     result = device_create_file(&pd->dev, panel_handle);
2881     if (result) {
2882         kfree(panel_handle);
2883         panel_handle = NULL;
2884         return result;
2885     }
2886 
2887     return 0;
2888 }
2889 
2890 static void sony_nc_panelid_cleanup(struct platform_device *pd)
2891 {
2892     if (panel_handle) {
2893         device_remove_file(&pd->dev, panel_handle);
2894         kfree(panel_handle);
2895         panel_handle = NULL;
2896     }
2897 }
2898 
2899 /* smart connect function */
2900 static struct device_attribute *sc_handle;
2901 
2902 static ssize_t sony_nc_smart_conn_store(struct device *dev,
2903         struct device_attribute *attr,
2904         const char *buffer, size_t count)
2905 {
2906     unsigned int result;
2907     unsigned long value;
2908 
2909     if (count > 31)
2910         return -EINVAL;
2911 
2912     if (kstrtoul(buffer, 10, &value) || value > 1)
2913         return -EINVAL;
2914 
2915     if (sony_call_snc_handle(0x0168, value << 0x10, &result))
2916         return -EIO;
2917 
2918     return count;
2919 }
2920 
2921 static int sony_nc_smart_conn_setup(struct platform_device *pd)
2922 {
2923     unsigned int result;
2924 
2925     sc_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2926     if (!sc_handle)
2927         return -ENOMEM;
2928 
2929     sysfs_attr_init(&sc_handle->attr);
2930     sc_handle->attr.name = "smart_connect";
2931     sc_handle->attr.mode = S_IWUSR;
2932     sc_handle->show = NULL;
2933     sc_handle->store = sony_nc_smart_conn_store;
2934 
2935     result = device_create_file(&pd->dev, sc_handle);
2936     if (result) {
2937         kfree(sc_handle);
2938         sc_handle = NULL;
2939         return result;
2940     }
2941 
2942     return 0;
2943 }
2944 
2945 static void sony_nc_smart_conn_cleanup(struct platform_device *pd)
2946 {
2947     if (sc_handle) {
2948         device_remove_file(&pd->dev, sc_handle);
2949         kfree(sc_handle);
2950         sc_handle = NULL;
2951     }
2952 }
2953 
2954 /* Touchpad enable/disable */
2955 struct touchpad_control {
2956     struct device_attribute attr;
2957     int handle;
2958 };
2959 static struct touchpad_control *tp_ctl;
2960 
2961 static ssize_t sony_nc_touchpad_store(struct device *dev,
2962         struct device_attribute *attr, const char *buffer, size_t count)
2963 {
2964     unsigned int result;
2965     unsigned long value;
2966 
2967     if (count > 31)
2968         return -EINVAL;
2969 
2970     if (kstrtoul(buffer, 10, &value) || value > 1)
2971         return -EINVAL;
2972 
2973     /* sysfs: 0 disabled, 1 enabled
2974      * EC: 0 enabled, 1 disabled
2975      */
2976     if (sony_call_snc_handle(tp_ctl->handle,
2977                 (!value << 0x10) | 0x100, &result))
2978         return -EIO;
2979 
2980     return count;
2981 }
2982 
2983 static ssize_t sony_nc_touchpad_show(struct device *dev,
2984         struct device_attribute *attr, char *buffer)
2985 {
2986     unsigned int result;
2987 
2988     if (sony_call_snc_handle(tp_ctl->handle, 0x000, &result))
2989         return -EINVAL;
2990 
2991     return sysfs_emit(buffer, "%d\n", !(result & 0x01));
2992 }
2993 
2994 static int sony_nc_touchpad_setup(struct platform_device *pd,
2995         unsigned int handle)
2996 {
2997     int ret = 0;
2998 
2999     tp_ctl = kzalloc(sizeof(struct touchpad_control), GFP_KERNEL);
3000     if (!tp_ctl)
3001         return -ENOMEM;
3002 
3003     tp_ctl->handle = handle;
3004 
3005     sysfs_attr_init(&tp_ctl->attr.attr);
3006     tp_ctl->attr.attr.name = "touchpad";
3007     tp_ctl->attr.attr.mode = S_IRUGO | S_IWUSR;
3008     tp_ctl->attr.show = sony_nc_touchpad_show;
3009     tp_ctl->attr.store = sony_nc_touchpad_store;
3010 
3011     ret = device_create_file(&pd->dev, &tp_ctl->attr);
3012     if (ret) {
3013         kfree(tp_ctl);
3014         tp_ctl = NULL;
3015     }
3016 
3017     return ret;
3018 }
3019 
3020 static void sony_nc_touchpad_cleanup(struct platform_device *pd)
3021 {
3022     if (tp_ctl) {
3023         device_remove_file(&pd->dev, &tp_ctl->attr);
3024         kfree(tp_ctl);
3025         tp_ctl = NULL;
3026     }
3027 }
3028 
3029 static void sony_nc_backlight_ng_read_limits(int handle,
3030         struct sony_backlight_props *props)
3031 {
3032     u64 offset;
3033     int i;
3034     int lvl_table_len = 0;
3035     u8 min = 0xff, max = 0x00;
3036     unsigned char buffer[32] = { 0 };
3037 
3038     props->handle = handle;
3039     props->offset = 0;
3040     props->maxlvl = 0xff;
3041 
3042     offset = sony_find_snc_handle(handle);
3043 
3044     /* try to read the boundaries from ACPI tables, if we fail the above
3045      * defaults should be reasonable
3046      */
3047     i = sony_nc_buffer_call(sony_nc_acpi_handle, "SN06", &offset, buffer,
3048             32);
3049     if (i < 0)
3050         return;
3051 
3052     switch (handle) {
3053     case 0x012f:
3054     case 0x0137:
3055         lvl_table_len = 9;
3056         break;
3057     case 0x143:
3058     case 0x14b:
3059     case 0x14c:
3060         lvl_table_len = 16;
3061         break;
3062     }
3063 
3064     /* the buffer lists brightness levels available, brightness levels are
3065      * from position 0 to 8 in the array, other values are used by ALS
3066      * control.
3067      */
3068     for (i = 0; i < lvl_table_len && i < ARRAY_SIZE(buffer); i++) {
3069 
3070         dprintk("Brightness level: %d\n", buffer[i]);
3071 
3072         if (!buffer[i])
3073             break;
3074 
3075         if (buffer[i] > max)
3076             max = buffer[i];
3077         if (buffer[i] < min)
3078             min = buffer[i];
3079     }
3080     props->offset = min;
3081     props->maxlvl = max;
3082     dprintk("Brightness levels: min=%d max=%d\n", props->offset,
3083             props->maxlvl);
3084 }
3085 
3086 static void sony_nc_backlight_setup(void)
3087 {
3088     int max_brightness = 0;
3089     const struct backlight_ops *ops = NULL;
3090     struct backlight_properties props;
3091 
3092     if (sony_find_snc_handle(0x12f) >= 0) {
3093         ops = &sony_backlight_ng_ops;
3094         sony_bl_props.cmd_base = 0x0100;
3095         sony_nc_backlight_ng_read_limits(0x12f, &sony_bl_props);
3096         max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
3097 
3098     } else if (sony_find_snc_handle(0x137) >= 0) {
3099         ops = &sony_backlight_ng_ops;
3100         sony_bl_props.cmd_base = 0x0100;
3101         sony_nc_backlight_ng_read_limits(0x137, &sony_bl_props);
3102         max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
3103 
3104     } else if (sony_find_snc_handle(0x143) >= 0) {
3105         ops = &sony_backlight_ng_ops;
3106         sony_bl_props.cmd_base = 0x3000;
3107         sony_nc_backlight_ng_read_limits(0x143, &sony_bl_props);
3108         max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
3109 
3110     } else if (sony_find_snc_handle(0x14b) >= 0) {
3111         ops = &sony_backlight_ng_ops;
3112         sony_bl_props.cmd_base = 0x3000;
3113         sony_nc_backlight_ng_read_limits(0x14b, &sony_bl_props);
3114         max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
3115 
3116     } else if (sony_find_snc_handle(0x14c) >= 0) {
3117         ops = &sony_backlight_ng_ops;
3118         sony_bl_props.cmd_base = 0x3000;
3119         sony_nc_backlight_ng_read_limits(0x14c, &sony_bl_props);
3120         max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
3121 
3122     } else if (acpi_has_method(sony_nc_acpi_handle, "GBRT")) {
3123         ops = &sony_backlight_ops;
3124         max_brightness = SONY_MAX_BRIGHTNESS - 1;
3125 
3126     } else
3127         return;
3128 
3129     memset(&props, 0, sizeof(struct backlight_properties));
3130     props.type = BACKLIGHT_PLATFORM;
3131     props.max_brightness = max_brightness;
3132     sony_bl_props.dev = backlight_device_register("sony", NULL,
3133                               &sony_bl_props,
3134                               ops, &props);
3135 
3136     if (IS_ERR(sony_bl_props.dev)) {
3137         pr_warn("unable to register backlight device\n");
3138         sony_bl_props.dev = NULL;
3139     } else
3140         sony_bl_props.dev->props.brightness =
3141             ops->get_brightness(sony_bl_props.dev);
3142 }
3143 
3144 static void sony_nc_backlight_cleanup(void)
3145 {
3146     backlight_device_unregister(sony_bl_props.dev);
3147 }
3148 
3149 static int sony_nc_add(struct acpi_device *device)
3150 {
3151     acpi_status status;
3152     int result = 0;
3153     struct sony_nc_value *item;
3154 
3155     sony_nc_acpi_device = device;
3156     strcpy(acpi_device_class(device), "sony/hotkey");
3157 
3158     sony_nc_acpi_handle = device->handle;
3159 
3160     /* read device status */
3161     result = acpi_bus_get_status(device);
3162     /* bail IFF the above call was successful and the device is not present */
3163     if (!result && !device->status.present) {
3164         dprintk("Device not present\n");
3165         result = -ENODEV;
3166         goto outwalk;
3167     }
3168 
3169     result = sony_pf_add();
3170     if (result)
3171         goto outpresent;
3172 
3173     if (debug) {
3174         status = acpi_walk_namespace(ACPI_TYPE_METHOD,
3175                 sony_nc_acpi_handle, 1, sony_walk_callback,
3176                 NULL, NULL, NULL);
3177         if (ACPI_FAILURE(status)) {
3178             pr_warn("unable to walk acpi resources\n");
3179             result = -ENODEV;
3180             goto outpresent;
3181         }
3182     }
3183 
3184     result = sony_laptop_setup_input(device);
3185     if (result) {
3186         pr_err("Unable to create input devices\n");
3187         goto outplatform;
3188     }
3189 
3190     if (acpi_has_method(sony_nc_acpi_handle, "ECON")) {
3191         int arg = 1;
3192         if (sony_nc_int_call(sony_nc_acpi_handle, "ECON", &arg, NULL))
3193             dprintk("ECON Method failed\n");
3194     }
3195 
3196     if (acpi_has_method(sony_nc_acpi_handle, "SN00")) {
3197         dprintk("Doing SNC setup\n");
3198         /* retrieve the available handles */
3199         result = sony_nc_handles_setup(sony_pf_device);
3200         if (!result)
3201             sony_nc_function_setup(device, sony_pf_device);
3202     }
3203 
3204     if (acpi_video_get_backlight_type() == acpi_backlight_vendor)
3205         sony_nc_backlight_setup();
3206 
3207     /* create sony_pf sysfs attributes related to the SNC device */
3208     for (item = sony_nc_values; item->name; ++item) {
3209 
3210         if (!debug && item->debug)
3211             continue;
3212 
3213         /* find the available acpiget as described in the DSDT */
3214         for (; item->acpiget && *item->acpiget; ++item->acpiget) {
3215             if (acpi_has_method(sony_nc_acpi_handle,
3216                             *item->acpiget)) {
3217                 dprintk("Found %s getter: %s\n",
3218                         item->name, *item->acpiget);
3219                 item->devattr.attr.mode |= S_IRUGO;
3220                 break;
3221             }
3222         }
3223 
3224         /* find the available acpiset as described in the DSDT */
3225         for (; item->acpiset && *item->acpiset; ++item->acpiset) {
3226             if (acpi_has_method(sony_nc_acpi_handle,
3227                             *item->acpiset)) {
3228                 dprintk("Found %s setter: %s\n",
3229                         item->name, *item->acpiset);
3230                 item->devattr.attr.mode |= S_IWUSR;
3231                 break;
3232             }
3233         }
3234 
3235         if (item->devattr.attr.mode != 0) {
3236             result =
3237                 device_create_file(&sony_pf_device->dev,
3238                            &item->devattr);
3239             if (result)
3240                 goto out_sysfs;
3241         }
3242     }
3243 
3244     pr_info("SNC setup done.\n");
3245     return 0;
3246 
3247 out_sysfs:
3248     for (item = sony_nc_values; item->name; ++item) {
3249         device_remove_file(&sony_pf_device->dev, &item->devattr);
3250     }
3251     sony_nc_backlight_cleanup();
3252     sony_nc_function_cleanup(sony_pf_device);
3253     sony_nc_handles_cleanup(sony_pf_device);
3254 
3255 outplatform:
3256     sony_laptop_remove_input();
3257 
3258 outpresent:
3259     sony_pf_remove();
3260 
3261 outwalk:
3262     sony_nc_rfkill_cleanup();
3263     return result;
3264 }
3265 
3266 static int sony_nc_remove(struct acpi_device *device)
3267 {
3268     struct sony_nc_value *item;
3269 
3270     sony_nc_backlight_cleanup();
3271 
3272     sony_nc_acpi_device = NULL;
3273 
3274     for (item = sony_nc_values; item->name; ++item) {
3275         device_remove_file(&sony_pf_device->dev, &item->devattr);
3276     }
3277 
3278     sony_nc_function_cleanup(sony_pf_device);
3279     sony_nc_handles_cleanup(sony_pf_device);
3280     sony_pf_remove();
3281     sony_laptop_remove_input();
3282     dprintk(SONY_NC_DRIVER_NAME " removed.\n");
3283 
3284     return 0;
3285 }
3286 
3287 static const struct acpi_device_id sony_device_ids[] = {
3288     {SONY_NC_HID, 0},
3289     {SONY_PIC_HID, 0},
3290     {"", 0},
3291 };
3292 MODULE_DEVICE_TABLE(acpi, sony_device_ids);
3293 
3294 static const struct acpi_device_id sony_nc_device_ids[] = {
3295     {SONY_NC_HID, 0},
3296     {"", 0},
3297 };
3298 
3299 static struct acpi_driver sony_nc_driver = {
3300     .name = SONY_NC_DRIVER_NAME,
3301     .class = SONY_NC_CLASS,
3302     .ids = sony_nc_device_ids,
3303     .owner = THIS_MODULE,
3304     .ops = {
3305         .add = sony_nc_add,
3306         .remove = sony_nc_remove,
3307         .notify = sony_nc_notify,
3308         },
3309     .drv.pm = &sony_nc_pm,
3310 };
3311 
3312 /*********** SPIC (SNY6001) Device ***********/
3313 
3314 #define SONYPI_DEVICE_TYPE1 0x00000001
3315 #define SONYPI_DEVICE_TYPE2 0x00000002
3316 #define SONYPI_DEVICE_TYPE3 0x00000004
3317 
3318 #define SONYPI_TYPE1_OFFSET 0x04
3319 #define SONYPI_TYPE2_OFFSET 0x12
3320 #define SONYPI_TYPE3_OFFSET 0x12
3321 
3322 struct sony_pic_ioport {
3323     struct acpi_resource_io io1;
3324     struct acpi_resource_io io2;
3325     struct list_head    list;
3326 };
3327 
3328 struct sony_pic_irq {
3329     struct acpi_resource_irq    irq;
3330     struct list_head        list;
3331 };
3332 
3333 struct sonypi_eventtypes {
3334     u8          data;
3335     unsigned long       mask;
3336     struct sonypi_event *events;
3337 };
3338 
3339 struct sony_pic_dev {
3340     struct acpi_device      *acpi_dev;
3341     struct sony_pic_irq     *cur_irq;
3342     struct sony_pic_ioport      *cur_ioport;
3343     struct list_head        interrupts;
3344     struct list_head        ioports;
3345     struct mutex            lock;
3346     struct sonypi_eventtypes    *event_types;
3347     int                             (*handle_irq)(const u8, const u8);
3348     int             model;
3349     u16             evport_offset;
3350     u8              camera_power;
3351     u8              bluetooth_power;
3352     u8              wwan_power;
3353 };
3354 
3355 static struct sony_pic_dev spic_dev = {
3356     .interrupts = LIST_HEAD_INIT(spic_dev.interrupts),
3357     .ioports    = LIST_HEAD_INIT(spic_dev.ioports),
3358 };
3359 
3360 static int spic_drv_registered;
3361 
3362 /* Event masks */
3363 #define SONYPI_JOGGER_MASK          0x00000001
3364 #define SONYPI_CAPTURE_MASK         0x00000002
3365 #define SONYPI_FNKEY_MASK           0x00000004
3366 #define SONYPI_BLUETOOTH_MASK           0x00000008
3367 #define SONYPI_PKEY_MASK            0x00000010
3368 #define SONYPI_BACK_MASK            0x00000020
3369 #define SONYPI_HELP_MASK            0x00000040
3370 #define SONYPI_LID_MASK             0x00000080
3371 #define SONYPI_ZOOM_MASK            0x00000100
3372 #define SONYPI_THUMBPHRASE_MASK         0x00000200
3373 #define SONYPI_MEYE_MASK            0x00000400
3374 #define SONYPI_MEMORYSTICK_MASK         0x00000800
3375 #define SONYPI_BATTERY_MASK         0x00001000
3376 #define SONYPI_WIRELESS_MASK            0x00002000
3377 
3378 struct sonypi_event {
3379     u8  data;
3380     u8  event;
3381 };
3382 
3383 /* The set of possible button release events */
3384 static struct sonypi_event sonypi_releaseev[] = {
3385     { 0x00, SONYPI_EVENT_ANYBUTTON_RELEASED },
3386     { 0, 0 }
3387 };
3388 
3389 /* The set of possible jogger events  */
3390 static struct sonypi_event sonypi_joggerev[] = {
3391     { 0x1f, SONYPI_EVENT_JOGDIAL_UP },
3392     { 0x01, SONYPI_EVENT_JOGDIAL_DOWN },
3393     { 0x5f, SONYPI_EVENT_JOGDIAL_UP_PRESSED },
3394     { 0x41, SONYPI_EVENT_JOGDIAL_DOWN_PRESSED },
3395     { 0x1e, SONYPI_EVENT_JOGDIAL_FAST_UP },
3396     { 0x02, SONYPI_EVENT_JOGDIAL_FAST_DOWN },
3397     { 0x5e, SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED },
3398     { 0x42, SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED },
3399     { 0x1d, SONYPI_EVENT_JOGDIAL_VFAST_UP },
3400     { 0x03, SONYPI_EVENT_JOGDIAL_VFAST_DOWN },
3401     { 0x5d, SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED },
3402     { 0x43, SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED },
3403     { 0x40, SONYPI_EVENT_JOGDIAL_PRESSED },
3404     { 0, 0 }
3405 };
3406 
3407 /* The set of possible capture button events */
3408 static struct sonypi_event sonypi_captureev[] = {
3409     { 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED },
3410     { 0x07, SONYPI_EVENT_CAPTURE_PRESSED },
3411     { 0x40, SONYPI_EVENT_CAPTURE_PRESSED },
3412     { 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED },
3413     { 0, 0 }
3414 };
3415 
3416 /* The set of possible fnkeys events */
3417 static struct sonypi_event sonypi_fnkeyev[] = {
3418     { 0x10, SONYPI_EVENT_FNKEY_ESC },
3419     { 0x11, SONYPI_EVENT_FNKEY_F1 },
3420     { 0x12, SONYPI_EVENT_FNKEY_F2 },
3421     { 0x13, SONYPI_EVENT_FNKEY_F3 },
3422     { 0x14, SONYPI_EVENT_FNKEY_F4 },
3423     { 0x15, SONYPI_EVENT_FNKEY_F5 },
3424     { 0x16, SONYPI_EVENT_FNKEY_F6 },
3425     { 0x17, SONYPI_EVENT_FNKEY_F7 },
3426     { 0x18, SONYPI_EVENT_FNKEY_F8 },
3427     { 0x19, SONYPI_EVENT_FNKEY_F9 },
3428     { 0x1a, SONYPI_EVENT_FNKEY_F10 },
3429     { 0x1b, SONYPI_EVENT_FNKEY_F11 },
3430     { 0x1c, SONYPI_EVENT_FNKEY_F12 },
3431     { 0x1f, SONYPI_EVENT_FNKEY_RELEASED },
3432     { 0x21, SONYPI_EVENT_FNKEY_1 },
3433     { 0x22, SONYPI_EVENT_FNKEY_2 },
3434     { 0x31, SONYPI_EVENT_FNKEY_D },
3435     { 0x32, SONYPI_EVENT_FNKEY_E },
3436     { 0x33, SONYPI_EVENT_FNKEY_F },
3437     { 0x34, SONYPI_EVENT_FNKEY_S },
3438     { 0x35, SONYPI_EVENT_FNKEY_B },
3439     { 0x36, SONYPI_EVENT_FNKEY_ONLY },
3440     { 0, 0 }
3441 };
3442 
3443 /* The set of possible program key events */
3444 static struct sonypi_event sonypi_pkeyev[] = {
3445     { 0x01, SONYPI_EVENT_PKEY_P1 },
3446     { 0x02, SONYPI_EVENT_PKEY_P2 },
3447     { 0x04, SONYPI_EVENT_PKEY_P3 },
3448     { 0x20, SONYPI_EVENT_PKEY_P1 },
3449     { 0, 0 }
3450 };
3451 
3452 /* The set of possible bluetooth events */
3453 static struct sonypi_event sonypi_blueev[] = {
3454     { 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED },
3455     { 0x59, SONYPI_EVENT_BLUETOOTH_ON },
3456     { 0x5a, SONYPI_EVENT_BLUETOOTH_OFF },
3457     { 0, 0 }
3458 };
3459 
3460 /* The set of possible wireless events */
3461 static struct sonypi_event sonypi_wlessev[] = {
3462     { 0x59, SONYPI_EVENT_IGNORE },
3463     { 0x5a, SONYPI_EVENT_IGNORE },
3464     { 0, 0 }
3465 };
3466 
3467 /* The set of possible back button events */
3468 static struct sonypi_event sonypi_backev[] = {
3469     { 0x20, SONYPI_EVENT_BACK_PRESSED },
3470     { 0, 0 }
3471 };
3472 
3473 /* The set of possible help button events */
3474 static struct sonypi_event sonypi_helpev[] = {
3475     { 0x3b, SONYPI_EVENT_HELP_PRESSED },
3476     { 0, 0 }
3477 };
3478 
3479 
3480 /* The set of possible lid events */
3481 static struct sonypi_event sonypi_lidev[] = {
3482     { 0x51, SONYPI_EVENT_LID_CLOSED },
3483     { 0x50, SONYPI_EVENT_LID_OPENED },
3484     { 0, 0 }
3485 };
3486 
3487 /* The set of possible zoom events */
3488 static struct sonypi_event sonypi_zoomev[] = {
3489     { 0x39, SONYPI_EVENT_ZOOM_PRESSED },
3490     { 0x10, SONYPI_EVENT_ZOOM_IN_PRESSED },
3491     { 0x20, SONYPI_EVENT_ZOOM_OUT_PRESSED },
3492     { 0x04, SONYPI_EVENT_ZOOM_PRESSED },
3493     { 0, 0 }
3494 };
3495 
3496 /* The set of possible thumbphrase events */
3497 static struct sonypi_event sonypi_thumbphraseev[] = {
3498     { 0x3a, SONYPI_EVENT_THUMBPHRASE_PRESSED },
3499     { 0, 0 }
3500 };
3501 
3502 /* The set of possible motioneye camera events */
3503 static struct sonypi_event sonypi_meyeev[] = {
3504     { 0x00, SONYPI_EVENT_MEYE_FACE },
3505     { 0x01, SONYPI_EVENT_MEYE_OPPOSITE },
3506     { 0, 0 }
3507 };
3508 
3509 /* The set of possible memorystick events */
3510 static struct sonypi_event sonypi_memorystickev[] = {
3511     { 0x53, SONYPI_EVENT_MEMORYSTICK_INSERT },
3512     { 0x54, SONYPI_EVENT_MEMORYSTICK_EJECT },
3513     { 0, 0 }
3514 };
3515 
3516 /* The set of possible battery events */
3517 static struct sonypi_event sonypi_batteryev[] = {
3518     { 0x20, SONYPI_EVENT_BATTERY_INSERT },
3519     { 0x30, SONYPI_EVENT_BATTERY_REMOVE },
3520     { 0, 0 }
3521 };
3522 
3523 /* The set of possible volume events */
3524 static struct sonypi_event sonypi_volumeev[] = {
3525     { 0x01, SONYPI_EVENT_VOLUME_INC_PRESSED },
3526     { 0x02, SONYPI_EVENT_VOLUME_DEC_PRESSED },
3527     { 0, 0 }
3528 };
3529 
3530 /* The set of possible brightness events */
3531 static struct sonypi_event sonypi_brightnessev[] = {
3532     { 0x80, SONYPI_EVENT_BRIGHTNESS_PRESSED },
3533     { 0, 0 }
3534 };
3535 
3536 static struct sonypi_eventtypes type1_events[] = {
3537     { 0, 0xffffffff, sonypi_releaseev },
3538     { 0x70, SONYPI_MEYE_MASK, sonypi_meyeev },
3539     { 0x30, SONYPI_LID_MASK, sonypi_lidev },
3540     { 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev },
3541     { 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev },
3542     { 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
3543     { 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
3544     { 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
3545     { 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
3546     { 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev },
3547     { 0 },
3548 };
3549 static struct sonypi_eventtypes type2_events[] = {
3550     { 0, 0xffffffff, sonypi_releaseev },
3551     { 0x38, SONYPI_LID_MASK, sonypi_lidev },
3552     { 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev },
3553     { 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev },
3554     { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
3555     { 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
3556     { 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
3557     { 0x11, SONYPI_BACK_MASK, sonypi_backev },
3558     { 0x21, SONYPI_HELP_MASK, sonypi_helpev },
3559     { 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev },
3560     { 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
3561     { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
3562     { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
3563     { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
3564     { 0 },
3565 };
3566 static struct sonypi_eventtypes type3_events[] = {
3567     { 0, 0xffffffff, sonypi_releaseev },
3568     { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
3569     { 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
3570     { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
3571     { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
3572     { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
3573     { 0x05, SONYPI_PKEY_MASK, sonypi_pkeyev },
3574     { 0x05, SONYPI_ZOOM_MASK, sonypi_zoomev },
3575     { 0x05, SONYPI_CAPTURE_MASK, sonypi_captureev },
3576     { 0x05, SONYPI_PKEY_MASK, sonypi_volumeev },
3577     { 0x05, SONYPI_PKEY_MASK, sonypi_brightnessev },
3578     { 0 },
3579 };
3580 
3581 /* low level spic calls */
3582 #define ITERATIONS_LONG     10000
3583 #define ITERATIONS_SHORT    10
3584 #define wait_on_command(command, iterations) {              \
3585     unsigned int n = iterations;                    \
3586     while (--n && (command))                    \
3587         udelay(1);                      \
3588     if (!n)                             \
3589         dprintk("command failed at %s : %s (line %d)\n",    \
3590                 __FILE__, __func__, __LINE__);  \
3591 }
3592 
3593 static u8 sony_pic_call1(u8 dev)
3594 {
3595     u8 v1, v2;
3596 
3597     wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
3598             ITERATIONS_LONG);
3599     outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
3600     v1 = inb_p(spic_dev.cur_ioport->io1.minimum + 4);
3601     v2 = inb_p(spic_dev.cur_ioport->io1.minimum);
3602     dprintk("sony_pic_call1(0x%.2x): 0x%.4x\n", dev, (v2 << 8) | v1);
3603     return v2;
3604 }
3605 
3606 static u8 sony_pic_call2(u8 dev, u8 fn)
3607 {
3608     u8 v1;
3609 
3610     wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
3611             ITERATIONS_LONG);
3612     outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
3613     wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
3614             ITERATIONS_LONG);
3615     outb(fn, spic_dev.cur_ioport->io1.minimum);
3616     v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
3617     dprintk("sony_pic_call2(0x%.2x - 0x%.2x): 0x%.4x\n", dev, fn, v1);
3618     return v1;
3619 }
3620 
3621 static u8 sony_pic_call3(u8 dev, u8 fn, u8 v)
3622 {
3623     u8 v1;
3624 
3625     wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
3626     outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
3627     wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
3628     outb(fn, spic_dev.cur_ioport->io1.minimum);
3629     wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
3630     outb(v, spic_dev.cur_ioport->io1.minimum);
3631     v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
3632     dprintk("sony_pic_call3(0x%.2x - 0x%.2x - 0x%.2x): 0x%.4x\n",
3633             dev, fn, v, v1);
3634     return v1;
3635 }
3636 
3637 /*
3638  * minidrivers for SPIC models
3639  */
3640 static int type3_handle_irq(const u8 data_mask, const u8 ev)
3641 {
3642     /*
3643      * 0x31 could mean we have to take some extra action and wait for
3644      * the next irq for some Type3 models, it will generate a new
3645      * irq and we can read new data from the device:
3646      *  - 0x5c and 0x5f requires 0xA0
3647      *  - 0x61 requires 0xB3
3648      */
3649     if (data_mask == 0x31) {
3650         if (ev == 0x5c || ev == 0x5f)
3651             sony_pic_call1(0xA0);
3652         else if (ev == 0x61)
3653             sony_pic_call1(0xB3);
3654         return 0;
3655     }
3656     return 1;
3657 }
3658 
3659 static void sony_pic_detect_device_type(struct sony_pic_dev *dev)
3660 {
3661     struct pci_dev *pcidev;
3662 
3663     pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
3664             PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
3665     if (pcidev) {
3666         dev->model = SONYPI_DEVICE_TYPE1;
3667         dev->evport_offset = SONYPI_TYPE1_OFFSET;
3668         dev->event_types = type1_events;
3669         goto out;
3670     }
3671 
3672     pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
3673             PCI_DEVICE_ID_INTEL_ICH6_1, NULL);
3674     if (pcidev) {
3675         dev->model = SONYPI_DEVICE_TYPE2;
3676         dev->evport_offset = SONYPI_TYPE2_OFFSET;
3677         dev->event_types = type2_events;
3678         goto out;
3679     }
3680 
3681     pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
3682             PCI_DEVICE_ID_INTEL_ICH7_1, NULL);
3683     if (pcidev) {
3684         dev->model = SONYPI_DEVICE_TYPE3;
3685         dev->handle_irq = type3_handle_irq;
3686         dev->evport_offset = SONYPI_TYPE3_OFFSET;
3687         dev->event_types = type3_events;
3688         goto out;
3689     }
3690 
3691     pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
3692             PCI_DEVICE_ID_INTEL_ICH8_4, NULL);
3693     if (pcidev) {
3694         dev->model = SONYPI_DEVICE_TYPE3;
3695         dev->handle_irq = type3_handle_irq;
3696         dev->evport_offset = SONYPI_TYPE3_OFFSET;
3697         dev->event_types = type3_events;
3698         goto out;
3699     }
3700 
3701     pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
3702             PCI_DEVICE_ID_INTEL_ICH9_1, NULL);
3703     if (pcidev) {
3704         dev->model = SONYPI_DEVICE_TYPE3;
3705         dev->handle_irq = type3_handle_irq;
3706         dev->evport_offset = SONYPI_TYPE3_OFFSET;
3707         dev->event_types = type3_events;
3708         goto out;
3709     }
3710 
3711     /* default */
3712     dev->model = SONYPI_DEVICE_TYPE2;
3713     dev->evport_offset = SONYPI_TYPE2_OFFSET;
3714     dev->event_types = type2_events;
3715 
3716 out:
3717     pci_dev_put(pcidev);
3718 
3719     pr_info("detected Type%d model\n",
3720         dev->model == SONYPI_DEVICE_TYPE1 ? 1 :
3721         dev->model == SONYPI_DEVICE_TYPE2 ? 2 : 3);
3722 }
3723 
3724 /* camera tests and poweron/poweroff */
3725 #define SONYPI_CAMERA_PICTURE       5
3726 #define SONYPI_CAMERA_CONTROL       0x10
3727 
3728 #define SONYPI_CAMERA_BRIGHTNESS        0
3729 #define SONYPI_CAMERA_CONTRAST          1
3730 #define SONYPI_CAMERA_HUE           2
3731 #define SONYPI_CAMERA_COLOR         3
3732 #define SONYPI_CAMERA_SHARPNESS         4
3733 
3734 #define SONYPI_CAMERA_EXPOSURE_MASK     0xC
3735 #define SONYPI_CAMERA_WHITE_BALANCE_MASK    0x3
3736 #define SONYPI_CAMERA_PICTURE_MODE_MASK     0x30
3737 #define SONYPI_CAMERA_MUTE_MASK         0x40
3738 
3739 /* the rest don't need a loop until not 0xff */
3740 #define SONYPI_CAMERA_AGC           6
3741 #define SONYPI_CAMERA_AGC_MASK          0x30
3742 #define SONYPI_CAMERA_SHUTTER_MASK      0x7
3743 
3744 #define SONYPI_CAMERA_SHUTDOWN_REQUEST      7
3745 #define SONYPI_CAMERA_CONTROL           0x10
3746 
3747 #define SONYPI_CAMERA_STATUS            7
3748 #define SONYPI_CAMERA_STATUS_READY      0x2
3749 #define SONYPI_CAMERA_STATUS_POSITION       0x4
3750 
3751 #define SONYPI_DIRECTION_BACKWARDS      0x4
3752 
3753 #define SONYPI_CAMERA_REVISION          8
3754 #define SONYPI_CAMERA_ROMVERSION        9
3755 
3756 static int __sony_pic_camera_ready(void)
3757 {
3758     u8 v;
3759 
3760     v = sony_pic_call2(0x8f, SONYPI_CAMERA_STATUS);
3761     return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY));
3762 }
3763 
3764 static int __sony_pic_camera_off(void)
3765 {
3766     if (!camera) {
3767         pr_warn("camera control not enabled\n");
3768         return -ENODEV;
3769     }
3770 
3771     wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE,
3772                 SONYPI_CAMERA_MUTE_MASK),
3773             ITERATIONS_SHORT);
3774 
3775     if (spic_dev.camera_power) {
3776         sony_pic_call2(0x91, 0);
3777         spic_dev.camera_power = 0;
3778     }
3779     return 0;
3780 }
3781 
3782 static int __sony_pic_camera_on(void)
3783 {
3784     int i, j, x;
3785 
3786     if (!camera) {
3787         pr_warn("camera control not enabled\n");
3788         return -ENODEV;
3789     }
3790 
3791     if (spic_dev.camera_power)
3792         return 0;
3793 
3794     for (j = 5; j > 0; j--) {
3795 
3796         for (x = 0; x < 100 && sony_pic_call2(0x91, 0x1); x++)
3797             msleep(10);
3798         sony_pic_call1(0x93);
3799 
3800         for (i = 400; i > 0; i--) {
3801             if (__sony_pic_camera_ready())
3802                 break;
3803             msleep(10);
3804         }
3805         if (i)
3806             break;
3807     }
3808 
3809     if (j == 0) {
3810         pr_warn("failed to power on camera\n");
3811         return -ENODEV;
3812     }
3813 
3814     wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTROL,
3815                 0x5a),
3816             ITERATIONS_SHORT);
3817 
3818     spic_dev.camera_power = 1;
3819     return 0;
3820 }
3821 
3822 /* External camera command (exported to the motion eye v4l driver) */
3823 int sony_pic_camera_command(int command, u8 value)
3824 {
3825     if (!camera)
3826         return -EIO;
3827 
3828     mutex_lock(&spic_dev.lock);
3829 
3830     switch (command) {
3831     case SONY_PIC_COMMAND_SETCAMERA:
3832         if (value)
3833             __sony_pic_camera_on();
3834         else
3835             __sony_pic_camera_off();
3836         break;
3837     case SONY_PIC_COMMAND_SETCAMERABRIGHTNESS:
3838         wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_BRIGHTNESS, value),
3839                 ITERATIONS_SHORT);
3840         break;
3841     case SONY_PIC_COMMAND_SETCAMERACONTRAST:
3842         wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTRAST, value),
3843                 ITERATIONS_SHORT);
3844         break;
3845     case SONY_PIC_COMMAND_SETCAMERAHUE:
3846         wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_HUE, value),
3847                 ITERATIONS_SHORT);
3848         break;
3849     case SONY_PIC_COMMAND_SETCAMERACOLOR:
3850         wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_COLOR, value),
3851                 ITERATIONS_SHORT);
3852         break;
3853     case SONY_PIC_COMMAND_SETCAMERASHARPNESS:
3854         wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_SHARPNESS, value),
3855                 ITERATIONS_SHORT);
3856         break;
3857     case SONY_PIC_COMMAND_SETCAMERAPICTURE:
3858         wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE, value),
3859                 ITERATIONS_SHORT);
3860         break;
3861     case SONY_PIC_COMMAND_SETCAMERAAGC:
3862         wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_AGC, value),
3863                 ITERATIONS_SHORT);
3864         break;
3865     default:
3866         pr_err("sony_pic_camera_command invalid: %d\n", command);
3867         break;
3868     }
3869     mutex_unlock(&spic_dev.lock);
3870     return 0;
3871 }
3872 EXPORT_SYMBOL(sony_pic_camera_command);
3873 
3874 /* gprs/edge modem (SZ460N and SZ210P), thanks to Joshua Wise */
3875 static void __sony_pic_set_wwanpower(u8 state)
3876 {
3877     state = !!state;
3878     if (spic_dev.wwan_power == state)
3879         return;
3880     sony_pic_call2(0xB0, state);
3881     sony_pic_call1(0x82);
3882     spic_dev.wwan_power = state;
3883 }
3884 
3885 static ssize_t sony_pic_wwanpower_store(struct device *dev,
3886         struct device_attribute *attr,
3887         const char *buffer, size_t count)
3888 {
3889     unsigned long value;
3890     if (count > 31)
3891         return -EINVAL;
3892 
3893     if (kstrtoul(buffer, 10, &value))
3894         return -EINVAL;
3895 
3896     mutex_lock(&spic_dev.lock);
3897     __sony_pic_set_wwanpower(value);
3898     mutex_unlock(&spic_dev.lock);
3899 
3900     return count;
3901 }
3902 
3903 static ssize_t sony_pic_wwanpower_show(struct device *dev,
3904         struct device_attribute *attr, char *buffer)
3905 {
3906     ssize_t count;
3907     mutex_lock(&spic_dev.lock);
3908     count = sysfs_emit(buffer, "%d\n", spic_dev.wwan_power);
3909     mutex_unlock(&spic_dev.lock);
3910     return count;
3911 }
3912 
3913 /* bluetooth subsystem power state */
3914 static void __sony_pic_set_bluetoothpower(u8 state)
3915 {
3916     state = !!state;
3917     if (spic_dev.bluetooth_power == state)
3918         return;
3919     sony_pic_call2(0x96, state);
3920     sony_pic_call1(0x82);
3921     spic_dev.bluetooth_power = state;
3922 }
3923 
3924 static ssize_t sony_pic_bluetoothpower_store(struct device *dev,
3925         struct device_attribute *attr,
3926         const char *buffer, size_t count)
3927 {
3928     unsigned long value;
3929     if (count > 31)
3930         return -EINVAL;
3931 
3932     if (kstrtoul(buffer, 10, &value))
3933         return -EINVAL;
3934 
3935     mutex_lock(&spic_dev.lock);
3936     __sony_pic_set_bluetoothpower(value);
3937     mutex_unlock(&spic_dev.lock);
3938 
3939     return count;
3940 }
3941 
3942 static ssize_t sony_pic_bluetoothpower_show(struct device *dev,
3943         struct device_attribute *attr, char *buffer)
3944 {
3945     ssize_t count = 0;
3946     mutex_lock(&spic_dev.lock);
3947     count = sysfs_emit(buffer, "%d\n", spic_dev.bluetooth_power);
3948     mutex_unlock(&spic_dev.lock);
3949     return count;
3950 }
3951 
3952 /* fan speed */
3953 /* FAN0 information (reverse engineered from ACPI tables) */
3954 #define SONY_PIC_FAN0_STATUS    0x93
3955 static int sony_pic_set_fanspeed(unsigned long value)
3956 {
3957     return ec_write(SONY_PIC_FAN0_STATUS, value);
3958 }
3959 
3960 static int sony_pic_get_fanspeed(u8 *value)
3961 {
3962     return ec_read(SONY_PIC_FAN0_STATUS, value);
3963 }
3964 
3965 static ssize_t sony_pic_fanspeed_store(struct device *dev,
3966         struct device_attribute *attr,
3967         const char *buffer, size_t count)
3968 {
3969     unsigned long value;
3970     if (count > 31)
3971         return -EINVAL;
3972 
3973     if (kstrtoul(buffer, 10, &value))
3974         return -EINVAL;
3975 
3976     if (sony_pic_set_fanspeed(value))
3977         return -EIO;
3978 
3979     return count;
3980 }
3981 
3982 static ssize_t sony_pic_fanspeed_show(struct device *dev,
3983         struct device_attribute *attr, char *buffer)
3984 {
3985     u8 value = 0;
3986     if (sony_pic_get_fanspeed(&value))
3987         return -EIO;
3988 
3989     return sysfs_emit(buffer, "%d\n", value);
3990 }
3991 
3992 #define SPIC_ATTR(_name, _mode)                 \
3993 struct device_attribute spic_attr_##_name = __ATTR(_name,   \
3994         _mode, sony_pic_## _name ##_show,       \
3995         sony_pic_## _name ##_store)
3996 
3997 static SPIC_ATTR(bluetoothpower, 0644);
3998 static SPIC_ATTR(wwanpower, 0644);
3999 static SPIC_ATTR(fanspeed, 0644);
4000 
4001 static struct attribute *spic_attributes[] = {
4002     &spic_attr_bluetoothpower.attr,
4003     &spic_attr_wwanpower.attr,
4004     &spic_attr_fanspeed.attr,
4005     NULL
4006 };
4007 
4008 static const struct attribute_group spic_attribute_group = {
4009     .attrs = spic_attributes
4010 };
4011 
4012 /******** SONYPI compatibility **********/
4013 #ifdef CONFIG_SONYPI_COMPAT
4014 
4015 /* battery / brightness / temperature  addresses */
4016 #define SONYPI_BAT_FLAGS    0x81
4017 #define SONYPI_LCD_LIGHT    0x96
4018 #define SONYPI_BAT1_PCTRM   0xa0
4019 #define SONYPI_BAT1_LEFT    0xa2
4020 #define SONYPI_BAT1_MAXRT   0xa4
4021 #define SONYPI_BAT2_PCTRM   0xa8
4022 #define SONYPI_BAT2_LEFT    0xaa
4023 #define SONYPI_BAT2_MAXRT   0xac
4024 #define SONYPI_BAT1_MAXTK   0xb0
4025 #define SONYPI_BAT1_FULL    0xb2
4026 #define SONYPI_BAT2_MAXTK   0xb8
4027 #define SONYPI_BAT2_FULL    0xba
4028 #define SONYPI_TEMP_STATUS  0xC1
4029 
4030 struct sonypi_compat_s {
4031     struct fasync_struct    *fifo_async;
4032     struct kfifo        fifo;
4033     spinlock_t      fifo_lock;
4034     wait_queue_head_t   fifo_proc_list;
4035     atomic_t        open_count;
4036 };
4037 static struct sonypi_compat_s sonypi_compat = {
4038     .open_count = ATOMIC_INIT(0),
4039 };
4040 
4041 static int sonypi_misc_fasync(int fd, struct file *filp, int on)
4042 {
4043     return fasync_helper(fd, filp, on, &sonypi_compat.fifo_async);
4044 }
4045 
4046 static int sonypi_misc_release(struct inode *inode, struct file *file)
4047 {
4048     atomic_dec(&sonypi_compat.open_count);
4049     return 0;
4050 }
4051 
4052 static int sonypi_misc_open(struct inode *inode, struct file *file)
4053 {
4054     /* Flush input queue on first open */
4055     unsigned long flags;
4056 
4057     spin_lock_irqsave(&sonypi_compat.fifo_lock, flags);
4058 
4059     if (atomic_inc_return(&sonypi_compat.open_count) == 1)
4060         kfifo_reset(&sonypi_compat.fifo);
4061 
4062     spin_unlock_irqrestore(&sonypi_compat.fifo_lock, flags);
4063 
4064     return 0;
4065 }
4066 
4067 static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
4068                 size_t count, loff_t *pos)
4069 {
4070     ssize_t ret;
4071     unsigned char c;
4072 
4073     if ((kfifo_len(&sonypi_compat.fifo) == 0) &&
4074         (file->f_flags & O_NONBLOCK))
4075         return -EAGAIN;
4076 
4077     ret = wait_event_interruptible(sonypi_compat.fifo_proc_list,
4078                        kfifo_len(&sonypi_compat.fifo) != 0);
4079     if (ret)
4080         return ret;
4081 
4082     while (ret < count &&
4083            (kfifo_out_locked(&sonypi_compat.fifo, &c, sizeof(c),
4084               &sonypi_compat.fifo_lock) == sizeof(c))) {
4085         if (put_user(c, buf++))
4086             return -EFAULT;
4087         ret++;
4088     }
4089 
4090     if (ret > 0) {
4091         struct inode *inode = file_inode(file);
4092         inode->i_atime = current_time(inode);
4093     }
4094 
4095     return ret;
4096 }
4097 
4098 static __poll_t sonypi_misc_poll(struct file *file, poll_table *wait)
4099 {
4100     poll_wait(file, &sonypi_compat.fifo_proc_list, wait);
4101     if (kfifo_len(&sonypi_compat.fifo))
4102         return EPOLLIN | EPOLLRDNORM;
4103     return 0;
4104 }
4105 
4106 static int ec_read16(u8 addr, u16 *value)
4107 {
4108     u8 val_lb, val_hb;
4109     if (ec_read(addr, &val_lb))
4110         return -1;
4111     if (ec_read(addr + 1, &val_hb))
4112         return -1;
4113     *value = val_lb | (val_hb << 8);
4114     return 0;
4115 }
4116 
4117 static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd,
4118                             unsigned long arg)
4119 {
4120     int ret = 0;
4121     void __user *argp = (void __user *)arg;
4122     u8 val8;
4123     u16 val16;
4124     int value;
4125 
4126     mutex_lock(&spic_dev.lock);
4127     switch (cmd) {
4128     case SONYPI_IOCGBRT:
4129         if (sony_bl_props.dev == NULL) {
4130             ret = -EIO;
4131             break;
4132         }
4133         if (sony_nc_int_call(sony_nc_acpi_handle, "GBRT", NULL,
4134                     &value)) {
4135             ret = -EIO;
4136             break;
4137         }
4138         val8 = ((value & 0xff) - 1) << 5;
4139         if (copy_to_user(argp, &val8, sizeof(val8)))
4140                 ret = -EFAULT;
4141         break;
4142     case SONYPI_IOCSBRT:
4143         if (sony_bl_props.dev == NULL) {
4144             ret = -EIO;
4145             break;
4146         }
4147         if (copy_from_user(&val8, argp, sizeof(val8))) {
4148             ret = -EFAULT;
4149             break;
4150         }
4151         value = (val8 >> 5) + 1;
4152         if (sony_nc_int_call(sony_nc_acpi_handle, "SBRT", &value,
4153                     NULL)) {
4154             ret = -EIO;
4155             break;
4156         }
4157         /* sync the backlight device status */
4158         sony_bl_props.dev->props.brightness =
4159             sony_backlight_get_brightness(sony_bl_props.dev);
4160         break;
4161     case SONYPI_IOCGBAT1CAP:
4162         if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
4163             ret = -EIO;
4164             break;
4165         }
4166         if (copy_to_user(argp, &val16, sizeof(val16)))
4167             ret = -EFAULT;
4168         break;
4169     case SONYPI_IOCGBAT1REM:
4170         if (ec_read16(SONYPI_BAT1_LEFT, &val16)) {
4171             ret = -EIO;
4172             break;
4173         }
4174         if (copy_to_user(argp, &val16, sizeof(val16)))
4175             ret = -EFAULT;
4176         break;
4177     case SONYPI_IOCGBAT2CAP:
4178         if (ec_read16(SONYPI_BAT2_FULL, &val16)) {
4179             ret = -EIO;
4180             break;
4181         }
4182         if (copy_to_user(argp, &val16, sizeof(val16)))
4183             ret = -EFAULT;
4184         break;
4185     case SONYPI_IOCGBAT2REM:
4186         if (ec_read16(SONYPI_BAT2_LEFT, &val16)) {
4187             ret = -EIO;
4188             break;
4189         }
4190         if (copy_to_user(argp, &val16, sizeof(val16)))
4191             ret = -EFAULT;
4192         break;
4193     case SONYPI_IOCGBATFLAGS:
4194         if (ec_read(SONYPI_BAT_FLAGS, &val8)) {
4195             ret = -EIO;
4196             break;
4197         }
4198         val8 &= 0x07;
4199         if (copy_to_user(argp, &val8, sizeof(val8)))
4200             ret = -EFAULT;
4201         break;
4202     case SONYPI_IOCGBLUE:
4203         val8 = spic_dev.bluetooth_power;
4204         if (copy_to_user(argp, &val8, sizeof(val8)))
4205             ret = -EFAULT;
4206         break;
4207     case SONYPI_IOCSBLUE:
4208         if (copy_from_user(&val8, argp, sizeof(val8))) {
4209             ret = -EFAULT;
4210             break;
4211         }
4212         __sony_pic_set_bluetoothpower(val8);
4213         break;
4214     /* FAN Controls */
4215     case SONYPI_IOCGFAN:
4216         if (sony_pic_get_fanspeed(&val8)) {
4217             ret = -EIO;
4218             break;
4219         }
4220         if (copy_to_user(argp, &val8, sizeof(val8)))
4221             ret = -EFAULT;
4222         break;
4223     case SONYPI_IOCSFAN:
4224         if (copy_from_user(&val8, argp, sizeof(val8))) {
4225             ret = -EFAULT;
4226             break;
4227         }
4228         if (sony_pic_set_fanspeed(val8))
4229             ret = -EIO;
4230         break;
4231     /* GET Temperature (useful under APM) */
4232     case SONYPI_IOCGTEMP:
4233         if (ec_read(SONYPI_TEMP_STATUS, &val8)) {
4234             ret = -EIO;
4235             break;
4236         }
4237         if (copy_to_user(argp, &val8, sizeof(val8)))
4238             ret = -EFAULT;
4239         break;
4240     default:
4241         ret = -EINVAL;
4242     }
4243     mutex_unlock(&spic_dev.lock);
4244     return ret;
4245 }
4246 
4247 static const struct file_operations sonypi_misc_fops = {
4248     .owner      = THIS_MODULE,
4249     .read       = sonypi_misc_read,
4250     .poll       = sonypi_misc_poll,
4251     .open       = sonypi_misc_open,
4252     .release    = sonypi_misc_release,
4253     .fasync     = sonypi_misc_fasync,
4254     .unlocked_ioctl = sonypi_misc_ioctl,
4255     .llseek     = noop_llseek,
4256 };
4257 
4258 static struct miscdevice sonypi_misc_device = {
4259     .minor      = MISC_DYNAMIC_MINOR,
4260     .name       = "sonypi",
4261     .fops       = &sonypi_misc_fops,
4262 };
4263 
4264 static void sonypi_compat_report_event(u8 event)
4265 {
4266     kfifo_in_locked(&sonypi_compat.fifo, (unsigned char *)&event,
4267             sizeof(event), &sonypi_compat.fifo_lock);
4268     kill_fasync(&sonypi_compat.fifo_async, SIGIO, POLL_IN);
4269     wake_up_interruptible(&sonypi_compat.fifo_proc_list);
4270 }
4271 
4272 static int sonypi_compat_init(void)
4273 {
4274     int error;
4275 
4276     spin_lock_init(&sonypi_compat.fifo_lock);
4277     error =
4278      kfifo_alloc(&sonypi_compat.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
4279     if (error) {
4280         pr_err("kfifo_alloc failed\n");
4281         return error;
4282     }
4283 
4284     init_waitqueue_head(&sonypi_compat.fifo_proc_list);
4285 
4286     if (minor != -1)
4287         sonypi_misc_device.minor = minor;
4288     error = misc_register(&sonypi_misc_device);
4289     if (error) {
4290         pr_err("misc_register failed\n");
4291         goto err_free_kfifo;
4292     }
4293     if (minor == -1)
4294         pr_info("device allocated minor is %d\n",
4295             sonypi_misc_device.minor);
4296 
4297     return 0;
4298 
4299 err_free_kfifo:
4300     kfifo_free(&sonypi_compat.fifo);
4301     return error;
4302 }
4303 
4304 static void sonypi_compat_exit(void)
4305 {
4306     misc_deregister(&sonypi_misc_device);
4307     kfifo_free(&sonypi_compat.fifo);
4308 }
4309 #else
4310 static int sonypi_compat_init(void) { return 0; }
4311 static void sonypi_compat_exit(void) { }
4312 static void sonypi_compat_report_event(u8 event) { }
4313 #endif /* CONFIG_SONYPI_COMPAT */
4314 
4315 /*
4316  * ACPI callbacks
4317  */
4318 static acpi_status
4319 sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
4320 {
4321     u32 i;
4322     struct sony_pic_dev *dev = (struct sony_pic_dev *)context;
4323 
4324     switch (resource->type) {
4325     case ACPI_RESOURCE_TYPE_START_DEPENDENT:
4326         {
4327             /* start IO enumeration */
4328             struct sony_pic_ioport *ioport = kzalloc(sizeof(*ioport), GFP_KERNEL);
4329             if (!ioport)
4330                 return AE_ERROR;
4331 
4332             list_add(&ioport->list, &dev->ioports);
4333             return AE_OK;
4334         }
4335 
4336     case ACPI_RESOURCE_TYPE_END_DEPENDENT:
4337         /* end IO enumeration */
4338         return AE_OK;
4339 
4340     case ACPI_RESOURCE_TYPE_IRQ:
4341         {
4342             struct acpi_resource_irq *p = &resource->data.irq;
4343             struct sony_pic_irq *interrupt = NULL;
4344             if (!p->interrupt_count) {
4345                 /*
4346                  * IRQ descriptors may have no IRQ# bits set,
4347                  * particularly those those w/ _STA disabled
4348                  */
4349                 dprintk("Blank IRQ resource\n");
4350                 return AE_OK;
4351             }
4352             for (i = 0; i < p->interrupt_count; i++) {
4353                 if (!p->interrupts[i]) {
4354                     pr_warn("Invalid IRQ %d\n",
4355                         p->interrupts[i]);
4356                     continue;
4357                 }
4358                 interrupt = kzalloc(sizeof(*interrupt),
4359                         GFP_KERNEL);
4360                 if (!interrupt)
4361                     return AE_ERROR;
4362 
4363                 list_add(&interrupt->list, &dev->interrupts);
4364                 interrupt->irq.triggering = p->triggering;
4365                 interrupt->irq.polarity = p->polarity;
4366                 interrupt->irq.shareable = p->shareable;
4367                 interrupt->irq.interrupt_count = 1;
4368                 interrupt->irq.interrupts[0] = p->interrupts[i];
4369             }
4370             return AE_OK;
4371         }
4372     case ACPI_RESOURCE_TYPE_IO:
4373         {
4374             struct acpi_resource_io *io = &resource->data.io;
4375             struct sony_pic_ioport *ioport =
4376                 list_first_entry(&dev->ioports, struct sony_pic_ioport, list);
4377             if (!ioport->io1.minimum) {
4378                 memcpy(&ioport->io1, io, sizeof(*io));
4379                 dprintk("IO1 at 0x%.4x (0x%.2x)\n", ioport->io1.minimum,
4380                         ioport->io1.address_length);
4381             }
4382             else if (!ioport->io2.minimum) {
4383                 memcpy(&ioport->io2, io, sizeof(*io));
4384                 dprintk("IO2 at 0x%.4x (0x%.2x)\n", ioport->io2.minimum,
4385                         ioport->io2.address_length);
4386             }
4387             else {
4388                 pr_err("Unknown SPIC Type, more than 2 IO Ports\n");
4389                 return AE_ERROR;
4390             }
4391             return AE_OK;
4392         }
4393 
4394     case ACPI_RESOURCE_TYPE_END_TAG:
4395         return AE_OK;
4396 
4397     default:
4398         dprintk("Resource %d isn't an IRQ nor an IO port\n",
4399             resource->type);
4400         return AE_CTRL_TERMINATE;
4401 
4402     }
4403 }
4404 
4405 static int sony_pic_possible_resources(struct acpi_device *device)
4406 {
4407     int result = 0;
4408     acpi_status status = AE_OK;
4409 
4410     if (!device)
4411         return -EINVAL;
4412 
4413     /* get device status */
4414     /* see acpi_pci_link_get_current acpi_pci_link_get_possible */
4415     dprintk("Evaluating _STA\n");
4416     result = acpi_bus_get_status(device);
4417     if (result) {
4418         pr_warn("Unable to read status\n");
4419         goto end;
4420     }
4421 
4422     if (!device->status.enabled)
4423         dprintk("Device disabled\n");
4424     else
4425         dprintk("Device enabled\n");
4426 
4427     /*
4428      * Query and parse 'method'
4429      */
4430     dprintk("Evaluating %s\n", METHOD_NAME__PRS);
4431     status = acpi_walk_resources(device->handle, METHOD_NAME__PRS,
4432             sony_pic_read_possible_resource, &spic_dev);
4433     if (ACPI_FAILURE(status)) {
4434         pr_warn("Failure evaluating %s\n", METHOD_NAME__PRS);
4435         result = -ENODEV;
4436     }
4437 end:
4438     return result;
4439 }
4440 
4441 /*
4442  *  Disable the spic device by calling its _DIS method
4443  */
4444 static int sony_pic_disable(struct acpi_device *device)
4445 {
4446     acpi_status ret = acpi_evaluate_object(device->handle, "_DIS", NULL,
4447                            NULL);
4448 
4449     if (ACPI_FAILURE(ret) && ret != AE_NOT_FOUND)
4450         return -ENXIO;
4451 
4452     dprintk("Device disabled\n");
4453     return 0;
4454 }
4455 
4456 
4457 /*
4458  *  Based on drivers/acpi/pci_link.c:acpi_pci_link_set
4459  *
4460  *  Call _SRS to set current resources
4461  */
4462 static int sony_pic_enable(struct acpi_device *device,
4463         struct sony_pic_ioport *ioport, struct sony_pic_irq *irq)
4464 {
4465     acpi_status status;
4466     int result = 0;
4467     /* Type 1 resource layout is:
4468      *    IO
4469      *    IO
4470      *    IRQNoFlags
4471      *    End
4472      *
4473      * Type 2 and 3 resource layout is:
4474      *    IO
4475      *    IRQNoFlags
4476      *    End
4477      */
4478     struct {
4479         struct acpi_resource res1;
4480         struct acpi_resource res2;
4481         struct acpi_resource res3;
4482         struct acpi_resource res4;
4483     } *resource;
4484     struct acpi_buffer buffer = { 0, NULL };
4485 
4486     if (!ioport || !irq)
4487         return -EINVAL;
4488 
4489     /* init acpi_buffer */
4490     resource = kzalloc(sizeof(*resource) + 1, GFP_KERNEL);
4491     if (!resource)
4492         return -ENOMEM;
4493 
4494     buffer.length = sizeof(*resource) + 1;
4495     buffer.pointer = resource;
4496 
4497     /* setup Type 1 resources */
4498     if (spic_dev.model == SONYPI_DEVICE_TYPE1) {
4499 
4500         /* setup io resources */
4501         resource->res1.type = ACPI_RESOURCE_TYPE_IO;
4502         resource->res1.length = sizeof(struct acpi_resource);
4503         memcpy(&resource->res1.data.io, &ioport->io1,
4504                 sizeof(struct acpi_resource_io));
4505 
4506         resource->res2.type = ACPI_RESOURCE_TYPE_IO;
4507         resource->res2.length = sizeof(struct acpi_resource);
4508         memcpy(&resource->res2.data.io, &ioport->io2,
4509                 sizeof(struct acpi_resource_io));
4510 
4511         /* setup irq resource */
4512         resource->res3.type = ACPI_RESOURCE_TYPE_IRQ;
4513         resource->res3.length = sizeof(struct acpi_resource);
4514         memcpy(&resource->res3.data.irq, &irq->irq,
4515                 sizeof(struct acpi_resource_irq));
4516         /* we requested a shared irq */
4517         resource->res3.data.irq.shareable = ACPI_SHARED;
4518 
4519         resource->res4.type = ACPI_RESOURCE_TYPE_END_TAG;
4520         resource->res4.length = sizeof(struct acpi_resource);
4521     }
4522     /* setup Type 2/3 resources */
4523     else {
4524         /* setup io resource */
4525         resource->res1.type = ACPI_RESOURCE_TYPE_IO;
4526         resource->res1.length = sizeof(struct acpi_resource);
4527         memcpy(&resource->res1.data.io, &ioport->io1,
4528                 sizeof(struct acpi_resource_io));
4529 
4530         /* setup irq resource */
4531         resource->res2.type = ACPI_RESOURCE_TYPE_IRQ;
4532         resource->res2.length = sizeof(struct acpi_resource);
4533         memcpy(&resource->res2.data.irq, &irq->irq,
4534                 sizeof(struct acpi_resource_irq));
4535         /* we requested a shared irq */
4536         resource->res2.data.irq.shareable = ACPI_SHARED;
4537 
4538         resource->res3.type = ACPI_RESOURCE_TYPE_END_TAG;
4539         resource->res3.length = sizeof(struct acpi_resource);
4540     }
4541 
4542     /* Attempt to set the resource */
4543     dprintk("Evaluating _SRS\n");
4544     status = acpi_set_current_resources(device->handle, &buffer);
4545 
4546     /* check for total failure */
4547     if (ACPI_FAILURE(status)) {
4548         pr_err("Error evaluating _SRS\n");
4549         result = -ENODEV;
4550         goto end;
4551     }
4552 
4553     /* Necessary device initializations calls (from sonypi) */
4554     sony_pic_call1(0x82);
4555     sony_pic_call2(0x81, 0xff);
4556     sony_pic_call1(compat ? 0x92 : 0x82);
4557 
4558 end:
4559     kfree(resource);
4560     return result;
4561 }
4562 
4563 /*****************
4564  *
4565  * ISR: some event is available
4566  *
4567  *****************/
4568 static irqreturn_t sony_pic_irq(int irq, void *dev_id)
4569 {
4570     int i, j;
4571     u8 ev = 0;
4572     u8 data_mask = 0;
4573     u8 device_event = 0;
4574 
4575     struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id;
4576 
4577     ev = inb_p(dev->cur_ioport->io1.minimum);
4578     if (dev->cur_ioport->io2.minimum)
4579         data_mask = inb_p(dev->cur_ioport->io2.minimum);
4580     else
4581         data_mask = inb_p(dev->cur_ioport->io1.minimum +
4582                 dev->evport_offset);
4583 
4584     dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
4585             ev, data_mask, dev->cur_ioport->io1.minimum,
4586             dev->evport_offset);
4587 
4588     if (ev == 0x00 || ev == 0xff)
4589         return IRQ_HANDLED;
4590 
4591     for (i = 0; dev->event_types[i].mask; i++) {
4592 
4593         if ((data_mask & dev->event_types[i].data) !=
4594             dev->event_types[i].data)
4595             continue;
4596 
4597         if (!(mask & dev->event_types[i].mask))
4598             continue;
4599 
4600         for (j = 0; dev->event_types[i].events[j].event; j++) {
4601             if (ev == dev->event_types[i].events[j].data) {
4602                 device_event =
4603                     dev->event_types[i].events[j].event;
4604                 /* some events may require ignoring */
4605                 if (!device_event)
4606                     return IRQ_HANDLED;
4607                 goto found;
4608             }
4609         }
4610     }
4611     /* Still not able to decode the event try to pass
4612      * it over to the minidriver
4613      */
4614     if (dev->handle_irq && dev->handle_irq(data_mask, ev) == 0)
4615         return IRQ_HANDLED;
4616 
4617     dprintk("unknown event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
4618             ev, data_mask, dev->cur_ioport->io1.minimum,
4619             dev->evport_offset);
4620     return IRQ_HANDLED;
4621 
4622 found:
4623     sony_laptop_report_input_event(device_event);
4624     sonypi_compat_report_event(device_event);
4625     return IRQ_HANDLED;
4626 }
4627 
4628 /*****************
4629  *
4630  *  ACPI driver
4631  *
4632  *****************/
4633 static int sony_pic_remove(struct acpi_device *device)
4634 {
4635     struct sony_pic_ioport *io, *tmp_io;
4636     struct sony_pic_irq *irq, *tmp_irq;
4637 
4638     if (sony_pic_disable(device)) {
4639         pr_err("Couldn't disable device\n");
4640         return -ENXIO;
4641     }
4642 
4643     free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
4644     release_region(spic_dev.cur_ioport->io1.minimum,
4645             spic_dev.cur_ioport->io1.address_length);
4646     if (spic_dev.cur_ioport->io2.minimum)
4647         release_region(spic_dev.cur_ioport->io2.minimum,
4648                 spic_dev.cur_ioport->io2.address_length);
4649 
4650     sonypi_compat_exit();
4651 
4652     sony_laptop_remove_input();
4653 
4654     /* pf attrs */
4655     sysfs_remove_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
4656     sony_pf_remove();
4657 
4658     list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
4659         list_del(&io->list);
4660         kfree(io);
4661     }
4662     list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
4663         list_del(&irq->list);
4664         kfree(irq);
4665     }
4666     spic_dev.cur_ioport = NULL;
4667     spic_dev.cur_irq = NULL;
4668 
4669     dprintk(SONY_PIC_DRIVER_NAME " removed.\n");
4670     return 0;
4671 }
4672 
4673 static int sony_pic_add(struct acpi_device *device)
4674 {
4675     int result;
4676     struct sony_pic_ioport *io, *tmp_io;
4677     struct sony_pic_irq *irq, *tmp_irq;
4678 
4679     spic_dev.acpi_dev = device;
4680     strcpy(acpi_device_class(device), "sony/hotkey");
4681     sony_pic_detect_device_type(&spic_dev);
4682     mutex_init(&spic_dev.lock);
4683 
4684     /* read _PRS resources */
4685     result = sony_pic_possible_resources(device);
4686     if (result) {
4687         pr_err("Unable to read possible resources\n");
4688         goto err_free_resources;
4689     }
4690 
4691     /* setup input devices and helper fifo */
4692     result = sony_laptop_setup_input(device);
4693     if (result) {
4694         pr_err("Unable to create input devices\n");
4695         goto err_free_resources;
4696     }
4697 
4698     result = sonypi_compat_init();
4699     if (result)
4700         goto err_remove_input;
4701 
4702     /* request io port */
4703     list_for_each_entry_reverse(io, &spic_dev.ioports, list) {
4704         if (request_region(io->io1.minimum, io->io1.address_length,
4705                     "Sony Programmable I/O Device")) {
4706             dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n",
4707                     io->io1.minimum, io->io1.maximum,
4708                     io->io1.address_length);
4709             /* Type 1 have 2 ioports */
4710             if (io->io2.minimum) {
4711                 if (request_region(io->io2.minimum,
4712                         io->io2.address_length,
4713                         "Sony Programmable I/O Device")) {
4714                     dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n",
4715                             io->io2.minimum, io->io2.maximum,
4716                             io->io2.address_length);
4717                     spic_dev.cur_ioport = io;
4718                     break;
4719                 }
4720                 else {
4721                     dprintk("Unable to get I/O port2: "
4722                             "0x%.4x (0x%.4x) + 0x%.2x\n",
4723                             io->io2.minimum, io->io2.maximum,
4724                             io->io2.address_length);
4725                     release_region(io->io1.minimum,
4726                             io->io1.address_length);
4727                 }
4728             }
4729             else {
4730                 spic_dev.cur_ioport = io;
4731                 break;
4732             }
4733         }
4734     }
4735     if (!spic_dev.cur_ioport) {
4736         pr_err("Failed to request_region\n");
4737         result = -ENODEV;
4738         goto err_remove_compat;
4739     }
4740 
4741     /* request IRQ */
4742     list_for_each_entry_reverse(irq, &spic_dev.interrupts, list) {
4743         if (!request_irq(irq->irq.interrupts[0], sony_pic_irq,
4744                     0, "sony-laptop", &spic_dev)) {
4745             dprintk("IRQ: %d - triggering: %d - "
4746                     "polarity: %d - shr: %d\n",
4747                     irq->irq.interrupts[0],
4748                     irq->irq.triggering,
4749                     irq->irq.polarity,
4750                     irq->irq.shareable);
4751             spic_dev.cur_irq = irq;
4752             break;
4753         }
4754     }
4755     if (!spic_dev.cur_irq) {
4756         pr_err("Failed to request_irq\n");
4757         result = -ENODEV;
4758         goto err_release_region;
4759     }
4760 
4761     /* set resource status _SRS */
4762     result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
4763     if (result) {
4764         pr_err("Couldn't enable device\n");
4765         goto err_free_irq;
4766     }
4767 
4768     spic_dev.bluetooth_power = -1;
4769     /* create device attributes */
4770     result = sony_pf_add();
4771     if (result)
4772         goto err_disable_device;
4773 
4774     result = sysfs_create_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
4775     if (result)
4776         goto err_remove_pf;
4777 
4778     pr_info("SPIC setup done.\n");
4779     return 0;
4780 
4781 err_remove_pf:
4782     sony_pf_remove();
4783 
4784 err_disable_device:
4785     sony_pic_disable(device);
4786 
4787 err_free_irq:
4788     free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
4789 
4790 err_release_region:
4791     release_region(spic_dev.cur_ioport->io1.minimum,
4792             spic_dev.cur_ioport->io1.address_length);
4793     if (spic_dev.cur_ioport->io2.minimum)
4794         release_region(spic_dev.cur_ioport->io2.minimum,
4795                 spic_dev.cur_ioport->io2.address_length);
4796 
4797 err_remove_compat:
4798     sonypi_compat_exit();
4799 
4800 err_remove_input:
4801     sony_laptop_remove_input();
4802 
4803 err_free_resources:
4804     list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
4805         list_del(&io->list);
4806         kfree(io);
4807     }
4808     list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
4809         list_del(&irq->list);
4810         kfree(irq);
4811     }
4812     spic_dev.cur_ioport = NULL;
4813     spic_dev.cur_irq = NULL;
4814 
4815     return result;
4816 }
4817 
4818 #ifdef CONFIG_PM_SLEEP
4819 static int sony_pic_suspend(struct device *dev)
4820 {
4821     if (sony_pic_disable(to_acpi_device(dev)))
4822         return -ENXIO;
4823     return 0;
4824 }
4825 
4826 static int sony_pic_resume(struct device *dev)
4827 {
4828     sony_pic_enable(to_acpi_device(dev),
4829             spic_dev.cur_ioport, spic_dev.cur_irq);
4830     return 0;
4831 }
4832 #endif
4833 
4834 static SIMPLE_DEV_PM_OPS(sony_pic_pm, sony_pic_suspend, sony_pic_resume);
4835 
4836 static const struct acpi_device_id sony_pic_device_ids[] = {
4837     {SONY_PIC_HID, 0},
4838     {"", 0},
4839 };
4840 
4841 static struct acpi_driver sony_pic_driver = {
4842     .name = SONY_PIC_DRIVER_NAME,
4843     .class = SONY_PIC_CLASS,
4844     .ids = sony_pic_device_ids,
4845     .owner = THIS_MODULE,
4846     .ops = {
4847         .add = sony_pic_add,
4848         .remove = sony_pic_remove,
4849         },
4850     .drv.pm = &sony_pic_pm,
4851 };
4852 
4853 static const struct dmi_system_id sonypi_dmi_table[] __initconst = {
4854     {
4855         .ident = "Sony Vaio",
4856         .matches = {
4857             DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
4858             DMI_MATCH(DMI_PRODUCT_NAME, "PCG-"),
4859         },
4860     },
4861     {
4862         .ident = "Sony Vaio",
4863         .matches = {
4864             DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
4865             DMI_MATCH(DMI_PRODUCT_NAME, "VGN-"),
4866         },
4867     },
4868     { }
4869 };
4870 
4871 static int __init sony_laptop_init(void)
4872 {
4873     int result;
4874 
4875     if (!no_spic && dmi_check_system(sonypi_dmi_table)) {
4876         result = acpi_bus_register_driver(&sony_pic_driver);
4877         if (result) {
4878             pr_err("Unable to register SPIC driver\n");
4879             goto out;
4880         }
4881         spic_drv_registered = 1;
4882     }
4883 
4884     result = acpi_bus_register_driver(&sony_nc_driver);
4885     if (result) {
4886         pr_err("Unable to register SNC driver\n");
4887         goto out_unregister_pic;
4888     }
4889 
4890     return 0;
4891 
4892 out_unregister_pic:
4893     if (spic_drv_registered)
4894         acpi_bus_unregister_driver(&sony_pic_driver);
4895 out:
4896     return result;
4897 }
4898 
4899 static void __exit sony_laptop_exit(void)
4900 {
4901     acpi_bus_unregister_driver(&sony_nc_driver);
4902     if (spic_drv_registered)
4903         acpi_bus_unregister_driver(&sony_pic_driver);
4904 }
4905 
4906 module_init(sony_laptop_init);
4907 module_exit(sony_laptop_exit);