cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sony-laptop.c (121904B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * ACPI Sony Notebook Control Driver (SNC and SPIC)
      4 *
      5 * Copyright (C) 2004-2005 Stelian Pop <stelian@popies.net>
      6 * Copyright (C) 2007-2009 Mattia Dongili <malattia@linux.it>
      7 *
      8 * Parts of this driver inspired from asus_acpi.c and ibm_acpi.c
      9 * which are copyrighted by their respective authors.
     10 *
     11 * The SNY6001 driver part is based on the sonypi driver which includes
     12 * material from:
     13 *
     14 * Copyright (C) 2001-2005 Stelian Pop <stelian@popies.net>
     15 *
     16 * Copyright (C) 2005 Narayanan R S <nars@kadamba.org>
     17 *
     18 * Copyright (C) 2001-2002 AlcĂ´ve <www.alcove.com>
     19 *
     20 * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
     21 *
     22 * Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
     23 *
     24 * Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp>
     25 *
     26 * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
     27 *
     28 * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras.
     29 */
     30
     31#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     32
     33#include <linux/kernel.h>
     34#include <linux/module.h>
     35#include <linux/moduleparam.h>
     36#include <linux/init.h>
     37#include <linux/types.h>
     38#include <linux/backlight.h>
     39#include <linux/platform_device.h>
     40#include <linux/err.h>
     41#include <linux/dmi.h>
     42#include <linux/pci.h>
     43#include <linux/interrupt.h>
     44#include <linux/delay.h>
     45#include <linux/input.h>
     46#include <linux/kfifo.h>
     47#include <linux/workqueue.h>
     48#include <linux/acpi.h>
     49#include <linux/slab.h>
     50#include <linux/sonypi.h>
     51#include <linux/sony-laptop.h>
     52#include <linux/rfkill.h>
     53#ifdef CONFIG_SONYPI_COMPAT
     54#include <linux/poll.h>
     55#include <linux/miscdevice.h>
     56#endif
     57#include <linux/uaccess.h>
     58#include <acpi/video.h>
     59
     60#define dprintk(fmt, ...)			\
     61do {						\
     62	if (debug)				\
     63		pr_warn(fmt, ##__VA_ARGS__);	\
     64} while (0)
     65
     66#define SONY_NC_CLASS		"sony-nc"
     67#define SONY_NC_HID		"SNY5001"
     68#define SONY_NC_DRIVER_NAME	"Sony Notebook Control Driver"
     69
     70#define SONY_PIC_CLASS		"sony-pic"
     71#define SONY_PIC_HID		"SNY6001"
     72#define SONY_PIC_DRIVER_NAME	"Sony Programmable IO Control Driver"
     73
     74MODULE_AUTHOR("Stelian Pop, Mattia Dongili");
     75MODULE_DESCRIPTION("Sony laptop extras driver (SPIC and SNC ACPI device)");
     76MODULE_LICENSE("GPL");
     77
     78static int debug;
     79module_param(debug, int, 0);
     80MODULE_PARM_DESC(debug, "set this to 1 (and RTFM) if you want to help "
     81		 "the development of this driver");
     82
     83static int no_spic;		/* = 0 */
     84module_param(no_spic, int, 0444);
     85MODULE_PARM_DESC(no_spic,
     86		 "set this if you don't want to enable the SPIC device");
     87
     88static int compat;		/* = 0 */
     89module_param(compat, int, 0444);
     90MODULE_PARM_DESC(compat,
     91		 "set this if you want to enable backward compatibility mode");
     92
     93static unsigned long mask = 0xffffffff;
     94module_param(mask, ulong, 0644);
     95MODULE_PARM_DESC(mask,
     96		 "set this to the mask of event you want to enable (see doc)");
     97
     98static int camera;		/* = 0 */
     99module_param(camera, int, 0444);
    100MODULE_PARM_DESC(camera,
    101		 "set this to 1 to enable Motion Eye camera controls "
    102		 "(only use it if you have a C1VE or C1VN model)");
    103
    104#ifdef CONFIG_SONYPI_COMPAT
    105static int minor = -1;
    106module_param(minor, int, 0);
    107MODULE_PARM_DESC(minor,
    108		 "minor number of the misc device for the SPIC compatibility code, "
    109		 "default is -1 (automatic)");
    110#endif
    111
    112static int kbd_backlight = -1;
    113module_param(kbd_backlight, int, 0444);
    114MODULE_PARM_DESC(kbd_backlight,
    115		 "set this to 0 to disable keyboard backlight, "
    116		 "1 to enable it with automatic control and 2 to have it always "
    117		 "on (default: no change from current value)");
    118
    119static int kbd_backlight_timeout = -1;
    120module_param(kbd_backlight_timeout, int, 0444);
    121MODULE_PARM_DESC(kbd_backlight_timeout,
    122		 "meaningful values vary from 0 to 3 and their meaning depends "
    123		 "on the model (default: no change from current value)");
    124
    125#ifdef CONFIG_PM_SLEEP
    126static void sony_nc_thermal_resume(void);
    127#endif
    128static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
    129		unsigned int handle);
    130static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd,
    131		unsigned int handle);
    132
    133static int sony_nc_battery_care_setup(struct platform_device *pd,
    134		unsigned int handle);
    135static void sony_nc_battery_care_cleanup(struct platform_device *pd);
    136
    137static int sony_nc_thermal_setup(struct platform_device *pd);
    138static void sony_nc_thermal_cleanup(struct platform_device *pd);
    139
    140static int sony_nc_lid_resume_setup(struct platform_device *pd,
    141				    unsigned int handle);
    142static void sony_nc_lid_resume_cleanup(struct platform_device *pd);
    143
    144static int sony_nc_gfx_switch_setup(struct platform_device *pd,
    145		unsigned int handle);
    146static void sony_nc_gfx_switch_cleanup(struct platform_device *pd);
    147static int __sony_nc_gfx_switch_status_get(void);
    148
    149static int sony_nc_highspeed_charging_setup(struct platform_device *pd);
    150static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd);
    151
    152static int sony_nc_lowbatt_setup(struct platform_device *pd);
    153static void sony_nc_lowbatt_cleanup(struct platform_device *pd);
    154
    155static int sony_nc_fanspeed_setup(struct platform_device *pd);
    156static void sony_nc_fanspeed_cleanup(struct platform_device *pd);
    157
    158static int sony_nc_usb_charge_setup(struct platform_device *pd);
    159static void sony_nc_usb_charge_cleanup(struct platform_device *pd);
    160
    161static int sony_nc_panelid_setup(struct platform_device *pd);
    162static void sony_nc_panelid_cleanup(struct platform_device *pd);
    163
    164static int sony_nc_smart_conn_setup(struct platform_device *pd);
    165static void sony_nc_smart_conn_cleanup(struct platform_device *pd);
    166
    167static int sony_nc_touchpad_setup(struct platform_device *pd,
    168				  unsigned int handle);
    169static void sony_nc_touchpad_cleanup(struct platform_device *pd);
    170
    171enum sony_nc_rfkill {
    172	SONY_WIFI,
    173	SONY_BLUETOOTH,
    174	SONY_WWAN,
    175	SONY_WIMAX,
    176	N_SONY_RFKILL,
    177};
    178
    179static int sony_rfkill_handle;
    180static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL];
    181static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900};
    182static int sony_nc_rfkill_setup(struct acpi_device *device,
    183		unsigned int handle);
    184static void sony_nc_rfkill_cleanup(void);
    185static void sony_nc_rfkill_update(void);
    186
    187/*********** Input Devices ***********/
    188
    189#define SONY_LAPTOP_BUF_SIZE	128
    190struct sony_laptop_input_s {
    191	atomic_t		users;
    192	struct input_dev	*jog_dev;
    193	struct input_dev	*key_dev;
    194	struct kfifo		fifo;
    195	spinlock_t		fifo_lock;
    196	struct timer_list	release_key_timer;
    197};
    198
    199static struct sony_laptop_input_s sony_laptop_input = {
    200	.users = ATOMIC_INIT(0),
    201};
    202
    203struct sony_laptop_keypress {
    204	struct input_dev *dev;
    205	int key;
    206};
    207
    208/* Correspondance table between sonypi events
    209 * and input layer indexes in the keymap
    210 */
    211static const int sony_laptop_input_index[] = {
    212	-1,	/*  0 no event */
    213	-1,	/*  1 SONYPI_EVENT_JOGDIAL_DOWN */
    214	-1,	/*  2 SONYPI_EVENT_JOGDIAL_UP */
    215	-1,	/*  3 SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */
    216	-1,	/*  4 SONYPI_EVENT_JOGDIAL_UP_PRESSED */
    217	-1,	/*  5 SONYPI_EVENT_JOGDIAL_PRESSED */
    218	-1,	/*  6 SONYPI_EVENT_JOGDIAL_RELEASED */
    219	 0,	/*  7 SONYPI_EVENT_CAPTURE_PRESSED */
    220	 1,	/*  8 SONYPI_EVENT_CAPTURE_RELEASED */
    221	 2,	/*  9 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
    222	 3,	/* 10 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
    223	 4,	/* 11 SONYPI_EVENT_FNKEY_ESC */
    224	 5,	/* 12 SONYPI_EVENT_FNKEY_F1 */
    225	 6,	/* 13 SONYPI_EVENT_FNKEY_F2 */
    226	 7,	/* 14 SONYPI_EVENT_FNKEY_F3 */
    227	 8,	/* 15 SONYPI_EVENT_FNKEY_F4 */
    228	 9,	/* 16 SONYPI_EVENT_FNKEY_F5 */
    229	10,	/* 17 SONYPI_EVENT_FNKEY_F6 */
    230	11,	/* 18 SONYPI_EVENT_FNKEY_F7 */
    231	12,	/* 19 SONYPI_EVENT_FNKEY_F8 */
    232	13,	/* 20 SONYPI_EVENT_FNKEY_F9 */
    233	14,	/* 21 SONYPI_EVENT_FNKEY_F10 */
    234	15,	/* 22 SONYPI_EVENT_FNKEY_F11 */
    235	16,	/* 23 SONYPI_EVENT_FNKEY_F12 */
    236	17,	/* 24 SONYPI_EVENT_FNKEY_1 */
    237	18,	/* 25 SONYPI_EVENT_FNKEY_2 */
    238	19,	/* 26 SONYPI_EVENT_FNKEY_D */
    239	20,	/* 27 SONYPI_EVENT_FNKEY_E */
    240	21,	/* 28 SONYPI_EVENT_FNKEY_F */
    241	22,	/* 29 SONYPI_EVENT_FNKEY_S */
    242	23,	/* 30 SONYPI_EVENT_FNKEY_B */
    243	24,	/* 31 SONYPI_EVENT_BLUETOOTH_PRESSED */
    244	25,	/* 32 SONYPI_EVENT_PKEY_P1 */
    245	26,	/* 33 SONYPI_EVENT_PKEY_P2 */
    246	27,	/* 34 SONYPI_EVENT_PKEY_P3 */
    247	28,	/* 35 SONYPI_EVENT_BACK_PRESSED */
    248	-1,	/* 36 SONYPI_EVENT_LID_CLOSED */
    249	-1,	/* 37 SONYPI_EVENT_LID_OPENED */
    250	29,	/* 38 SONYPI_EVENT_BLUETOOTH_ON */
    251	30,	/* 39 SONYPI_EVENT_BLUETOOTH_OFF */
    252	31,	/* 40 SONYPI_EVENT_HELP_PRESSED */
    253	32,	/* 41 SONYPI_EVENT_FNKEY_ONLY */
    254	33,	/* 42 SONYPI_EVENT_JOGDIAL_FAST_DOWN */
    255	34,	/* 43 SONYPI_EVENT_JOGDIAL_FAST_UP */
    256	35,	/* 44 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
    257	36,	/* 45 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
    258	37,	/* 46 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
    259	38,	/* 47 SONYPI_EVENT_JOGDIAL_VFAST_UP */
    260	39,	/* 48 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
    261	40,	/* 49 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
    262	41,	/* 50 SONYPI_EVENT_ZOOM_PRESSED */
    263	42,	/* 51 SONYPI_EVENT_THUMBPHRASE_PRESSED */
    264	43,	/* 52 SONYPI_EVENT_MEYE_FACE */
    265	44,	/* 53 SONYPI_EVENT_MEYE_OPPOSITE */
    266	45,	/* 54 SONYPI_EVENT_MEMORYSTICK_INSERT */
    267	46,	/* 55 SONYPI_EVENT_MEMORYSTICK_EJECT */
    268	-1,	/* 56 SONYPI_EVENT_ANYBUTTON_RELEASED */
    269	-1,	/* 57 SONYPI_EVENT_BATTERY_INSERT */
    270	-1,	/* 58 SONYPI_EVENT_BATTERY_REMOVE */
    271	-1,	/* 59 SONYPI_EVENT_FNKEY_RELEASED */
    272	47,	/* 60 SONYPI_EVENT_WIRELESS_ON */
    273	48,	/* 61 SONYPI_EVENT_WIRELESS_OFF */
    274	49,	/* 62 SONYPI_EVENT_ZOOM_IN_PRESSED */
    275	50,	/* 63 SONYPI_EVENT_ZOOM_OUT_PRESSED */
    276	51,	/* 64 SONYPI_EVENT_CD_EJECT_PRESSED */
    277	52,	/* 65 SONYPI_EVENT_MODEKEY_PRESSED */
    278	53,	/* 66 SONYPI_EVENT_PKEY_P4 */
    279	54,	/* 67 SONYPI_EVENT_PKEY_P5 */
    280	55,	/* 68 SONYPI_EVENT_SETTINGKEY_PRESSED */
    281	56,	/* 69 SONYPI_EVENT_VOLUME_INC_PRESSED */
    282	57,	/* 70 SONYPI_EVENT_VOLUME_DEC_PRESSED */
    283	-1,	/* 71 SONYPI_EVENT_BRIGHTNESS_PRESSED */
    284	58,	/* 72 SONYPI_EVENT_MEDIA_PRESSED */
    285	59,	/* 72 SONYPI_EVENT_VENDOR_PRESSED */
    286};
    287
    288static int sony_laptop_input_keycode_map[] = {
    289	KEY_CAMERA,	/*  0 SONYPI_EVENT_CAPTURE_PRESSED */
    290	KEY_RESERVED,	/*  1 SONYPI_EVENT_CAPTURE_RELEASED */
    291	KEY_RESERVED,	/*  2 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
    292	KEY_RESERVED,	/*  3 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
    293	KEY_FN_ESC,	/*  4 SONYPI_EVENT_FNKEY_ESC */
    294	KEY_FN_F1,	/*  5 SONYPI_EVENT_FNKEY_F1 */
    295	KEY_FN_F2,	/*  6 SONYPI_EVENT_FNKEY_F2 */
    296	KEY_FN_F3,	/*  7 SONYPI_EVENT_FNKEY_F3 */
    297	KEY_FN_F4,	/*  8 SONYPI_EVENT_FNKEY_F4 */
    298	KEY_FN_F5,	/*  9 SONYPI_EVENT_FNKEY_F5 */
    299	KEY_FN_F6,	/* 10 SONYPI_EVENT_FNKEY_F6 */
    300	KEY_FN_F7,	/* 11 SONYPI_EVENT_FNKEY_F7 */
    301	KEY_FN_F8,	/* 12 SONYPI_EVENT_FNKEY_F8 */
    302	KEY_FN_F9,	/* 13 SONYPI_EVENT_FNKEY_F9 */
    303	KEY_FN_F10,	/* 14 SONYPI_EVENT_FNKEY_F10 */
    304	KEY_FN_F11,	/* 15 SONYPI_EVENT_FNKEY_F11 */
    305	KEY_FN_F12,	/* 16 SONYPI_EVENT_FNKEY_F12 */
    306	KEY_FN_1,	/* 17 SONYPI_EVENT_FNKEY_1 */
    307	KEY_FN_2,	/* 18 SONYPI_EVENT_FNKEY_2 */
    308	KEY_FN_D,	/* 19 SONYPI_EVENT_FNKEY_D */
    309	KEY_FN_E,	/* 20 SONYPI_EVENT_FNKEY_E */
    310	KEY_FN_F,	/* 21 SONYPI_EVENT_FNKEY_F */
    311	KEY_FN_S,	/* 22 SONYPI_EVENT_FNKEY_S */
    312	KEY_FN_B,	/* 23 SONYPI_EVENT_FNKEY_B */
    313	KEY_BLUETOOTH,	/* 24 SONYPI_EVENT_BLUETOOTH_PRESSED */
    314	KEY_PROG1,	/* 25 SONYPI_EVENT_PKEY_P1 */
    315	KEY_PROG2,	/* 26 SONYPI_EVENT_PKEY_P2 */
    316	KEY_PROG3,	/* 27 SONYPI_EVENT_PKEY_P3 */
    317	KEY_BACK,	/* 28 SONYPI_EVENT_BACK_PRESSED */
    318	KEY_BLUETOOTH,	/* 29 SONYPI_EVENT_BLUETOOTH_ON */
    319	KEY_BLUETOOTH,	/* 30 SONYPI_EVENT_BLUETOOTH_OFF */
    320	KEY_HELP,	/* 31 SONYPI_EVENT_HELP_PRESSED */
    321	KEY_FN,		/* 32 SONYPI_EVENT_FNKEY_ONLY */
    322	KEY_RESERVED,	/* 33 SONYPI_EVENT_JOGDIAL_FAST_DOWN */
    323	KEY_RESERVED,	/* 34 SONYPI_EVENT_JOGDIAL_FAST_UP */
    324	KEY_RESERVED,	/* 35 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
    325	KEY_RESERVED,	/* 36 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
    326	KEY_RESERVED,	/* 37 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
    327	KEY_RESERVED,	/* 38 SONYPI_EVENT_JOGDIAL_VFAST_UP */
    328	KEY_RESERVED,	/* 39 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
    329	KEY_RESERVED,	/* 40 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
    330	KEY_ZOOM,	/* 41 SONYPI_EVENT_ZOOM_PRESSED */
    331	BTN_THUMB,	/* 42 SONYPI_EVENT_THUMBPHRASE_PRESSED */
    332	KEY_RESERVED,	/* 43 SONYPI_EVENT_MEYE_FACE */
    333	KEY_RESERVED,	/* 44 SONYPI_EVENT_MEYE_OPPOSITE */
    334	KEY_RESERVED,	/* 45 SONYPI_EVENT_MEMORYSTICK_INSERT */
    335	KEY_RESERVED,	/* 46 SONYPI_EVENT_MEMORYSTICK_EJECT */
    336	KEY_WLAN,	/* 47 SONYPI_EVENT_WIRELESS_ON */
    337	KEY_WLAN,	/* 48 SONYPI_EVENT_WIRELESS_OFF */
    338	KEY_ZOOMIN,	/* 49 SONYPI_EVENT_ZOOM_IN_PRESSED */
    339	KEY_ZOOMOUT,	/* 50 SONYPI_EVENT_ZOOM_OUT_PRESSED */
    340	KEY_EJECTCD,	/* 51 SONYPI_EVENT_CD_EJECT_PRESSED */
    341	KEY_F13,	/* 52 SONYPI_EVENT_MODEKEY_PRESSED */
    342	KEY_PROG4,	/* 53 SONYPI_EVENT_PKEY_P4 */
    343	KEY_F14,	/* 54 SONYPI_EVENT_PKEY_P5 */
    344	KEY_F15,	/* 55 SONYPI_EVENT_SETTINGKEY_PRESSED */
    345	KEY_VOLUMEUP,	/* 56 SONYPI_EVENT_VOLUME_INC_PRESSED */
    346	KEY_VOLUMEDOWN,	/* 57 SONYPI_EVENT_VOLUME_DEC_PRESSED */
    347	KEY_MEDIA,	/* 58 SONYPI_EVENT_MEDIA_PRESSED */
    348	KEY_VENDOR,	/* 59 SONYPI_EVENT_VENDOR_PRESSED */
    349};
    350
    351/* release buttons after a short delay if pressed */
    352static void do_sony_laptop_release_key(struct timer_list *unused)
    353{
    354	struct sony_laptop_keypress kp;
    355	unsigned long flags;
    356
    357	spin_lock_irqsave(&sony_laptop_input.fifo_lock, flags);
    358
    359	if (kfifo_out(&sony_laptop_input.fifo,
    360		      (unsigned char *)&kp, sizeof(kp)) == sizeof(kp)) {
    361		input_report_key(kp.dev, kp.key, 0);
    362		input_sync(kp.dev);
    363	}
    364
    365	/* If there is something in the fifo schedule next release. */
    366	if (kfifo_len(&sony_laptop_input.fifo) != 0)
    367		mod_timer(&sony_laptop_input.release_key_timer,
    368			  jiffies + msecs_to_jiffies(10));
    369
    370	spin_unlock_irqrestore(&sony_laptop_input.fifo_lock, flags);
    371}
    372
    373/* forward event to the input subsystem */
    374static void sony_laptop_report_input_event(u8 event)
    375{
    376	struct input_dev *jog_dev = sony_laptop_input.jog_dev;
    377	struct input_dev *key_dev = sony_laptop_input.key_dev;
    378	struct sony_laptop_keypress kp = { NULL };
    379	int scancode = -1;
    380
    381	if (event == SONYPI_EVENT_FNKEY_RELEASED ||
    382			event == SONYPI_EVENT_ANYBUTTON_RELEASED) {
    383		/* Nothing, not all VAIOs generate this event */
    384		return;
    385	}
    386
    387	/* report events */
    388	switch (event) {
    389	/* jog_dev events */
    390	case SONYPI_EVENT_JOGDIAL_UP:
    391	case SONYPI_EVENT_JOGDIAL_UP_PRESSED:
    392		input_report_rel(jog_dev, REL_WHEEL, 1);
    393		input_sync(jog_dev);
    394		return;
    395
    396	case SONYPI_EVENT_JOGDIAL_DOWN:
    397	case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED:
    398		input_report_rel(jog_dev, REL_WHEEL, -1);
    399		input_sync(jog_dev);
    400		return;
    401
    402	/* key_dev events */
    403	case SONYPI_EVENT_JOGDIAL_PRESSED:
    404		kp.key = BTN_MIDDLE;
    405		kp.dev = jog_dev;
    406		break;
    407
    408	default:
    409		if (event >= ARRAY_SIZE(sony_laptop_input_index)) {
    410			dprintk("sony_laptop_report_input_event, event not known: %d\n", event);
    411			break;
    412		}
    413		if ((scancode = sony_laptop_input_index[event]) != -1) {
    414			kp.key = sony_laptop_input_keycode_map[scancode];
    415			if (kp.key != KEY_UNKNOWN)
    416				kp.dev = key_dev;
    417		}
    418		break;
    419	}
    420
    421	if (kp.dev) {
    422		/* if we have a scancode we emit it so we can always
    423		    remap the key */
    424		if (scancode != -1)
    425			input_event(kp.dev, EV_MSC, MSC_SCAN, scancode);
    426		input_report_key(kp.dev, kp.key, 1);
    427		input_sync(kp.dev);
    428
    429		/* schedule key release */
    430		kfifo_in_locked(&sony_laptop_input.fifo,
    431				(unsigned char *)&kp, sizeof(kp),
    432				&sony_laptop_input.fifo_lock);
    433		mod_timer(&sony_laptop_input.release_key_timer,
    434			  jiffies + msecs_to_jiffies(10));
    435	} else
    436		dprintk("unknown input event %.2x\n", event);
    437}
    438
    439static int sony_laptop_setup_input(struct acpi_device *acpi_device)
    440{
    441	struct input_dev *jog_dev;
    442	struct input_dev *key_dev;
    443	int i;
    444	int error;
    445
    446	/* don't run again if already initialized */
    447	if (atomic_add_return(1, &sony_laptop_input.users) > 1)
    448		return 0;
    449
    450	/* kfifo */
    451	spin_lock_init(&sony_laptop_input.fifo_lock);
    452	error = kfifo_alloc(&sony_laptop_input.fifo,
    453			    SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
    454	if (error) {
    455		pr_err("kfifo_alloc failed\n");
    456		goto err_dec_users;
    457	}
    458
    459	timer_setup(&sony_laptop_input.release_key_timer,
    460		    do_sony_laptop_release_key, 0);
    461
    462	/* input keys */
    463	key_dev = input_allocate_device();
    464	if (!key_dev) {
    465		error = -ENOMEM;
    466		goto err_free_kfifo;
    467	}
    468
    469	key_dev->name = "Sony Vaio Keys";
    470	key_dev->id.bustype = BUS_ISA;
    471	key_dev->id.vendor = PCI_VENDOR_ID_SONY;
    472	key_dev->dev.parent = &acpi_device->dev;
    473
    474	/* Initialize the Input Drivers: special keys */
    475	input_set_capability(key_dev, EV_MSC, MSC_SCAN);
    476
    477	__set_bit(EV_KEY, key_dev->evbit);
    478	key_dev->keycodesize = sizeof(sony_laptop_input_keycode_map[0]);
    479	key_dev->keycodemax = ARRAY_SIZE(sony_laptop_input_keycode_map);
    480	key_dev->keycode = &sony_laptop_input_keycode_map;
    481	for (i = 0; i < ARRAY_SIZE(sony_laptop_input_keycode_map); i++)
    482		__set_bit(sony_laptop_input_keycode_map[i], key_dev->keybit);
    483	__clear_bit(KEY_RESERVED, key_dev->keybit);
    484
    485	error = input_register_device(key_dev);
    486	if (error)
    487		goto err_free_keydev;
    488
    489	sony_laptop_input.key_dev = key_dev;
    490
    491	/* jogdial */
    492	jog_dev = input_allocate_device();
    493	if (!jog_dev) {
    494		error = -ENOMEM;
    495		goto err_unregister_keydev;
    496	}
    497
    498	jog_dev->name = "Sony Vaio Jogdial";
    499	jog_dev->id.bustype = BUS_ISA;
    500	jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
    501	jog_dev->dev.parent = &acpi_device->dev;
    502
    503	input_set_capability(jog_dev, EV_KEY, BTN_MIDDLE);
    504	input_set_capability(jog_dev, EV_REL, REL_WHEEL);
    505
    506	error = input_register_device(jog_dev);
    507	if (error)
    508		goto err_free_jogdev;
    509
    510	sony_laptop_input.jog_dev = jog_dev;
    511
    512	return 0;
    513
    514err_free_jogdev:
    515	input_free_device(jog_dev);
    516
    517err_unregister_keydev:
    518	input_unregister_device(key_dev);
    519	/* to avoid kref underflow below at input_free_device */
    520	key_dev = NULL;
    521
    522err_free_keydev:
    523	input_free_device(key_dev);
    524
    525err_free_kfifo:
    526	kfifo_free(&sony_laptop_input.fifo);
    527
    528err_dec_users:
    529	atomic_dec(&sony_laptop_input.users);
    530	return error;
    531}
    532
    533static void sony_laptop_remove_input(void)
    534{
    535	struct sony_laptop_keypress kp = { NULL };
    536
    537	/* Cleanup only after the last user has gone */
    538	if (!atomic_dec_and_test(&sony_laptop_input.users))
    539		return;
    540
    541	del_timer_sync(&sony_laptop_input.release_key_timer);
    542
    543	/*
    544	 * Generate key-up events for remaining keys. Note that we don't
    545	 * need locking since nobody is adding new events to the kfifo.
    546	 */
    547	while (kfifo_out(&sony_laptop_input.fifo,
    548			 (unsigned char *)&kp, sizeof(kp)) == sizeof(kp)) {
    549		input_report_key(kp.dev, kp.key, 0);
    550		input_sync(kp.dev);
    551	}
    552
    553	/* destroy input devs */
    554	input_unregister_device(sony_laptop_input.key_dev);
    555	sony_laptop_input.key_dev = NULL;
    556
    557	if (sony_laptop_input.jog_dev) {
    558		input_unregister_device(sony_laptop_input.jog_dev);
    559		sony_laptop_input.jog_dev = NULL;
    560	}
    561
    562	kfifo_free(&sony_laptop_input.fifo);
    563}
    564
    565/*********** Platform Device ***********/
    566
    567static atomic_t sony_pf_users = ATOMIC_INIT(0);
    568static struct platform_driver sony_pf_driver = {
    569	.driver = {
    570		   .name = "sony-laptop",
    571		   }
    572};
    573static struct platform_device *sony_pf_device;
    574
    575static int sony_pf_add(void)
    576{
    577	int ret = 0;
    578
    579	/* don't run again if already initialized */
    580	if (atomic_add_return(1, &sony_pf_users) > 1)
    581		return 0;
    582
    583	ret = platform_driver_register(&sony_pf_driver);
    584	if (ret)
    585		goto out;
    586
    587	sony_pf_device = platform_device_alloc("sony-laptop", -1);
    588	if (!sony_pf_device) {
    589		ret = -ENOMEM;
    590		goto out_platform_registered;
    591	}
    592
    593	ret = platform_device_add(sony_pf_device);
    594	if (ret)
    595		goto out_platform_alloced;
    596
    597	return 0;
    598
    599      out_platform_alloced:
    600	platform_device_put(sony_pf_device);
    601	sony_pf_device = NULL;
    602      out_platform_registered:
    603	platform_driver_unregister(&sony_pf_driver);
    604      out:
    605	atomic_dec(&sony_pf_users);
    606	return ret;
    607}
    608
    609static void sony_pf_remove(void)
    610{
    611	/* deregister only after the last user has gone */
    612	if (!atomic_dec_and_test(&sony_pf_users))
    613		return;
    614
    615	platform_device_unregister(sony_pf_device);
    616	platform_driver_unregister(&sony_pf_driver);
    617}
    618
    619/*********** SNC (SNY5001) Device ***********/
    620
    621/* the device uses 1-based values, while the backlight subsystem uses
    622   0-based values */
    623#define SONY_MAX_BRIGHTNESS	8
    624
    625#define SNC_VALIDATE_IN		0
    626#define SNC_VALIDATE_OUT	1
    627
    628static ssize_t sony_nc_sysfs_show(struct device *, struct device_attribute *,
    629			      char *);
    630static ssize_t sony_nc_sysfs_store(struct device *, struct device_attribute *,
    631			       const char *, size_t);
    632static int boolean_validate(const int, const int);
    633static int brightness_default_validate(const int, const int);
    634
    635struct sony_nc_value {
    636	char *name;		/* name of the entry */
    637	char **acpiget;		/* names of the ACPI get function */
    638	char **acpiset;		/* names of the ACPI set function */
    639	int (*validate)(const int, const int);	/* input/output validation */
    640	int value;		/* current setting */
    641	int valid;		/* Has ever been set */
    642	int debug;		/* active only in debug mode ? */
    643	struct device_attribute devattr;	/* sysfs attribute */
    644};
    645
    646#define SNC_HANDLE_NAMES(_name, _values...) \
    647	static char *snc_##_name[] = { _values, NULL }
    648
    649#define SNC_HANDLE(_name, _getters, _setters, _validate, _debug) \
    650	{ \
    651		.name		= __stringify(_name), \
    652		.acpiget	= _getters, \
    653		.acpiset	= _setters, \
    654		.validate	= _validate, \
    655		.debug		= _debug, \
    656		.devattr	= __ATTR(_name, 0, sony_nc_sysfs_show, sony_nc_sysfs_store), \
    657	}
    658
    659#define SNC_HANDLE_NULL	{ .name = NULL }
    660
    661SNC_HANDLE_NAMES(fnkey_get, "GHKE");
    662
    663SNC_HANDLE_NAMES(brightness_def_get, "GPBR");
    664SNC_HANDLE_NAMES(brightness_def_set, "SPBR");
    665
    666SNC_HANDLE_NAMES(cdpower_get, "GCDP");
    667SNC_HANDLE_NAMES(cdpower_set, "SCDP", "CDPW");
    668
    669SNC_HANDLE_NAMES(audiopower_get, "GAZP");
    670SNC_HANDLE_NAMES(audiopower_set, "AZPW");
    671
    672SNC_HANDLE_NAMES(lanpower_get, "GLNP");
    673SNC_HANDLE_NAMES(lanpower_set, "LNPW");
    674
    675SNC_HANDLE_NAMES(lidstate_get, "GLID");
    676
    677SNC_HANDLE_NAMES(indicatorlamp_get, "GILS");
    678SNC_HANDLE_NAMES(indicatorlamp_set, "SILS");
    679
    680SNC_HANDLE_NAMES(gainbass_get, "GMGB");
    681SNC_HANDLE_NAMES(gainbass_set, "CMGB");
    682
    683SNC_HANDLE_NAMES(PID_get, "GPID");
    684
    685SNC_HANDLE_NAMES(CTR_get, "GCTR");
    686SNC_HANDLE_NAMES(CTR_set, "SCTR");
    687
    688SNC_HANDLE_NAMES(PCR_get, "GPCR");
    689SNC_HANDLE_NAMES(PCR_set, "SPCR");
    690
    691SNC_HANDLE_NAMES(CMI_get, "GCMI");
    692SNC_HANDLE_NAMES(CMI_set, "SCMI");
    693
    694static struct sony_nc_value sony_nc_values[] = {
    695	SNC_HANDLE(brightness_default, snc_brightness_def_get,
    696			snc_brightness_def_set, brightness_default_validate, 0),
    697	SNC_HANDLE(fnkey, snc_fnkey_get, NULL, NULL, 0),
    698	SNC_HANDLE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0),
    699	SNC_HANDLE(audiopower, snc_audiopower_get, snc_audiopower_set,
    700			boolean_validate, 0),
    701	SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set,
    702			boolean_validate, 1),
    703	SNC_HANDLE(lidstate, snc_lidstate_get, NULL,
    704			boolean_validate, 0),
    705	SNC_HANDLE(indicatorlamp, snc_indicatorlamp_get, snc_indicatorlamp_set,
    706			boolean_validate, 0),
    707	SNC_HANDLE(gainbass, snc_gainbass_get, snc_gainbass_set,
    708			boolean_validate, 0),
    709	/* unknown methods */
    710	SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1),
    711	SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1),
    712	SNC_HANDLE(PCR, snc_PCR_get, snc_PCR_set, NULL, 1),
    713	SNC_HANDLE(CMI, snc_CMI_get, snc_CMI_set, NULL, 1),
    714	SNC_HANDLE_NULL
    715};
    716
    717static acpi_handle sony_nc_acpi_handle;
    718static struct acpi_device *sony_nc_acpi_device = NULL;
    719
    720/*
    721 * acpi_evaluate_object wrappers
    722 * all useful calls into SNC methods take one or zero parameters and return
    723 * integers or arrays.
    724 */
    725static union acpi_object *__call_snc_method(acpi_handle handle, char *method,
    726		u64 *value)
    727{
    728	union acpi_object *result = NULL;
    729	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
    730	acpi_status status;
    731
    732	if (value) {
    733		struct acpi_object_list params;
    734		union acpi_object in;
    735		in.type = ACPI_TYPE_INTEGER;
    736		in.integer.value = *value;
    737		params.count = 1;
    738		params.pointer = &in;
    739		status = acpi_evaluate_object(handle, method, &params, &output);
    740		dprintk("__call_snc_method: [%s:0x%.8x%.8x]\n", method,
    741				(unsigned int)(*value >> 32),
    742				(unsigned int)*value & 0xffffffff);
    743	} else {
    744		status = acpi_evaluate_object(handle, method, NULL, &output);
    745		dprintk("__call_snc_method: [%s]\n", method);
    746	}
    747
    748	if (ACPI_FAILURE(status)) {
    749		pr_err("Failed to evaluate [%s]\n", method);
    750		return NULL;
    751	}
    752
    753	result = (union acpi_object *) output.pointer;
    754	if (!result)
    755		dprintk("No return object [%s]\n", method);
    756
    757	return result;
    758}
    759
    760#define MIN(a, b)	(a > b ? b : a)
    761static int sony_nc_buffer_call(acpi_handle handle, char *name, u64 *value,
    762		void *buffer, size_t buflen)
    763{
    764	int ret = 0;
    765	size_t len;
    766	union acpi_object *object = __call_snc_method(handle, name, value);
    767
    768	if (!object)
    769		return -EINVAL;
    770
    771	if (!buffer) {
    772		/* do nothing */
    773	} else if (object->type == ACPI_TYPE_BUFFER) {
    774		len = MIN(buflen, object->buffer.length);
    775		memset(buffer, 0, buflen);
    776		memcpy(buffer, object->buffer.pointer, len);
    777
    778	} else if (object->type == ACPI_TYPE_INTEGER) {
    779		len = MIN(buflen, sizeof(object->integer.value));
    780		memset(buffer, 0, buflen);
    781		memcpy(buffer, &object->integer.value, len);
    782
    783	} else {
    784		pr_warn("Unexpected acpi_object: 0x%x\n", object->type);
    785		ret = -EINVAL;
    786	}
    787
    788	kfree(object);
    789	return ret;
    790}
    791
    792static int sony_nc_int_call(acpi_handle handle, char *name, int *value, int
    793		*result)
    794{
    795	int ret;
    796
    797	if (value) {
    798		u64 v = *value;
    799
    800		ret = sony_nc_buffer_call(handle, name, &v, result,
    801				sizeof(*result));
    802	} else {
    803		ret =  sony_nc_buffer_call(handle, name, NULL, result,
    804				sizeof(*result));
    805	}
    806	return ret;
    807}
    808
    809struct sony_nc_handles {
    810	u16 cap[0x10];
    811	struct device_attribute devattr;
    812};
    813
    814static struct sony_nc_handles *handles;
    815
    816static ssize_t sony_nc_handles_show(struct device *dev,
    817		struct device_attribute *attr, char *buffer)
    818{
    819	ssize_t len = 0;
    820	int i;
    821
    822	for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
    823		len += scnprintf(buffer + len, PAGE_SIZE - len, "0x%.4x ",
    824				handles->cap[i]);
    825	}
    826	len += scnprintf(buffer + len, PAGE_SIZE - len, "\n");
    827
    828	return len;
    829}
    830
    831static int sony_nc_handles_setup(struct platform_device *pd)
    832{
    833	int i, r, result, arg;
    834
    835	handles = kzalloc(sizeof(*handles), GFP_KERNEL);
    836	if (!handles)
    837		return -ENOMEM;
    838
    839	for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
    840		arg = i + 0x20;
    841		r = sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg,
    842					&result);
    843		if (!r) {
    844			dprintk("caching handle 0x%.4x (offset: 0x%.2x)\n",
    845					result, i);
    846			handles->cap[i] = result;
    847		}
    848	}
    849
    850	if (debug) {
    851		sysfs_attr_init(&handles->devattr.attr);
    852		handles->devattr.attr.name = "handles";
    853		handles->devattr.attr.mode = S_IRUGO;
    854		handles->devattr.show = sony_nc_handles_show;
    855
    856		/* allow reading capabilities via sysfs */
    857		if (device_create_file(&pd->dev, &handles->devattr)) {
    858			kfree(handles);
    859			handles = NULL;
    860			return -1;
    861		}
    862	}
    863
    864	return 0;
    865}
    866
    867static int sony_nc_handles_cleanup(struct platform_device *pd)
    868{
    869	if (handles) {
    870		if (debug)
    871			device_remove_file(&pd->dev, &handles->devattr);
    872		kfree(handles);
    873		handles = NULL;
    874	}
    875	return 0;
    876}
    877
    878static int sony_find_snc_handle(int handle)
    879{
    880	int i;
    881
    882	/* not initialized yet, return early */
    883	if (!handles || !handle)
    884		return -EINVAL;
    885
    886	for (i = 0; i < 0x10; i++) {
    887		if (handles->cap[i] == handle) {
    888			dprintk("found handle 0x%.4x (offset: 0x%.2x)\n",
    889					handle, i);
    890			return i;
    891		}
    892	}
    893	dprintk("handle 0x%.4x not found\n", handle);
    894	return -EINVAL;
    895}
    896
    897static int sony_call_snc_handle(int handle, int argument, int *result)
    898{
    899	int arg, ret = 0;
    900	int offset = sony_find_snc_handle(handle);
    901
    902	if (offset < 0)
    903		return offset;
    904
    905	arg = offset | argument;
    906	ret = sony_nc_int_call(sony_nc_acpi_handle, "SN07", &arg, result);
    907	dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n", arg, *result);
    908	return ret;
    909}
    910
    911/*
    912 * sony_nc_values input/output validate functions
    913 */
    914
    915/* brightness_default_validate:
    916 *
    917 * manipulate input output values to keep consistency with the
    918 * backlight framework for which brightness values are 0-based.
    919 */
    920static int brightness_default_validate(const int direction, const int value)
    921{
    922	switch (direction) {
    923		case SNC_VALIDATE_OUT:
    924			return value - 1;
    925		case SNC_VALIDATE_IN:
    926			if (value >= 0 && value < SONY_MAX_BRIGHTNESS)
    927				return value + 1;
    928	}
    929	return -EINVAL;
    930}
    931
    932/* boolean_validate:
    933 *
    934 * on input validate boolean values 0/1, on output just pass the
    935 * received value.
    936 */
    937static int boolean_validate(const int direction, const int value)
    938{
    939	if (direction == SNC_VALIDATE_IN) {
    940		if (value != 0 && value != 1)
    941			return -EINVAL;
    942	}
    943	return value;
    944}
    945
    946/*
    947 * Sysfs show/store common to all sony_nc_values
    948 */
    949static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr,
    950			      char *buffer)
    951{
    952	int value, ret = 0;
    953	struct sony_nc_value *item =
    954	    container_of(attr, struct sony_nc_value, devattr);
    955
    956	if (!*item->acpiget)
    957		return -EIO;
    958
    959	ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiget, NULL,
    960				&value);
    961	if (ret < 0)
    962		return -EIO;
    963
    964	if (item->validate)
    965		value = item->validate(SNC_VALIDATE_OUT, value);
    966
    967	return sysfs_emit(buffer, "%d\n", value);
    968}
    969
    970static ssize_t sony_nc_sysfs_store(struct device *dev,
    971			       struct device_attribute *attr,
    972			       const char *buffer, size_t count)
    973{
    974	int value;
    975	int ret = 0;
    976	struct sony_nc_value *item =
    977	    container_of(attr, struct sony_nc_value, devattr);
    978
    979	if (!item->acpiset)
    980		return -EIO;
    981
    982	if (count > 31)
    983		return -EINVAL;
    984
    985	if (kstrtoint(buffer, 10, &value))
    986		return -EINVAL;
    987
    988	if (item->validate)
    989		value = item->validate(SNC_VALIDATE_IN, value);
    990
    991	if (value < 0)
    992		return value;
    993
    994	ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiset,
    995			       &value, NULL);
    996	if (ret < 0)
    997		return -EIO;
    998
    999	item->value = value;
   1000	item->valid = 1;
   1001	return count;
   1002}
   1003
   1004
   1005/*
   1006 * Backlight device
   1007 */
   1008struct sony_backlight_props {
   1009	struct backlight_device *dev;
   1010	int			handle;
   1011	int			cmd_base;
   1012	u8			offset;
   1013	u8			maxlvl;
   1014};
   1015static struct sony_backlight_props sony_bl_props;
   1016
   1017static 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
   1023static 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
   1033static 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
   1044static 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
   1058static 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};
   1063static 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 */
   1072struct sony_nc_event {
   1073	u8	data;
   1074	u8	event;
   1075};
   1076
   1077static 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
   1123static 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
   1141static 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 */
   1177enum event_types {
   1178	HOTKEY = 1,
   1179	KILLSWITCH,
   1180	GFX_SWITCH
   1181};
   1182static 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
   1275static 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 */
   1293static 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
   1424static 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
   1505static 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
   1547static 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
   1577static SIMPLE_DEV_PM_OPS(sony_nc_pm, NULL, sony_nc_resume);
   1578
   1579static 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
   1591static 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
   1602static const struct rfkill_ops sony_rfkill_ops = {
   1603	.set_block = sony_nc_rfkill_set,
   1604};
   1605
   1606static 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
   1670static 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
   1698static 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 */
   1757struct 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
   1767static struct kbd_backlight *kbdbl_ctl;
   1768
   1769static 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
   1791static 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
   1811static 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
   1817static 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
   1833static 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
   1853static 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
   1859static 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
   1943outmode:
   1944	device_remove_file(&pd->dev, &kbdbl_ctl->mode_attr);
   1945outkzalloc:
   1946	kfree(kbdbl_ctl);
   1947	kbdbl_ctl = NULL;
   1948	return ret;
   1949}
   1950
   1951static 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
   1963struct battery_care_control {
   1964	struct device_attribute attrs[2];
   1965	unsigned int handle;
   1966};
   1967static struct battery_care_control *bcare_ctl;
   1968
   1969static 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
   2026static 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
   2053static 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
   2064static 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
   2100outlimiter:
   2101	device_remove_file(&pd->dev, &bcare_ctl->attrs[0]);
   2102
   2103outkzalloc:
   2104	kfree(bcare_ctl);
   2105	bcare_ctl = NULL;
   2106
   2107	return ret;
   2108}
   2109
   2110static 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
   2122struct snc_thermal_ctrl {
   2123	unsigned int mode;
   2124	unsigned int profiles;
   2125	struct device_attribute mode_attr;
   2126	struct device_attribute profiles_attr;
   2127};
   2128static struct snc_thermal_ctrl *th_handle;
   2129
   2130#define THM_PROFILE_MAX 3
   2131static const char * const snc_thermal_profiles[] = {
   2132	"balanced",
   2133	"silent",
   2134	"performance"
   2135};
   2136
   2137static 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
   2158static 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
   2168static 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
   2184static 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
   2208static 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
   2219static int sony_nc_thermal_setup(struct platform_device *pd)
   2220{
   2221	int ret = 0;
   2222	th_handle = kzalloc(sizeof(struct snc_thermal_ctrl), GFP_KERNEL);
   2223	if (!th_handle)
   2224		return -ENOMEM;
   2225
   2226	ret = sony_call_snc_handle(0x0122, 0x0000, &th_handle->profiles);
   2227	if (ret) {
   2228		pr_warn("couldn't to read the thermal profiles\n");
   2229		goto outkzalloc;
   2230	}
   2231
   2232	ret = sony_nc_thermal_mode_get();
   2233	if (ret < 0) {
   2234		pr_warn("couldn't to read the current thermal profile");
   2235		goto outkzalloc;
   2236	}
   2237	th_handle->mode = ret;
   2238
   2239	sysfs_attr_init(&th_handle->profiles_attr.attr);
   2240	th_handle->profiles_attr.attr.name = "thermal_profiles";
   2241	th_handle->profiles_attr.attr.mode = S_IRUGO;
   2242	th_handle->profiles_attr.show = sony_nc_thermal_profiles_show;
   2243
   2244	sysfs_attr_init(&th_handle->mode_attr.attr);
   2245	th_handle->mode_attr.attr.name = "thermal_control";
   2246	th_handle->mode_attr.attr.mode = S_IRUGO | S_IWUSR;
   2247	th_handle->mode_attr.show = sony_nc_thermal_mode_show;
   2248	th_handle->mode_attr.store = sony_nc_thermal_mode_store;
   2249
   2250	ret = device_create_file(&pd->dev, &th_handle->profiles_attr);
   2251	if (ret)
   2252		goto outkzalloc;
   2253
   2254	ret = device_create_file(&pd->dev, &th_handle->mode_attr);
   2255	if (ret)
   2256		goto outprofiles;
   2257
   2258	return 0;
   2259
   2260outprofiles:
   2261	device_remove_file(&pd->dev, &th_handle->profiles_attr);
   2262outkzalloc:
   2263	kfree(th_handle);
   2264	th_handle = NULL;
   2265	return ret;
   2266}
   2267
   2268static void sony_nc_thermal_cleanup(struct platform_device *pd)
   2269{
   2270	if (th_handle) {
   2271		device_remove_file(&pd->dev, &th_handle->profiles_attr);
   2272		device_remove_file(&pd->dev, &th_handle->mode_attr);
   2273		kfree(th_handle);
   2274		th_handle = NULL;
   2275	}
   2276}
   2277
   2278#ifdef CONFIG_PM_SLEEP
   2279static void sony_nc_thermal_resume(void)
   2280{
   2281	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
   2298struct snc_lid_resume_control {
   2299	struct device_attribute attrs[LID_RESUME_MAX];
   2300	unsigned int status;
   2301	int handle;
   2302};
   2303static struct snc_lid_resume_control *lid_ctl;
   2304
   2305static 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
   2346static 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
   2361static 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
   2405liderror:
   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
   2415static 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 */
   2433enum gfx_switch {
   2434	SPEED,
   2435	STAMINA,
   2436	AUTO
   2437};
   2438struct snc_gfx_switch_control {
   2439	struct device_attribute attr;
   2440	unsigned int handle;
   2441};
   2442static struct snc_gfx_switch_control *gfxs_ctl;
   2443
   2444/* returns 0 for speed, 1 for stamina */
   2445static 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
   2477static 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
   2492static 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
   2514gfxerror:
   2515	kfree(gfxs_ctl);
   2516	gfxs_ctl = NULL;
   2517
   2518	return result;
   2519}
   2520
   2521static 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 */
   2532static struct device_attribute *hsc_handle;
   2533
   2534static 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
   2553static 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
   2564static 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
   2596static 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 */
   2606static struct device_attribute *lowbatt_handle;
   2607
   2608static 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
   2627static 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
   2638static 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
   2662static 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 */
   2672static struct device_attribute *fan_handle, *hsf_handle;
   2673
   2674static 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
   2693static 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
   2704static 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
   2715static 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
   2751out_hsf_handle:
   2752	device_remove_file(&pd->dev, fan_handle);
   2753
   2754out_fan_handle:
   2755	kfree(hsf_handle);
   2756	hsf_handle = NULL;
   2757
   2758out_hsf_handle_alloc:
   2759	kfree(fan_handle);
   2760	fan_handle = NULL;
   2761	return result;
   2762}
   2763
   2764static 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 */
   2779static struct device_attribute *uc_handle;
   2780
   2781static 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
   2800static 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
   2811static 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
   2843static 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 */
   2853static struct device_attribute *panel_handle;
   2854
   2855static 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
   2866static 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
   2890static 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 */
   2900static struct device_attribute *sc_handle;
   2901
   2902static 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
   2921static 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
   2945static 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 */
   2955struct touchpad_control {
   2956	struct device_attribute attr;
   2957	int handle;
   2958};
   2959static struct touchpad_control *tp_ctl;
   2960
   2961static 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
   2983static 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
   2994static 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
   3020static 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
   3029static 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
   3086static 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
   3144static void sony_nc_backlight_cleanup(void)
   3145{
   3146	backlight_device_unregister(sony_bl_props.dev);
   3147}
   3148
   3149static 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
   3247out_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
   3255outplatform:
   3256	sony_laptop_remove_input();
   3257
   3258outpresent:
   3259	sony_pf_remove();
   3260
   3261outwalk:
   3262	sony_nc_rfkill_cleanup();
   3263	return result;
   3264}
   3265
   3266static 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
   3287static const struct acpi_device_id sony_device_ids[] = {
   3288	{SONY_NC_HID, 0},
   3289	{SONY_PIC_HID, 0},
   3290	{"", 0},
   3291};
   3292MODULE_DEVICE_TABLE(acpi, sony_device_ids);
   3293
   3294static const struct acpi_device_id sony_nc_device_ids[] = {
   3295	{SONY_NC_HID, 0},
   3296	{"", 0},
   3297};
   3298
   3299static 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
   3322struct sony_pic_ioport {
   3323	struct acpi_resource_io	io1;
   3324	struct acpi_resource_io	io2;
   3325	struct list_head	list;
   3326};
   3327
   3328struct sony_pic_irq {
   3329	struct acpi_resource_irq	irq;
   3330	struct list_head		list;
   3331};
   3332
   3333struct sonypi_eventtypes {
   3334	u8			data;
   3335	unsigned long		mask;
   3336	struct sonypi_event	*events;
   3337};
   3338
   3339struct 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
   3355static struct sony_pic_dev spic_dev = {
   3356	.interrupts	= LIST_HEAD_INIT(spic_dev.interrupts),
   3357	.ioports	= LIST_HEAD_INIT(spic_dev.ioports),
   3358};
   3359
   3360static 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
   3378struct sonypi_event {
   3379	u8	data;
   3380	u8	event;
   3381};
   3382
   3383/* The set of possible button release events */
   3384static struct sonypi_event sonypi_releaseev[] = {
   3385	{ 0x00, SONYPI_EVENT_ANYBUTTON_RELEASED },
   3386	{ 0, 0 }
   3387};
   3388
   3389/* The set of possible jogger events  */
   3390static 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 */
   3408static 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 */
   3417static 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 */
   3444static 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 */
   3453static 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 */
   3461static 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 */
   3468static struct sonypi_event sonypi_backev[] = {
   3469	{ 0x20, SONYPI_EVENT_BACK_PRESSED },
   3470	{ 0, 0 }
   3471};
   3472
   3473/* The set of possible help button events */
   3474static struct sonypi_event sonypi_helpev[] = {
   3475	{ 0x3b, SONYPI_EVENT_HELP_PRESSED },
   3476	{ 0, 0 }
   3477};
   3478
   3479
   3480/* The set of possible lid events */
   3481static 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 */
   3488static 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 */
   3497static struct sonypi_event sonypi_thumbphraseev[] = {
   3498	{ 0x3a, SONYPI_EVENT_THUMBPHRASE_PRESSED },
   3499	{ 0, 0 }
   3500};
   3501
   3502/* The set of possible motioneye camera events */
   3503static 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 */
   3510static 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 */
   3517static 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 */
   3524static 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 */
   3531static struct sonypi_event sonypi_brightnessev[] = {
   3532	{ 0x80, SONYPI_EVENT_BRIGHTNESS_PRESSED },
   3533	{ 0, 0 }
   3534};
   3535
   3536static 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};
   3549static 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};
   3566static 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
   3593static 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
   3606static 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
   3621static 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 */
   3640static 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
   3659static 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
   3716out:
   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
   3756static 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
   3764static 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
   3782static 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) */
   3823int 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}
   3872EXPORT_SYMBOL(sony_pic_camera_command);
   3873
   3874/* gprs/edge modem (SZ460N and SZ210P), thanks to Joshua Wise */
   3875static 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
   3885static 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
   3903static 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 */
   3914static 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
   3924static 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
   3942static 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
   3955static int sony_pic_set_fanspeed(unsigned long value)
   3956{
   3957	return ec_write(SONY_PIC_FAN0_STATUS, value);
   3958}
   3959
   3960static int sony_pic_get_fanspeed(u8 *value)
   3961{
   3962	return ec_read(SONY_PIC_FAN0_STATUS, value);
   3963}
   3964
   3965static 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
   3982static 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)					\
   3993struct device_attribute spic_attr_##_name = __ATTR(_name,	\
   3994		_mode, sony_pic_## _name ##_show,		\
   3995		sony_pic_## _name ##_store)
   3996
   3997static SPIC_ATTR(bluetoothpower, 0644);
   3998static SPIC_ATTR(wwanpower, 0644);
   3999static SPIC_ATTR(fanspeed, 0644);
   4000
   4001static struct attribute *spic_attributes[] = {
   4002	&spic_attr_bluetoothpower.attr,
   4003	&spic_attr_wwanpower.attr,
   4004	&spic_attr_fanspeed.attr,
   4005	NULL
   4006};
   4007
   4008static 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
   4030struct 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};
   4037static struct sonypi_compat_s sonypi_compat = {
   4038	.open_count = ATOMIC_INIT(0),
   4039};
   4040
   4041static 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
   4046static int sonypi_misc_release(struct inode *inode, struct file *file)
   4047{
   4048	atomic_dec(&sonypi_compat.open_count);
   4049	return 0;
   4050}
   4051
   4052static 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
   4067static 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
   4098static __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
   4106static 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
   4117static 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
   4247static 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
   4258static struct miscdevice sonypi_misc_device = {
   4259	.minor		= MISC_DYNAMIC_MINOR,
   4260	.name		= "sonypi",
   4261	.fops		= &sonypi_misc_fops,
   4262};
   4263
   4264static 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
   4272static 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
   4299err_free_kfifo:
   4300	kfifo_free(&sonypi_compat.fifo);
   4301	return error;
   4302}
   4303
   4304static void sonypi_compat_exit(void)
   4305{
   4306	misc_deregister(&sonypi_misc_device);
   4307	kfifo_free(&sonypi_compat.fifo);
   4308}
   4309#else
   4310static int sonypi_compat_init(void) { return 0; }
   4311static void sonypi_compat_exit(void) { }
   4312static void sonypi_compat_report_event(u8 event) { }
   4313#endif /* CONFIG_SONYPI_COMPAT */
   4314
   4315/*
   4316 * ACPI callbacks
   4317 */
   4318static acpi_status
   4319sony_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 || !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 (!io) {
   4378				dprintk("Blank IO resource\n");
   4379				return AE_OK;
   4380			}
   4381
   4382			if (!ioport->io1.minimum) {
   4383				memcpy(&ioport->io1, io, sizeof(*io));
   4384				dprintk("IO1 at 0x%.4x (0x%.2x)\n", ioport->io1.minimum,
   4385						ioport->io1.address_length);
   4386			}
   4387			else if (!ioport->io2.minimum) {
   4388				memcpy(&ioport->io2, io, sizeof(*io));
   4389				dprintk("IO2 at 0x%.4x (0x%.2x)\n", ioport->io2.minimum,
   4390						ioport->io2.address_length);
   4391			}
   4392			else {
   4393				pr_err("Unknown SPIC Type, more than 2 IO Ports\n");
   4394				return AE_ERROR;
   4395			}
   4396			return AE_OK;
   4397		}
   4398
   4399	case ACPI_RESOURCE_TYPE_END_TAG:
   4400		return AE_OK;
   4401
   4402	default:
   4403		dprintk("Resource %d isn't an IRQ nor an IO port\n",
   4404			resource->type);
   4405		return AE_CTRL_TERMINATE;
   4406
   4407	}
   4408}
   4409
   4410static int sony_pic_possible_resources(struct acpi_device *device)
   4411{
   4412	int result = 0;
   4413	acpi_status status = AE_OK;
   4414
   4415	if (!device)
   4416		return -EINVAL;
   4417
   4418	/* get device status */
   4419	/* see acpi_pci_link_get_current acpi_pci_link_get_possible */
   4420	dprintk("Evaluating _STA\n");
   4421	result = acpi_bus_get_status(device);
   4422	if (result) {
   4423		pr_warn("Unable to read status\n");
   4424		goto end;
   4425	}
   4426
   4427	if (!device->status.enabled)
   4428		dprintk("Device disabled\n");
   4429	else
   4430		dprintk("Device enabled\n");
   4431
   4432	/*
   4433	 * Query and parse 'method'
   4434	 */
   4435	dprintk("Evaluating %s\n", METHOD_NAME__PRS);
   4436	status = acpi_walk_resources(device->handle, METHOD_NAME__PRS,
   4437			sony_pic_read_possible_resource, &spic_dev);
   4438	if (ACPI_FAILURE(status)) {
   4439		pr_warn("Failure evaluating %s\n", METHOD_NAME__PRS);
   4440		result = -ENODEV;
   4441	}
   4442end:
   4443	return result;
   4444}
   4445
   4446/*
   4447 *  Disable the spic device by calling its _DIS method
   4448 */
   4449static int sony_pic_disable(struct acpi_device *device)
   4450{
   4451	acpi_status ret = acpi_evaluate_object(device->handle, "_DIS", NULL,
   4452					       NULL);
   4453
   4454	if (ACPI_FAILURE(ret) && ret != AE_NOT_FOUND)
   4455		return -ENXIO;
   4456
   4457	dprintk("Device disabled\n");
   4458	return 0;
   4459}
   4460
   4461
   4462/*
   4463 *  Based on drivers/acpi/pci_link.c:acpi_pci_link_set
   4464 *
   4465 *  Call _SRS to set current resources
   4466 */
   4467static int sony_pic_enable(struct acpi_device *device,
   4468		struct sony_pic_ioport *ioport, struct sony_pic_irq *irq)
   4469{
   4470	acpi_status status;
   4471	int result = 0;
   4472	/* Type 1 resource layout is:
   4473	 *    IO
   4474	 *    IO
   4475	 *    IRQNoFlags
   4476	 *    End
   4477	 *
   4478	 * Type 2 and 3 resource layout is:
   4479	 *    IO
   4480	 *    IRQNoFlags
   4481	 *    End
   4482	 */
   4483	struct {
   4484		struct acpi_resource res1;
   4485		struct acpi_resource res2;
   4486		struct acpi_resource res3;
   4487		struct acpi_resource res4;
   4488	} *resource;
   4489	struct acpi_buffer buffer = { 0, NULL };
   4490
   4491	if (!ioport || !irq)
   4492		return -EINVAL;
   4493
   4494	/* init acpi_buffer */
   4495	resource = kzalloc(sizeof(*resource) + 1, GFP_KERNEL);
   4496	if (!resource)
   4497		return -ENOMEM;
   4498
   4499	buffer.length = sizeof(*resource) + 1;
   4500	buffer.pointer = resource;
   4501
   4502	/* setup Type 1 resources */
   4503	if (spic_dev.model == SONYPI_DEVICE_TYPE1) {
   4504
   4505		/* setup io resources */
   4506		resource->res1.type = ACPI_RESOURCE_TYPE_IO;
   4507		resource->res1.length = sizeof(struct acpi_resource);
   4508		memcpy(&resource->res1.data.io, &ioport->io1,
   4509				sizeof(struct acpi_resource_io));
   4510
   4511		resource->res2.type = ACPI_RESOURCE_TYPE_IO;
   4512		resource->res2.length = sizeof(struct acpi_resource);
   4513		memcpy(&resource->res2.data.io, &ioport->io2,
   4514				sizeof(struct acpi_resource_io));
   4515
   4516		/* setup irq resource */
   4517		resource->res3.type = ACPI_RESOURCE_TYPE_IRQ;
   4518		resource->res3.length = sizeof(struct acpi_resource);
   4519		memcpy(&resource->res3.data.irq, &irq->irq,
   4520				sizeof(struct acpi_resource_irq));
   4521		/* we requested a shared irq */
   4522		resource->res3.data.irq.shareable = ACPI_SHARED;
   4523
   4524		resource->res4.type = ACPI_RESOURCE_TYPE_END_TAG;
   4525		resource->res4.length = sizeof(struct acpi_resource);
   4526	}
   4527	/* setup Type 2/3 resources */
   4528	else {
   4529		/* setup io resource */
   4530		resource->res1.type = ACPI_RESOURCE_TYPE_IO;
   4531		resource->res1.length = sizeof(struct acpi_resource);
   4532		memcpy(&resource->res1.data.io, &ioport->io1,
   4533				sizeof(struct acpi_resource_io));
   4534
   4535		/* setup irq resource */
   4536		resource->res2.type = ACPI_RESOURCE_TYPE_IRQ;
   4537		resource->res2.length = sizeof(struct acpi_resource);
   4538		memcpy(&resource->res2.data.irq, &irq->irq,
   4539				sizeof(struct acpi_resource_irq));
   4540		/* we requested a shared irq */
   4541		resource->res2.data.irq.shareable = ACPI_SHARED;
   4542
   4543		resource->res3.type = ACPI_RESOURCE_TYPE_END_TAG;
   4544		resource->res3.length = sizeof(struct acpi_resource);
   4545	}
   4546
   4547	/* Attempt to set the resource */
   4548	dprintk("Evaluating _SRS\n");
   4549	status = acpi_set_current_resources(device->handle, &buffer);
   4550
   4551	/* check for total failure */
   4552	if (ACPI_FAILURE(status)) {
   4553		pr_err("Error evaluating _SRS\n");
   4554		result = -ENODEV;
   4555		goto end;
   4556	}
   4557
   4558	/* Necessary device initializations calls (from sonypi) */
   4559	sony_pic_call1(0x82);
   4560	sony_pic_call2(0x81, 0xff);
   4561	sony_pic_call1(compat ? 0x92 : 0x82);
   4562
   4563end:
   4564	kfree(resource);
   4565	return result;
   4566}
   4567
   4568/*****************
   4569 *
   4570 * ISR: some event is available
   4571 *
   4572 *****************/
   4573static irqreturn_t sony_pic_irq(int irq, void *dev_id)
   4574{
   4575	int i, j;
   4576	u8 ev = 0;
   4577	u8 data_mask = 0;
   4578	u8 device_event = 0;
   4579
   4580	struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id;
   4581
   4582	ev = inb_p(dev->cur_ioport->io1.minimum);
   4583	if (dev->cur_ioport->io2.minimum)
   4584		data_mask = inb_p(dev->cur_ioport->io2.minimum);
   4585	else
   4586		data_mask = inb_p(dev->cur_ioport->io1.minimum +
   4587				dev->evport_offset);
   4588
   4589	dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
   4590			ev, data_mask, dev->cur_ioport->io1.minimum,
   4591			dev->evport_offset);
   4592
   4593	if (ev == 0x00 || ev == 0xff)
   4594		return IRQ_HANDLED;
   4595
   4596	for (i = 0; dev->event_types[i].mask; i++) {
   4597
   4598		if ((data_mask & dev->event_types[i].data) !=
   4599		    dev->event_types[i].data)
   4600			continue;
   4601
   4602		if (!(mask & dev->event_types[i].mask))
   4603			continue;
   4604
   4605		for (j = 0; dev->event_types[i].events[j].event; j++) {
   4606			if (ev == dev->event_types[i].events[j].data) {
   4607				device_event =
   4608					dev->event_types[i].events[j].event;
   4609				/* some events may require ignoring */
   4610				if (!device_event)
   4611					return IRQ_HANDLED;
   4612				goto found;
   4613			}
   4614		}
   4615	}
   4616	/* Still not able to decode the event try to pass
   4617	 * it over to the minidriver
   4618	 */
   4619	if (dev->handle_irq && dev->handle_irq(data_mask, ev) == 0)
   4620		return IRQ_HANDLED;
   4621
   4622	dprintk("unknown event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
   4623			ev, data_mask, dev->cur_ioport->io1.minimum,
   4624			dev->evport_offset);
   4625	return IRQ_HANDLED;
   4626
   4627found:
   4628	sony_laptop_report_input_event(device_event);
   4629	sonypi_compat_report_event(device_event);
   4630	return IRQ_HANDLED;
   4631}
   4632
   4633/*****************
   4634 *
   4635 *  ACPI driver
   4636 *
   4637 *****************/
   4638static int sony_pic_remove(struct acpi_device *device)
   4639{
   4640	struct sony_pic_ioport *io, *tmp_io;
   4641	struct sony_pic_irq *irq, *tmp_irq;
   4642
   4643	if (sony_pic_disable(device)) {
   4644		pr_err("Couldn't disable device\n");
   4645		return -ENXIO;
   4646	}
   4647
   4648	free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
   4649	release_region(spic_dev.cur_ioport->io1.minimum,
   4650			spic_dev.cur_ioport->io1.address_length);
   4651	if (spic_dev.cur_ioport->io2.minimum)
   4652		release_region(spic_dev.cur_ioport->io2.minimum,
   4653				spic_dev.cur_ioport->io2.address_length);
   4654
   4655	sonypi_compat_exit();
   4656
   4657	sony_laptop_remove_input();
   4658
   4659	/* pf attrs */
   4660	sysfs_remove_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
   4661	sony_pf_remove();
   4662
   4663	list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
   4664		list_del(&io->list);
   4665		kfree(io);
   4666	}
   4667	list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
   4668		list_del(&irq->list);
   4669		kfree(irq);
   4670	}
   4671	spic_dev.cur_ioport = NULL;
   4672	spic_dev.cur_irq = NULL;
   4673
   4674	dprintk(SONY_PIC_DRIVER_NAME " removed.\n");
   4675	return 0;
   4676}
   4677
   4678static int sony_pic_add(struct acpi_device *device)
   4679{
   4680	int result;
   4681	struct sony_pic_ioport *io, *tmp_io;
   4682	struct sony_pic_irq *irq, *tmp_irq;
   4683
   4684	spic_dev.acpi_dev = device;
   4685	strcpy(acpi_device_class(device), "sony/hotkey");
   4686	sony_pic_detect_device_type(&spic_dev);
   4687	mutex_init(&spic_dev.lock);
   4688
   4689	/* read _PRS resources */
   4690	result = sony_pic_possible_resources(device);
   4691	if (result) {
   4692		pr_err("Unable to read possible resources\n");
   4693		goto err_free_resources;
   4694	}
   4695
   4696	/* setup input devices and helper fifo */
   4697	result = sony_laptop_setup_input(device);
   4698	if (result) {
   4699		pr_err("Unable to create input devices\n");
   4700		goto err_free_resources;
   4701	}
   4702
   4703	result = sonypi_compat_init();
   4704	if (result)
   4705		goto err_remove_input;
   4706
   4707	/* request io port */
   4708	list_for_each_entry_reverse(io, &spic_dev.ioports, list) {
   4709		if (request_region(io->io1.minimum, io->io1.address_length,
   4710					"Sony Programmable I/O Device")) {
   4711			dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n",
   4712					io->io1.minimum, io->io1.maximum,
   4713					io->io1.address_length);
   4714			/* Type 1 have 2 ioports */
   4715			if (io->io2.minimum) {
   4716				if (request_region(io->io2.minimum,
   4717						io->io2.address_length,
   4718						"Sony Programmable I/O Device")) {
   4719					dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n",
   4720							io->io2.minimum, io->io2.maximum,
   4721							io->io2.address_length);
   4722					spic_dev.cur_ioport = io;
   4723					break;
   4724				}
   4725				else {
   4726					dprintk("Unable to get I/O port2: "
   4727							"0x%.4x (0x%.4x) + 0x%.2x\n",
   4728							io->io2.minimum, io->io2.maximum,
   4729							io->io2.address_length);
   4730					release_region(io->io1.minimum,
   4731							io->io1.address_length);
   4732				}
   4733			}
   4734			else {
   4735				spic_dev.cur_ioport = io;
   4736				break;
   4737			}
   4738		}
   4739	}
   4740	if (!spic_dev.cur_ioport) {
   4741		pr_err("Failed to request_region\n");
   4742		result = -ENODEV;
   4743		goto err_remove_compat;
   4744	}
   4745
   4746	/* request IRQ */
   4747	list_for_each_entry_reverse(irq, &spic_dev.interrupts, list) {
   4748		if (!request_irq(irq->irq.interrupts[0], sony_pic_irq,
   4749					0, "sony-laptop", &spic_dev)) {
   4750			dprintk("IRQ: %d - triggering: %d - "
   4751					"polarity: %d - shr: %d\n",
   4752					irq->irq.interrupts[0],
   4753					irq->irq.triggering,
   4754					irq->irq.polarity,
   4755					irq->irq.shareable);
   4756			spic_dev.cur_irq = irq;
   4757			break;
   4758		}
   4759	}
   4760	if (!spic_dev.cur_irq) {
   4761		pr_err("Failed to request_irq\n");
   4762		result = -ENODEV;
   4763		goto err_release_region;
   4764	}
   4765
   4766	/* set resource status _SRS */
   4767	result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
   4768	if (result) {
   4769		pr_err("Couldn't enable device\n");
   4770		goto err_free_irq;
   4771	}
   4772
   4773	spic_dev.bluetooth_power = -1;
   4774	/* create device attributes */
   4775	result = sony_pf_add();
   4776	if (result)
   4777		goto err_disable_device;
   4778
   4779	result = sysfs_create_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
   4780	if (result)
   4781		goto err_remove_pf;
   4782
   4783	pr_info("SPIC setup done.\n");
   4784	return 0;
   4785
   4786err_remove_pf:
   4787	sony_pf_remove();
   4788
   4789err_disable_device:
   4790	sony_pic_disable(device);
   4791
   4792err_free_irq:
   4793	free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
   4794
   4795err_release_region:
   4796	release_region(spic_dev.cur_ioport->io1.minimum,
   4797			spic_dev.cur_ioport->io1.address_length);
   4798	if (spic_dev.cur_ioport->io2.minimum)
   4799		release_region(spic_dev.cur_ioport->io2.minimum,
   4800				spic_dev.cur_ioport->io2.address_length);
   4801
   4802err_remove_compat:
   4803	sonypi_compat_exit();
   4804
   4805err_remove_input:
   4806	sony_laptop_remove_input();
   4807
   4808err_free_resources:
   4809	list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
   4810		list_del(&io->list);
   4811		kfree(io);
   4812	}
   4813	list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
   4814		list_del(&irq->list);
   4815		kfree(irq);
   4816	}
   4817	spic_dev.cur_ioport = NULL;
   4818	spic_dev.cur_irq = NULL;
   4819
   4820	return result;
   4821}
   4822
   4823#ifdef CONFIG_PM_SLEEP
   4824static int sony_pic_suspend(struct device *dev)
   4825{
   4826	if (sony_pic_disable(to_acpi_device(dev)))
   4827		return -ENXIO;
   4828	return 0;
   4829}
   4830
   4831static int sony_pic_resume(struct device *dev)
   4832{
   4833	sony_pic_enable(to_acpi_device(dev),
   4834			spic_dev.cur_ioport, spic_dev.cur_irq);
   4835	return 0;
   4836}
   4837#endif
   4838
   4839static SIMPLE_DEV_PM_OPS(sony_pic_pm, sony_pic_suspend, sony_pic_resume);
   4840
   4841static const struct acpi_device_id sony_pic_device_ids[] = {
   4842	{SONY_PIC_HID, 0},
   4843	{"", 0},
   4844};
   4845
   4846static struct acpi_driver sony_pic_driver = {
   4847	.name = SONY_PIC_DRIVER_NAME,
   4848	.class = SONY_PIC_CLASS,
   4849	.ids = sony_pic_device_ids,
   4850	.owner = THIS_MODULE,
   4851	.ops = {
   4852		.add = sony_pic_add,
   4853		.remove = sony_pic_remove,
   4854		},
   4855	.drv.pm = &sony_pic_pm,
   4856};
   4857
   4858static const struct dmi_system_id sonypi_dmi_table[] __initconst = {
   4859	{
   4860		.ident = "Sony Vaio",
   4861		.matches = {
   4862			DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
   4863			DMI_MATCH(DMI_PRODUCT_NAME, "PCG-"),
   4864		},
   4865	},
   4866	{
   4867		.ident = "Sony Vaio",
   4868		.matches = {
   4869			DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
   4870			DMI_MATCH(DMI_PRODUCT_NAME, "VGN-"),
   4871		},
   4872	},
   4873	{ }
   4874};
   4875
   4876static int __init sony_laptop_init(void)
   4877{
   4878	int result;
   4879
   4880	if (!no_spic && dmi_check_system(sonypi_dmi_table)) {
   4881		result = acpi_bus_register_driver(&sony_pic_driver);
   4882		if (result) {
   4883			pr_err("Unable to register SPIC driver\n");
   4884			goto out;
   4885		}
   4886		spic_drv_registered = 1;
   4887	}
   4888
   4889	result = acpi_bus_register_driver(&sony_nc_driver);
   4890	if (result) {
   4891		pr_err("Unable to register SNC driver\n");
   4892		goto out_unregister_pic;
   4893	}
   4894
   4895	return 0;
   4896
   4897out_unregister_pic:
   4898	if (spic_drv_registered)
   4899		acpi_bus_unregister_driver(&sony_pic_driver);
   4900out:
   4901	return result;
   4902}
   4903
   4904static void __exit sony_laptop_exit(void)
   4905{
   4906	acpi_bus_unregister_driver(&sony_nc_driver);
   4907	if (spic_drv_registered)
   4908		acpi_bus_unregister_driver(&sony_pic_driver);
   4909}
   4910
   4911module_init(sony_laptop_init);
   4912module_exit(sony_laptop_exit);