18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Sony Programmable I/O Control Device driver for VAIO
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2007 Mattia Dongili <malattia@linux.it>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (C) 2001-2005 Stelian Pop <stelian@popies.net>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Copyright (C) 2005 Narayanan R S <nars@kadamba.org>
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci * Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp>
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras.
228c2ecf20Sopenharmony_ci */
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include <linux/module.h>
258c2ecf20Sopenharmony_ci#include <linux/sched.h>
268c2ecf20Sopenharmony_ci#include <linux/input.h>
278c2ecf20Sopenharmony_ci#include <linux/pci.h>
288c2ecf20Sopenharmony_ci#include <linux/init.h>
298c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
308c2ecf20Sopenharmony_ci#include <linux/miscdevice.h>
318c2ecf20Sopenharmony_ci#include <linux/poll.h>
328c2ecf20Sopenharmony_ci#include <linux/delay.h>
338c2ecf20Sopenharmony_ci#include <linux/wait.h>
348c2ecf20Sopenharmony_ci#include <linux/acpi.h>
358c2ecf20Sopenharmony_ci#include <linux/dmi.h>
368c2ecf20Sopenharmony_ci#include <linux/err.h>
378c2ecf20Sopenharmony_ci#include <linux/kfifo.h>
388c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
398c2ecf20Sopenharmony_ci#include <linux/gfp.h>
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
428c2ecf20Sopenharmony_ci#include <asm/io.h>
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#include <linux/sonypi.h>
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#define SONYPI_DRIVER_VERSION	 "1.26"
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ciMODULE_AUTHOR("Stelian Pop <stelian@popies.net>");
498c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Sony Programmable I/O Control Device driver");
508c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
518c2ecf20Sopenharmony_ciMODULE_VERSION(SONYPI_DRIVER_VERSION);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic int minor = -1;
548c2ecf20Sopenharmony_cimodule_param(minor, int, 0);
558c2ecf20Sopenharmony_ciMODULE_PARM_DESC(minor,
568c2ecf20Sopenharmony_ci		 "minor number of the misc device, default is -1 (automatic)");
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic int verbose;		/* = 0 */
598c2ecf20Sopenharmony_cimodule_param(verbose, int, 0644);
608c2ecf20Sopenharmony_ciMODULE_PARM_DESC(verbose, "be verbose, default is 0 (no)");
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic int fnkeyinit;		/* = 0 */
638c2ecf20Sopenharmony_cimodule_param(fnkeyinit, int, 0444);
648c2ecf20Sopenharmony_ciMODULE_PARM_DESC(fnkeyinit,
658c2ecf20Sopenharmony_ci		 "set this if your Fn keys do not generate any event");
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic int camera;		/* = 0 */
688c2ecf20Sopenharmony_cimodule_param(camera, int, 0444);
698c2ecf20Sopenharmony_ciMODULE_PARM_DESC(camera,
708c2ecf20Sopenharmony_ci		 "set this if you have a MotionEye camera (PictureBook series)");
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic int compat;		/* = 0 */
738c2ecf20Sopenharmony_cimodule_param(compat, int, 0444);
748c2ecf20Sopenharmony_ciMODULE_PARM_DESC(compat,
758c2ecf20Sopenharmony_ci		 "set this if you want to enable backward compatibility mode");
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistatic unsigned long mask = 0xffffffff;
788c2ecf20Sopenharmony_cimodule_param(mask, ulong, 0644);
798c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mask,
808c2ecf20Sopenharmony_ci		 "set this to the mask of event you want to enable (see doc)");
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic int useinput = 1;
838c2ecf20Sopenharmony_cimodule_param(useinput, int, 0444);
848c2ecf20Sopenharmony_ciMODULE_PARM_DESC(useinput,
858c2ecf20Sopenharmony_ci		 "set this if you would like sonypi to feed events to the input subsystem");
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic int check_ioport = 1;
888c2ecf20Sopenharmony_cimodule_param(check_ioport, int, 0444);
898c2ecf20Sopenharmony_ciMODULE_PARM_DESC(check_ioport,
908c2ecf20Sopenharmony_ci		 "set this to 0 if you think the automatic ioport check for sony-laptop is wrong");
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci#define SONYPI_DEVICE_MODEL_TYPE1	1
938c2ecf20Sopenharmony_ci#define SONYPI_DEVICE_MODEL_TYPE2	2
948c2ecf20Sopenharmony_ci#define SONYPI_DEVICE_MODEL_TYPE3	3
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci/* type1 models use those */
978c2ecf20Sopenharmony_ci#define SONYPI_IRQ_PORT			0x8034
988c2ecf20Sopenharmony_ci#define SONYPI_IRQ_SHIFT		22
998c2ecf20Sopenharmony_ci#define SONYPI_TYPE1_BASE		0x50
1008c2ecf20Sopenharmony_ci#define SONYPI_G10A			(SONYPI_TYPE1_BASE+0x14)
1018c2ecf20Sopenharmony_ci#define SONYPI_TYPE1_REGION_SIZE	0x08
1028c2ecf20Sopenharmony_ci#define SONYPI_TYPE1_EVTYPE_OFFSET	0x04
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci/* type2 series specifics */
1058c2ecf20Sopenharmony_ci#define SONYPI_SIRQ			0x9b
1068c2ecf20Sopenharmony_ci#define SONYPI_SLOB			0x9c
1078c2ecf20Sopenharmony_ci#define SONYPI_SHIB			0x9d
1088c2ecf20Sopenharmony_ci#define SONYPI_TYPE2_REGION_SIZE	0x20
1098c2ecf20Sopenharmony_ci#define SONYPI_TYPE2_EVTYPE_OFFSET	0x12
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci/* type3 series specifics */
1128c2ecf20Sopenharmony_ci#define SONYPI_TYPE3_BASE		0x40
1138c2ecf20Sopenharmony_ci#define SONYPI_TYPE3_GID2		(SONYPI_TYPE3_BASE+0x48) /* 16 bits */
1148c2ecf20Sopenharmony_ci#define SONYPI_TYPE3_MISC		(SONYPI_TYPE3_BASE+0x6d) /* 8 bits  */
1158c2ecf20Sopenharmony_ci#define SONYPI_TYPE3_REGION_SIZE	0x20
1168c2ecf20Sopenharmony_ci#define SONYPI_TYPE3_EVTYPE_OFFSET	0x12
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci/* battery / brightness addresses */
1198c2ecf20Sopenharmony_ci#define SONYPI_BAT_FLAGS	0x81
1208c2ecf20Sopenharmony_ci#define SONYPI_LCD_LIGHT	0x96
1218c2ecf20Sopenharmony_ci#define SONYPI_BAT1_PCTRM	0xa0
1228c2ecf20Sopenharmony_ci#define SONYPI_BAT1_LEFT	0xa2
1238c2ecf20Sopenharmony_ci#define SONYPI_BAT1_MAXRT	0xa4
1248c2ecf20Sopenharmony_ci#define SONYPI_BAT2_PCTRM	0xa8
1258c2ecf20Sopenharmony_ci#define SONYPI_BAT2_LEFT	0xaa
1268c2ecf20Sopenharmony_ci#define SONYPI_BAT2_MAXRT	0xac
1278c2ecf20Sopenharmony_ci#define SONYPI_BAT1_MAXTK	0xb0
1288c2ecf20Sopenharmony_ci#define SONYPI_BAT1_FULL	0xb2
1298c2ecf20Sopenharmony_ci#define SONYPI_BAT2_MAXTK	0xb8
1308c2ecf20Sopenharmony_ci#define SONYPI_BAT2_FULL	0xba
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci/* FAN0 information (reverse engineered from ACPI tables) */
1338c2ecf20Sopenharmony_ci#define SONYPI_FAN0_STATUS	0x93
1348c2ecf20Sopenharmony_ci#define SONYPI_TEMP_STATUS	0xC1
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci/* ioports used for brightness and type2 events */
1378c2ecf20Sopenharmony_ci#define SONYPI_DATA_IOPORT	0x62
1388c2ecf20Sopenharmony_ci#define SONYPI_CST_IOPORT	0x66
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci/* The set of possible ioports */
1418c2ecf20Sopenharmony_cistruct sonypi_ioport_list {
1428c2ecf20Sopenharmony_ci	u16	port1;
1438c2ecf20Sopenharmony_ci	u16	port2;
1448c2ecf20Sopenharmony_ci};
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_cistatic struct sonypi_ioport_list sonypi_type1_ioport_list[] = {
1478c2ecf20Sopenharmony_ci	{ 0x10c0, 0x10c4 },	/* looks like the default on C1Vx */
1488c2ecf20Sopenharmony_ci	{ 0x1080, 0x1084 },
1498c2ecf20Sopenharmony_ci	{ 0x1090, 0x1094 },
1508c2ecf20Sopenharmony_ci	{ 0x10a0, 0x10a4 },
1518c2ecf20Sopenharmony_ci	{ 0x10b0, 0x10b4 },
1528c2ecf20Sopenharmony_ci	{ 0x0, 0x0 }
1538c2ecf20Sopenharmony_ci};
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cistatic struct sonypi_ioport_list sonypi_type2_ioport_list[] = {
1568c2ecf20Sopenharmony_ci	{ 0x1080, 0x1084 },
1578c2ecf20Sopenharmony_ci	{ 0x10a0, 0x10a4 },
1588c2ecf20Sopenharmony_ci	{ 0x10c0, 0x10c4 },
1598c2ecf20Sopenharmony_ci	{ 0x10e0, 0x10e4 },
1608c2ecf20Sopenharmony_ci	{ 0x0, 0x0 }
1618c2ecf20Sopenharmony_ci};
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci/* same as in type 2 models */
1648c2ecf20Sopenharmony_cistatic struct sonypi_ioport_list *sonypi_type3_ioport_list =
1658c2ecf20Sopenharmony_ci	sonypi_type2_ioport_list;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci/* The set of possible interrupts */
1688c2ecf20Sopenharmony_cistruct sonypi_irq_list {
1698c2ecf20Sopenharmony_ci	u16	irq;
1708c2ecf20Sopenharmony_ci	u16	bits;
1718c2ecf20Sopenharmony_ci};
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic struct sonypi_irq_list sonypi_type1_irq_list[] = {
1748c2ecf20Sopenharmony_ci	{ 11, 0x2 },	/* IRQ 11, GO22=0,GO23=1 in AML */
1758c2ecf20Sopenharmony_ci	{ 10, 0x1 },	/* IRQ 10, GO22=1,GO23=0 in AML */
1768c2ecf20Sopenharmony_ci	{  5, 0x0 },	/* IRQ  5, GO22=0,GO23=0 in AML */
1778c2ecf20Sopenharmony_ci	{  0, 0x3 }	/* no IRQ, GO22=1,GO23=1 in AML */
1788c2ecf20Sopenharmony_ci};
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_cistatic struct sonypi_irq_list sonypi_type2_irq_list[] = {
1818c2ecf20Sopenharmony_ci	{ 11, 0x80 },	/* IRQ 11, 0x80 in SIRQ in AML */
1828c2ecf20Sopenharmony_ci	{ 10, 0x40 },	/* IRQ 10, 0x40 in SIRQ in AML */
1838c2ecf20Sopenharmony_ci	{  9, 0x20 },	/* IRQ  9, 0x20 in SIRQ in AML */
1848c2ecf20Sopenharmony_ci	{  6, 0x10 },	/* IRQ  6, 0x10 in SIRQ in AML */
1858c2ecf20Sopenharmony_ci	{  0, 0x00 }	/* no IRQ, 0x00 in SIRQ in AML */
1868c2ecf20Sopenharmony_ci};
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci/* same as in type2 models */
1898c2ecf20Sopenharmony_cistatic struct sonypi_irq_list *sonypi_type3_irq_list = sonypi_type2_irq_list;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci#define SONYPI_CAMERA_BRIGHTNESS		0
1928c2ecf20Sopenharmony_ci#define SONYPI_CAMERA_CONTRAST			1
1938c2ecf20Sopenharmony_ci#define SONYPI_CAMERA_HUE			2
1948c2ecf20Sopenharmony_ci#define SONYPI_CAMERA_COLOR			3
1958c2ecf20Sopenharmony_ci#define SONYPI_CAMERA_SHARPNESS			4
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci#define SONYPI_CAMERA_PICTURE			5
1988c2ecf20Sopenharmony_ci#define SONYPI_CAMERA_EXPOSURE_MASK		0xC
1998c2ecf20Sopenharmony_ci#define SONYPI_CAMERA_WHITE_BALANCE_MASK	0x3
2008c2ecf20Sopenharmony_ci#define SONYPI_CAMERA_PICTURE_MODE_MASK		0x30
2018c2ecf20Sopenharmony_ci#define SONYPI_CAMERA_MUTE_MASK			0x40
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci/* the rest don't need a loop until not 0xff */
2048c2ecf20Sopenharmony_ci#define SONYPI_CAMERA_AGC			6
2058c2ecf20Sopenharmony_ci#define SONYPI_CAMERA_AGC_MASK			0x30
2068c2ecf20Sopenharmony_ci#define SONYPI_CAMERA_SHUTTER_MASK 		0x7
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci#define SONYPI_CAMERA_SHUTDOWN_REQUEST		7
2098c2ecf20Sopenharmony_ci#define SONYPI_CAMERA_CONTROL			0x10
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci#define SONYPI_CAMERA_STATUS 			7
2128c2ecf20Sopenharmony_ci#define SONYPI_CAMERA_STATUS_READY 		0x2
2138c2ecf20Sopenharmony_ci#define SONYPI_CAMERA_STATUS_POSITION		0x4
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci#define SONYPI_DIRECTION_BACKWARDS 		0x4
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci#define SONYPI_CAMERA_REVISION 			8
2188c2ecf20Sopenharmony_ci#define SONYPI_CAMERA_ROMVERSION 		9
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci/* Event masks */
2218c2ecf20Sopenharmony_ci#define SONYPI_JOGGER_MASK			0x00000001
2228c2ecf20Sopenharmony_ci#define SONYPI_CAPTURE_MASK			0x00000002
2238c2ecf20Sopenharmony_ci#define SONYPI_FNKEY_MASK			0x00000004
2248c2ecf20Sopenharmony_ci#define SONYPI_BLUETOOTH_MASK			0x00000008
2258c2ecf20Sopenharmony_ci#define SONYPI_PKEY_MASK			0x00000010
2268c2ecf20Sopenharmony_ci#define SONYPI_BACK_MASK			0x00000020
2278c2ecf20Sopenharmony_ci#define SONYPI_HELP_MASK			0x00000040
2288c2ecf20Sopenharmony_ci#define SONYPI_LID_MASK				0x00000080
2298c2ecf20Sopenharmony_ci#define SONYPI_ZOOM_MASK			0x00000100
2308c2ecf20Sopenharmony_ci#define SONYPI_THUMBPHRASE_MASK			0x00000200
2318c2ecf20Sopenharmony_ci#define SONYPI_MEYE_MASK			0x00000400
2328c2ecf20Sopenharmony_ci#define SONYPI_MEMORYSTICK_MASK			0x00000800
2338c2ecf20Sopenharmony_ci#define SONYPI_BATTERY_MASK			0x00001000
2348c2ecf20Sopenharmony_ci#define SONYPI_WIRELESS_MASK			0x00002000
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cistruct sonypi_event {
2378c2ecf20Sopenharmony_ci	u8	data;
2388c2ecf20Sopenharmony_ci	u8	event;
2398c2ecf20Sopenharmony_ci};
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci/* The set of possible button release events */
2428c2ecf20Sopenharmony_cistatic struct sonypi_event sonypi_releaseev[] = {
2438c2ecf20Sopenharmony_ci	{ 0x00, SONYPI_EVENT_ANYBUTTON_RELEASED },
2448c2ecf20Sopenharmony_ci	{ 0, 0 }
2458c2ecf20Sopenharmony_ci};
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci/* The set of possible jogger events  */
2488c2ecf20Sopenharmony_cistatic struct sonypi_event sonypi_joggerev[] = {
2498c2ecf20Sopenharmony_ci	{ 0x1f, SONYPI_EVENT_JOGDIAL_UP },
2508c2ecf20Sopenharmony_ci	{ 0x01, SONYPI_EVENT_JOGDIAL_DOWN },
2518c2ecf20Sopenharmony_ci	{ 0x5f, SONYPI_EVENT_JOGDIAL_UP_PRESSED },
2528c2ecf20Sopenharmony_ci	{ 0x41, SONYPI_EVENT_JOGDIAL_DOWN_PRESSED },
2538c2ecf20Sopenharmony_ci	{ 0x1e, SONYPI_EVENT_JOGDIAL_FAST_UP },
2548c2ecf20Sopenharmony_ci	{ 0x02, SONYPI_EVENT_JOGDIAL_FAST_DOWN },
2558c2ecf20Sopenharmony_ci	{ 0x5e, SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED },
2568c2ecf20Sopenharmony_ci	{ 0x42, SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED },
2578c2ecf20Sopenharmony_ci	{ 0x1d, SONYPI_EVENT_JOGDIAL_VFAST_UP },
2588c2ecf20Sopenharmony_ci	{ 0x03, SONYPI_EVENT_JOGDIAL_VFAST_DOWN },
2598c2ecf20Sopenharmony_ci	{ 0x5d, SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED },
2608c2ecf20Sopenharmony_ci	{ 0x43, SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED },
2618c2ecf20Sopenharmony_ci	{ 0x40, SONYPI_EVENT_JOGDIAL_PRESSED },
2628c2ecf20Sopenharmony_ci	{ 0, 0 }
2638c2ecf20Sopenharmony_ci};
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci/* The set of possible capture button events */
2668c2ecf20Sopenharmony_cistatic struct sonypi_event sonypi_captureev[] = {
2678c2ecf20Sopenharmony_ci	{ 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED },
2688c2ecf20Sopenharmony_ci	{ 0x07, SONYPI_EVENT_CAPTURE_PRESSED },
2698c2ecf20Sopenharmony_ci	{ 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED },
2708c2ecf20Sopenharmony_ci	{ 0, 0 }
2718c2ecf20Sopenharmony_ci};
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci/* The set of possible fnkeys events */
2748c2ecf20Sopenharmony_cistatic struct sonypi_event sonypi_fnkeyev[] = {
2758c2ecf20Sopenharmony_ci	{ 0x10, SONYPI_EVENT_FNKEY_ESC },
2768c2ecf20Sopenharmony_ci	{ 0x11, SONYPI_EVENT_FNKEY_F1 },
2778c2ecf20Sopenharmony_ci	{ 0x12, SONYPI_EVENT_FNKEY_F2 },
2788c2ecf20Sopenharmony_ci	{ 0x13, SONYPI_EVENT_FNKEY_F3 },
2798c2ecf20Sopenharmony_ci	{ 0x14, SONYPI_EVENT_FNKEY_F4 },
2808c2ecf20Sopenharmony_ci	{ 0x15, SONYPI_EVENT_FNKEY_F5 },
2818c2ecf20Sopenharmony_ci	{ 0x16, SONYPI_EVENT_FNKEY_F6 },
2828c2ecf20Sopenharmony_ci	{ 0x17, SONYPI_EVENT_FNKEY_F7 },
2838c2ecf20Sopenharmony_ci	{ 0x18, SONYPI_EVENT_FNKEY_F8 },
2848c2ecf20Sopenharmony_ci	{ 0x19, SONYPI_EVENT_FNKEY_F9 },
2858c2ecf20Sopenharmony_ci	{ 0x1a, SONYPI_EVENT_FNKEY_F10 },
2868c2ecf20Sopenharmony_ci	{ 0x1b, SONYPI_EVENT_FNKEY_F11 },
2878c2ecf20Sopenharmony_ci	{ 0x1c, SONYPI_EVENT_FNKEY_F12 },
2888c2ecf20Sopenharmony_ci	{ 0x1f, SONYPI_EVENT_FNKEY_RELEASED },
2898c2ecf20Sopenharmony_ci	{ 0x21, SONYPI_EVENT_FNKEY_1 },
2908c2ecf20Sopenharmony_ci	{ 0x22, SONYPI_EVENT_FNKEY_2 },
2918c2ecf20Sopenharmony_ci	{ 0x31, SONYPI_EVENT_FNKEY_D },
2928c2ecf20Sopenharmony_ci	{ 0x32, SONYPI_EVENT_FNKEY_E },
2938c2ecf20Sopenharmony_ci	{ 0x33, SONYPI_EVENT_FNKEY_F },
2948c2ecf20Sopenharmony_ci	{ 0x34, SONYPI_EVENT_FNKEY_S },
2958c2ecf20Sopenharmony_ci	{ 0x35, SONYPI_EVENT_FNKEY_B },
2968c2ecf20Sopenharmony_ci	{ 0x36, SONYPI_EVENT_FNKEY_ONLY },
2978c2ecf20Sopenharmony_ci	{ 0, 0 }
2988c2ecf20Sopenharmony_ci};
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci/* The set of possible program key events */
3018c2ecf20Sopenharmony_cistatic struct sonypi_event sonypi_pkeyev[] = {
3028c2ecf20Sopenharmony_ci	{ 0x01, SONYPI_EVENT_PKEY_P1 },
3038c2ecf20Sopenharmony_ci	{ 0x02, SONYPI_EVENT_PKEY_P2 },
3048c2ecf20Sopenharmony_ci	{ 0x04, SONYPI_EVENT_PKEY_P3 },
3058c2ecf20Sopenharmony_ci	{ 0x5c, SONYPI_EVENT_PKEY_P1 },
3068c2ecf20Sopenharmony_ci	{ 0, 0 }
3078c2ecf20Sopenharmony_ci};
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci/* The set of possible bluetooth events */
3108c2ecf20Sopenharmony_cistatic struct sonypi_event sonypi_blueev[] = {
3118c2ecf20Sopenharmony_ci	{ 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED },
3128c2ecf20Sopenharmony_ci	{ 0x59, SONYPI_EVENT_BLUETOOTH_ON },
3138c2ecf20Sopenharmony_ci	{ 0x5a, SONYPI_EVENT_BLUETOOTH_OFF },
3148c2ecf20Sopenharmony_ci	{ 0, 0 }
3158c2ecf20Sopenharmony_ci};
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci/* The set of possible wireless events */
3188c2ecf20Sopenharmony_cistatic struct sonypi_event sonypi_wlessev[] = {
3198c2ecf20Sopenharmony_ci	{ 0x59, SONYPI_EVENT_WIRELESS_ON },
3208c2ecf20Sopenharmony_ci	{ 0x5a, SONYPI_EVENT_WIRELESS_OFF },
3218c2ecf20Sopenharmony_ci	{ 0, 0 }
3228c2ecf20Sopenharmony_ci};
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci/* The set of possible back button events */
3258c2ecf20Sopenharmony_cistatic struct sonypi_event sonypi_backev[] = {
3268c2ecf20Sopenharmony_ci	{ 0x20, SONYPI_EVENT_BACK_PRESSED },
3278c2ecf20Sopenharmony_ci	{ 0, 0 }
3288c2ecf20Sopenharmony_ci};
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci/* The set of possible help button events */
3318c2ecf20Sopenharmony_cistatic struct sonypi_event sonypi_helpev[] = {
3328c2ecf20Sopenharmony_ci	{ 0x3b, SONYPI_EVENT_HELP_PRESSED },
3338c2ecf20Sopenharmony_ci	{ 0, 0 }
3348c2ecf20Sopenharmony_ci};
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci/* The set of possible lid events */
3388c2ecf20Sopenharmony_cistatic struct sonypi_event sonypi_lidev[] = {
3398c2ecf20Sopenharmony_ci	{ 0x51, SONYPI_EVENT_LID_CLOSED },
3408c2ecf20Sopenharmony_ci	{ 0x50, SONYPI_EVENT_LID_OPENED },
3418c2ecf20Sopenharmony_ci	{ 0, 0 }
3428c2ecf20Sopenharmony_ci};
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci/* The set of possible zoom events */
3458c2ecf20Sopenharmony_cistatic struct sonypi_event sonypi_zoomev[] = {
3468c2ecf20Sopenharmony_ci	{ 0x39, SONYPI_EVENT_ZOOM_PRESSED },
3478c2ecf20Sopenharmony_ci	{ 0, 0 }
3488c2ecf20Sopenharmony_ci};
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci/* The set of possible thumbphrase events */
3518c2ecf20Sopenharmony_cistatic struct sonypi_event sonypi_thumbphraseev[] = {
3528c2ecf20Sopenharmony_ci	{ 0x3a, SONYPI_EVENT_THUMBPHRASE_PRESSED },
3538c2ecf20Sopenharmony_ci	{ 0, 0 }
3548c2ecf20Sopenharmony_ci};
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci/* The set of possible motioneye camera events */
3578c2ecf20Sopenharmony_cistatic struct sonypi_event sonypi_meyeev[] = {
3588c2ecf20Sopenharmony_ci	{ 0x00, SONYPI_EVENT_MEYE_FACE },
3598c2ecf20Sopenharmony_ci	{ 0x01, SONYPI_EVENT_MEYE_OPPOSITE },
3608c2ecf20Sopenharmony_ci	{ 0, 0 }
3618c2ecf20Sopenharmony_ci};
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci/* The set of possible memorystick events */
3648c2ecf20Sopenharmony_cistatic struct sonypi_event sonypi_memorystickev[] = {
3658c2ecf20Sopenharmony_ci	{ 0x53, SONYPI_EVENT_MEMORYSTICK_INSERT },
3668c2ecf20Sopenharmony_ci	{ 0x54, SONYPI_EVENT_MEMORYSTICK_EJECT },
3678c2ecf20Sopenharmony_ci	{ 0, 0 }
3688c2ecf20Sopenharmony_ci};
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci/* The set of possible battery events */
3718c2ecf20Sopenharmony_cistatic struct sonypi_event sonypi_batteryev[] = {
3728c2ecf20Sopenharmony_ci	{ 0x20, SONYPI_EVENT_BATTERY_INSERT },
3738c2ecf20Sopenharmony_ci	{ 0x30, SONYPI_EVENT_BATTERY_REMOVE },
3748c2ecf20Sopenharmony_ci	{ 0, 0 }
3758c2ecf20Sopenharmony_ci};
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_cistatic struct sonypi_eventtypes {
3788c2ecf20Sopenharmony_ci	int			model;
3798c2ecf20Sopenharmony_ci	u8			data;
3808c2ecf20Sopenharmony_ci	unsigned long		mask;
3818c2ecf20Sopenharmony_ci	struct sonypi_event *	events;
3828c2ecf20Sopenharmony_ci} sonypi_eventtypes[] = {
3838c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE1, 0, 0xffffffff, sonypi_releaseev },
3848c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE1, 0x70, SONYPI_MEYE_MASK, sonypi_meyeev },
3858c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE1, 0x30, SONYPI_LID_MASK, sonypi_lidev },
3868c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE1, 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev },
3878c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE1, 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev },
3888c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE1, 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
3898c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE1, 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
3908c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE1, 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
3918c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE1, 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
3928c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE1, 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev },
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE2, 0, 0xffffffff, sonypi_releaseev },
3958c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE2, 0x38, SONYPI_LID_MASK, sonypi_lidev },
3968c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE2, 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev },
3978c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE2, 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev },
3988c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
3998c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
4008c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
4018c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE2, 0x11, SONYPI_BACK_MASK, sonypi_backev },
4028c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_HELP_MASK, sonypi_helpev },
4038c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev },
4048c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE2, 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
4058c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
4068c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE2, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
4078c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE3, 0, 0xffffffff, sonypi_releaseev },
4108c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE3, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
4118c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
4128c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
4138c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE3, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
4148c2ecf20Sopenharmony_ci	{ SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
4158c2ecf20Sopenharmony_ci	{ 0 }
4168c2ecf20Sopenharmony_ci};
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci#define SONYPI_BUF_SIZE	128
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci/* Correspondance table between sonypi events and input layer events */
4218c2ecf20Sopenharmony_cistatic struct {
4228c2ecf20Sopenharmony_ci	int sonypiev;
4238c2ecf20Sopenharmony_ci	int inputev;
4248c2ecf20Sopenharmony_ci} sonypi_inputkeys[] = {
4258c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_CAPTURE_PRESSED,	 	KEY_CAMERA },
4268c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_FNKEY_ONLY, 		KEY_FN },
4278c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_FNKEY_ESC, 		KEY_FN_ESC },
4288c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_FNKEY_F1, 		KEY_FN_F1 },
4298c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_FNKEY_F2, 		KEY_FN_F2 },
4308c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_FNKEY_F3, 		KEY_FN_F3 },
4318c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_FNKEY_F4, 		KEY_FN_F4 },
4328c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_FNKEY_F5, 		KEY_FN_F5 },
4338c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_FNKEY_F6, 		KEY_FN_F6 },
4348c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_FNKEY_F7, 		KEY_FN_F7 },
4358c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_FNKEY_F8, 		KEY_FN_F8 },
4368c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_FNKEY_F9,		KEY_FN_F9 },
4378c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_FNKEY_F10,		KEY_FN_F10 },
4388c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_FNKEY_F11, 		KEY_FN_F11 },
4398c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_FNKEY_F12,		KEY_FN_F12 },
4408c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_FNKEY_1, 		KEY_FN_1 },
4418c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_FNKEY_2, 		KEY_FN_2 },
4428c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_FNKEY_D,			KEY_FN_D },
4438c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_FNKEY_E,			KEY_FN_E },
4448c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_FNKEY_F,			KEY_FN_F },
4458c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_FNKEY_S,			KEY_FN_S },
4468c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_FNKEY_B,			KEY_FN_B },
4478c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_BLUETOOTH_PRESSED, 	KEY_BLUE },
4488c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_BLUETOOTH_ON, 		KEY_BLUE },
4498c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_PKEY_P1, 		KEY_PROG1 },
4508c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_PKEY_P2, 		KEY_PROG2 },
4518c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_PKEY_P3, 		KEY_PROG3 },
4528c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_BACK_PRESSED, 		KEY_BACK },
4538c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_HELP_PRESSED, 		KEY_HELP },
4548c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_ZOOM_PRESSED, 		KEY_ZOOM },
4558c2ecf20Sopenharmony_ci	{ SONYPI_EVENT_THUMBPHRASE_PRESSED, 	BTN_THUMB },
4568c2ecf20Sopenharmony_ci	{ 0, 0 },
4578c2ecf20Sopenharmony_ci};
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_cistruct sonypi_keypress {
4608c2ecf20Sopenharmony_ci	struct input_dev *dev;
4618c2ecf20Sopenharmony_ci	int key;
4628c2ecf20Sopenharmony_ci};
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_cistatic struct sonypi_device {
4658c2ecf20Sopenharmony_ci	struct pci_dev *dev;
4668c2ecf20Sopenharmony_ci	u16 irq;
4678c2ecf20Sopenharmony_ci	u16 bits;
4688c2ecf20Sopenharmony_ci	u16 ioport1;
4698c2ecf20Sopenharmony_ci	u16 ioport2;
4708c2ecf20Sopenharmony_ci	u16 region_size;
4718c2ecf20Sopenharmony_ci	u16 evtype_offset;
4728c2ecf20Sopenharmony_ci	int camera_power;
4738c2ecf20Sopenharmony_ci	int bluetooth_power;
4748c2ecf20Sopenharmony_ci	struct mutex lock;
4758c2ecf20Sopenharmony_ci	struct kfifo fifo;
4768c2ecf20Sopenharmony_ci	spinlock_t fifo_lock;
4778c2ecf20Sopenharmony_ci	wait_queue_head_t fifo_proc_list;
4788c2ecf20Sopenharmony_ci	struct fasync_struct *fifo_async;
4798c2ecf20Sopenharmony_ci	int open_count;
4808c2ecf20Sopenharmony_ci	int model;
4818c2ecf20Sopenharmony_ci	struct input_dev *input_jog_dev;
4828c2ecf20Sopenharmony_ci	struct input_dev *input_key_dev;
4838c2ecf20Sopenharmony_ci	struct work_struct input_work;
4848c2ecf20Sopenharmony_ci	struct kfifo input_fifo;
4858c2ecf20Sopenharmony_ci	spinlock_t input_fifo_lock;
4868c2ecf20Sopenharmony_ci} sonypi_device;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci#define ITERATIONS_LONG		10000
4898c2ecf20Sopenharmony_ci#define ITERATIONS_SHORT	10
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci#define wait_on_command(quiet, command, iterations) { \
4928c2ecf20Sopenharmony_ci	unsigned int n = iterations; \
4938c2ecf20Sopenharmony_ci	while (--n && (command)) \
4948c2ecf20Sopenharmony_ci		udelay(1); \
4958c2ecf20Sopenharmony_ci	if (!n && (verbose || !quiet)) \
4968c2ecf20Sopenharmony_ci		printk(KERN_WARNING "sonypi command failed at %s : %s (line %d)\n", __FILE__, __func__, __LINE__); \
4978c2ecf20Sopenharmony_ci}
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI
5008c2ecf20Sopenharmony_ci#define SONYPI_ACPI_ACTIVE (!acpi_disabled)
5018c2ecf20Sopenharmony_ci#else
5028c2ecf20Sopenharmony_ci#define SONYPI_ACPI_ACTIVE 0
5038c2ecf20Sopenharmony_ci#endif				/* CONFIG_ACPI */
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI
5068c2ecf20Sopenharmony_cistatic struct acpi_device *sonypi_acpi_device;
5078c2ecf20Sopenharmony_cistatic int acpi_driver_registered;
5088c2ecf20Sopenharmony_ci#endif
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_cistatic int sonypi_ec_write(u8 addr, u8 value)
5118c2ecf20Sopenharmony_ci{
5128c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI
5138c2ecf20Sopenharmony_ci	if (SONYPI_ACPI_ACTIVE)
5148c2ecf20Sopenharmony_ci		return ec_write(addr, value);
5158c2ecf20Sopenharmony_ci#endif
5168c2ecf20Sopenharmony_ci	wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3, ITERATIONS_LONG);
5178c2ecf20Sopenharmony_ci	outb_p(0x81, SONYPI_CST_IOPORT);
5188c2ecf20Sopenharmony_ci	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
5198c2ecf20Sopenharmony_ci	outb_p(addr, SONYPI_DATA_IOPORT);
5208c2ecf20Sopenharmony_ci	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
5218c2ecf20Sopenharmony_ci	outb_p(value, SONYPI_DATA_IOPORT);
5228c2ecf20Sopenharmony_ci	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
5238c2ecf20Sopenharmony_ci	return 0;
5248c2ecf20Sopenharmony_ci}
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_cistatic int sonypi_ec_read(u8 addr, u8 *value)
5278c2ecf20Sopenharmony_ci{
5288c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI
5298c2ecf20Sopenharmony_ci	if (SONYPI_ACPI_ACTIVE)
5308c2ecf20Sopenharmony_ci		return ec_read(addr, value);
5318c2ecf20Sopenharmony_ci#endif
5328c2ecf20Sopenharmony_ci	wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3, ITERATIONS_LONG);
5338c2ecf20Sopenharmony_ci	outb_p(0x80, SONYPI_CST_IOPORT);
5348c2ecf20Sopenharmony_ci	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
5358c2ecf20Sopenharmony_ci	outb_p(addr, SONYPI_DATA_IOPORT);
5368c2ecf20Sopenharmony_ci	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
5378c2ecf20Sopenharmony_ci	*value = inb_p(SONYPI_DATA_IOPORT);
5388c2ecf20Sopenharmony_ci	return 0;
5398c2ecf20Sopenharmony_ci}
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_cistatic int ec_read16(u8 addr, u16 *value)
5428c2ecf20Sopenharmony_ci{
5438c2ecf20Sopenharmony_ci	u8 val_lb, val_hb;
5448c2ecf20Sopenharmony_ci	if (sonypi_ec_read(addr, &val_lb))
5458c2ecf20Sopenharmony_ci		return -1;
5468c2ecf20Sopenharmony_ci	if (sonypi_ec_read(addr + 1, &val_hb))
5478c2ecf20Sopenharmony_ci		return -1;
5488c2ecf20Sopenharmony_ci	*value = val_lb | (val_hb << 8);
5498c2ecf20Sopenharmony_ci	return 0;
5508c2ecf20Sopenharmony_ci}
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci/* Initializes the device - this comes from the AML code in the ACPI bios */
5538c2ecf20Sopenharmony_cistatic void sonypi_type1_srs(void)
5548c2ecf20Sopenharmony_ci{
5558c2ecf20Sopenharmony_ci	u32 v;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
5588c2ecf20Sopenharmony_ci	v = (v & 0xFFFF0000) | ((u32) sonypi_device.ioport1);
5598c2ecf20Sopenharmony_ci	pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
5628c2ecf20Sopenharmony_ci	v = (v & 0xFFF0FFFF) |
5638c2ecf20Sopenharmony_ci	    (((u32) sonypi_device.ioport1 ^ sonypi_device.ioport2) << 16);
5648c2ecf20Sopenharmony_ci	pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	v = inl(SONYPI_IRQ_PORT);
5678c2ecf20Sopenharmony_ci	v &= ~(((u32) 0x3) << SONYPI_IRQ_SHIFT);
5688c2ecf20Sopenharmony_ci	v |= (((u32) sonypi_device.bits) << SONYPI_IRQ_SHIFT);
5698c2ecf20Sopenharmony_ci	outl(v, SONYPI_IRQ_PORT);
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
5728c2ecf20Sopenharmony_ci	v = (v & 0xFF1FFFFF) | 0x00C00000;
5738c2ecf20Sopenharmony_ci	pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
5748c2ecf20Sopenharmony_ci}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_cistatic void sonypi_type2_srs(void)
5778c2ecf20Sopenharmony_ci{
5788c2ecf20Sopenharmony_ci	if (sonypi_ec_write(SONYPI_SHIB, (sonypi_device.ioport1 & 0xFF00) >> 8))
5798c2ecf20Sopenharmony_ci		printk(KERN_WARNING "ec_write failed\n");
5808c2ecf20Sopenharmony_ci	if (sonypi_ec_write(SONYPI_SLOB, sonypi_device.ioport1 & 0x00FF))
5818c2ecf20Sopenharmony_ci		printk(KERN_WARNING "ec_write failed\n");
5828c2ecf20Sopenharmony_ci	if (sonypi_ec_write(SONYPI_SIRQ, sonypi_device.bits))
5838c2ecf20Sopenharmony_ci		printk(KERN_WARNING "ec_write failed\n");
5848c2ecf20Sopenharmony_ci	udelay(10);
5858c2ecf20Sopenharmony_ci}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_cistatic void sonypi_type3_srs(void)
5888c2ecf20Sopenharmony_ci{
5898c2ecf20Sopenharmony_ci	u16 v16;
5908c2ecf20Sopenharmony_ci	u8  v8;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	/* This model type uses the same initialization of
5938c2ecf20Sopenharmony_ci	 * the embedded controller as the type2 models. */
5948c2ecf20Sopenharmony_ci	sonypi_type2_srs();
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	/* Initialization of PCI config space of the LPC interface bridge. */
5978c2ecf20Sopenharmony_ci	v16 = (sonypi_device.ioport1 & 0xFFF0) | 0x01;
5988c2ecf20Sopenharmony_ci	pci_write_config_word(sonypi_device.dev, SONYPI_TYPE3_GID2, v16);
5998c2ecf20Sopenharmony_ci	pci_read_config_byte(sonypi_device.dev, SONYPI_TYPE3_MISC, &v8);
6008c2ecf20Sopenharmony_ci	v8 = (v8 & 0xCF) | 0x10;
6018c2ecf20Sopenharmony_ci	pci_write_config_byte(sonypi_device.dev, SONYPI_TYPE3_MISC, v8);
6028c2ecf20Sopenharmony_ci}
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci/* Disables the device - this comes from the AML code in the ACPI bios */
6058c2ecf20Sopenharmony_cistatic void sonypi_type1_dis(void)
6068c2ecf20Sopenharmony_ci{
6078c2ecf20Sopenharmony_ci	u32 v;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
6108c2ecf20Sopenharmony_ci	v = v & 0xFF3FFFFF;
6118c2ecf20Sopenharmony_ci	pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	v = inl(SONYPI_IRQ_PORT);
6148c2ecf20Sopenharmony_ci	v |= (0x3 << SONYPI_IRQ_SHIFT);
6158c2ecf20Sopenharmony_ci	outl(v, SONYPI_IRQ_PORT);
6168c2ecf20Sopenharmony_ci}
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_cistatic void sonypi_type2_dis(void)
6198c2ecf20Sopenharmony_ci{
6208c2ecf20Sopenharmony_ci	if (sonypi_ec_write(SONYPI_SHIB, 0))
6218c2ecf20Sopenharmony_ci		printk(KERN_WARNING "ec_write failed\n");
6228c2ecf20Sopenharmony_ci	if (sonypi_ec_write(SONYPI_SLOB, 0))
6238c2ecf20Sopenharmony_ci		printk(KERN_WARNING "ec_write failed\n");
6248c2ecf20Sopenharmony_ci	if (sonypi_ec_write(SONYPI_SIRQ, 0))
6258c2ecf20Sopenharmony_ci		printk(KERN_WARNING "ec_write failed\n");
6268c2ecf20Sopenharmony_ci}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_cistatic void sonypi_type3_dis(void)
6298c2ecf20Sopenharmony_ci{
6308c2ecf20Sopenharmony_ci	sonypi_type2_dis();
6318c2ecf20Sopenharmony_ci	udelay(10);
6328c2ecf20Sopenharmony_ci	pci_write_config_word(sonypi_device.dev, SONYPI_TYPE3_GID2, 0);
6338c2ecf20Sopenharmony_ci}
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_cistatic u8 sonypi_call1(u8 dev)
6368c2ecf20Sopenharmony_ci{
6378c2ecf20Sopenharmony_ci	u8 v1, v2;
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
6408c2ecf20Sopenharmony_ci	outb(dev, sonypi_device.ioport2);
6418c2ecf20Sopenharmony_ci	v1 = inb_p(sonypi_device.ioport2);
6428c2ecf20Sopenharmony_ci	v2 = inb_p(sonypi_device.ioport1);
6438c2ecf20Sopenharmony_ci	return v2;
6448c2ecf20Sopenharmony_ci}
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_cistatic u8 sonypi_call2(u8 dev, u8 fn)
6478c2ecf20Sopenharmony_ci{
6488c2ecf20Sopenharmony_ci	u8 v1;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
6518c2ecf20Sopenharmony_ci	outb(dev, sonypi_device.ioport2);
6528c2ecf20Sopenharmony_ci	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
6538c2ecf20Sopenharmony_ci	outb(fn, sonypi_device.ioport1);
6548c2ecf20Sopenharmony_ci	v1 = inb_p(sonypi_device.ioport1);
6558c2ecf20Sopenharmony_ci	return v1;
6568c2ecf20Sopenharmony_ci}
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_cistatic u8 sonypi_call3(u8 dev, u8 fn, u8 v)
6598c2ecf20Sopenharmony_ci{
6608c2ecf20Sopenharmony_ci	u8 v1;
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
6638c2ecf20Sopenharmony_ci	outb(dev, sonypi_device.ioport2);
6648c2ecf20Sopenharmony_ci	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
6658c2ecf20Sopenharmony_ci	outb(fn, sonypi_device.ioport1);
6668c2ecf20Sopenharmony_ci	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
6678c2ecf20Sopenharmony_ci	outb(v, sonypi_device.ioport1);
6688c2ecf20Sopenharmony_ci	v1 = inb_p(sonypi_device.ioport1);
6698c2ecf20Sopenharmony_ci	return v1;
6708c2ecf20Sopenharmony_ci}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci#if 0
6738c2ecf20Sopenharmony_ci/* Get brightness, hue etc. Unreliable... */
6748c2ecf20Sopenharmony_cistatic u8 sonypi_read(u8 fn)
6758c2ecf20Sopenharmony_ci{
6768c2ecf20Sopenharmony_ci	u8 v1, v2;
6778c2ecf20Sopenharmony_ci	int n = 100;
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	while (n--) {
6808c2ecf20Sopenharmony_ci		v1 = sonypi_call2(0x8f, fn);
6818c2ecf20Sopenharmony_ci		v2 = sonypi_call2(0x8f, fn);
6828c2ecf20Sopenharmony_ci		if (v1 == v2 && v1 != 0xff)
6838c2ecf20Sopenharmony_ci			return v1;
6848c2ecf20Sopenharmony_ci	}
6858c2ecf20Sopenharmony_ci	return 0xff;
6868c2ecf20Sopenharmony_ci}
6878c2ecf20Sopenharmony_ci#endif
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci/* Set brightness, hue etc */
6908c2ecf20Sopenharmony_cistatic void sonypi_set(u8 fn, u8 v)
6918c2ecf20Sopenharmony_ci{
6928c2ecf20Sopenharmony_ci	wait_on_command(0, sonypi_call3(0x90, fn, v), ITERATIONS_SHORT);
6938c2ecf20Sopenharmony_ci}
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci/* Tests if the camera is ready */
6968c2ecf20Sopenharmony_cistatic int sonypi_camera_ready(void)
6978c2ecf20Sopenharmony_ci{
6988c2ecf20Sopenharmony_ci	u8 v;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	v = sonypi_call2(0x8f, SONYPI_CAMERA_STATUS);
7018c2ecf20Sopenharmony_ci	return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY));
7028c2ecf20Sopenharmony_ci}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci/* Turns the camera off */
7058c2ecf20Sopenharmony_cistatic void sonypi_camera_off(void)
7068c2ecf20Sopenharmony_ci{
7078c2ecf20Sopenharmony_ci	sonypi_set(SONYPI_CAMERA_PICTURE, SONYPI_CAMERA_MUTE_MASK);
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	if (!sonypi_device.camera_power)
7108c2ecf20Sopenharmony_ci		return;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	sonypi_call2(0x91, 0);
7138c2ecf20Sopenharmony_ci	sonypi_device.camera_power = 0;
7148c2ecf20Sopenharmony_ci}
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci/* Turns the camera on */
7178c2ecf20Sopenharmony_cistatic void sonypi_camera_on(void)
7188c2ecf20Sopenharmony_ci{
7198c2ecf20Sopenharmony_ci	int i, j;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	if (sonypi_device.camera_power)
7228c2ecf20Sopenharmony_ci		return;
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	for (j = 5; j > 0; j--) {
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci		while (sonypi_call2(0x91, 0x1))
7278c2ecf20Sopenharmony_ci			msleep(10);
7288c2ecf20Sopenharmony_ci		sonypi_call1(0x93);
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci		for (i = 400; i > 0; i--) {
7318c2ecf20Sopenharmony_ci			if (sonypi_camera_ready())
7328c2ecf20Sopenharmony_ci				break;
7338c2ecf20Sopenharmony_ci			msleep(10);
7348c2ecf20Sopenharmony_ci		}
7358c2ecf20Sopenharmony_ci		if (i)
7368c2ecf20Sopenharmony_ci			break;
7378c2ecf20Sopenharmony_ci	}
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	if (j == 0) {
7408c2ecf20Sopenharmony_ci		printk(KERN_WARNING "sonypi: failed to power on camera\n");
7418c2ecf20Sopenharmony_ci		return;
7428c2ecf20Sopenharmony_ci	}
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	sonypi_set(0x10, 0x5a);
7458c2ecf20Sopenharmony_ci	sonypi_device.camera_power = 1;
7468c2ecf20Sopenharmony_ci}
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci/* sets the bluetooth subsystem power state */
7498c2ecf20Sopenharmony_cistatic void sonypi_setbluetoothpower(u8 state)
7508c2ecf20Sopenharmony_ci{
7518c2ecf20Sopenharmony_ci	state = !!state;
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	if (sonypi_device.bluetooth_power == state)
7548c2ecf20Sopenharmony_ci		return;
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	sonypi_call2(0x96, state);
7578c2ecf20Sopenharmony_ci	sonypi_call1(0x82);
7588c2ecf20Sopenharmony_ci	sonypi_device.bluetooth_power = state;
7598c2ecf20Sopenharmony_ci}
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_cistatic void input_keyrelease(struct work_struct *work)
7628c2ecf20Sopenharmony_ci{
7638c2ecf20Sopenharmony_ci	struct sonypi_keypress kp;
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	while (kfifo_out_locked(&sonypi_device.input_fifo, (unsigned char *)&kp,
7668c2ecf20Sopenharmony_ci			 sizeof(kp), &sonypi_device.input_fifo_lock)
7678c2ecf20Sopenharmony_ci			== sizeof(kp)) {
7688c2ecf20Sopenharmony_ci		msleep(10);
7698c2ecf20Sopenharmony_ci		input_report_key(kp.dev, kp.key, 0);
7708c2ecf20Sopenharmony_ci		input_sync(kp.dev);
7718c2ecf20Sopenharmony_ci	}
7728c2ecf20Sopenharmony_ci}
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_cistatic void sonypi_report_input_event(u8 event)
7758c2ecf20Sopenharmony_ci{
7768c2ecf20Sopenharmony_ci	struct input_dev *jog_dev = sonypi_device.input_jog_dev;
7778c2ecf20Sopenharmony_ci	struct input_dev *key_dev = sonypi_device.input_key_dev;
7788c2ecf20Sopenharmony_ci	struct sonypi_keypress kp = { NULL };
7798c2ecf20Sopenharmony_ci	int i;
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	switch (event) {
7828c2ecf20Sopenharmony_ci	case SONYPI_EVENT_JOGDIAL_UP:
7838c2ecf20Sopenharmony_ci	case SONYPI_EVENT_JOGDIAL_UP_PRESSED:
7848c2ecf20Sopenharmony_ci		input_report_rel(jog_dev, REL_WHEEL, 1);
7858c2ecf20Sopenharmony_ci		input_sync(jog_dev);
7868c2ecf20Sopenharmony_ci		break;
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	case SONYPI_EVENT_JOGDIAL_DOWN:
7898c2ecf20Sopenharmony_ci	case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED:
7908c2ecf20Sopenharmony_ci		input_report_rel(jog_dev, REL_WHEEL, -1);
7918c2ecf20Sopenharmony_ci		input_sync(jog_dev);
7928c2ecf20Sopenharmony_ci		break;
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	case SONYPI_EVENT_JOGDIAL_PRESSED:
7958c2ecf20Sopenharmony_ci		kp.key = BTN_MIDDLE;
7968c2ecf20Sopenharmony_ci		kp.dev = jog_dev;
7978c2ecf20Sopenharmony_ci		break;
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	case SONYPI_EVENT_FNKEY_RELEASED:
8008c2ecf20Sopenharmony_ci		/* Nothing, not all VAIOs generate this event */
8018c2ecf20Sopenharmony_ci		break;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	default:
8048c2ecf20Sopenharmony_ci		for (i = 0; sonypi_inputkeys[i].sonypiev; i++)
8058c2ecf20Sopenharmony_ci			if (event == sonypi_inputkeys[i].sonypiev) {
8068c2ecf20Sopenharmony_ci				kp.dev = key_dev;
8078c2ecf20Sopenharmony_ci				kp.key = sonypi_inputkeys[i].inputev;
8088c2ecf20Sopenharmony_ci				break;
8098c2ecf20Sopenharmony_ci			}
8108c2ecf20Sopenharmony_ci		break;
8118c2ecf20Sopenharmony_ci	}
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	if (kp.dev) {
8148c2ecf20Sopenharmony_ci		input_report_key(kp.dev, kp.key, 1);
8158c2ecf20Sopenharmony_ci		input_sync(kp.dev);
8168c2ecf20Sopenharmony_ci		kfifo_in_locked(&sonypi_device.input_fifo,
8178c2ecf20Sopenharmony_ci			(unsigned char *)&kp, sizeof(kp),
8188c2ecf20Sopenharmony_ci			&sonypi_device.input_fifo_lock);
8198c2ecf20Sopenharmony_ci		schedule_work(&sonypi_device.input_work);
8208c2ecf20Sopenharmony_ci	}
8218c2ecf20Sopenharmony_ci}
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci/* Interrupt handler: some event is available */
8248c2ecf20Sopenharmony_cistatic irqreturn_t sonypi_irq(int irq, void *dev_id)
8258c2ecf20Sopenharmony_ci{
8268c2ecf20Sopenharmony_ci	u8 v1, v2, event = 0;
8278c2ecf20Sopenharmony_ci	int i, j;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	v1 = inb_p(sonypi_device.ioport1);
8308c2ecf20Sopenharmony_ci	v2 = inb_p(sonypi_device.ioport1 + sonypi_device.evtype_offset);
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	for (i = 0; sonypi_eventtypes[i].model; i++) {
8338c2ecf20Sopenharmony_ci		if (sonypi_device.model != sonypi_eventtypes[i].model)
8348c2ecf20Sopenharmony_ci			continue;
8358c2ecf20Sopenharmony_ci		if ((v2 & sonypi_eventtypes[i].data) !=
8368c2ecf20Sopenharmony_ci		    sonypi_eventtypes[i].data)
8378c2ecf20Sopenharmony_ci			continue;
8388c2ecf20Sopenharmony_ci		if (!(mask & sonypi_eventtypes[i].mask))
8398c2ecf20Sopenharmony_ci			continue;
8408c2ecf20Sopenharmony_ci		for (j = 0; sonypi_eventtypes[i].events[j].event; j++) {
8418c2ecf20Sopenharmony_ci			if (v1 == sonypi_eventtypes[i].events[j].data) {
8428c2ecf20Sopenharmony_ci				event = sonypi_eventtypes[i].events[j].event;
8438c2ecf20Sopenharmony_ci				goto found;
8448c2ecf20Sopenharmony_ci			}
8458c2ecf20Sopenharmony_ci		}
8468c2ecf20Sopenharmony_ci	}
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	if (verbose)
8498c2ecf20Sopenharmony_ci		printk(KERN_WARNING
8508c2ecf20Sopenharmony_ci		       "sonypi: unknown event port1=0x%02x,port2=0x%02x\n",
8518c2ecf20Sopenharmony_ci		       v1, v2);
8528c2ecf20Sopenharmony_ci	/* We need to return IRQ_HANDLED here because there *are*
8538c2ecf20Sopenharmony_ci	 * events belonging to the sonypi device we don't know about,
8548c2ecf20Sopenharmony_ci	 * but we still don't want those to pollute the logs... */
8558c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_cifound:
8588c2ecf20Sopenharmony_ci	if (verbose > 1)
8598c2ecf20Sopenharmony_ci		printk(KERN_INFO
8608c2ecf20Sopenharmony_ci		       "sonypi: event port1=0x%02x,port2=0x%02x\n", v1, v2);
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	if (useinput)
8638c2ecf20Sopenharmony_ci		sonypi_report_input_event(event);
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci	kfifo_in_locked(&sonypi_device.fifo, (unsigned char *)&event,
8668c2ecf20Sopenharmony_ci			sizeof(event), &sonypi_device.fifo_lock);
8678c2ecf20Sopenharmony_ci	kill_fasync(&sonypi_device.fifo_async, SIGIO, POLL_IN);
8688c2ecf20Sopenharmony_ci	wake_up_interruptible(&sonypi_device.fifo_proc_list);
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
8718c2ecf20Sopenharmony_ci}
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_cistatic int sonypi_misc_fasync(int fd, struct file *filp, int on)
8748c2ecf20Sopenharmony_ci{
8758c2ecf20Sopenharmony_ci	return fasync_helper(fd, filp, on, &sonypi_device.fifo_async);
8768c2ecf20Sopenharmony_ci}
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_cistatic int sonypi_misc_release(struct inode *inode, struct file *file)
8798c2ecf20Sopenharmony_ci{
8808c2ecf20Sopenharmony_ci	mutex_lock(&sonypi_device.lock);
8818c2ecf20Sopenharmony_ci	sonypi_device.open_count--;
8828c2ecf20Sopenharmony_ci	mutex_unlock(&sonypi_device.lock);
8838c2ecf20Sopenharmony_ci	return 0;
8848c2ecf20Sopenharmony_ci}
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_cistatic int sonypi_misc_open(struct inode *inode, struct file *file)
8878c2ecf20Sopenharmony_ci{
8888c2ecf20Sopenharmony_ci	mutex_lock(&sonypi_device.lock);
8898c2ecf20Sopenharmony_ci	/* Flush input queue on first open */
8908c2ecf20Sopenharmony_ci	if (!sonypi_device.open_count)
8918c2ecf20Sopenharmony_ci		kfifo_reset(&sonypi_device.fifo);
8928c2ecf20Sopenharmony_ci	sonypi_device.open_count++;
8938c2ecf20Sopenharmony_ci	mutex_unlock(&sonypi_device.lock);
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	return 0;
8968c2ecf20Sopenharmony_ci}
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_cistatic ssize_t sonypi_misc_read(struct file *file, char __user *buf,
8998c2ecf20Sopenharmony_ci				size_t count, loff_t *pos)
9008c2ecf20Sopenharmony_ci{
9018c2ecf20Sopenharmony_ci	ssize_t ret;
9028c2ecf20Sopenharmony_ci	unsigned char c;
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	if ((kfifo_len(&sonypi_device.fifo) == 0) &&
9058c2ecf20Sopenharmony_ci	    (file->f_flags & O_NONBLOCK))
9068c2ecf20Sopenharmony_ci		return -EAGAIN;
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	ret = wait_event_interruptible(sonypi_device.fifo_proc_list,
9098c2ecf20Sopenharmony_ci				       kfifo_len(&sonypi_device.fifo) != 0);
9108c2ecf20Sopenharmony_ci	if (ret)
9118c2ecf20Sopenharmony_ci		return ret;
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci	while (ret < count &&
9148c2ecf20Sopenharmony_ci	       (kfifo_out_locked(&sonypi_device.fifo, &c, sizeof(c),
9158c2ecf20Sopenharmony_ci				 &sonypi_device.fifo_lock) == sizeof(c))) {
9168c2ecf20Sopenharmony_ci		if (put_user(c, buf++))
9178c2ecf20Sopenharmony_ci			return -EFAULT;
9188c2ecf20Sopenharmony_ci		ret++;
9198c2ecf20Sopenharmony_ci	}
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	if (ret > 0) {
9228c2ecf20Sopenharmony_ci		struct inode *inode = file_inode(file);
9238c2ecf20Sopenharmony_ci		inode->i_atime = current_time(inode);
9248c2ecf20Sopenharmony_ci	}
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	return ret;
9278c2ecf20Sopenharmony_ci}
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_cistatic __poll_t sonypi_misc_poll(struct file *file, poll_table *wait)
9308c2ecf20Sopenharmony_ci{
9318c2ecf20Sopenharmony_ci	poll_wait(file, &sonypi_device.fifo_proc_list, wait);
9328c2ecf20Sopenharmony_ci	if (kfifo_len(&sonypi_device.fifo))
9338c2ecf20Sopenharmony_ci		return EPOLLIN | EPOLLRDNORM;
9348c2ecf20Sopenharmony_ci	return 0;
9358c2ecf20Sopenharmony_ci}
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_cistatic long sonypi_misc_ioctl(struct file *fp,
9388c2ecf20Sopenharmony_ci			     unsigned int cmd, unsigned long arg)
9398c2ecf20Sopenharmony_ci{
9408c2ecf20Sopenharmony_ci	long ret = 0;
9418c2ecf20Sopenharmony_ci	void __user *argp = (void __user *)arg;
9428c2ecf20Sopenharmony_ci	u8 val8;
9438c2ecf20Sopenharmony_ci	u16 val16;
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	mutex_lock(&sonypi_device.lock);
9468c2ecf20Sopenharmony_ci	switch (cmd) {
9478c2ecf20Sopenharmony_ci	case SONYPI_IOCGBRT:
9488c2ecf20Sopenharmony_ci		if (sonypi_ec_read(SONYPI_LCD_LIGHT, &val8)) {
9498c2ecf20Sopenharmony_ci			ret = -EIO;
9508c2ecf20Sopenharmony_ci			break;
9518c2ecf20Sopenharmony_ci		}
9528c2ecf20Sopenharmony_ci		if (copy_to_user(argp, &val8, sizeof(val8)))
9538c2ecf20Sopenharmony_ci			ret = -EFAULT;
9548c2ecf20Sopenharmony_ci		break;
9558c2ecf20Sopenharmony_ci	case SONYPI_IOCSBRT:
9568c2ecf20Sopenharmony_ci		if (copy_from_user(&val8, argp, sizeof(val8))) {
9578c2ecf20Sopenharmony_ci			ret = -EFAULT;
9588c2ecf20Sopenharmony_ci			break;
9598c2ecf20Sopenharmony_ci		}
9608c2ecf20Sopenharmony_ci		if (sonypi_ec_write(SONYPI_LCD_LIGHT, val8))
9618c2ecf20Sopenharmony_ci			ret = -EIO;
9628c2ecf20Sopenharmony_ci		break;
9638c2ecf20Sopenharmony_ci	case SONYPI_IOCGBAT1CAP:
9648c2ecf20Sopenharmony_ci		if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
9658c2ecf20Sopenharmony_ci			ret = -EIO;
9668c2ecf20Sopenharmony_ci			break;
9678c2ecf20Sopenharmony_ci		}
9688c2ecf20Sopenharmony_ci		if (copy_to_user(argp, &val16, sizeof(val16)))
9698c2ecf20Sopenharmony_ci			ret = -EFAULT;
9708c2ecf20Sopenharmony_ci		break;
9718c2ecf20Sopenharmony_ci	case SONYPI_IOCGBAT1REM:
9728c2ecf20Sopenharmony_ci		if (ec_read16(SONYPI_BAT1_LEFT, &val16)) {
9738c2ecf20Sopenharmony_ci			ret = -EIO;
9748c2ecf20Sopenharmony_ci			break;
9758c2ecf20Sopenharmony_ci		}
9768c2ecf20Sopenharmony_ci		if (copy_to_user(argp, &val16, sizeof(val16)))
9778c2ecf20Sopenharmony_ci			ret = -EFAULT;
9788c2ecf20Sopenharmony_ci		break;
9798c2ecf20Sopenharmony_ci	case SONYPI_IOCGBAT2CAP:
9808c2ecf20Sopenharmony_ci		if (ec_read16(SONYPI_BAT2_FULL, &val16)) {
9818c2ecf20Sopenharmony_ci			ret = -EIO;
9828c2ecf20Sopenharmony_ci			break;
9838c2ecf20Sopenharmony_ci		}
9848c2ecf20Sopenharmony_ci		if (copy_to_user(argp, &val16, sizeof(val16)))
9858c2ecf20Sopenharmony_ci			ret = -EFAULT;
9868c2ecf20Sopenharmony_ci		break;
9878c2ecf20Sopenharmony_ci	case SONYPI_IOCGBAT2REM:
9888c2ecf20Sopenharmony_ci		if (ec_read16(SONYPI_BAT2_LEFT, &val16)) {
9898c2ecf20Sopenharmony_ci			ret = -EIO;
9908c2ecf20Sopenharmony_ci			break;
9918c2ecf20Sopenharmony_ci		}
9928c2ecf20Sopenharmony_ci		if (copy_to_user(argp, &val16, sizeof(val16)))
9938c2ecf20Sopenharmony_ci			ret = -EFAULT;
9948c2ecf20Sopenharmony_ci		break;
9958c2ecf20Sopenharmony_ci	case SONYPI_IOCGBATFLAGS:
9968c2ecf20Sopenharmony_ci		if (sonypi_ec_read(SONYPI_BAT_FLAGS, &val8)) {
9978c2ecf20Sopenharmony_ci			ret = -EIO;
9988c2ecf20Sopenharmony_ci			break;
9998c2ecf20Sopenharmony_ci		}
10008c2ecf20Sopenharmony_ci		val8 &= 0x07;
10018c2ecf20Sopenharmony_ci		if (copy_to_user(argp, &val8, sizeof(val8)))
10028c2ecf20Sopenharmony_ci			ret = -EFAULT;
10038c2ecf20Sopenharmony_ci		break;
10048c2ecf20Sopenharmony_ci	case SONYPI_IOCGBLUE:
10058c2ecf20Sopenharmony_ci		val8 = sonypi_device.bluetooth_power;
10068c2ecf20Sopenharmony_ci		if (copy_to_user(argp, &val8, sizeof(val8)))
10078c2ecf20Sopenharmony_ci			ret = -EFAULT;
10088c2ecf20Sopenharmony_ci		break;
10098c2ecf20Sopenharmony_ci	case SONYPI_IOCSBLUE:
10108c2ecf20Sopenharmony_ci		if (copy_from_user(&val8, argp, sizeof(val8))) {
10118c2ecf20Sopenharmony_ci			ret = -EFAULT;
10128c2ecf20Sopenharmony_ci			break;
10138c2ecf20Sopenharmony_ci		}
10148c2ecf20Sopenharmony_ci		sonypi_setbluetoothpower(val8);
10158c2ecf20Sopenharmony_ci		break;
10168c2ecf20Sopenharmony_ci	/* FAN Controls */
10178c2ecf20Sopenharmony_ci	case SONYPI_IOCGFAN:
10188c2ecf20Sopenharmony_ci		if (sonypi_ec_read(SONYPI_FAN0_STATUS, &val8)) {
10198c2ecf20Sopenharmony_ci			ret = -EIO;
10208c2ecf20Sopenharmony_ci			break;
10218c2ecf20Sopenharmony_ci		}
10228c2ecf20Sopenharmony_ci		if (copy_to_user(argp, &val8, sizeof(val8)))
10238c2ecf20Sopenharmony_ci			ret = -EFAULT;
10248c2ecf20Sopenharmony_ci		break;
10258c2ecf20Sopenharmony_ci	case SONYPI_IOCSFAN:
10268c2ecf20Sopenharmony_ci		if (copy_from_user(&val8, argp, sizeof(val8))) {
10278c2ecf20Sopenharmony_ci			ret = -EFAULT;
10288c2ecf20Sopenharmony_ci			break;
10298c2ecf20Sopenharmony_ci		}
10308c2ecf20Sopenharmony_ci		if (sonypi_ec_write(SONYPI_FAN0_STATUS, val8))
10318c2ecf20Sopenharmony_ci			ret = -EIO;
10328c2ecf20Sopenharmony_ci		break;
10338c2ecf20Sopenharmony_ci	/* GET Temperature (useful under APM) */
10348c2ecf20Sopenharmony_ci	case SONYPI_IOCGTEMP:
10358c2ecf20Sopenharmony_ci		if (sonypi_ec_read(SONYPI_TEMP_STATUS, &val8)) {
10368c2ecf20Sopenharmony_ci			ret = -EIO;
10378c2ecf20Sopenharmony_ci			break;
10388c2ecf20Sopenharmony_ci		}
10398c2ecf20Sopenharmony_ci		if (copy_to_user(argp, &val8, sizeof(val8)))
10408c2ecf20Sopenharmony_ci			ret = -EFAULT;
10418c2ecf20Sopenharmony_ci		break;
10428c2ecf20Sopenharmony_ci	default:
10438c2ecf20Sopenharmony_ci		ret = -EINVAL;
10448c2ecf20Sopenharmony_ci	}
10458c2ecf20Sopenharmony_ci	mutex_unlock(&sonypi_device.lock);
10468c2ecf20Sopenharmony_ci	return ret;
10478c2ecf20Sopenharmony_ci}
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_cistatic const struct file_operations sonypi_misc_fops = {
10508c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
10518c2ecf20Sopenharmony_ci	.read		= sonypi_misc_read,
10528c2ecf20Sopenharmony_ci	.poll		= sonypi_misc_poll,
10538c2ecf20Sopenharmony_ci	.open		= sonypi_misc_open,
10548c2ecf20Sopenharmony_ci	.release	= sonypi_misc_release,
10558c2ecf20Sopenharmony_ci	.fasync		= sonypi_misc_fasync,
10568c2ecf20Sopenharmony_ci	.unlocked_ioctl	= sonypi_misc_ioctl,
10578c2ecf20Sopenharmony_ci	.llseek		= no_llseek,
10588c2ecf20Sopenharmony_ci};
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_cistatic struct miscdevice sonypi_misc_device = {
10618c2ecf20Sopenharmony_ci	.minor		= MISC_DYNAMIC_MINOR,
10628c2ecf20Sopenharmony_ci	.name		= "sonypi",
10638c2ecf20Sopenharmony_ci	.fops		= &sonypi_misc_fops,
10648c2ecf20Sopenharmony_ci};
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_cistatic void sonypi_enable(unsigned int camera_on)
10678c2ecf20Sopenharmony_ci{
10688c2ecf20Sopenharmony_ci	switch (sonypi_device.model) {
10698c2ecf20Sopenharmony_ci	case SONYPI_DEVICE_MODEL_TYPE1:
10708c2ecf20Sopenharmony_ci		sonypi_type1_srs();
10718c2ecf20Sopenharmony_ci		break;
10728c2ecf20Sopenharmony_ci	case SONYPI_DEVICE_MODEL_TYPE2:
10738c2ecf20Sopenharmony_ci		sonypi_type2_srs();
10748c2ecf20Sopenharmony_ci		break;
10758c2ecf20Sopenharmony_ci	case SONYPI_DEVICE_MODEL_TYPE3:
10768c2ecf20Sopenharmony_ci		sonypi_type3_srs();
10778c2ecf20Sopenharmony_ci		break;
10788c2ecf20Sopenharmony_ci	}
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	sonypi_call1(0x82);
10818c2ecf20Sopenharmony_ci	sonypi_call2(0x81, 0xff);
10828c2ecf20Sopenharmony_ci	sonypi_call1(compat ? 0x92 : 0x82);
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci	/* Enable ACPI mode to get Fn key events */
10858c2ecf20Sopenharmony_ci	if (!SONYPI_ACPI_ACTIVE && fnkeyinit)
10868c2ecf20Sopenharmony_ci		outb(0xf0, 0xb2);
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci	if (camera && camera_on)
10898c2ecf20Sopenharmony_ci		sonypi_camera_on();
10908c2ecf20Sopenharmony_ci}
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_cistatic int sonypi_disable(void)
10938c2ecf20Sopenharmony_ci{
10948c2ecf20Sopenharmony_ci	sonypi_call2(0x81, 0);	/* make sure we don't get any more events */
10958c2ecf20Sopenharmony_ci	if (camera)
10968c2ecf20Sopenharmony_ci		sonypi_camera_off();
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	/* disable ACPI mode */
10998c2ecf20Sopenharmony_ci	if (!SONYPI_ACPI_ACTIVE && fnkeyinit)
11008c2ecf20Sopenharmony_ci		outb(0xf1, 0xb2);
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci	switch (sonypi_device.model) {
11038c2ecf20Sopenharmony_ci	case SONYPI_DEVICE_MODEL_TYPE1:
11048c2ecf20Sopenharmony_ci		sonypi_type1_dis();
11058c2ecf20Sopenharmony_ci		break;
11068c2ecf20Sopenharmony_ci	case SONYPI_DEVICE_MODEL_TYPE2:
11078c2ecf20Sopenharmony_ci		sonypi_type2_dis();
11088c2ecf20Sopenharmony_ci		break;
11098c2ecf20Sopenharmony_ci	case SONYPI_DEVICE_MODEL_TYPE3:
11108c2ecf20Sopenharmony_ci		sonypi_type3_dis();
11118c2ecf20Sopenharmony_ci		break;
11128c2ecf20Sopenharmony_ci	}
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	return 0;
11158c2ecf20Sopenharmony_ci}
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI
11188c2ecf20Sopenharmony_cistatic int sonypi_acpi_add(struct acpi_device *device)
11198c2ecf20Sopenharmony_ci{
11208c2ecf20Sopenharmony_ci	sonypi_acpi_device = device;
11218c2ecf20Sopenharmony_ci	strcpy(acpi_device_name(device), "Sony laptop hotkeys");
11228c2ecf20Sopenharmony_ci	strcpy(acpi_device_class(device), "sony/hotkey");
11238c2ecf20Sopenharmony_ci	return 0;
11248c2ecf20Sopenharmony_ci}
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_cistatic int sonypi_acpi_remove(struct acpi_device *device)
11278c2ecf20Sopenharmony_ci{
11288c2ecf20Sopenharmony_ci	sonypi_acpi_device = NULL;
11298c2ecf20Sopenharmony_ci	return 0;
11308c2ecf20Sopenharmony_ci}
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_cistatic const struct acpi_device_id sonypi_device_ids[] = {
11338c2ecf20Sopenharmony_ci	{"SNY6001", 0},
11348c2ecf20Sopenharmony_ci	{"", 0},
11358c2ecf20Sopenharmony_ci};
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_cistatic struct acpi_driver sonypi_acpi_driver = {
11388c2ecf20Sopenharmony_ci	.name           = "sonypi",
11398c2ecf20Sopenharmony_ci	.class          = "hkey",
11408c2ecf20Sopenharmony_ci	.ids            = sonypi_device_ids,
11418c2ecf20Sopenharmony_ci	.ops            = {
11428c2ecf20Sopenharmony_ci		           .add = sonypi_acpi_add,
11438c2ecf20Sopenharmony_ci			   .remove = sonypi_acpi_remove,
11448c2ecf20Sopenharmony_ci	},
11458c2ecf20Sopenharmony_ci};
11468c2ecf20Sopenharmony_ci#endif
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_cistatic int sonypi_create_input_devices(struct platform_device *pdev)
11498c2ecf20Sopenharmony_ci{
11508c2ecf20Sopenharmony_ci	struct input_dev *jog_dev;
11518c2ecf20Sopenharmony_ci	struct input_dev *key_dev;
11528c2ecf20Sopenharmony_ci	int i;
11538c2ecf20Sopenharmony_ci	int error;
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_ci	sonypi_device.input_jog_dev = jog_dev = input_allocate_device();
11568c2ecf20Sopenharmony_ci	if (!jog_dev)
11578c2ecf20Sopenharmony_ci		return -ENOMEM;
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci	jog_dev->name = "Sony Vaio Jogdial";
11608c2ecf20Sopenharmony_ci	jog_dev->id.bustype = BUS_ISA;
11618c2ecf20Sopenharmony_ci	jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
11628c2ecf20Sopenharmony_ci	jog_dev->dev.parent = &pdev->dev;
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_ci	jog_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
11658c2ecf20Sopenharmony_ci	jog_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_MIDDLE);
11668c2ecf20Sopenharmony_ci	jog_dev->relbit[0] = BIT_MASK(REL_WHEEL);
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci	sonypi_device.input_key_dev = key_dev = input_allocate_device();
11698c2ecf20Sopenharmony_ci	if (!key_dev) {
11708c2ecf20Sopenharmony_ci		error = -ENOMEM;
11718c2ecf20Sopenharmony_ci		goto err_free_jogdev;
11728c2ecf20Sopenharmony_ci	}
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci	key_dev->name = "Sony Vaio Keys";
11758c2ecf20Sopenharmony_ci	key_dev->id.bustype = BUS_ISA;
11768c2ecf20Sopenharmony_ci	key_dev->id.vendor = PCI_VENDOR_ID_SONY;
11778c2ecf20Sopenharmony_ci	key_dev->dev.parent = &pdev->dev;
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci	/* Initialize the Input Drivers: special keys */
11808c2ecf20Sopenharmony_ci	key_dev->evbit[0] = BIT_MASK(EV_KEY);
11818c2ecf20Sopenharmony_ci	for (i = 0; sonypi_inputkeys[i].sonypiev; i++)
11828c2ecf20Sopenharmony_ci		if (sonypi_inputkeys[i].inputev)
11838c2ecf20Sopenharmony_ci			set_bit(sonypi_inputkeys[i].inputev, key_dev->keybit);
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci	error = input_register_device(jog_dev);
11868c2ecf20Sopenharmony_ci	if (error)
11878c2ecf20Sopenharmony_ci		goto err_free_keydev;
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci	error = input_register_device(key_dev);
11908c2ecf20Sopenharmony_ci	if (error)
11918c2ecf20Sopenharmony_ci		goto err_unregister_jogdev;
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci	return 0;
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci err_unregister_jogdev:
11968c2ecf20Sopenharmony_ci	input_unregister_device(jog_dev);
11978c2ecf20Sopenharmony_ci	/* Set to NULL so we don't free it again below */
11988c2ecf20Sopenharmony_ci	jog_dev = NULL;
11998c2ecf20Sopenharmony_ci err_free_keydev:
12008c2ecf20Sopenharmony_ci	input_free_device(key_dev);
12018c2ecf20Sopenharmony_ci	sonypi_device.input_key_dev = NULL;
12028c2ecf20Sopenharmony_ci err_free_jogdev:
12038c2ecf20Sopenharmony_ci	input_free_device(jog_dev);
12048c2ecf20Sopenharmony_ci	sonypi_device.input_jog_dev = NULL;
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	return error;
12078c2ecf20Sopenharmony_ci}
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_cistatic int sonypi_setup_ioports(struct sonypi_device *dev,
12108c2ecf20Sopenharmony_ci				const struct sonypi_ioport_list *ioport_list)
12118c2ecf20Sopenharmony_ci{
12128c2ecf20Sopenharmony_ci	/* try to detect if sony-laptop is being used and thus
12138c2ecf20Sopenharmony_ci	 * has already requested one of the known ioports.
12148c2ecf20Sopenharmony_ci	 * As in the deprecated check_region this is racy has we have
12158c2ecf20Sopenharmony_ci	 * multiple ioports available and one of them can be requested
12168c2ecf20Sopenharmony_ci	 * between this check and the subsequent request. Anyway, as an
12178c2ecf20Sopenharmony_ci	 * attempt to be some more user-friendly as we currently are,
12188c2ecf20Sopenharmony_ci	 * this is enough.
12198c2ecf20Sopenharmony_ci	 */
12208c2ecf20Sopenharmony_ci	const struct sonypi_ioport_list *check = ioport_list;
12218c2ecf20Sopenharmony_ci	while (check_ioport && check->port1) {
12228c2ecf20Sopenharmony_ci		if (!request_region(check->port1,
12238c2ecf20Sopenharmony_ci				   sonypi_device.region_size,
12248c2ecf20Sopenharmony_ci				   "Sony Programmable I/O Device Check")) {
12258c2ecf20Sopenharmony_ci			printk(KERN_ERR "sonypi: ioport 0x%.4x busy, using sony-laptop? "
12268c2ecf20Sopenharmony_ci					"if not use check_ioport=0\n",
12278c2ecf20Sopenharmony_ci					check->port1);
12288c2ecf20Sopenharmony_ci			return -EBUSY;
12298c2ecf20Sopenharmony_ci		}
12308c2ecf20Sopenharmony_ci		release_region(check->port1, sonypi_device.region_size);
12318c2ecf20Sopenharmony_ci		check++;
12328c2ecf20Sopenharmony_ci	}
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	while (ioport_list->port1) {
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ci		if (request_region(ioport_list->port1,
12378c2ecf20Sopenharmony_ci				   sonypi_device.region_size,
12388c2ecf20Sopenharmony_ci				   "Sony Programmable I/O Device")) {
12398c2ecf20Sopenharmony_ci			dev->ioport1 = ioport_list->port1;
12408c2ecf20Sopenharmony_ci			dev->ioport2 = ioport_list->port2;
12418c2ecf20Sopenharmony_ci			return 0;
12428c2ecf20Sopenharmony_ci		}
12438c2ecf20Sopenharmony_ci		ioport_list++;
12448c2ecf20Sopenharmony_ci	}
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	return -EBUSY;
12478c2ecf20Sopenharmony_ci}
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_cistatic int sonypi_setup_irq(struct sonypi_device *dev,
12508c2ecf20Sopenharmony_ci				      const struct sonypi_irq_list *irq_list)
12518c2ecf20Sopenharmony_ci{
12528c2ecf20Sopenharmony_ci	while (irq_list->irq) {
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci		if (!request_irq(irq_list->irq, sonypi_irq,
12558c2ecf20Sopenharmony_ci				 IRQF_SHARED, "sonypi", sonypi_irq)) {
12568c2ecf20Sopenharmony_ci			dev->irq = irq_list->irq;
12578c2ecf20Sopenharmony_ci			dev->bits = irq_list->bits;
12588c2ecf20Sopenharmony_ci			return 0;
12598c2ecf20Sopenharmony_ci		}
12608c2ecf20Sopenharmony_ci		irq_list++;
12618c2ecf20Sopenharmony_ci	}
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci	return -EBUSY;
12648c2ecf20Sopenharmony_ci}
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_cistatic void sonypi_display_info(void)
12678c2ecf20Sopenharmony_ci{
12688c2ecf20Sopenharmony_ci	printk(KERN_INFO "sonypi: detected type%d model, "
12698c2ecf20Sopenharmony_ci	       "verbose = %d, fnkeyinit = %s, camera = %s, "
12708c2ecf20Sopenharmony_ci	       "compat = %s, mask = 0x%08lx, useinput = %s, acpi = %s\n",
12718c2ecf20Sopenharmony_ci	       sonypi_device.model,
12728c2ecf20Sopenharmony_ci	       verbose,
12738c2ecf20Sopenharmony_ci	       fnkeyinit ? "on" : "off",
12748c2ecf20Sopenharmony_ci	       camera ? "on" : "off",
12758c2ecf20Sopenharmony_ci	       compat ? "on" : "off",
12768c2ecf20Sopenharmony_ci	       mask,
12778c2ecf20Sopenharmony_ci	       useinput ? "on" : "off",
12788c2ecf20Sopenharmony_ci	       SONYPI_ACPI_ACTIVE ? "on" : "off");
12798c2ecf20Sopenharmony_ci	printk(KERN_INFO "sonypi: enabled at irq=%d, port1=0x%x, port2=0x%x\n",
12808c2ecf20Sopenharmony_ci	       sonypi_device.irq,
12818c2ecf20Sopenharmony_ci	       sonypi_device.ioport1, sonypi_device.ioport2);
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	if (minor == -1)
12848c2ecf20Sopenharmony_ci		printk(KERN_INFO "sonypi: device allocated minor is %d\n",
12858c2ecf20Sopenharmony_ci		       sonypi_misc_device.minor);
12868c2ecf20Sopenharmony_ci}
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_cistatic int sonypi_probe(struct platform_device *dev)
12898c2ecf20Sopenharmony_ci{
12908c2ecf20Sopenharmony_ci	const struct sonypi_ioport_list *ioport_list;
12918c2ecf20Sopenharmony_ci	const struct sonypi_irq_list *irq_list;
12928c2ecf20Sopenharmony_ci	struct pci_dev *pcidev;
12938c2ecf20Sopenharmony_ci	int error;
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_ci	printk(KERN_WARNING "sonypi: please try the sony-laptop module instead "
12968c2ecf20Sopenharmony_ci			"and report failures, see also "
12978c2ecf20Sopenharmony_ci			"http://www.linux.it/~malattia/wiki/index.php/Sony_drivers\n");
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_ci	spin_lock_init(&sonypi_device.fifo_lock);
13008c2ecf20Sopenharmony_ci	error = kfifo_alloc(&sonypi_device.fifo, SONYPI_BUF_SIZE, GFP_KERNEL);
13018c2ecf20Sopenharmony_ci	if (error) {
13028c2ecf20Sopenharmony_ci		printk(KERN_ERR "sonypi: kfifo_alloc failed\n");
13038c2ecf20Sopenharmony_ci		return error;
13048c2ecf20Sopenharmony_ci	}
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci	init_waitqueue_head(&sonypi_device.fifo_proc_list);
13078c2ecf20Sopenharmony_ci	mutex_init(&sonypi_device.lock);
13088c2ecf20Sopenharmony_ci	sonypi_device.bluetooth_power = -1;
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci	if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
13118c2ecf20Sopenharmony_ci				     PCI_DEVICE_ID_INTEL_82371AB_3, NULL)))
13128c2ecf20Sopenharmony_ci		sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE1;
13138c2ecf20Sopenharmony_ci	else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
13148c2ecf20Sopenharmony_ci					  PCI_DEVICE_ID_INTEL_ICH6_1, NULL)))
13158c2ecf20Sopenharmony_ci		sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3;
13168c2ecf20Sopenharmony_ci	else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
13178c2ecf20Sopenharmony_ci					  PCI_DEVICE_ID_INTEL_ICH7_1, NULL)))
13188c2ecf20Sopenharmony_ci		sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3;
13198c2ecf20Sopenharmony_ci	else
13208c2ecf20Sopenharmony_ci		sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2;
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci	if (pcidev && pci_enable_device(pcidev)) {
13238c2ecf20Sopenharmony_ci		printk(KERN_ERR "sonypi: pci_enable_device failed\n");
13248c2ecf20Sopenharmony_ci		error = -EIO;
13258c2ecf20Sopenharmony_ci		goto err_put_pcidev;
13268c2ecf20Sopenharmony_ci	}
13278c2ecf20Sopenharmony_ci
13288c2ecf20Sopenharmony_ci	sonypi_device.dev = pcidev;
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci	if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) {
13318c2ecf20Sopenharmony_ci		ioport_list = sonypi_type1_ioport_list;
13328c2ecf20Sopenharmony_ci		sonypi_device.region_size = SONYPI_TYPE1_REGION_SIZE;
13338c2ecf20Sopenharmony_ci		sonypi_device.evtype_offset = SONYPI_TYPE1_EVTYPE_OFFSET;
13348c2ecf20Sopenharmony_ci		irq_list = sonypi_type1_irq_list;
13358c2ecf20Sopenharmony_ci	} else if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) {
13368c2ecf20Sopenharmony_ci		ioport_list = sonypi_type2_ioport_list;
13378c2ecf20Sopenharmony_ci		sonypi_device.region_size = SONYPI_TYPE2_REGION_SIZE;
13388c2ecf20Sopenharmony_ci		sonypi_device.evtype_offset = SONYPI_TYPE2_EVTYPE_OFFSET;
13398c2ecf20Sopenharmony_ci		irq_list = sonypi_type2_irq_list;
13408c2ecf20Sopenharmony_ci	} else {
13418c2ecf20Sopenharmony_ci		ioport_list = sonypi_type3_ioport_list;
13428c2ecf20Sopenharmony_ci		sonypi_device.region_size = SONYPI_TYPE3_REGION_SIZE;
13438c2ecf20Sopenharmony_ci		sonypi_device.evtype_offset = SONYPI_TYPE3_EVTYPE_OFFSET;
13448c2ecf20Sopenharmony_ci		irq_list = sonypi_type3_irq_list;
13458c2ecf20Sopenharmony_ci	}
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci	error = sonypi_setup_ioports(&sonypi_device, ioport_list);
13488c2ecf20Sopenharmony_ci	if (error) {
13498c2ecf20Sopenharmony_ci		printk(KERN_ERR "sonypi: failed to request ioports\n");
13508c2ecf20Sopenharmony_ci		goto err_disable_pcidev;
13518c2ecf20Sopenharmony_ci	}
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ci	error = sonypi_setup_irq(&sonypi_device, irq_list);
13548c2ecf20Sopenharmony_ci	if (error) {
13558c2ecf20Sopenharmony_ci		printk(KERN_ERR "sonypi: request_irq failed\n");
13568c2ecf20Sopenharmony_ci		goto err_free_ioports;
13578c2ecf20Sopenharmony_ci	}
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_ci	if (minor != -1)
13608c2ecf20Sopenharmony_ci		sonypi_misc_device.minor = minor;
13618c2ecf20Sopenharmony_ci	error = misc_register(&sonypi_misc_device);
13628c2ecf20Sopenharmony_ci	if (error) {
13638c2ecf20Sopenharmony_ci		printk(KERN_ERR "sonypi: misc_register failed\n");
13648c2ecf20Sopenharmony_ci		goto err_free_irq;
13658c2ecf20Sopenharmony_ci	}
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci	sonypi_display_info();
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_ci	if (useinput) {
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_ci		error = sonypi_create_input_devices(dev);
13728c2ecf20Sopenharmony_ci		if (error) {
13738c2ecf20Sopenharmony_ci			printk(KERN_ERR
13748c2ecf20Sopenharmony_ci				"sonypi: failed to create input devices\n");
13758c2ecf20Sopenharmony_ci			goto err_miscdev_unregister;
13768c2ecf20Sopenharmony_ci		}
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci		spin_lock_init(&sonypi_device.input_fifo_lock);
13798c2ecf20Sopenharmony_ci		error = kfifo_alloc(&sonypi_device.input_fifo, SONYPI_BUF_SIZE,
13808c2ecf20Sopenharmony_ci				GFP_KERNEL);
13818c2ecf20Sopenharmony_ci		if (error) {
13828c2ecf20Sopenharmony_ci			printk(KERN_ERR "sonypi: kfifo_alloc failed\n");
13838c2ecf20Sopenharmony_ci			goto err_inpdev_unregister;
13848c2ecf20Sopenharmony_ci		}
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci		INIT_WORK(&sonypi_device.input_work, input_keyrelease);
13878c2ecf20Sopenharmony_ci	}
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	sonypi_enable(0);
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci	return 0;
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_ci err_inpdev_unregister:
13948c2ecf20Sopenharmony_ci	input_unregister_device(sonypi_device.input_key_dev);
13958c2ecf20Sopenharmony_ci	input_unregister_device(sonypi_device.input_jog_dev);
13968c2ecf20Sopenharmony_ci err_miscdev_unregister:
13978c2ecf20Sopenharmony_ci	misc_deregister(&sonypi_misc_device);
13988c2ecf20Sopenharmony_ci err_free_irq:
13998c2ecf20Sopenharmony_ci	free_irq(sonypi_device.irq, sonypi_irq);
14008c2ecf20Sopenharmony_ci err_free_ioports:
14018c2ecf20Sopenharmony_ci	release_region(sonypi_device.ioport1, sonypi_device.region_size);
14028c2ecf20Sopenharmony_ci err_disable_pcidev:
14038c2ecf20Sopenharmony_ci	if (pcidev)
14048c2ecf20Sopenharmony_ci		pci_disable_device(pcidev);
14058c2ecf20Sopenharmony_ci err_put_pcidev:
14068c2ecf20Sopenharmony_ci	pci_dev_put(pcidev);
14078c2ecf20Sopenharmony_ci	kfifo_free(&sonypi_device.fifo);
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_ci	return error;
14108c2ecf20Sopenharmony_ci}
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_cistatic int sonypi_remove(struct platform_device *dev)
14138c2ecf20Sopenharmony_ci{
14148c2ecf20Sopenharmony_ci	sonypi_disable();
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_ci	synchronize_irq(sonypi_device.irq);
14178c2ecf20Sopenharmony_ci	flush_work(&sonypi_device.input_work);
14188c2ecf20Sopenharmony_ci
14198c2ecf20Sopenharmony_ci	if (useinput) {
14208c2ecf20Sopenharmony_ci		input_unregister_device(sonypi_device.input_key_dev);
14218c2ecf20Sopenharmony_ci		input_unregister_device(sonypi_device.input_jog_dev);
14228c2ecf20Sopenharmony_ci		kfifo_free(&sonypi_device.input_fifo);
14238c2ecf20Sopenharmony_ci	}
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ci	misc_deregister(&sonypi_misc_device);
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_ci	free_irq(sonypi_device.irq, sonypi_irq);
14288c2ecf20Sopenharmony_ci	release_region(sonypi_device.ioport1, sonypi_device.region_size);
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci	if (sonypi_device.dev) {
14318c2ecf20Sopenharmony_ci		pci_disable_device(sonypi_device.dev);
14328c2ecf20Sopenharmony_ci		pci_dev_put(sonypi_device.dev);
14338c2ecf20Sopenharmony_ci	}
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_ci	kfifo_free(&sonypi_device.fifo);
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_ci	return 0;
14388c2ecf20Sopenharmony_ci}
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
14418c2ecf20Sopenharmony_cistatic int old_camera_power;
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_cistatic int sonypi_suspend(struct device *dev)
14448c2ecf20Sopenharmony_ci{
14458c2ecf20Sopenharmony_ci	old_camera_power = sonypi_device.camera_power;
14468c2ecf20Sopenharmony_ci	sonypi_disable();
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci	return 0;
14498c2ecf20Sopenharmony_ci}
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_cistatic int sonypi_resume(struct device *dev)
14528c2ecf20Sopenharmony_ci{
14538c2ecf20Sopenharmony_ci	sonypi_enable(old_camera_power);
14548c2ecf20Sopenharmony_ci	return 0;
14558c2ecf20Sopenharmony_ci}
14568c2ecf20Sopenharmony_ci
14578c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(sonypi_pm, sonypi_suspend, sonypi_resume);
14588c2ecf20Sopenharmony_ci#define SONYPI_PM	(&sonypi_pm)
14598c2ecf20Sopenharmony_ci#else
14608c2ecf20Sopenharmony_ci#define SONYPI_PM	NULL
14618c2ecf20Sopenharmony_ci#endif
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_cistatic void sonypi_shutdown(struct platform_device *dev)
14648c2ecf20Sopenharmony_ci{
14658c2ecf20Sopenharmony_ci	sonypi_disable();
14668c2ecf20Sopenharmony_ci}
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_cistatic struct platform_driver sonypi_driver = {
14698c2ecf20Sopenharmony_ci	.driver		= {
14708c2ecf20Sopenharmony_ci		.name	= "sonypi",
14718c2ecf20Sopenharmony_ci		.pm	= SONYPI_PM,
14728c2ecf20Sopenharmony_ci	},
14738c2ecf20Sopenharmony_ci	.probe		= sonypi_probe,
14748c2ecf20Sopenharmony_ci	.remove		= sonypi_remove,
14758c2ecf20Sopenharmony_ci	.shutdown	= sonypi_shutdown,
14768c2ecf20Sopenharmony_ci};
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_cistatic struct platform_device *sonypi_platform_device;
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_cistatic const struct dmi_system_id sonypi_dmi_table[] __initconst = {
14818c2ecf20Sopenharmony_ci	{
14828c2ecf20Sopenharmony_ci		.ident = "Sony Vaio",
14838c2ecf20Sopenharmony_ci		.matches = {
14848c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
14858c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "PCG-"),
14868c2ecf20Sopenharmony_ci		},
14878c2ecf20Sopenharmony_ci	},
14888c2ecf20Sopenharmony_ci	{
14898c2ecf20Sopenharmony_ci		.ident = "Sony Vaio",
14908c2ecf20Sopenharmony_ci		.matches = {
14918c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
14928c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "VGN-"),
14938c2ecf20Sopenharmony_ci		},
14948c2ecf20Sopenharmony_ci	},
14958c2ecf20Sopenharmony_ci	{ }
14968c2ecf20Sopenharmony_ci};
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_cistatic int __init sonypi_init(void)
14998c2ecf20Sopenharmony_ci{
15008c2ecf20Sopenharmony_ci	int error;
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci	printk(KERN_INFO
15038c2ecf20Sopenharmony_ci		"sonypi: Sony Programmable I/O Controller Driver v%s.\n",
15048c2ecf20Sopenharmony_ci		SONYPI_DRIVER_VERSION);
15058c2ecf20Sopenharmony_ci
15068c2ecf20Sopenharmony_ci	if (!dmi_check_system(sonypi_dmi_table))
15078c2ecf20Sopenharmony_ci		return -ENODEV;
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_ci	error = platform_driver_register(&sonypi_driver);
15108c2ecf20Sopenharmony_ci	if (error)
15118c2ecf20Sopenharmony_ci		return error;
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci	sonypi_platform_device = platform_device_alloc("sonypi", -1);
15148c2ecf20Sopenharmony_ci	if (!sonypi_platform_device) {
15158c2ecf20Sopenharmony_ci		error = -ENOMEM;
15168c2ecf20Sopenharmony_ci		goto err_driver_unregister;
15178c2ecf20Sopenharmony_ci	}
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci	error = platform_device_add(sonypi_platform_device);
15208c2ecf20Sopenharmony_ci	if (error)
15218c2ecf20Sopenharmony_ci		goto err_free_device;
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI
15248c2ecf20Sopenharmony_ci	if (acpi_bus_register_driver(&sonypi_acpi_driver) >= 0)
15258c2ecf20Sopenharmony_ci		acpi_driver_registered = 1;
15268c2ecf20Sopenharmony_ci#endif
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci	return 0;
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_ci err_free_device:
15318c2ecf20Sopenharmony_ci	platform_device_put(sonypi_platform_device);
15328c2ecf20Sopenharmony_ci err_driver_unregister:
15338c2ecf20Sopenharmony_ci	platform_driver_unregister(&sonypi_driver);
15348c2ecf20Sopenharmony_ci	return error;
15358c2ecf20Sopenharmony_ci}
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_cistatic void __exit sonypi_exit(void)
15388c2ecf20Sopenharmony_ci{
15398c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI
15408c2ecf20Sopenharmony_ci	if (acpi_driver_registered)
15418c2ecf20Sopenharmony_ci		acpi_bus_unregister_driver(&sonypi_acpi_driver);
15428c2ecf20Sopenharmony_ci#endif
15438c2ecf20Sopenharmony_ci	platform_device_unregister(sonypi_platform_device);
15448c2ecf20Sopenharmony_ci	platform_driver_unregister(&sonypi_driver);
15458c2ecf20Sopenharmony_ci	printk(KERN_INFO "sonypi: removed.\n");
15468c2ecf20Sopenharmony_ci}
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_cimodule_init(sonypi_init);
15498c2ecf20Sopenharmony_cimodule_exit(sonypi_exit);
1550