1 |
62 |
marcus.erl |
/*
|
2 |
|
|
* Sony Programmable I/O Control Device driver for VAIO
|
3 |
|
|
*
|
4 |
|
|
* Copyright (C) 2007 Mattia Dongili <malattia@linux.it>
|
5 |
|
|
*
|
6 |
|
|
* Copyright (C) 2001-2005 Stelian Pop <stelian@popies.net>
|
7 |
|
|
*
|
8 |
|
|
* Copyright (C) 2005 Narayanan R S <nars@kadamba.org>
|
9 |
|
|
*
|
10 |
|
|
* Copyright (C) 2001-2002 Alcôve <www.alcove.com>
|
11 |
|
|
*
|
12 |
|
|
* Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
|
13 |
|
|
*
|
14 |
|
|
* Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
|
15 |
|
|
*
|
16 |
|
|
* Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp>
|
17 |
|
|
*
|
18 |
|
|
* Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
|
19 |
|
|
*
|
20 |
|
|
* Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras.
|
21 |
|
|
*
|
22 |
|
|
* This program is free software; you can redistribute it and/or modify
|
23 |
|
|
* it under the terms of the GNU General Public License as published by
|
24 |
|
|
* the Free Software Foundation; either version 2 of the License, or
|
25 |
|
|
* (at your option) any later version.
|
26 |
|
|
*
|
27 |
|
|
* This program is distributed in the hope that it will be useful,
|
28 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
29 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
30 |
|
|
* GNU General Public License for more details.
|
31 |
|
|
*
|
32 |
|
|
* You should have received a copy of the GNU General Public License
|
33 |
|
|
* along with this program; if not, write to the Free Software
|
34 |
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
35 |
|
|
*
|
36 |
|
|
*/
|
37 |
|
|
|
38 |
|
|
#include <linux/module.h>
|
39 |
|
|
#include <linux/input.h>
|
40 |
|
|
#include <linux/pci.h>
|
41 |
|
|
#include <linux/init.h>
|
42 |
|
|
#include <linux/interrupt.h>
|
43 |
|
|
#include <linux/miscdevice.h>
|
44 |
|
|
#include <linux/poll.h>
|
45 |
|
|
#include <linux/delay.h>
|
46 |
|
|
#include <linux/wait.h>
|
47 |
|
|
#include <linux/acpi.h>
|
48 |
|
|
#include <linux/dmi.h>
|
49 |
|
|
#include <linux/err.h>
|
50 |
|
|
#include <linux/kfifo.h>
|
51 |
|
|
#include <linux/platform_device.h>
|
52 |
|
|
|
53 |
|
|
#include <asm/uaccess.h>
|
54 |
|
|
#include <asm/io.h>
|
55 |
|
|
#include <asm/system.h>
|
56 |
|
|
|
57 |
|
|
#include <linux/sonypi.h>
|
58 |
|
|
|
59 |
|
|
#define SONYPI_DRIVER_VERSION "1.26"
|
60 |
|
|
|
61 |
|
|
MODULE_AUTHOR("Stelian Pop <stelian@popies.net>");
|
62 |
|
|
MODULE_DESCRIPTION("Sony Programmable I/O Control Device driver");
|
63 |
|
|
MODULE_LICENSE("GPL");
|
64 |
|
|
MODULE_VERSION(SONYPI_DRIVER_VERSION);
|
65 |
|
|
|
66 |
|
|
static int minor = -1;
|
67 |
|
|
module_param(minor, int, 0);
|
68 |
|
|
MODULE_PARM_DESC(minor,
|
69 |
|
|
"minor number of the misc device, default is -1 (automatic)");
|
70 |
|
|
|
71 |
|
|
static int verbose; /* = 0 */
|
72 |
|
|
module_param(verbose, int, 0644);
|
73 |
|
|
MODULE_PARM_DESC(verbose, "be verbose, default is 0 (no)");
|
74 |
|
|
|
75 |
|
|
static int fnkeyinit; /* = 0 */
|
76 |
|
|
module_param(fnkeyinit, int, 0444);
|
77 |
|
|
MODULE_PARM_DESC(fnkeyinit,
|
78 |
|
|
"set this if your Fn keys do not generate any event");
|
79 |
|
|
|
80 |
|
|
static int camera; /* = 0 */
|
81 |
|
|
module_param(camera, int, 0444);
|
82 |
|
|
MODULE_PARM_DESC(camera,
|
83 |
|
|
"set this if you have a MotionEye camera (PictureBook series)");
|
84 |
|
|
|
85 |
|
|
static int compat; /* = 0 */
|
86 |
|
|
module_param(compat, int, 0444);
|
87 |
|
|
MODULE_PARM_DESC(compat,
|
88 |
|
|
"set this if you want to enable backward compatibility mode");
|
89 |
|
|
|
90 |
|
|
static unsigned long mask = 0xffffffff;
|
91 |
|
|
module_param(mask, ulong, 0644);
|
92 |
|
|
MODULE_PARM_DESC(mask,
|
93 |
|
|
"set this to the mask of event you want to enable (see doc)");
|
94 |
|
|
|
95 |
|
|
static int useinput = 1;
|
96 |
|
|
module_param(useinput, int, 0444);
|
97 |
|
|
MODULE_PARM_DESC(useinput,
|
98 |
|
|
"set this if you would like sonypi to feed events to the input subsystem");
|
99 |
|
|
|
100 |
|
|
static int check_ioport = 1;
|
101 |
|
|
module_param(check_ioport, int, 0444);
|
102 |
|
|
MODULE_PARM_DESC(check_ioport,
|
103 |
|
|
"set this to 0 if you think the automatic ioport check for sony-laptop is wrong");
|
104 |
|
|
|
105 |
|
|
#define SONYPI_DEVICE_MODEL_TYPE1 1
|
106 |
|
|
#define SONYPI_DEVICE_MODEL_TYPE2 2
|
107 |
|
|
#define SONYPI_DEVICE_MODEL_TYPE3 3
|
108 |
|
|
|
109 |
|
|
/* type1 models use those */
|
110 |
|
|
#define SONYPI_IRQ_PORT 0x8034
|
111 |
|
|
#define SONYPI_IRQ_SHIFT 22
|
112 |
|
|
#define SONYPI_TYPE1_BASE 0x50
|
113 |
|
|
#define SONYPI_G10A (SONYPI_TYPE1_BASE+0x14)
|
114 |
|
|
#define SONYPI_TYPE1_REGION_SIZE 0x08
|
115 |
|
|
#define SONYPI_TYPE1_EVTYPE_OFFSET 0x04
|
116 |
|
|
|
117 |
|
|
/* type2 series specifics */
|
118 |
|
|
#define SONYPI_SIRQ 0x9b
|
119 |
|
|
#define SONYPI_SLOB 0x9c
|
120 |
|
|
#define SONYPI_SHIB 0x9d
|
121 |
|
|
#define SONYPI_TYPE2_REGION_SIZE 0x20
|
122 |
|
|
#define SONYPI_TYPE2_EVTYPE_OFFSET 0x12
|
123 |
|
|
|
124 |
|
|
/* type3 series specifics */
|
125 |
|
|
#define SONYPI_TYPE3_BASE 0x40
|
126 |
|
|
#define SONYPI_TYPE3_GID2 (SONYPI_TYPE3_BASE+0x48) /* 16 bits */
|
127 |
|
|
#define SONYPI_TYPE3_MISC (SONYPI_TYPE3_BASE+0x6d) /* 8 bits */
|
128 |
|
|
#define SONYPI_TYPE3_REGION_SIZE 0x20
|
129 |
|
|
#define SONYPI_TYPE3_EVTYPE_OFFSET 0x12
|
130 |
|
|
|
131 |
|
|
/* battery / brightness addresses */
|
132 |
|
|
#define SONYPI_BAT_FLAGS 0x81
|
133 |
|
|
#define SONYPI_LCD_LIGHT 0x96
|
134 |
|
|
#define SONYPI_BAT1_PCTRM 0xa0
|
135 |
|
|
#define SONYPI_BAT1_LEFT 0xa2
|
136 |
|
|
#define SONYPI_BAT1_MAXRT 0xa4
|
137 |
|
|
#define SONYPI_BAT2_PCTRM 0xa8
|
138 |
|
|
#define SONYPI_BAT2_LEFT 0xaa
|
139 |
|
|
#define SONYPI_BAT2_MAXRT 0xac
|
140 |
|
|
#define SONYPI_BAT1_MAXTK 0xb0
|
141 |
|
|
#define SONYPI_BAT1_FULL 0xb2
|
142 |
|
|
#define SONYPI_BAT2_MAXTK 0xb8
|
143 |
|
|
#define SONYPI_BAT2_FULL 0xba
|
144 |
|
|
|
145 |
|
|
/* FAN0 information (reverse engineered from ACPI tables) */
|
146 |
|
|
#define SONYPI_FAN0_STATUS 0x93
|
147 |
|
|
#define SONYPI_TEMP_STATUS 0xC1
|
148 |
|
|
|
149 |
|
|
/* ioports used for brightness and type2 events */
|
150 |
|
|
#define SONYPI_DATA_IOPORT 0x62
|
151 |
|
|
#define SONYPI_CST_IOPORT 0x66
|
152 |
|
|
|
153 |
|
|
/* The set of possible ioports */
|
154 |
|
|
struct sonypi_ioport_list {
|
155 |
|
|
u16 port1;
|
156 |
|
|
u16 port2;
|
157 |
|
|
};
|
158 |
|
|
|
159 |
|
|
static struct sonypi_ioport_list sonypi_type1_ioport_list[] = {
|
160 |
|
|
{ 0x10c0, 0x10c4 }, /* looks like the default on C1Vx */
|
161 |
|
|
{ 0x1080, 0x1084 },
|
162 |
|
|
{ 0x1090, 0x1094 },
|
163 |
|
|
{ 0x10a0, 0x10a4 },
|
164 |
|
|
{ 0x10b0, 0x10b4 },
|
165 |
|
|
{ 0x0, 0x0 }
|
166 |
|
|
};
|
167 |
|
|
|
168 |
|
|
static struct sonypi_ioport_list sonypi_type2_ioport_list[] = {
|
169 |
|
|
{ 0x1080, 0x1084 },
|
170 |
|
|
{ 0x10a0, 0x10a4 },
|
171 |
|
|
{ 0x10c0, 0x10c4 },
|
172 |
|
|
{ 0x10e0, 0x10e4 },
|
173 |
|
|
{ 0x0, 0x0 }
|
174 |
|
|
};
|
175 |
|
|
|
176 |
|
|
/* same as in type 2 models */
|
177 |
|
|
static struct sonypi_ioport_list *sonypi_type3_ioport_list =
|
178 |
|
|
sonypi_type2_ioport_list;
|
179 |
|
|
|
180 |
|
|
/* The set of possible interrupts */
|
181 |
|
|
struct sonypi_irq_list {
|
182 |
|
|
u16 irq;
|
183 |
|
|
u16 bits;
|
184 |
|
|
};
|
185 |
|
|
|
186 |
|
|
static struct sonypi_irq_list sonypi_type1_irq_list[] = {
|
187 |
|
|
{ 11, 0x2 }, /* IRQ 11, GO22=0,GO23=1 in AML */
|
188 |
|
|
{ 10, 0x1 }, /* IRQ 10, GO22=1,GO23=0 in AML */
|
189 |
|
|
{ 5, 0x0 }, /* IRQ 5, GO22=0,GO23=0 in AML */
|
190 |
|
|
{ 0, 0x3 } /* no IRQ, GO22=1,GO23=1 in AML */
|
191 |
|
|
};
|
192 |
|
|
|
193 |
|
|
static struct sonypi_irq_list sonypi_type2_irq_list[] = {
|
194 |
|
|
{ 11, 0x80 }, /* IRQ 11, 0x80 in SIRQ in AML */
|
195 |
|
|
{ 10, 0x40 }, /* IRQ 10, 0x40 in SIRQ in AML */
|
196 |
|
|
{ 9, 0x20 }, /* IRQ 9, 0x20 in SIRQ in AML */
|
197 |
|
|
{ 6, 0x10 }, /* IRQ 6, 0x10 in SIRQ in AML */
|
198 |
|
|
{ 0, 0x00 } /* no IRQ, 0x00 in SIRQ in AML */
|
199 |
|
|
};
|
200 |
|
|
|
201 |
|
|
/* same as in type2 models */
|
202 |
|
|
static struct sonypi_irq_list *sonypi_type3_irq_list = sonypi_type2_irq_list;
|
203 |
|
|
|
204 |
|
|
#define SONYPI_CAMERA_BRIGHTNESS 0
|
205 |
|
|
#define SONYPI_CAMERA_CONTRAST 1
|
206 |
|
|
#define SONYPI_CAMERA_HUE 2
|
207 |
|
|
#define SONYPI_CAMERA_COLOR 3
|
208 |
|
|
#define SONYPI_CAMERA_SHARPNESS 4
|
209 |
|
|
|
210 |
|
|
#define SONYPI_CAMERA_PICTURE 5
|
211 |
|
|
#define SONYPI_CAMERA_EXPOSURE_MASK 0xC
|
212 |
|
|
#define SONYPI_CAMERA_WHITE_BALANCE_MASK 0x3
|
213 |
|
|
#define SONYPI_CAMERA_PICTURE_MODE_MASK 0x30
|
214 |
|
|
#define SONYPI_CAMERA_MUTE_MASK 0x40
|
215 |
|
|
|
216 |
|
|
/* the rest don't need a loop until not 0xff */
|
217 |
|
|
#define SONYPI_CAMERA_AGC 6
|
218 |
|
|
#define SONYPI_CAMERA_AGC_MASK 0x30
|
219 |
|
|
#define SONYPI_CAMERA_SHUTTER_MASK 0x7
|
220 |
|
|
|
221 |
|
|
#define SONYPI_CAMERA_SHUTDOWN_REQUEST 7
|
222 |
|
|
#define SONYPI_CAMERA_CONTROL 0x10
|
223 |
|
|
|
224 |
|
|
#define SONYPI_CAMERA_STATUS 7
|
225 |
|
|
#define SONYPI_CAMERA_STATUS_READY 0x2
|
226 |
|
|
#define SONYPI_CAMERA_STATUS_POSITION 0x4
|
227 |
|
|
|
228 |
|
|
#define SONYPI_DIRECTION_BACKWARDS 0x4
|
229 |
|
|
|
230 |
|
|
#define SONYPI_CAMERA_REVISION 8
|
231 |
|
|
#define SONYPI_CAMERA_ROMVERSION 9
|
232 |
|
|
|
233 |
|
|
/* Event masks */
|
234 |
|
|
#define SONYPI_JOGGER_MASK 0x00000001
|
235 |
|
|
#define SONYPI_CAPTURE_MASK 0x00000002
|
236 |
|
|
#define SONYPI_FNKEY_MASK 0x00000004
|
237 |
|
|
#define SONYPI_BLUETOOTH_MASK 0x00000008
|
238 |
|
|
#define SONYPI_PKEY_MASK 0x00000010
|
239 |
|
|
#define SONYPI_BACK_MASK 0x00000020
|
240 |
|
|
#define SONYPI_HELP_MASK 0x00000040
|
241 |
|
|
#define SONYPI_LID_MASK 0x00000080
|
242 |
|
|
#define SONYPI_ZOOM_MASK 0x00000100
|
243 |
|
|
#define SONYPI_THUMBPHRASE_MASK 0x00000200
|
244 |
|
|
#define SONYPI_MEYE_MASK 0x00000400
|
245 |
|
|
#define SONYPI_MEMORYSTICK_MASK 0x00000800
|
246 |
|
|
#define SONYPI_BATTERY_MASK 0x00001000
|
247 |
|
|
#define SONYPI_WIRELESS_MASK 0x00002000
|
248 |
|
|
|
249 |
|
|
struct sonypi_event {
|
250 |
|
|
u8 data;
|
251 |
|
|
u8 event;
|
252 |
|
|
};
|
253 |
|
|
|
254 |
|
|
/* The set of possible button release events */
|
255 |
|
|
static struct sonypi_event sonypi_releaseev[] = {
|
256 |
|
|
{ 0x00, SONYPI_EVENT_ANYBUTTON_RELEASED },
|
257 |
|
|
{ 0, 0 }
|
258 |
|
|
};
|
259 |
|
|
|
260 |
|
|
/* The set of possible jogger events */
|
261 |
|
|
static struct sonypi_event sonypi_joggerev[] = {
|
262 |
|
|
{ 0x1f, SONYPI_EVENT_JOGDIAL_UP },
|
263 |
|
|
{ 0x01, SONYPI_EVENT_JOGDIAL_DOWN },
|
264 |
|
|
{ 0x5f, SONYPI_EVENT_JOGDIAL_UP_PRESSED },
|
265 |
|
|
{ 0x41, SONYPI_EVENT_JOGDIAL_DOWN_PRESSED },
|
266 |
|
|
{ 0x1e, SONYPI_EVENT_JOGDIAL_FAST_UP },
|
267 |
|
|
{ 0x02, SONYPI_EVENT_JOGDIAL_FAST_DOWN },
|
268 |
|
|
{ 0x5e, SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED },
|
269 |
|
|
{ 0x42, SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED },
|
270 |
|
|
{ 0x1d, SONYPI_EVENT_JOGDIAL_VFAST_UP },
|
271 |
|
|
{ 0x03, SONYPI_EVENT_JOGDIAL_VFAST_DOWN },
|
272 |
|
|
{ 0x5d, SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED },
|
273 |
|
|
{ 0x43, SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED },
|
274 |
|
|
{ 0x40, SONYPI_EVENT_JOGDIAL_PRESSED },
|
275 |
|
|
{ 0, 0 }
|
276 |
|
|
};
|
277 |
|
|
|
278 |
|
|
/* The set of possible capture button events */
|
279 |
|
|
static struct sonypi_event sonypi_captureev[] = {
|
280 |
|
|
{ 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED },
|
281 |
|
|
{ 0x07, SONYPI_EVENT_CAPTURE_PRESSED },
|
282 |
|
|
{ 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED },
|
283 |
|
|
{ 0, 0 }
|
284 |
|
|
};
|
285 |
|
|
|
286 |
|
|
/* The set of possible fnkeys events */
|
287 |
|
|
static struct sonypi_event sonypi_fnkeyev[] = {
|
288 |
|
|
{ 0x10, SONYPI_EVENT_FNKEY_ESC },
|
289 |
|
|
{ 0x11, SONYPI_EVENT_FNKEY_F1 },
|
290 |
|
|
{ 0x12, SONYPI_EVENT_FNKEY_F2 },
|
291 |
|
|
{ 0x13, SONYPI_EVENT_FNKEY_F3 },
|
292 |
|
|
{ 0x14, SONYPI_EVENT_FNKEY_F4 },
|
293 |
|
|
{ 0x15, SONYPI_EVENT_FNKEY_F5 },
|
294 |
|
|
{ 0x16, SONYPI_EVENT_FNKEY_F6 },
|
295 |
|
|
{ 0x17, SONYPI_EVENT_FNKEY_F7 },
|
296 |
|
|
{ 0x18, SONYPI_EVENT_FNKEY_F8 },
|
297 |
|
|
{ 0x19, SONYPI_EVENT_FNKEY_F9 },
|
298 |
|
|
{ 0x1a, SONYPI_EVENT_FNKEY_F10 },
|
299 |
|
|
{ 0x1b, SONYPI_EVENT_FNKEY_F11 },
|
300 |
|
|
{ 0x1c, SONYPI_EVENT_FNKEY_F12 },
|
301 |
|
|
{ 0x1f, SONYPI_EVENT_FNKEY_RELEASED },
|
302 |
|
|
{ 0x21, SONYPI_EVENT_FNKEY_1 },
|
303 |
|
|
{ 0x22, SONYPI_EVENT_FNKEY_2 },
|
304 |
|
|
{ 0x31, SONYPI_EVENT_FNKEY_D },
|
305 |
|
|
{ 0x32, SONYPI_EVENT_FNKEY_E },
|
306 |
|
|
{ 0x33, SONYPI_EVENT_FNKEY_F },
|
307 |
|
|
{ 0x34, SONYPI_EVENT_FNKEY_S },
|
308 |
|
|
{ 0x35, SONYPI_EVENT_FNKEY_B },
|
309 |
|
|
{ 0x36, SONYPI_EVENT_FNKEY_ONLY },
|
310 |
|
|
{ 0, 0 }
|
311 |
|
|
};
|
312 |
|
|
|
313 |
|
|
/* The set of possible program key events */
|
314 |
|
|
static struct sonypi_event sonypi_pkeyev[] = {
|
315 |
|
|
{ 0x01, SONYPI_EVENT_PKEY_P1 },
|
316 |
|
|
{ 0x02, SONYPI_EVENT_PKEY_P2 },
|
317 |
|
|
{ 0x04, SONYPI_EVENT_PKEY_P3 },
|
318 |
|
|
{ 0x5c, SONYPI_EVENT_PKEY_P1 },
|
319 |
|
|
{ 0, 0 }
|
320 |
|
|
};
|
321 |
|
|
|
322 |
|
|
/* The set of possible bluetooth events */
|
323 |
|
|
static struct sonypi_event sonypi_blueev[] = {
|
324 |
|
|
{ 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED },
|
325 |
|
|
{ 0x59, SONYPI_EVENT_BLUETOOTH_ON },
|
326 |
|
|
{ 0x5a, SONYPI_EVENT_BLUETOOTH_OFF },
|
327 |
|
|
{ 0, 0 }
|
328 |
|
|
};
|
329 |
|
|
|
330 |
|
|
/* The set of possible wireless events */
|
331 |
|
|
static struct sonypi_event sonypi_wlessev[] = {
|
332 |
|
|
{ 0x59, SONYPI_EVENT_WIRELESS_ON },
|
333 |
|
|
{ 0x5a, SONYPI_EVENT_WIRELESS_OFF },
|
334 |
|
|
{ 0, 0 }
|
335 |
|
|
};
|
336 |
|
|
|
337 |
|
|
/* The set of possible back button events */
|
338 |
|
|
static struct sonypi_event sonypi_backev[] = {
|
339 |
|
|
{ 0x20, SONYPI_EVENT_BACK_PRESSED },
|
340 |
|
|
{ 0, 0 }
|
341 |
|
|
};
|
342 |
|
|
|
343 |
|
|
/* The set of possible help button events */
|
344 |
|
|
static struct sonypi_event sonypi_helpev[] = {
|
345 |
|
|
{ 0x3b, SONYPI_EVENT_HELP_PRESSED },
|
346 |
|
|
{ 0, 0 }
|
347 |
|
|
};
|
348 |
|
|
|
349 |
|
|
|
350 |
|
|
/* The set of possible lid events */
|
351 |
|
|
static struct sonypi_event sonypi_lidev[] = {
|
352 |
|
|
{ 0x51, SONYPI_EVENT_LID_CLOSED },
|
353 |
|
|
{ 0x50, SONYPI_EVENT_LID_OPENED },
|
354 |
|
|
{ 0, 0 }
|
355 |
|
|
};
|
356 |
|
|
|
357 |
|
|
/* The set of possible zoom events */
|
358 |
|
|
static struct sonypi_event sonypi_zoomev[] = {
|
359 |
|
|
{ 0x39, SONYPI_EVENT_ZOOM_PRESSED },
|
360 |
|
|
{ 0, 0 }
|
361 |
|
|
};
|
362 |
|
|
|
363 |
|
|
/* The set of possible thumbphrase events */
|
364 |
|
|
static struct sonypi_event sonypi_thumbphraseev[] = {
|
365 |
|
|
{ 0x3a, SONYPI_EVENT_THUMBPHRASE_PRESSED },
|
366 |
|
|
{ 0, 0 }
|
367 |
|
|
};
|
368 |
|
|
|
369 |
|
|
/* The set of possible motioneye camera events */
|
370 |
|
|
static struct sonypi_event sonypi_meyeev[] = {
|
371 |
|
|
{ 0x00, SONYPI_EVENT_MEYE_FACE },
|
372 |
|
|
{ 0x01, SONYPI_EVENT_MEYE_OPPOSITE },
|
373 |
|
|
{ 0, 0 }
|
374 |
|
|
};
|
375 |
|
|
|
376 |
|
|
/* The set of possible memorystick events */
|
377 |
|
|
static struct sonypi_event sonypi_memorystickev[] = {
|
378 |
|
|
{ 0x53, SONYPI_EVENT_MEMORYSTICK_INSERT },
|
379 |
|
|
{ 0x54, SONYPI_EVENT_MEMORYSTICK_EJECT },
|
380 |
|
|
{ 0, 0 }
|
381 |
|
|
};
|
382 |
|
|
|
383 |
|
|
/* The set of possible battery events */
|
384 |
|
|
static struct sonypi_event sonypi_batteryev[] = {
|
385 |
|
|
{ 0x20, SONYPI_EVENT_BATTERY_INSERT },
|
386 |
|
|
{ 0x30, SONYPI_EVENT_BATTERY_REMOVE },
|
387 |
|
|
{ 0, 0 }
|
388 |
|
|
};
|
389 |
|
|
|
390 |
|
|
static struct sonypi_eventtypes {
|
391 |
|
|
int model;
|
392 |
|
|
u8 data;
|
393 |
|
|
unsigned long mask;
|
394 |
|
|
struct sonypi_event * events;
|
395 |
|
|
} sonypi_eventtypes[] = {
|
396 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE1, 0, 0xffffffff, sonypi_releaseev },
|
397 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE1, 0x70, SONYPI_MEYE_MASK, sonypi_meyeev },
|
398 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE1, 0x30, SONYPI_LID_MASK, sonypi_lidev },
|
399 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE1, 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev },
|
400 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE1, 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev },
|
401 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE1, 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
|
402 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE1, 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
|
403 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE1, 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
|
404 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE1, 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
|
405 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE1, 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev },
|
406 |
|
|
|
407 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE2, 0, 0xffffffff, sonypi_releaseev },
|
408 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE2, 0x38, SONYPI_LID_MASK, sonypi_lidev },
|
409 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE2, 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev },
|
410 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE2, 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev },
|
411 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
|
412 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
|
413 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
|
414 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE2, 0x11, SONYPI_BACK_MASK, sonypi_backev },
|
415 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_HELP_MASK, sonypi_helpev },
|
416 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev },
|
417 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE2, 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
|
418 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
|
419 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE2, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
|
420 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
|
421 |
|
|
|
422 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE3, 0, 0xffffffff, sonypi_releaseev },
|
423 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE3, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
|
424 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
|
425 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
|
426 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE3, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
|
427 |
|
|
{ SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
|
428 |
|
|
{ 0 }
|
429 |
|
|
};
|
430 |
|
|
|
431 |
|
|
#define SONYPI_BUF_SIZE 128
|
432 |
|
|
|
433 |
|
|
/* Correspondance table between sonypi events and input layer events */
|
434 |
|
|
static struct {
|
435 |
|
|
int sonypiev;
|
436 |
|
|
int inputev;
|
437 |
|
|
} sonypi_inputkeys[] = {
|
438 |
|
|
{ SONYPI_EVENT_CAPTURE_PRESSED, KEY_CAMERA },
|
439 |
|
|
{ SONYPI_EVENT_FNKEY_ONLY, KEY_FN },
|
440 |
|
|
{ SONYPI_EVENT_FNKEY_ESC, KEY_FN_ESC },
|
441 |
|
|
{ SONYPI_EVENT_FNKEY_F1, KEY_FN_F1 },
|
442 |
|
|
{ SONYPI_EVENT_FNKEY_F2, KEY_FN_F2 },
|
443 |
|
|
{ SONYPI_EVENT_FNKEY_F3, KEY_FN_F3 },
|
444 |
|
|
{ SONYPI_EVENT_FNKEY_F4, KEY_FN_F4 },
|
445 |
|
|
{ SONYPI_EVENT_FNKEY_F5, KEY_FN_F5 },
|
446 |
|
|
{ SONYPI_EVENT_FNKEY_F6, KEY_FN_F6 },
|
447 |
|
|
{ SONYPI_EVENT_FNKEY_F7, KEY_FN_F7 },
|
448 |
|
|
{ SONYPI_EVENT_FNKEY_F8, KEY_FN_F8 },
|
449 |
|
|
{ SONYPI_EVENT_FNKEY_F9, KEY_FN_F9 },
|
450 |
|
|
{ SONYPI_EVENT_FNKEY_F10, KEY_FN_F10 },
|
451 |
|
|
{ SONYPI_EVENT_FNKEY_F11, KEY_FN_F11 },
|
452 |
|
|
{ SONYPI_EVENT_FNKEY_F12, KEY_FN_F12 },
|
453 |
|
|
{ SONYPI_EVENT_FNKEY_1, KEY_FN_1 },
|
454 |
|
|
{ SONYPI_EVENT_FNKEY_2, KEY_FN_2 },
|
455 |
|
|
{ SONYPI_EVENT_FNKEY_D, KEY_FN_D },
|
456 |
|
|
{ SONYPI_EVENT_FNKEY_E, KEY_FN_E },
|
457 |
|
|
{ SONYPI_EVENT_FNKEY_F, KEY_FN_F },
|
458 |
|
|
{ SONYPI_EVENT_FNKEY_S, KEY_FN_S },
|
459 |
|
|
{ SONYPI_EVENT_FNKEY_B, KEY_FN_B },
|
460 |
|
|
{ SONYPI_EVENT_BLUETOOTH_PRESSED, KEY_BLUE },
|
461 |
|
|
{ SONYPI_EVENT_BLUETOOTH_ON, KEY_BLUE },
|
462 |
|
|
{ SONYPI_EVENT_PKEY_P1, KEY_PROG1 },
|
463 |
|
|
{ SONYPI_EVENT_PKEY_P2, KEY_PROG2 },
|
464 |
|
|
{ SONYPI_EVENT_PKEY_P3, KEY_PROG3 },
|
465 |
|
|
{ SONYPI_EVENT_BACK_PRESSED, KEY_BACK },
|
466 |
|
|
{ SONYPI_EVENT_HELP_PRESSED, KEY_HELP },
|
467 |
|
|
{ SONYPI_EVENT_ZOOM_PRESSED, KEY_ZOOM },
|
468 |
|
|
{ SONYPI_EVENT_THUMBPHRASE_PRESSED, BTN_THUMB },
|
469 |
|
|
{ 0, 0 },
|
470 |
|
|
};
|
471 |
|
|
|
472 |
|
|
struct sonypi_keypress {
|
473 |
|
|
struct input_dev *dev;
|
474 |
|
|
int key;
|
475 |
|
|
};
|
476 |
|
|
|
477 |
|
|
static struct sonypi_device {
|
478 |
|
|
struct pci_dev *dev;
|
479 |
|
|
u16 irq;
|
480 |
|
|
u16 bits;
|
481 |
|
|
u16 ioport1;
|
482 |
|
|
u16 ioport2;
|
483 |
|
|
u16 region_size;
|
484 |
|
|
u16 evtype_offset;
|
485 |
|
|
int camera_power;
|
486 |
|
|
int bluetooth_power;
|
487 |
|
|
struct mutex lock;
|
488 |
|
|
struct kfifo *fifo;
|
489 |
|
|
spinlock_t fifo_lock;
|
490 |
|
|
wait_queue_head_t fifo_proc_list;
|
491 |
|
|
struct fasync_struct *fifo_async;
|
492 |
|
|
int open_count;
|
493 |
|
|
int model;
|
494 |
|
|
struct input_dev *input_jog_dev;
|
495 |
|
|
struct input_dev *input_key_dev;
|
496 |
|
|
struct work_struct input_work;
|
497 |
|
|
struct kfifo *input_fifo;
|
498 |
|
|
spinlock_t input_fifo_lock;
|
499 |
|
|
} sonypi_device;
|
500 |
|
|
|
501 |
|
|
#define ITERATIONS_LONG 10000
|
502 |
|
|
#define ITERATIONS_SHORT 10
|
503 |
|
|
|
504 |
|
|
#define wait_on_command(quiet, command, iterations) { \
|
505 |
|
|
unsigned int n = iterations; \
|
506 |
|
|
while (--n && (command)) \
|
507 |
|
|
udelay(1); \
|
508 |
|
|
if (!n && (verbose || !quiet)) \
|
509 |
|
|
printk(KERN_WARNING "sonypi command failed at %s : %s (line %d)\n", __FILE__, __FUNCTION__, __LINE__); \
|
510 |
|
|
}
|
511 |
|
|
|
512 |
|
|
#ifdef CONFIG_ACPI
|
513 |
|
|
#define SONYPI_ACPI_ACTIVE (!acpi_disabled)
|
514 |
|
|
#else
|
515 |
|
|
#define SONYPI_ACPI_ACTIVE 0
|
516 |
|
|
#endif /* CONFIG_ACPI */
|
517 |
|
|
|
518 |
|
|
#ifdef CONFIG_ACPI
|
519 |
|
|
static struct acpi_device *sonypi_acpi_device;
|
520 |
|
|
static int acpi_driver_registered;
|
521 |
|
|
#endif
|
522 |
|
|
|
523 |
|
|
static int sonypi_ec_write(u8 addr, u8 value)
|
524 |
|
|
{
|
525 |
|
|
#ifdef CONFIG_ACPI_EC
|
526 |
|
|
if (SONYPI_ACPI_ACTIVE)
|
527 |
|
|
return ec_write(addr, value);
|
528 |
|
|
#endif
|
529 |
|
|
wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3, ITERATIONS_LONG);
|
530 |
|
|
outb_p(0x81, SONYPI_CST_IOPORT);
|
531 |
|
|
wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
|
532 |
|
|
outb_p(addr, SONYPI_DATA_IOPORT);
|
533 |
|
|
wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
|
534 |
|
|
outb_p(value, SONYPI_DATA_IOPORT);
|
535 |
|
|
wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
|
536 |
|
|
return 0;
|
537 |
|
|
}
|
538 |
|
|
|
539 |
|
|
static int sonypi_ec_read(u8 addr, u8 *value)
|
540 |
|
|
{
|
541 |
|
|
#ifdef CONFIG_ACPI_EC
|
542 |
|
|
if (SONYPI_ACPI_ACTIVE)
|
543 |
|
|
return ec_read(addr, value);
|
544 |
|
|
#endif
|
545 |
|
|
wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3, ITERATIONS_LONG);
|
546 |
|
|
outb_p(0x80, SONYPI_CST_IOPORT);
|
547 |
|
|
wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
|
548 |
|
|
outb_p(addr, SONYPI_DATA_IOPORT);
|
549 |
|
|
wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
|
550 |
|
|
*value = inb_p(SONYPI_DATA_IOPORT);
|
551 |
|
|
return 0;
|
552 |
|
|
}
|
553 |
|
|
|
554 |
|
|
static int ec_read16(u8 addr, u16 *value)
|
555 |
|
|
{
|
556 |
|
|
u8 val_lb, val_hb;
|
557 |
|
|
if (sonypi_ec_read(addr, &val_lb))
|
558 |
|
|
return -1;
|
559 |
|
|
if (sonypi_ec_read(addr + 1, &val_hb))
|
560 |
|
|
return -1;
|
561 |
|
|
*value = val_lb | (val_hb << 8);
|
562 |
|
|
return 0;
|
563 |
|
|
}
|
564 |
|
|
|
565 |
|
|
/* Initializes the device - this comes from the AML code in the ACPI bios */
|
566 |
|
|
static void sonypi_type1_srs(void)
|
567 |
|
|
{
|
568 |
|
|
u32 v;
|
569 |
|
|
|
570 |
|
|
pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
|
571 |
|
|
v = (v & 0xFFFF0000) | ((u32) sonypi_device.ioport1);
|
572 |
|
|
pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
|
573 |
|
|
|
574 |
|
|
pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
|
575 |
|
|
v = (v & 0xFFF0FFFF) |
|
576 |
|
|
(((u32) sonypi_device.ioport1 ^ sonypi_device.ioport2) << 16);
|
577 |
|
|
pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
|
578 |
|
|
|
579 |
|
|
v = inl(SONYPI_IRQ_PORT);
|
580 |
|
|
v &= ~(((u32) 0x3) << SONYPI_IRQ_SHIFT);
|
581 |
|
|
v |= (((u32) sonypi_device.bits) << SONYPI_IRQ_SHIFT);
|
582 |
|
|
outl(v, SONYPI_IRQ_PORT);
|
583 |
|
|
|
584 |
|
|
pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
|
585 |
|
|
v = (v & 0xFF1FFFFF) | 0x00C00000;
|
586 |
|
|
pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
|
587 |
|
|
}
|
588 |
|
|
|
589 |
|
|
static void sonypi_type2_srs(void)
|
590 |
|
|
{
|
591 |
|
|
if (sonypi_ec_write(SONYPI_SHIB, (sonypi_device.ioport1 & 0xFF00) >> 8))
|
592 |
|
|
printk(KERN_WARNING "ec_write failed\n");
|
593 |
|
|
if (sonypi_ec_write(SONYPI_SLOB, sonypi_device.ioport1 & 0x00FF))
|
594 |
|
|
printk(KERN_WARNING "ec_write failed\n");
|
595 |
|
|
if (sonypi_ec_write(SONYPI_SIRQ, sonypi_device.bits))
|
596 |
|
|
printk(KERN_WARNING "ec_write failed\n");
|
597 |
|
|
udelay(10);
|
598 |
|
|
}
|
599 |
|
|
|
600 |
|
|
static void sonypi_type3_srs(void)
|
601 |
|
|
{
|
602 |
|
|
u16 v16;
|
603 |
|
|
u8 v8;
|
604 |
|
|
|
605 |
|
|
/* This model type uses the same initialiazation of
|
606 |
|
|
* the embedded controller as the type2 models. */
|
607 |
|
|
sonypi_type2_srs();
|
608 |
|
|
|
609 |
|
|
/* Initialization of PCI config space of the LPC interface bridge. */
|
610 |
|
|
v16 = (sonypi_device.ioport1 & 0xFFF0) | 0x01;
|
611 |
|
|
pci_write_config_word(sonypi_device.dev, SONYPI_TYPE3_GID2, v16);
|
612 |
|
|
pci_read_config_byte(sonypi_device.dev, SONYPI_TYPE3_MISC, &v8);
|
613 |
|
|
v8 = (v8 & 0xCF) | 0x10;
|
614 |
|
|
pci_write_config_byte(sonypi_device.dev, SONYPI_TYPE3_MISC, v8);
|
615 |
|
|
}
|
616 |
|
|
|
617 |
|
|
/* Disables the device - this comes from the AML code in the ACPI bios */
|
618 |
|
|
static void sonypi_type1_dis(void)
|
619 |
|
|
{
|
620 |
|
|
u32 v;
|
621 |
|
|
|
622 |
|
|
pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
|
623 |
|
|
v = v & 0xFF3FFFFF;
|
624 |
|
|
pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
|
625 |
|
|
|
626 |
|
|
v = inl(SONYPI_IRQ_PORT);
|
627 |
|
|
v |= (0x3 << SONYPI_IRQ_SHIFT);
|
628 |
|
|
outl(v, SONYPI_IRQ_PORT);
|
629 |
|
|
}
|
630 |
|
|
|
631 |
|
|
static void sonypi_type2_dis(void)
|
632 |
|
|
{
|
633 |
|
|
if (sonypi_ec_write(SONYPI_SHIB, 0))
|
634 |
|
|
printk(KERN_WARNING "ec_write failed\n");
|
635 |
|
|
if (sonypi_ec_write(SONYPI_SLOB, 0))
|
636 |
|
|
printk(KERN_WARNING "ec_write failed\n");
|
637 |
|
|
if (sonypi_ec_write(SONYPI_SIRQ, 0))
|
638 |
|
|
printk(KERN_WARNING "ec_write failed\n");
|
639 |
|
|
}
|
640 |
|
|
|
641 |
|
|
static void sonypi_type3_dis(void)
|
642 |
|
|
{
|
643 |
|
|
sonypi_type2_dis();
|
644 |
|
|
udelay(10);
|
645 |
|
|
pci_write_config_word(sonypi_device.dev, SONYPI_TYPE3_GID2, 0);
|
646 |
|
|
}
|
647 |
|
|
|
648 |
|
|
static u8 sonypi_call1(u8 dev)
|
649 |
|
|
{
|
650 |
|
|
u8 v1, v2;
|
651 |
|
|
|
652 |
|
|
wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
|
653 |
|
|
outb(dev, sonypi_device.ioport2);
|
654 |
|
|
v1 = inb_p(sonypi_device.ioport2);
|
655 |
|
|
v2 = inb_p(sonypi_device.ioport1);
|
656 |
|
|
return v2;
|
657 |
|
|
}
|
658 |
|
|
|
659 |
|
|
static u8 sonypi_call2(u8 dev, u8 fn)
|
660 |
|
|
{
|
661 |
|
|
u8 v1;
|
662 |
|
|
|
663 |
|
|
wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
|
664 |
|
|
outb(dev, sonypi_device.ioport2);
|
665 |
|
|
wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
|
666 |
|
|
outb(fn, sonypi_device.ioport1);
|
667 |
|
|
v1 = inb_p(sonypi_device.ioport1);
|
668 |
|
|
return v1;
|
669 |
|
|
}
|
670 |
|
|
|
671 |
|
|
static u8 sonypi_call3(u8 dev, u8 fn, u8 v)
|
672 |
|
|
{
|
673 |
|
|
u8 v1;
|
674 |
|
|
|
675 |
|
|
wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
|
676 |
|
|
outb(dev, sonypi_device.ioport2);
|
677 |
|
|
wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
|
678 |
|
|
outb(fn, sonypi_device.ioport1);
|
679 |
|
|
wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
|
680 |
|
|
outb(v, sonypi_device.ioport1);
|
681 |
|
|
v1 = inb_p(sonypi_device.ioport1);
|
682 |
|
|
return v1;
|
683 |
|
|
}
|
684 |
|
|
|
685 |
|
|
#if 0
|
686 |
|
|
/* Get brightness, hue etc. Unreliable... */
|
687 |
|
|
static u8 sonypi_read(u8 fn)
|
688 |
|
|
{
|
689 |
|
|
u8 v1, v2;
|
690 |
|
|
int n = 100;
|
691 |
|
|
|
692 |
|
|
while (n--) {
|
693 |
|
|
v1 = sonypi_call2(0x8f, fn);
|
694 |
|
|
v2 = sonypi_call2(0x8f, fn);
|
695 |
|
|
if (v1 == v2 && v1 != 0xff)
|
696 |
|
|
return v1;
|
697 |
|
|
}
|
698 |
|
|
return 0xff;
|
699 |
|
|
}
|
700 |
|
|
#endif
|
701 |
|
|
|
702 |
|
|
/* Set brightness, hue etc */
|
703 |
|
|
static void sonypi_set(u8 fn, u8 v)
|
704 |
|
|
{
|
705 |
|
|
wait_on_command(0, sonypi_call3(0x90, fn, v), ITERATIONS_SHORT);
|
706 |
|
|
}
|
707 |
|
|
|
708 |
|
|
/* Tests if the camera is ready */
|
709 |
|
|
static int sonypi_camera_ready(void)
|
710 |
|
|
{
|
711 |
|
|
u8 v;
|
712 |
|
|
|
713 |
|
|
v = sonypi_call2(0x8f, SONYPI_CAMERA_STATUS);
|
714 |
|
|
return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY));
|
715 |
|
|
}
|
716 |
|
|
|
717 |
|
|
/* Turns the camera off */
|
718 |
|
|
static void sonypi_camera_off(void)
|
719 |
|
|
{
|
720 |
|
|
sonypi_set(SONYPI_CAMERA_PICTURE, SONYPI_CAMERA_MUTE_MASK);
|
721 |
|
|
|
722 |
|
|
if (!sonypi_device.camera_power)
|
723 |
|
|
return;
|
724 |
|
|
|
725 |
|
|
sonypi_call2(0x91, 0);
|
726 |
|
|
sonypi_device.camera_power = 0;
|
727 |
|
|
}
|
728 |
|
|
|
729 |
|
|
/* Turns the camera on */
|
730 |
|
|
static void sonypi_camera_on(void)
|
731 |
|
|
{
|
732 |
|
|
int i, j;
|
733 |
|
|
|
734 |
|
|
if (sonypi_device.camera_power)
|
735 |
|
|
return;
|
736 |
|
|
|
737 |
|
|
for (j = 5; j > 0; j--) {
|
738 |
|
|
|
739 |
|
|
while (sonypi_call2(0x91, 0x1))
|
740 |
|
|
msleep(10);
|
741 |
|
|
sonypi_call1(0x93);
|
742 |
|
|
|
743 |
|
|
for (i = 400; i > 0; i--) {
|
744 |
|
|
if (sonypi_camera_ready())
|
745 |
|
|
break;
|
746 |
|
|
msleep(10);
|
747 |
|
|
}
|
748 |
|
|
if (i)
|
749 |
|
|
break;
|
750 |
|
|
}
|
751 |
|
|
|
752 |
|
|
if (j == 0) {
|
753 |
|
|
printk(KERN_WARNING "sonypi: failed to power on camera\n");
|
754 |
|
|
return;
|
755 |
|
|
}
|
756 |
|
|
|
757 |
|
|
sonypi_set(0x10, 0x5a);
|
758 |
|
|
sonypi_device.camera_power = 1;
|
759 |
|
|
}
|
760 |
|
|
|
761 |
|
|
/* sets the bluetooth subsystem power state */
|
762 |
|
|
static void sonypi_setbluetoothpower(u8 state)
|
763 |
|
|
{
|
764 |
|
|
state = !!state;
|
765 |
|
|
|
766 |
|
|
if (sonypi_device.bluetooth_power == state)
|
767 |
|
|
return;
|
768 |
|
|
|
769 |
|
|
sonypi_call2(0x96, state);
|
770 |
|
|
sonypi_call1(0x82);
|
771 |
|
|
sonypi_device.bluetooth_power = state;
|
772 |
|
|
}
|
773 |
|
|
|
774 |
|
|
static void input_keyrelease(struct work_struct *work)
|
775 |
|
|
{
|
776 |
|
|
struct sonypi_keypress kp;
|
777 |
|
|
|
778 |
|
|
while (kfifo_get(sonypi_device.input_fifo, (unsigned char *)&kp,
|
779 |
|
|
sizeof(kp)) == sizeof(kp)) {
|
780 |
|
|
msleep(10);
|
781 |
|
|
input_report_key(kp.dev, kp.key, 0);
|
782 |
|
|
input_sync(kp.dev);
|
783 |
|
|
}
|
784 |
|
|
}
|
785 |
|
|
|
786 |
|
|
static void sonypi_report_input_event(u8 event)
|
787 |
|
|
{
|
788 |
|
|
struct input_dev *jog_dev = sonypi_device.input_jog_dev;
|
789 |
|
|
struct input_dev *key_dev = sonypi_device.input_key_dev;
|
790 |
|
|
struct sonypi_keypress kp = { NULL };
|
791 |
|
|
int i;
|
792 |
|
|
|
793 |
|
|
switch (event) {
|
794 |
|
|
case SONYPI_EVENT_JOGDIAL_UP:
|
795 |
|
|
case SONYPI_EVENT_JOGDIAL_UP_PRESSED:
|
796 |
|
|
input_report_rel(jog_dev, REL_WHEEL, 1);
|
797 |
|
|
input_sync(jog_dev);
|
798 |
|
|
break;
|
799 |
|
|
|
800 |
|
|
case SONYPI_EVENT_JOGDIAL_DOWN:
|
801 |
|
|
case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED:
|
802 |
|
|
input_report_rel(jog_dev, REL_WHEEL, -1);
|
803 |
|
|
input_sync(jog_dev);
|
804 |
|
|
break;
|
805 |
|
|
|
806 |
|
|
case SONYPI_EVENT_JOGDIAL_PRESSED:
|
807 |
|
|
kp.key = BTN_MIDDLE;
|
808 |
|
|
kp.dev = jog_dev;
|
809 |
|
|
break;
|
810 |
|
|
|
811 |
|
|
case SONYPI_EVENT_FNKEY_RELEASED:
|
812 |
|
|
/* Nothing, not all VAIOs generate this event */
|
813 |
|
|
break;
|
814 |
|
|
|
815 |
|
|
default:
|
816 |
|
|
for (i = 0; sonypi_inputkeys[i].sonypiev; i++)
|
817 |
|
|
if (event == sonypi_inputkeys[i].sonypiev) {
|
818 |
|
|
kp.dev = key_dev;
|
819 |
|
|
kp.key = sonypi_inputkeys[i].inputev;
|
820 |
|
|
break;
|
821 |
|
|
}
|
822 |
|
|
break;
|
823 |
|
|
}
|
824 |
|
|
|
825 |
|
|
if (kp.dev) {
|
826 |
|
|
input_report_key(kp.dev, kp.key, 1);
|
827 |
|
|
input_sync(kp.dev);
|
828 |
|
|
kfifo_put(sonypi_device.input_fifo,
|
829 |
|
|
(unsigned char *)&kp, sizeof(kp));
|
830 |
|
|
schedule_work(&sonypi_device.input_work);
|
831 |
|
|
}
|
832 |
|
|
}
|
833 |
|
|
|
834 |
|
|
/* Interrupt handler: some event is available */
|
835 |
|
|
static irqreturn_t sonypi_irq(int irq, void *dev_id)
|
836 |
|
|
{
|
837 |
|
|
u8 v1, v2, event = 0;
|
838 |
|
|
int i, j;
|
839 |
|
|
|
840 |
|
|
v1 = inb_p(sonypi_device.ioport1);
|
841 |
|
|
v2 = inb_p(sonypi_device.ioport1 + sonypi_device.evtype_offset);
|
842 |
|
|
|
843 |
|
|
for (i = 0; sonypi_eventtypes[i].model; i++) {
|
844 |
|
|
if (sonypi_device.model != sonypi_eventtypes[i].model)
|
845 |
|
|
continue;
|
846 |
|
|
if ((v2 & sonypi_eventtypes[i].data) !=
|
847 |
|
|
sonypi_eventtypes[i].data)
|
848 |
|
|
continue;
|
849 |
|
|
if (!(mask & sonypi_eventtypes[i].mask))
|
850 |
|
|
continue;
|
851 |
|
|
for (j = 0; sonypi_eventtypes[i].events[j].event; j++) {
|
852 |
|
|
if (v1 == sonypi_eventtypes[i].events[j].data) {
|
853 |
|
|
event = sonypi_eventtypes[i].events[j].event;
|
854 |
|
|
goto found;
|
855 |
|
|
}
|
856 |
|
|
}
|
857 |
|
|
}
|
858 |
|
|
|
859 |
|
|
if (verbose)
|
860 |
|
|
printk(KERN_WARNING
|
861 |
|
|
"sonypi: unknown event port1=0x%02x,port2=0x%02x\n",
|
862 |
|
|
v1, v2);
|
863 |
|
|
/* We need to return IRQ_HANDLED here because there *are*
|
864 |
|
|
* events belonging to the sonypi device we don't know about,
|
865 |
|
|
* but we still don't want those to pollute the logs... */
|
866 |
|
|
return IRQ_HANDLED;
|
867 |
|
|
|
868 |
|
|
found:
|
869 |
|
|
if (verbose > 1)
|
870 |
|
|
printk(KERN_INFO
|
871 |
|
|
"sonypi: event port1=0x%02x,port2=0x%02x\n", v1, v2);
|
872 |
|
|
|
873 |
|
|
if (useinput)
|
874 |
|
|
sonypi_report_input_event(event);
|
875 |
|
|
|
876 |
|
|
#ifdef CONFIG_ACPI
|
877 |
|
|
if (sonypi_acpi_device)
|
878 |
|
|
acpi_bus_generate_proc_event(sonypi_acpi_device, 1, event);
|
879 |
|
|
#endif
|
880 |
|
|
|
881 |
|
|
kfifo_put(sonypi_device.fifo, (unsigned char *)&event, sizeof(event));
|
882 |
|
|
kill_fasync(&sonypi_device.fifo_async, SIGIO, POLL_IN);
|
883 |
|
|
wake_up_interruptible(&sonypi_device.fifo_proc_list);
|
884 |
|
|
|
885 |
|
|
return IRQ_HANDLED;
|
886 |
|
|
}
|
887 |
|
|
|
888 |
|
|
static int sonypi_misc_fasync(int fd, struct file *filp, int on)
|
889 |
|
|
{
|
890 |
|
|
int retval;
|
891 |
|
|
|
892 |
|
|
retval = fasync_helper(fd, filp, on, &sonypi_device.fifo_async);
|
893 |
|
|
if (retval < 0)
|
894 |
|
|
return retval;
|
895 |
|
|
return 0;
|
896 |
|
|
}
|
897 |
|
|
|
898 |
|
|
static int sonypi_misc_release(struct inode *inode, struct file *file)
|
899 |
|
|
{
|
900 |
|
|
sonypi_misc_fasync(-1, file, 0);
|
901 |
|
|
mutex_lock(&sonypi_device.lock);
|
902 |
|
|
sonypi_device.open_count--;
|
903 |
|
|
mutex_unlock(&sonypi_device.lock);
|
904 |
|
|
return 0;
|
905 |
|
|
}
|
906 |
|
|
|
907 |
|
|
static int sonypi_misc_open(struct inode *inode, struct file *file)
|
908 |
|
|
{
|
909 |
|
|
mutex_lock(&sonypi_device.lock);
|
910 |
|
|
/* Flush input queue on first open */
|
911 |
|
|
if (!sonypi_device.open_count)
|
912 |
|
|
kfifo_reset(sonypi_device.fifo);
|
913 |
|
|
sonypi_device.open_count++;
|
914 |
|
|
mutex_unlock(&sonypi_device.lock);
|
915 |
|
|
return 0;
|
916 |
|
|
}
|
917 |
|
|
|
918 |
|
|
static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
|
919 |
|
|
size_t count, loff_t *pos)
|
920 |
|
|
{
|
921 |
|
|
ssize_t ret;
|
922 |
|
|
unsigned char c;
|
923 |
|
|
|
924 |
|
|
if ((kfifo_len(sonypi_device.fifo) == 0) &&
|
925 |
|
|
(file->f_flags & O_NONBLOCK))
|
926 |
|
|
return -EAGAIN;
|
927 |
|
|
|
928 |
|
|
ret = wait_event_interruptible(sonypi_device.fifo_proc_list,
|
929 |
|
|
kfifo_len(sonypi_device.fifo) != 0);
|
930 |
|
|
if (ret)
|
931 |
|
|
return ret;
|
932 |
|
|
|
933 |
|
|
while (ret < count &&
|
934 |
|
|
(kfifo_get(sonypi_device.fifo, &c, sizeof(c)) == sizeof(c))) {
|
935 |
|
|
if (put_user(c, buf++))
|
936 |
|
|
return -EFAULT;
|
937 |
|
|
ret++;
|
938 |
|
|
}
|
939 |
|
|
|
940 |
|
|
if (ret > 0) {
|
941 |
|
|
struct inode *inode = file->f_path.dentry->d_inode;
|
942 |
|
|
inode->i_atime = current_fs_time(inode->i_sb);
|
943 |
|
|
}
|
944 |
|
|
|
945 |
|
|
return ret;
|
946 |
|
|
}
|
947 |
|
|
|
948 |
|
|
static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait)
|
949 |
|
|
{
|
950 |
|
|
poll_wait(file, &sonypi_device.fifo_proc_list, wait);
|
951 |
|
|
if (kfifo_len(sonypi_device.fifo))
|
952 |
|
|
return POLLIN | POLLRDNORM;
|
953 |
|
|
return 0;
|
954 |
|
|
}
|
955 |
|
|
|
956 |
|
|
static int sonypi_misc_ioctl(struct inode *ip, struct file *fp,
|
957 |
|
|
unsigned int cmd, unsigned long arg)
|
958 |
|
|
{
|
959 |
|
|
int ret = 0;
|
960 |
|
|
void __user *argp = (void __user *)arg;
|
961 |
|
|
u8 val8;
|
962 |
|
|
u16 val16;
|
963 |
|
|
|
964 |
|
|
mutex_lock(&sonypi_device.lock);
|
965 |
|
|
switch (cmd) {
|
966 |
|
|
case SONYPI_IOCGBRT:
|
967 |
|
|
if (sonypi_ec_read(SONYPI_LCD_LIGHT, &val8)) {
|
968 |
|
|
ret = -EIO;
|
969 |
|
|
break;
|
970 |
|
|
}
|
971 |
|
|
if (copy_to_user(argp, &val8, sizeof(val8)))
|
972 |
|
|
ret = -EFAULT;
|
973 |
|
|
break;
|
974 |
|
|
case SONYPI_IOCSBRT:
|
975 |
|
|
if (copy_from_user(&val8, argp, sizeof(val8))) {
|
976 |
|
|
ret = -EFAULT;
|
977 |
|
|
break;
|
978 |
|
|
}
|
979 |
|
|
if (sonypi_ec_write(SONYPI_LCD_LIGHT, val8))
|
980 |
|
|
ret = -EIO;
|
981 |
|
|
break;
|
982 |
|
|
case SONYPI_IOCGBAT1CAP:
|
983 |
|
|
if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
|
984 |
|
|
ret = -EIO;
|
985 |
|
|
break;
|
986 |
|
|
}
|
987 |
|
|
if (copy_to_user(argp, &val16, sizeof(val16)))
|
988 |
|
|
ret = -EFAULT;
|
989 |
|
|
break;
|
990 |
|
|
case SONYPI_IOCGBAT1REM:
|
991 |
|
|
if (ec_read16(SONYPI_BAT1_LEFT, &val16)) {
|
992 |
|
|
ret = -EIO;
|
993 |
|
|
break;
|
994 |
|
|
}
|
995 |
|
|
if (copy_to_user(argp, &val16, sizeof(val16)))
|
996 |
|
|
ret = -EFAULT;
|
997 |
|
|
break;
|
998 |
|
|
case SONYPI_IOCGBAT2CAP:
|
999 |
|
|
if (ec_read16(SONYPI_BAT2_FULL, &val16)) {
|
1000 |
|
|
ret = -EIO;
|
1001 |
|
|
break;
|
1002 |
|
|
}
|
1003 |
|
|
if (copy_to_user(argp, &val16, sizeof(val16)))
|
1004 |
|
|
ret = -EFAULT;
|
1005 |
|
|
break;
|
1006 |
|
|
case SONYPI_IOCGBAT2REM:
|
1007 |
|
|
if (ec_read16(SONYPI_BAT2_LEFT, &val16)) {
|
1008 |
|
|
ret = -EIO;
|
1009 |
|
|
break;
|
1010 |
|
|
}
|
1011 |
|
|
if (copy_to_user(argp, &val16, sizeof(val16)))
|
1012 |
|
|
ret = -EFAULT;
|
1013 |
|
|
break;
|
1014 |
|
|
case SONYPI_IOCGBATFLAGS:
|
1015 |
|
|
if (sonypi_ec_read(SONYPI_BAT_FLAGS, &val8)) {
|
1016 |
|
|
ret = -EIO;
|
1017 |
|
|
break;
|
1018 |
|
|
}
|
1019 |
|
|
val8 &= 0x07;
|
1020 |
|
|
if (copy_to_user(argp, &val8, sizeof(val8)))
|
1021 |
|
|
ret = -EFAULT;
|
1022 |
|
|
break;
|
1023 |
|
|
case SONYPI_IOCGBLUE:
|
1024 |
|
|
val8 = sonypi_device.bluetooth_power;
|
1025 |
|
|
if (copy_to_user(argp, &val8, sizeof(val8)))
|
1026 |
|
|
ret = -EFAULT;
|
1027 |
|
|
break;
|
1028 |
|
|
case SONYPI_IOCSBLUE:
|
1029 |
|
|
if (copy_from_user(&val8, argp, sizeof(val8))) {
|
1030 |
|
|
ret = -EFAULT;
|
1031 |
|
|
break;
|
1032 |
|
|
}
|
1033 |
|
|
sonypi_setbluetoothpower(val8);
|
1034 |
|
|
break;
|
1035 |
|
|
/* FAN Controls */
|
1036 |
|
|
case SONYPI_IOCGFAN:
|
1037 |
|
|
if (sonypi_ec_read(SONYPI_FAN0_STATUS, &val8)) {
|
1038 |
|
|
ret = -EIO;
|
1039 |
|
|
break;
|
1040 |
|
|
}
|
1041 |
|
|
if (copy_to_user(argp, &val8, sizeof(val8)))
|
1042 |
|
|
ret = -EFAULT;
|
1043 |
|
|
break;
|
1044 |
|
|
case SONYPI_IOCSFAN:
|
1045 |
|
|
if (copy_from_user(&val8, argp, sizeof(val8))) {
|
1046 |
|
|
ret = -EFAULT;
|
1047 |
|
|
break;
|
1048 |
|
|
}
|
1049 |
|
|
if (sonypi_ec_write(SONYPI_FAN0_STATUS, val8))
|
1050 |
|
|
ret = -EIO;
|
1051 |
|
|
break;
|
1052 |
|
|
/* GET Temperature (useful under APM) */
|
1053 |
|
|
case SONYPI_IOCGTEMP:
|
1054 |
|
|
if (sonypi_ec_read(SONYPI_TEMP_STATUS, &val8)) {
|
1055 |
|
|
ret = -EIO;
|
1056 |
|
|
break;
|
1057 |
|
|
}
|
1058 |
|
|
if (copy_to_user(argp, &val8, sizeof(val8)))
|
1059 |
|
|
ret = -EFAULT;
|
1060 |
|
|
break;
|
1061 |
|
|
default:
|
1062 |
|
|
ret = -EINVAL;
|
1063 |
|
|
}
|
1064 |
|
|
mutex_unlock(&sonypi_device.lock);
|
1065 |
|
|
return ret;
|
1066 |
|
|
}
|
1067 |
|
|
|
1068 |
|
|
static const struct file_operations sonypi_misc_fops = {
|
1069 |
|
|
.owner = THIS_MODULE,
|
1070 |
|
|
.read = sonypi_misc_read,
|
1071 |
|
|
.poll = sonypi_misc_poll,
|
1072 |
|
|
.open = sonypi_misc_open,
|
1073 |
|
|
.release = sonypi_misc_release,
|
1074 |
|
|
.fasync = sonypi_misc_fasync,
|
1075 |
|
|
.ioctl = sonypi_misc_ioctl,
|
1076 |
|
|
};
|
1077 |
|
|
|
1078 |
|
|
static struct miscdevice sonypi_misc_device = {
|
1079 |
|
|
.minor = MISC_DYNAMIC_MINOR,
|
1080 |
|
|
.name = "sonypi",
|
1081 |
|
|
.fops = &sonypi_misc_fops,
|
1082 |
|
|
};
|
1083 |
|
|
|
1084 |
|
|
static void sonypi_enable(unsigned int camera_on)
|
1085 |
|
|
{
|
1086 |
|
|
switch (sonypi_device.model) {
|
1087 |
|
|
case SONYPI_DEVICE_MODEL_TYPE1:
|
1088 |
|
|
sonypi_type1_srs();
|
1089 |
|
|
break;
|
1090 |
|
|
case SONYPI_DEVICE_MODEL_TYPE2:
|
1091 |
|
|
sonypi_type2_srs();
|
1092 |
|
|
break;
|
1093 |
|
|
case SONYPI_DEVICE_MODEL_TYPE3:
|
1094 |
|
|
sonypi_type3_srs();
|
1095 |
|
|
break;
|
1096 |
|
|
}
|
1097 |
|
|
|
1098 |
|
|
sonypi_call1(0x82);
|
1099 |
|
|
sonypi_call2(0x81, 0xff);
|
1100 |
|
|
sonypi_call1(compat ? 0x92 : 0x82);
|
1101 |
|
|
|
1102 |
|
|
/* Enable ACPI mode to get Fn key events */
|
1103 |
|
|
if (!SONYPI_ACPI_ACTIVE && fnkeyinit)
|
1104 |
|
|
outb(0xf0, 0xb2);
|
1105 |
|
|
|
1106 |
|
|
if (camera && camera_on)
|
1107 |
|
|
sonypi_camera_on();
|
1108 |
|
|
}
|
1109 |
|
|
|
1110 |
|
|
static int sonypi_disable(void)
|
1111 |
|
|
{
|
1112 |
|
|
sonypi_call2(0x81, 0); /* make sure we don't get any more events */
|
1113 |
|
|
if (camera)
|
1114 |
|
|
sonypi_camera_off();
|
1115 |
|
|
|
1116 |
|
|
/* disable ACPI mode */
|
1117 |
|
|
if (!SONYPI_ACPI_ACTIVE && fnkeyinit)
|
1118 |
|
|
outb(0xf1, 0xb2);
|
1119 |
|
|
|
1120 |
|
|
switch (sonypi_device.model) {
|
1121 |
|
|
case SONYPI_DEVICE_MODEL_TYPE1:
|
1122 |
|
|
sonypi_type1_dis();
|
1123 |
|
|
break;
|
1124 |
|
|
case SONYPI_DEVICE_MODEL_TYPE2:
|
1125 |
|
|
sonypi_type2_dis();
|
1126 |
|
|
break;
|
1127 |
|
|
case SONYPI_DEVICE_MODEL_TYPE3:
|
1128 |
|
|
sonypi_type3_dis();
|
1129 |
|
|
break;
|
1130 |
|
|
}
|
1131 |
|
|
|
1132 |
|
|
return 0;
|
1133 |
|
|
}
|
1134 |
|
|
|
1135 |
|
|
#ifdef CONFIG_ACPI
|
1136 |
|
|
static int sonypi_acpi_add(struct acpi_device *device)
|
1137 |
|
|
{
|
1138 |
|
|
sonypi_acpi_device = device;
|
1139 |
|
|
strcpy(acpi_device_name(device), "Sony laptop hotkeys");
|
1140 |
|
|
strcpy(acpi_device_class(device), "sony/hotkey");
|
1141 |
|
|
return 0;
|
1142 |
|
|
}
|
1143 |
|
|
|
1144 |
|
|
static int sonypi_acpi_remove(struct acpi_device *device, int type)
|
1145 |
|
|
{
|
1146 |
|
|
sonypi_acpi_device = NULL;
|
1147 |
|
|
return 0;
|
1148 |
|
|
}
|
1149 |
|
|
|
1150 |
|
|
const static struct acpi_device_id sonypi_device_ids[] = {
|
1151 |
|
|
{"SNY6001", 0},
|
1152 |
|
|
{"", 0},
|
1153 |
|
|
};
|
1154 |
|
|
|
1155 |
|
|
static struct acpi_driver sonypi_acpi_driver = {
|
1156 |
|
|
.name = "sonypi",
|
1157 |
|
|
.class = "hkey",
|
1158 |
|
|
.ids = sonypi_device_ids,
|
1159 |
|
|
.ops = {
|
1160 |
|
|
.add = sonypi_acpi_add,
|
1161 |
|
|
.remove = sonypi_acpi_remove,
|
1162 |
|
|
},
|
1163 |
|
|
};
|
1164 |
|
|
#endif
|
1165 |
|
|
|
1166 |
|
|
static int __devinit sonypi_create_input_devices(struct platform_device *pdev)
|
1167 |
|
|
{
|
1168 |
|
|
struct input_dev *jog_dev;
|
1169 |
|
|
struct input_dev *key_dev;
|
1170 |
|
|
int i;
|
1171 |
|
|
int error;
|
1172 |
|
|
|
1173 |
|
|
sonypi_device.input_jog_dev = jog_dev = input_allocate_device();
|
1174 |
|
|
if (!jog_dev)
|
1175 |
|
|
return -ENOMEM;
|
1176 |
|
|
|
1177 |
|
|
jog_dev->name = "Sony Vaio Jogdial";
|
1178 |
|
|
jog_dev->id.bustype = BUS_ISA;
|
1179 |
|
|
jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
|
1180 |
|
|
jog_dev->dev.parent = &pdev->dev;
|
1181 |
|
|
|
1182 |
|
|
jog_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
|
1183 |
|
|
jog_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_MIDDLE);
|
1184 |
|
|
jog_dev->relbit[0] = BIT_MASK(REL_WHEEL);
|
1185 |
|
|
|
1186 |
|
|
sonypi_device.input_key_dev = key_dev = input_allocate_device();
|
1187 |
|
|
if (!key_dev) {
|
1188 |
|
|
error = -ENOMEM;
|
1189 |
|
|
goto err_free_jogdev;
|
1190 |
|
|
}
|
1191 |
|
|
|
1192 |
|
|
key_dev->name = "Sony Vaio Keys";
|
1193 |
|
|
key_dev->id.bustype = BUS_ISA;
|
1194 |
|
|
key_dev->id.vendor = PCI_VENDOR_ID_SONY;
|
1195 |
|
|
key_dev->dev.parent = &pdev->dev;
|
1196 |
|
|
|
1197 |
|
|
/* Initialize the Input Drivers: special keys */
|
1198 |
|
|
key_dev->evbit[0] = BIT_MASK(EV_KEY);
|
1199 |
|
|
for (i = 0; sonypi_inputkeys[i].sonypiev; i++)
|
1200 |
|
|
if (sonypi_inputkeys[i].inputev)
|
1201 |
|
|
set_bit(sonypi_inputkeys[i].inputev, key_dev->keybit);
|
1202 |
|
|
|
1203 |
|
|
error = input_register_device(jog_dev);
|
1204 |
|
|
if (error)
|
1205 |
|
|
goto err_free_keydev;
|
1206 |
|
|
|
1207 |
|
|
error = input_register_device(key_dev);
|
1208 |
|
|
if (error)
|
1209 |
|
|
goto err_unregister_jogdev;
|
1210 |
|
|
|
1211 |
|
|
return 0;
|
1212 |
|
|
|
1213 |
|
|
err_unregister_jogdev:
|
1214 |
|
|
input_unregister_device(jog_dev);
|
1215 |
|
|
/* Set to NULL so we don't free it again below */
|
1216 |
|
|
jog_dev = NULL;
|
1217 |
|
|
err_free_keydev:
|
1218 |
|
|
input_free_device(key_dev);
|
1219 |
|
|
sonypi_device.input_key_dev = NULL;
|
1220 |
|
|
err_free_jogdev:
|
1221 |
|
|
input_free_device(jog_dev);
|
1222 |
|
|
sonypi_device.input_jog_dev = NULL;
|
1223 |
|
|
|
1224 |
|
|
return error;
|
1225 |
|
|
}
|
1226 |
|
|
|
1227 |
|
|
static int __devinit sonypi_setup_ioports(struct sonypi_device *dev,
|
1228 |
|
|
const struct sonypi_ioport_list *ioport_list)
|
1229 |
|
|
{
|
1230 |
|
|
/* try to detect if sony-laptop is being used and thus
|
1231 |
|
|
* has already requested one of the known ioports.
|
1232 |
|
|
* As in the deprecated check_region this is racy has we have
|
1233 |
|
|
* multiple ioports available and one of them can be requested
|
1234 |
|
|
* between this check and the subsequent request. Anyway, as an
|
1235 |
|
|
* attempt to be some more user-friendly as we currently are,
|
1236 |
|
|
* this is enough.
|
1237 |
|
|
*/
|
1238 |
|
|
const struct sonypi_ioport_list *check = ioport_list;
|
1239 |
|
|
while (check_ioport && check->port1) {
|
1240 |
|
|
if (!request_region(check->port1,
|
1241 |
|
|
sonypi_device.region_size,
|
1242 |
|
|
"Sony Programable I/O Device Check")) {
|
1243 |
|
|
printk(KERN_ERR "sonypi: ioport 0x%.4x busy, using sony-laptop? "
|
1244 |
|
|
"if not use check_ioport=0\n",
|
1245 |
|
|
check->port1);
|
1246 |
|
|
return -EBUSY;
|
1247 |
|
|
}
|
1248 |
|
|
release_region(check->port1, sonypi_device.region_size);
|
1249 |
|
|
check++;
|
1250 |
|
|
}
|
1251 |
|
|
|
1252 |
|
|
while (ioport_list->port1) {
|
1253 |
|
|
|
1254 |
|
|
if (request_region(ioport_list->port1,
|
1255 |
|
|
sonypi_device.region_size,
|
1256 |
|
|
"Sony Programable I/O Device")) {
|
1257 |
|
|
dev->ioport1 = ioport_list->port1;
|
1258 |
|
|
dev->ioport2 = ioport_list->port2;
|
1259 |
|
|
return 0;
|
1260 |
|
|
}
|
1261 |
|
|
ioport_list++;
|
1262 |
|
|
}
|
1263 |
|
|
|
1264 |
|
|
return -EBUSY;
|
1265 |
|
|
}
|
1266 |
|
|
|
1267 |
|
|
static int __devinit sonypi_setup_irq(struct sonypi_device *dev,
|
1268 |
|
|
const struct sonypi_irq_list *irq_list)
|
1269 |
|
|
{
|
1270 |
|
|
while (irq_list->irq) {
|
1271 |
|
|
|
1272 |
|
|
if (!request_irq(irq_list->irq, sonypi_irq,
|
1273 |
|
|
IRQF_SHARED, "sonypi", sonypi_irq)) {
|
1274 |
|
|
dev->irq = irq_list->irq;
|
1275 |
|
|
dev->bits = irq_list->bits;
|
1276 |
|
|
return 0;
|
1277 |
|
|
}
|
1278 |
|
|
irq_list++;
|
1279 |
|
|
}
|
1280 |
|
|
|
1281 |
|
|
return -EBUSY;
|
1282 |
|
|
}
|
1283 |
|
|
|
1284 |
|
|
static void __devinit sonypi_display_info(void)
|
1285 |
|
|
{
|
1286 |
|
|
printk(KERN_INFO "sonypi: detected type%d model, "
|
1287 |
|
|
"verbose = %d, fnkeyinit = %s, camera = %s, "
|
1288 |
|
|
"compat = %s, mask = 0x%08lx, useinput = %s, acpi = %s\n",
|
1289 |
|
|
sonypi_device.model,
|
1290 |
|
|
verbose,
|
1291 |
|
|
fnkeyinit ? "on" : "off",
|
1292 |
|
|
camera ? "on" : "off",
|
1293 |
|
|
compat ? "on" : "off",
|
1294 |
|
|
mask,
|
1295 |
|
|
useinput ? "on" : "off",
|
1296 |
|
|
SONYPI_ACPI_ACTIVE ? "on" : "off");
|
1297 |
|
|
printk(KERN_INFO "sonypi: enabled at irq=%d, port1=0x%x, port2=0x%x\n",
|
1298 |
|
|
sonypi_device.irq,
|
1299 |
|
|
sonypi_device.ioport1, sonypi_device.ioport2);
|
1300 |
|
|
|
1301 |
|
|
if (minor == -1)
|
1302 |
|
|
printk(KERN_INFO "sonypi: device allocated minor is %d\n",
|
1303 |
|
|
sonypi_misc_device.minor);
|
1304 |
|
|
}
|
1305 |
|
|
|
1306 |
|
|
static int __devinit sonypi_probe(struct platform_device *dev)
|
1307 |
|
|
{
|
1308 |
|
|
const struct sonypi_ioport_list *ioport_list;
|
1309 |
|
|
const struct sonypi_irq_list *irq_list;
|
1310 |
|
|
struct pci_dev *pcidev;
|
1311 |
|
|
int error;
|
1312 |
|
|
|
1313 |
|
|
printk(KERN_WARNING "sonypi: please try the sony-laptop module instead "
|
1314 |
|
|
"and report failures, see also "
|
1315 |
|
|
"http://www.linux.it/~malattia/wiki/index.php/Sony_drivers\n");
|
1316 |
|
|
|
1317 |
|
|
spin_lock_init(&sonypi_device.fifo_lock);
|
1318 |
|
|
sonypi_device.fifo = kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL,
|
1319 |
|
|
&sonypi_device.fifo_lock);
|
1320 |
|
|
if (IS_ERR(sonypi_device.fifo)) {
|
1321 |
|
|
printk(KERN_ERR "sonypi: kfifo_alloc failed\n");
|
1322 |
|
|
return PTR_ERR(sonypi_device.fifo);
|
1323 |
|
|
}
|
1324 |
|
|
|
1325 |
|
|
init_waitqueue_head(&sonypi_device.fifo_proc_list);
|
1326 |
|
|
mutex_init(&sonypi_device.lock);
|
1327 |
|
|
sonypi_device.bluetooth_power = -1;
|
1328 |
|
|
|
1329 |
|
|
if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
|
1330 |
|
|
PCI_DEVICE_ID_INTEL_82371AB_3, NULL)))
|
1331 |
|
|
sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE1;
|
1332 |
|
|
else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
|
1333 |
|
|
PCI_DEVICE_ID_INTEL_ICH6_1, NULL)))
|
1334 |
|
|
sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3;
|
1335 |
|
|
else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
|
1336 |
|
|
PCI_DEVICE_ID_INTEL_ICH7_1, NULL)))
|
1337 |
|
|
sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3;
|
1338 |
|
|
else
|
1339 |
|
|
sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2;
|
1340 |
|
|
|
1341 |
|
|
if (pcidev && pci_enable_device(pcidev)) {
|
1342 |
|
|
printk(KERN_ERR "sonypi: pci_enable_device failed\n");
|
1343 |
|
|
error = -EIO;
|
1344 |
|
|
goto err_put_pcidev;
|
1345 |
|
|
}
|
1346 |
|
|
|
1347 |
|
|
sonypi_device.dev = pcidev;
|
1348 |
|
|
|
1349 |
|
|
if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) {
|
1350 |
|
|
ioport_list = sonypi_type1_ioport_list;
|
1351 |
|
|
sonypi_device.region_size = SONYPI_TYPE1_REGION_SIZE;
|
1352 |
|
|
sonypi_device.evtype_offset = SONYPI_TYPE1_EVTYPE_OFFSET;
|
1353 |
|
|
irq_list = sonypi_type1_irq_list;
|
1354 |
|
|
} else if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) {
|
1355 |
|
|
ioport_list = sonypi_type2_ioport_list;
|
1356 |
|
|
sonypi_device.region_size = SONYPI_TYPE2_REGION_SIZE;
|
1357 |
|
|
sonypi_device.evtype_offset = SONYPI_TYPE2_EVTYPE_OFFSET;
|
1358 |
|
|
irq_list = sonypi_type2_irq_list;
|
1359 |
|
|
} else {
|
1360 |
|
|
ioport_list = sonypi_type3_ioport_list;
|
1361 |
|
|
sonypi_device.region_size = SONYPI_TYPE3_REGION_SIZE;
|
1362 |
|
|
sonypi_device.evtype_offset = SONYPI_TYPE3_EVTYPE_OFFSET;
|
1363 |
|
|
irq_list = sonypi_type3_irq_list;
|
1364 |
|
|
}
|
1365 |
|
|
|
1366 |
|
|
error = sonypi_setup_ioports(&sonypi_device, ioport_list);
|
1367 |
|
|
if (error) {
|
1368 |
|
|
printk(KERN_ERR "sonypi: failed to request ioports\n");
|
1369 |
|
|
goto err_disable_pcidev;
|
1370 |
|
|
}
|
1371 |
|
|
|
1372 |
|
|
error = sonypi_setup_irq(&sonypi_device, irq_list);
|
1373 |
|
|
if (error) {
|
1374 |
|
|
printk(KERN_ERR "sonypi: request_irq failed\n");
|
1375 |
|
|
goto err_free_ioports;
|
1376 |
|
|
}
|
1377 |
|
|
|
1378 |
|
|
if (minor != -1)
|
1379 |
|
|
sonypi_misc_device.minor = minor;
|
1380 |
|
|
error = misc_register(&sonypi_misc_device);
|
1381 |
|
|
if (error) {
|
1382 |
|
|
printk(KERN_ERR "sonypi: misc_register failed\n");
|
1383 |
|
|
goto err_free_irq;
|
1384 |
|
|
}
|
1385 |
|
|
|
1386 |
|
|
sonypi_display_info();
|
1387 |
|
|
|
1388 |
|
|
if (useinput) {
|
1389 |
|
|
|
1390 |
|
|
error = sonypi_create_input_devices(dev);
|
1391 |
|
|
if (error) {
|
1392 |
|
|
printk(KERN_ERR
|
1393 |
|
|
"sonypi: failed to create input devices\n");
|
1394 |
|
|
goto err_miscdev_unregister;
|
1395 |
|
|
}
|
1396 |
|
|
|
1397 |
|
|
spin_lock_init(&sonypi_device.input_fifo_lock);
|
1398 |
|
|
sonypi_device.input_fifo =
|
1399 |
|
|
kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL,
|
1400 |
|
|
&sonypi_device.input_fifo_lock);
|
1401 |
|
|
if (IS_ERR(sonypi_device.input_fifo)) {
|
1402 |
|
|
printk(KERN_ERR "sonypi: kfifo_alloc failed\n");
|
1403 |
|
|
error = PTR_ERR(sonypi_device.input_fifo);
|
1404 |
|
|
goto err_inpdev_unregister;
|
1405 |
|
|
}
|
1406 |
|
|
|
1407 |
|
|
INIT_WORK(&sonypi_device.input_work, input_keyrelease);
|
1408 |
|
|
}
|
1409 |
|
|
|
1410 |
|
|
sonypi_enable(0);
|
1411 |
|
|
|
1412 |
|
|
return 0;
|
1413 |
|
|
|
1414 |
|
|
err_inpdev_unregister:
|
1415 |
|
|
input_unregister_device(sonypi_device.input_key_dev);
|
1416 |
|
|
input_unregister_device(sonypi_device.input_jog_dev);
|
1417 |
|
|
err_miscdev_unregister:
|
1418 |
|
|
misc_deregister(&sonypi_misc_device);
|
1419 |
|
|
err_free_irq:
|
1420 |
|
|
free_irq(sonypi_device.irq, sonypi_irq);
|
1421 |
|
|
err_free_ioports:
|
1422 |
|
|
release_region(sonypi_device.ioport1, sonypi_device.region_size);
|
1423 |
|
|
err_disable_pcidev:
|
1424 |
|
|
if (pcidev)
|
1425 |
|
|
pci_disable_device(pcidev);
|
1426 |
|
|
err_put_pcidev:
|
1427 |
|
|
pci_dev_put(pcidev);
|
1428 |
|
|
kfifo_free(sonypi_device.fifo);
|
1429 |
|
|
|
1430 |
|
|
return error;
|
1431 |
|
|
}
|
1432 |
|
|
|
1433 |
|
|
static int __devexit sonypi_remove(struct platform_device *dev)
|
1434 |
|
|
{
|
1435 |
|
|
sonypi_disable();
|
1436 |
|
|
|
1437 |
|
|
synchronize_irq(sonypi_device.irq);
|
1438 |
|
|
flush_scheduled_work();
|
1439 |
|
|
|
1440 |
|
|
if (useinput) {
|
1441 |
|
|
input_unregister_device(sonypi_device.input_key_dev);
|
1442 |
|
|
input_unregister_device(sonypi_device.input_jog_dev);
|
1443 |
|
|
kfifo_free(sonypi_device.input_fifo);
|
1444 |
|
|
}
|
1445 |
|
|
|
1446 |
|
|
misc_deregister(&sonypi_misc_device);
|
1447 |
|
|
|
1448 |
|
|
free_irq(sonypi_device.irq, sonypi_irq);
|
1449 |
|
|
release_region(sonypi_device.ioport1, sonypi_device.region_size);
|
1450 |
|
|
|
1451 |
|
|
if (sonypi_device.dev) {
|
1452 |
|
|
pci_disable_device(sonypi_device.dev);
|
1453 |
|
|
pci_dev_put(sonypi_device.dev);
|
1454 |
|
|
}
|
1455 |
|
|
|
1456 |
|
|
kfifo_free(sonypi_device.fifo);
|
1457 |
|
|
|
1458 |
|
|
return 0;
|
1459 |
|
|
}
|
1460 |
|
|
|
1461 |
|
|
#ifdef CONFIG_PM
|
1462 |
|
|
static int old_camera_power;
|
1463 |
|
|
|
1464 |
|
|
static int sonypi_suspend(struct platform_device *dev, pm_message_t state)
|
1465 |
|
|
{
|
1466 |
|
|
old_camera_power = sonypi_device.camera_power;
|
1467 |
|
|
sonypi_disable();
|
1468 |
|
|
|
1469 |
|
|
return 0;
|
1470 |
|
|
}
|
1471 |
|
|
|
1472 |
|
|
static int sonypi_resume(struct platform_device *dev)
|
1473 |
|
|
{
|
1474 |
|
|
sonypi_enable(old_camera_power);
|
1475 |
|
|
return 0;
|
1476 |
|
|
}
|
1477 |
|
|
#else
|
1478 |
|
|
#define sonypi_suspend NULL
|
1479 |
|
|
#define sonypi_resume NULL
|
1480 |
|
|
#endif
|
1481 |
|
|
|
1482 |
|
|
static void sonypi_shutdown(struct platform_device *dev)
|
1483 |
|
|
{
|
1484 |
|
|
sonypi_disable();
|
1485 |
|
|
}
|
1486 |
|
|
|
1487 |
|
|
static struct platform_driver sonypi_driver = {
|
1488 |
|
|
.driver = {
|
1489 |
|
|
.name = "sonypi",
|
1490 |
|
|
.owner = THIS_MODULE,
|
1491 |
|
|
},
|
1492 |
|
|
.probe = sonypi_probe,
|
1493 |
|
|
.remove = __devexit_p(sonypi_remove),
|
1494 |
|
|
.shutdown = sonypi_shutdown,
|
1495 |
|
|
.suspend = sonypi_suspend,
|
1496 |
|
|
.resume = sonypi_resume,
|
1497 |
|
|
};
|
1498 |
|
|
|
1499 |
|
|
static struct platform_device *sonypi_platform_device;
|
1500 |
|
|
|
1501 |
|
|
static struct dmi_system_id __initdata sonypi_dmi_table[] = {
|
1502 |
|
|
{
|
1503 |
|
|
.ident = "Sony Vaio",
|
1504 |
|
|
.matches = {
|
1505 |
|
|
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
|
1506 |
|
|
DMI_MATCH(DMI_PRODUCT_NAME, "PCG-"),
|
1507 |
|
|
},
|
1508 |
|
|
},
|
1509 |
|
|
{
|
1510 |
|
|
.ident = "Sony Vaio",
|
1511 |
|
|
.matches = {
|
1512 |
|
|
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
|
1513 |
|
|
DMI_MATCH(DMI_PRODUCT_NAME, "VGN-"),
|
1514 |
|
|
},
|
1515 |
|
|
},
|
1516 |
|
|
{ }
|
1517 |
|
|
};
|
1518 |
|
|
|
1519 |
|
|
static int __init sonypi_init(void)
|
1520 |
|
|
{
|
1521 |
|
|
int error;
|
1522 |
|
|
|
1523 |
|
|
printk(KERN_INFO
|
1524 |
|
|
"sonypi: Sony Programmable I/O Controller Driver v%s.\n",
|
1525 |
|
|
SONYPI_DRIVER_VERSION);
|
1526 |
|
|
|
1527 |
|
|
if (!dmi_check_system(sonypi_dmi_table))
|
1528 |
|
|
return -ENODEV;
|
1529 |
|
|
|
1530 |
|
|
error = platform_driver_register(&sonypi_driver);
|
1531 |
|
|
if (error)
|
1532 |
|
|
return error;
|
1533 |
|
|
|
1534 |
|
|
sonypi_platform_device = platform_device_alloc("sonypi", -1);
|
1535 |
|
|
if (!sonypi_platform_device) {
|
1536 |
|
|
error = -ENOMEM;
|
1537 |
|
|
goto err_driver_unregister;
|
1538 |
|
|
}
|
1539 |
|
|
|
1540 |
|
|
error = platform_device_add(sonypi_platform_device);
|
1541 |
|
|
if (error)
|
1542 |
|
|
goto err_free_device;
|
1543 |
|
|
|
1544 |
|
|
#ifdef CONFIG_ACPI
|
1545 |
|
|
if (acpi_bus_register_driver(&sonypi_acpi_driver) >= 0)
|
1546 |
|
|
acpi_driver_registered = 1;
|
1547 |
|
|
#endif
|
1548 |
|
|
|
1549 |
|
|
return 0;
|
1550 |
|
|
|
1551 |
|
|
err_free_device:
|
1552 |
|
|
platform_device_put(sonypi_platform_device);
|
1553 |
|
|
err_driver_unregister:
|
1554 |
|
|
platform_driver_unregister(&sonypi_driver);
|
1555 |
|
|
return error;
|
1556 |
|
|
}
|
1557 |
|
|
|
1558 |
|
|
static void __exit sonypi_exit(void)
|
1559 |
|
|
{
|
1560 |
|
|
#ifdef CONFIG_ACPI
|
1561 |
|
|
if (acpi_driver_registered)
|
1562 |
|
|
acpi_bus_unregister_driver(&sonypi_acpi_driver);
|
1563 |
|
|
#endif
|
1564 |
|
|
platform_device_unregister(sonypi_platform_device);
|
1565 |
|
|
platform_driver_unregister(&sonypi_driver);
|
1566 |
|
|
printk(KERN_INFO "sonypi: removed.\n");
|
1567 |
|
|
}
|
1568 |
|
|
|
1569 |
|
|
module_init(sonypi_init);
|
1570 |
|
|
module_exit(sonypi_exit);
|