File Index
Files and directories
Sign in
FILE

sony-laptop.c

File preview with syntax highlighting.

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