Blame view

drivers/char/sonypi.c 41 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   * Sony Programmable I/O Control Device driver for VAIO
   *
74a882e48   malattia@linux.it   sonypi: suggest s...
4
5
   * Copyright (C) 2007 Mattia Dongili <malattia@linux.it>
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
7
8
9
   * Copyright (C) 2001-2005 Stelian Pop <stelian@popies.net>
   *
   * Copyright (C) 2005 Narayanan R S <nars@kadamba.org>
   *
96de0e252   Jan Engelhardt   Convert files to ...
10
   * Copyright (C) 2001-2002 AlcĂ´ve <www.alcove.com>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
   *
   * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
   *
   * Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
   *
   * Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp>
   *
   * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
   *
   * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras.
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   *
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
  #include <linux/module.h>
86ae13b00   Ingo Molnar   headers: Fix buil...
38
  #include <linux/sched.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
  #include <linux/input.h>
  #include <linux/pci.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
43
44
45
46
47
48
49
50
  #include <linux/init.h>
  #include <linux/interrupt.h>
  #include <linux/miscdevice.h>
  #include <linux/poll.h>
  #include <linux/delay.h>
  #include <linux/wait.h>
  #include <linux/acpi.h>
  #include <linux/dmi.h>
  #include <linux/err.h>
  #include <linux/kfifo.h>
d052d1bef   Russell King   Create platform_d...
51
  #include <linux/platform_device.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
52
  #include <linux/gfp.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
54
55
  
  #include <asm/uaccess.h>
  #include <asm/io.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  
  #include <linux/sonypi.h>
  
  #define SONYPI_DRIVER_VERSION	 "1.26"
  
  MODULE_AUTHOR("Stelian Pop <stelian@popies.net>");
  MODULE_DESCRIPTION("Sony Programmable I/O Control Device driver");
  MODULE_LICENSE("GPL");
  MODULE_VERSION(SONYPI_DRIVER_VERSION);
  
  static int minor = -1;
  module_param(minor, int, 0);
  MODULE_PARM_DESC(minor,
  		 "minor number of the misc device, default is -1 (automatic)");
  
  static int verbose;		/* = 0 */
  module_param(verbose, int, 0644);
  MODULE_PARM_DESC(verbose, "be verbose, default is 0 (no)");
  
  static int fnkeyinit;		/* = 0 */
  module_param(fnkeyinit, int, 0444);
  MODULE_PARM_DESC(fnkeyinit,
  		 "set this if your Fn keys do not generate any event");
  
  static int camera;		/* = 0 */
  module_param(camera, int, 0444);
  MODULE_PARM_DESC(camera,
  		 "set this if you have a MotionEye camera (PictureBook series)");
  
  static int compat;		/* = 0 */
  module_param(compat, int, 0444);
  MODULE_PARM_DESC(compat,
  		 "set this if you want to enable backward compatibility mode");
  
  static unsigned long mask = 0xffffffff;
  module_param(mask, ulong, 0644);
  MODULE_PARM_DESC(mask,
  		 "set this to the mask of event you want to enable (see doc)");
  
  static int useinput = 1;
  module_param(useinput, int, 0444);
  MODULE_PARM_DESC(useinput,
  		 "set this if you would like sonypi to feed events to the input subsystem");
1a3e32390   malattia@linux.it   sonypi: try to de...
99
100
101
102
  static int check_ioport = 1;
  module_param(check_ioport, int, 0444);
  MODULE_PARM_DESC(check_ioport,
  		 "set this to 0 if you think the automatic ioport check for sony-laptop is wrong");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
104
  #define SONYPI_DEVICE_MODEL_TYPE1	1
  #define SONYPI_DEVICE_MODEL_TYPE2	2
d2052c167   Erik Waling   [PATCH] sonypi SP...
105
  #define SONYPI_DEVICE_MODEL_TYPE3	3
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
107
108
109
  
  /* type1 models use those */
  #define SONYPI_IRQ_PORT			0x8034
  #define SONYPI_IRQ_SHIFT		22
d2052c167   Erik Waling   [PATCH] sonypi SP...
110
111
  #define SONYPI_TYPE1_BASE		0x50
  #define SONYPI_G10A			(SONYPI_TYPE1_BASE+0x14)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
113
114
115
116
117
118
119
120
  #define SONYPI_TYPE1_REGION_SIZE	0x08
  #define SONYPI_TYPE1_EVTYPE_OFFSET	0x04
  
  /* type2 series specifics */
  #define SONYPI_SIRQ			0x9b
  #define SONYPI_SLOB			0x9c
  #define SONYPI_SHIB			0x9d
  #define SONYPI_TYPE2_REGION_SIZE	0x20
  #define SONYPI_TYPE2_EVTYPE_OFFSET	0x12
d2052c167   Erik Waling   [PATCH] sonypi SP...
121
122
123
124
125
126
  /* type3 series specifics */
  #define SONYPI_TYPE3_BASE		0x40
  #define SONYPI_TYPE3_GID2		(SONYPI_TYPE3_BASE+0x48) /* 16 bits */
  #define SONYPI_TYPE3_MISC		(SONYPI_TYPE3_BASE+0x6d) /* 8 bits  */
  #define SONYPI_TYPE3_REGION_SIZE	0x20
  #define SONYPI_TYPE3_EVTYPE_OFFSET	0x12
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
  /* battery / brightness addresses */
  #define SONYPI_BAT_FLAGS	0x81
  #define SONYPI_LCD_LIGHT	0x96
  #define SONYPI_BAT1_PCTRM	0xa0
  #define SONYPI_BAT1_LEFT	0xa2
  #define SONYPI_BAT1_MAXRT	0xa4
  #define SONYPI_BAT2_PCTRM	0xa8
  #define SONYPI_BAT2_LEFT	0xaa
  #define SONYPI_BAT2_MAXRT	0xac
  #define SONYPI_BAT1_MAXTK	0xb0
  #define SONYPI_BAT1_FULL	0xb2
  #define SONYPI_BAT2_MAXTK	0xb8
  #define SONYPI_BAT2_FULL	0xba
  
  /* FAN0 information (reverse engineered from ACPI tables) */
  #define SONYPI_FAN0_STATUS	0x93
  #define SONYPI_TEMP_STATUS	0xC1
  
  /* ioports used for brightness and type2 events */
  #define SONYPI_DATA_IOPORT	0x62
  #define SONYPI_CST_IOPORT	0x66
  
  /* The set of possible ioports */
  struct sonypi_ioport_list {
  	u16	port1;
  	u16	port2;
  };
  
  static struct sonypi_ioport_list sonypi_type1_ioport_list[] = {
  	{ 0x10c0, 0x10c4 },	/* looks like the default on C1Vx */
  	{ 0x1080, 0x1084 },
  	{ 0x1090, 0x1094 },
  	{ 0x10a0, 0x10a4 },
  	{ 0x10b0, 0x10b4 },
  	{ 0x0, 0x0 }
  };
  
  static struct sonypi_ioport_list sonypi_type2_ioport_list[] = {
  	{ 0x1080, 0x1084 },
  	{ 0x10a0, 0x10a4 },
  	{ 0x10c0, 0x10c4 },
  	{ 0x10e0, 0x10e4 },
  	{ 0x0, 0x0 }
  };
d2052c167   Erik Waling   [PATCH] sonypi SP...
171
172
173
  /* same as in type 2 models */
  static struct sonypi_ioport_list *sonypi_type3_ioport_list =
  	sonypi_type2_ioport_list;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
  /* The set of possible interrupts */
  struct sonypi_irq_list {
  	u16	irq;
  	u16	bits;
  };
  
  static struct sonypi_irq_list sonypi_type1_irq_list[] = {
  	{ 11, 0x2 },	/* IRQ 11, GO22=0,GO23=1 in AML */
  	{ 10, 0x1 },	/* IRQ 10, GO22=1,GO23=0 in AML */
  	{  5, 0x0 },	/* IRQ  5, GO22=0,GO23=0 in AML */
  	{  0, 0x3 }	/* no IRQ, GO22=1,GO23=1 in AML */
  };
  
  static struct sonypi_irq_list sonypi_type2_irq_list[] = {
  	{ 11, 0x80 },	/* IRQ 11, 0x80 in SIRQ in AML */
  	{ 10, 0x40 },	/* IRQ 10, 0x40 in SIRQ in AML */
  	{  9, 0x20 },	/* IRQ  9, 0x20 in SIRQ in AML */
  	{  6, 0x10 },	/* IRQ  6, 0x10 in SIRQ in AML */
  	{  0, 0x00 }	/* no IRQ, 0x00 in SIRQ in AML */
  };
d2052c167   Erik Waling   [PATCH] sonypi SP...
194
195
  /* same as in type2 models */
  static struct sonypi_irq_list *sonypi_type3_irq_list = sonypi_type2_irq_list;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
  #define SONYPI_CAMERA_BRIGHTNESS		0
  #define SONYPI_CAMERA_CONTRAST			1
  #define SONYPI_CAMERA_HUE			2
  #define SONYPI_CAMERA_COLOR			3
  #define SONYPI_CAMERA_SHARPNESS			4
  
  #define SONYPI_CAMERA_PICTURE			5
  #define SONYPI_CAMERA_EXPOSURE_MASK		0xC
  #define SONYPI_CAMERA_WHITE_BALANCE_MASK	0x3
  #define SONYPI_CAMERA_PICTURE_MODE_MASK		0x30
  #define SONYPI_CAMERA_MUTE_MASK			0x40
  
  /* the rest don't need a loop until not 0xff */
  #define SONYPI_CAMERA_AGC			6
  #define SONYPI_CAMERA_AGC_MASK			0x30
  #define SONYPI_CAMERA_SHUTTER_MASK 		0x7
  
  #define SONYPI_CAMERA_SHUTDOWN_REQUEST		7
  #define SONYPI_CAMERA_CONTROL			0x10
  
  #define SONYPI_CAMERA_STATUS 			7
  #define SONYPI_CAMERA_STATUS_READY 		0x2
  #define SONYPI_CAMERA_STATUS_POSITION		0x4
  
  #define SONYPI_DIRECTION_BACKWARDS 		0x4
  
  #define SONYPI_CAMERA_REVISION 			8
  #define SONYPI_CAMERA_ROMVERSION 		9
  
  /* Event masks */
  #define SONYPI_JOGGER_MASK			0x00000001
  #define SONYPI_CAPTURE_MASK			0x00000002
  #define SONYPI_FNKEY_MASK			0x00000004
  #define SONYPI_BLUETOOTH_MASK			0x00000008
  #define SONYPI_PKEY_MASK			0x00000010
  #define SONYPI_BACK_MASK			0x00000020
  #define SONYPI_HELP_MASK			0x00000040
  #define SONYPI_LID_MASK				0x00000080
  #define SONYPI_ZOOM_MASK			0x00000100
  #define SONYPI_THUMBPHRASE_MASK			0x00000200
  #define SONYPI_MEYE_MASK			0x00000400
  #define SONYPI_MEMORYSTICK_MASK			0x00000800
  #define SONYPI_BATTERY_MASK			0x00001000
d2052c167   Erik Waling   [PATCH] sonypi SP...
239
  #define SONYPI_WIRELESS_MASK			0x00002000
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
  
  struct sonypi_event {
  	u8	data;
  	u8	event;
  };
  
  /* The set of possible button release events */
  static struct sonypi_event sonypi_releaseev[] = {
  	{ 0x00, SONYPI_EVENT_ANYBUTTON_RELEASED },
  	{ 0, 0 }
  };
  
  /* The set of possible jogger events  */
  static struct sonypi_event sonypi_joggerev[] = {
  	{ 0x1f, SONYPI_EVENT_JOGDIAL_UP },
  	{ 0x01, SONYPI_EVENT_JOGDIAL_DOWN },
  	{ 0x5f, SONYPI_EVENT_JOGDIAL_UP_PRESSED },
  	{ 0x41, SONYPI_EVENT_JOGDIAL_DOWN_PRESSED },
  	{ 0x1e, SONYPI_EVENT_JOGDIAL_FAST_UP },
  	{ 0x02, SONYPI_EVENT_JOGDIAL_FAST_DOWN },
  	{ 0x5e, SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED },
  	{ 0x42, SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED },
  	{ 0x1d, SONYPI_EVENT_JOGDIAL_VFAST_UP },
  	{ 0x03, SONYPI_EVENT_JOGDIAL_VFAST_DOWN },
  	{ 0x5d, SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED },
  	{ 0x43, SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED },
  	{ 0x40, SONYPI_EVENT_JOGDIAL_PRESSED },
  	{ 0, 0 }
  };
  
  /* The set of possible capture button events */
  static struct sonypi_event sonypi_captureev[] = {
  	{ 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED },
  	{ 0x07, SONYPI_EVENT_CAPTURE_PRESSED },
  	{ 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED },
  	{ 0, 0 }
  };
  
  /* The set of possible fnkeys events */
  static struct sonypi_event sonypi_fnkeyev[] = {
  	{ 0x10, SONYPI_EVENT_FNKEY_ESC },
  	{ 0x11, SONYPI_EVENT_FNKEY_F1 },
  	{ 0x12, SONYPI_EVENT_FNKEY_F2 },
  	{ 0x13, SONYPI_EVENT_FNKEY_F3 },
  	{ 0x14, SONYPI_EVENT_FNKEY_F4 },
  	{ 0x15, SONYPI_EVENT_FNKEY_F5 },
  	{ 0x16, SONYPI_EVENT_FNKEY_F6 },
  	{ 0x17, SONYPI_EVENT_FNKEY_F7 },
  	{ 0x18, SONYPI_EVENT_FNKEY_F8 },
  	{ 0x19, SONYPI_EVENT_FNKEY_F9 },
  	{ 0x1a, SONYPI_EVENT_FNKEY_F10 },
  	{ 0x1b, SONYPI_EVENT_FNKEY_F11 },
  	{ 0x1c, SONYPI_EVENT_FNKEY_F12 },
  	{ 0x1f, SONYPI_EVENT_FNKEY_RELEASED },
  	{ 0x21, SONYPI_EVENT_FNKEY_1 },
  	{ 0x22, SONYPI_EVENT_FNKEY_2 },
  	{ 0x31, SONYPI_EVENT_FNKEY_D },
  	{ 0x32, SONYPI_EVENT_FNKEY_E },
  	{ 0x33, SONYPI_EVENT_FNKEY_F },
  	{ 0x34, SONYPI_EVENT_FNKEY_S },
  	{ 0x35, SONYPI_EVENT_FNKEY_B },
  	{ 0x36, SONYPI_EVENT_FNKEY_ONLY },
  	{ 0, 0 }
  };
  
  /* The set of possible program key events */
  static struct sonypi_event sonypi_pkeyev[] = {
  	{ 0x01, SONYPI_EVENT_PKEY_P1 },
  	{ 0x02, SONYPI_EVENT_PKEY_P2 },
  	{ 0x04, SONYPI_EVENT_PKEY_P3 },
  	{ 0x5c, SONYPI_EVENT_PKEY_P1 },
  	{ 0, 0 }
  };
  
  /* The set of possible bluetooth events */
  static struct sonypi_event sonypi_blueev[] = {
  	{ 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED },
  	{ 0x59, SONYPI_EVENT_BLUETOOTH_ON },
  	{ 0x5a, SONYPI_EVENT_BLUETOOTH_OFF },
  	{ 0, 0 }
  };
d2052c167   Erik Waling   [PATCH] sonypi SP...
321
322
323
324
325
326
  /* The set of possible wireless events */
  static struct sonypi_event sonypi_wlessev[] = {
  	{ 0x59, SONYPI_EVENT_WIRELESS_ON },
  	{ 0x5a, SONYPI_EVENT_WIRELESS_OFF },
  	{ 0, 0 }
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
  /* The set of possible back button events */
  static struct sonypi_event sonypi_backev[] = {
  	{ 0x20, SONYPI_EVENT_BACK_PRESSED },
  	{ 0, 0 }
  };
  
  /* The set of possible help button events */
  static struct sonypi_event sonypi_helpev[] = {
  	{ 0x3b, SONYPI_EVENT_HELP_PRESSED },
  	{ 0, 0 }
  };
  
  
  /* The set of possible lid events */
  static struct sonypi_event sonypi_lidev[] = {
  	{ 0x51, SONYPI_EVENT_LID_CLOSED },
  	{ 0x50, SONYPI_EVENT_LID_OPENED },
  	{ 0, 0 }
  };
  
  /* The set of possible zoom events */
  static struct sonypi_event sonypi_zoomev[] = {
  	{ 0x39, SONYPI_EVENT_ZOOM_PRESSED },
  	{ 0, 0 }
  };
  
  /* The set of possible thumbphrase events */
  static struct sonypi_event sonypi_thumbphraseev[] = {
  	{ 0x3a, SONYPI_EVENT_THUMBPHRASE_PRESSED },
  	{ 0, 0 }
  };
  
  /* The set of possible motioneye camera events */
  static struct sonypi_event sonypi_meyeev[] = {
  	{ 0x00, SONYPI_EVENT_MEYE_FACE },
  	{ 0x01, SONYPI_EVENT_MEYE_OPPOSITE },
  	{ 0, 0 }
  };
  
  /* The set of possible memorystick events */
  static struct sonypi_event sonypi_memorystickev[] = {
  	{ 0x53, SONYPI_EVENT_MEMORYSTICK_INSERT },
  	{ 0x54, SONYPI_EVENT_MEMORYSTICK_EJECT },
  	{ 0, 0 }
  };
  
  /* The set of possible battery events */
  static struct sonypi_event sonypi_batteryev[] = {
  	{ 0x20, SONYPI_EVENT_BATTERY_INSERT },
  	{ 0x30, SONYPI_EVENT_BATTERY_REMOVE },
  	{ 0, 0 }
  };
  
  static struct sonypi_eventtypes {
  	int			model;
  	u8			data;
  	unsigned long		mask;
  	struct sonypi_event *	events;
  } sonypi_eventtypes[] = {
  	{ SONYPI_DEVICE_MODEL_TYPE1, 0, 0xffffffff, sonypi_releaseev },
  	{ SONYPI_DEVICE_MODEL_TYPE1, 0x70, SONYPI_MEYE_MASK, sonypi_meyeev },
  	{ SONYPI_DEVICE_MODEL_TYPE1, 0x30, SONYPI_LID_MASK, sonypi_lidev },
  	{ SONYPI_DEVICE_MODEL_TYPE1, 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev },
  	{ SONYPI_DEVICE_MODEL_TYPE1, 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev },
  	{ SONYPI_DEVICE_MODEL_TYPE1, 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
  	{ SONYPI_DEVICE_MODEL_TYPE1, 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
  	{ SONYPI_DEVICE_MODEL_TYPE1, 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
  	{ SONYPI_DEVICE_MODEL_TYPE1, 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
  	{ SONYPI_DEVICE_MODEL_TYPE1, 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev },
  
  	{ SONYPI_DEVICE_MODEL_TYPE2, 0, 0xffffffff, sonypi_releaseev },
  	{ SONYPI_DEVICE_MODEL_TYPE2, 0x38, SONYPI_LID_MASK, sonypi_lidev },
  	{ SONYPI_DEVICE_MODEL_TYPE2, 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev },
  	{ SONYPI_DEVICE_MODEL_TYPE2, 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev },
  	{ SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
  	{ SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
  	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
  	{ SONYPI_DEVICE_MODEL_TYPE2, 0x11, SONYPI_BACK_MASK, sonypi_backev },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
406
407
408
409
410
  	{ SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_HELP_MASK, sonypi_helpev },
  	{ SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev },
  	{ SONYPI_DEVICE_MODEL_TYPE2, 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
  	{ SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
  	{ SONYPI_DEVICE_MODEL_TYPE2, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
  	{ SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
d2052c167   Erik Waling   [PATCH] sonypi SP...
411
412
413
414
415
416
  	{ SONYPI_DEVICE_MODEL_TYPE3, 0, 0xffffffff, sonypi_releaseev },
  	{ SONYPI_DEVICE_MODEL_TYPE3, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
  	{ SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
  	{ SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
  	{ SONYPI_DEVICE_MODEL_TYPE3, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
  	{ SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417
418
419
420
  	{ 0 }
  };
  
  #define SONYPI_BUF_SIZE	128
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
  /* Correspondance table between sonypi events and input layer events */
  static struct {
  	int sonypiev;
  	int inputev;
  } sonypi_inputkeys[] = {
  	{ SONYPI_EVENT_CAPTURE_PRESSED,	 	KEY_CAMERA },
  	{ SONYPI_EVENT_FNKEY_ONLY, 		KEY_FN },
  	{ SONYPI_EVENT_FNKEY_ESC, 		KEY_FN_ESC },
  	{ SONYPI_EVENT_FNKEY_F1, 		KEY_FN_F1 },
  	{ SONYPI_EVENT_FNKEY_F2, 		KEY_FN_F2 },
  	{ SONYPI_EVENT_FNKEY_F3, 		KEY_FN_F3 },
  	{ SONYPI_EVENT_FNKEY_F4, 		KEY_FN_F4 },
  	{ SONYPI_EVENT_FNKEY_F5, 		KEY_FN_F5 },
  	{ SONYPI_EVENT_FNKEY_F6, 		KEY_FN_F6 },
  	{ SONYPI_EVENT_FNKEY_F7, 		KEY_FN_F7 },
  	{ SONYPI_EVENT_FNKEY_F8, 		KEY_FN_F8 },
  	{ SONYPI_EVENT_FNKEY_F9,		KEY_FN_F9 },
  	{ SONYPI_EVENT_FNKEY_F10,		KEY_FN_F10 },
  	{ SONYPI_EVENT_FNKEY_F11, 		KEY_FN_F11 },
  	{ SONYPI_EVENT_FNKEY_F12,		KEY_FN_F12 },
  	{ SONYPI_EVENT_FNKEY_1, 		KEY_FN_1 },
  	{ SONYPI_EVENT_FNKEY_2, 		KEY_FN_2 },
  	{ SONYPI_EVENT_FNKEY_D,			KEY_FN_D },
  	{ SONYPI_EVENT_FNKEY_E,			KEY_FN_E },
  	{ SONYPI_EVENT_FNKEY_F,			KEY_FN_F },
  	{ SONYPI_EVENT_FNKEY_S,			KEY_FN_S },
  	{ SONYPI_EVENT_FNKEY_B,			KEY_FN_B },
  	{ SONYPI_EVENT_BLUETOOTH_PRESSED, 	KEY_BLUE },
  	{ SONYPI_EVENT_BLUETOOTH_ON, 		KEY_BLUE },
  	{ SONYPI_EVENT_PKEY_P1, 		KEY_PROG1 },
  	{ SONYPI_EVENT_PKEY_P2, 		KEY_PROG2 },
  	{ SONYPI_EVENT_PKEY_P3, 		KEY_PROG3 },
  	{ SONYPI_EVENT_BACK_PRESSED, 		KEY_BACK },
  	{ SONYPI_EVENT_HELP_PRESSED, 		KEY_HELP },
  	{ SONYPI_EVENT_ZOOM_PRESSED, 		KEY_ZOOM },
  	{ SONYPI_EVENT_THUMBPHRASE_PRESSED, 	BTN_THUMB },
  	{ 0, 0 },
  };
fb2ce3c00   Dmitry Torokhov   Sonypi: make sure...
459
460
461
462
  struct sonypi_keypress {
  	struct input_dev *dev;
  	int key;
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
463
464
  static struct sonypi_device {
  	struct pci_dev *dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
466
467
468
469
470
471
472
  	u16 irq;
  	u16 bits;
  	u16 ioport1;
  	u16 ioport2;
  	u16 region_size;
  	u16 evtype_offset;
  	int camera_power;
  	int bluetooth_power;
c6c60106b   Matthias Kaehlcke   sonypi: use mutex...
473
  	struct mutex lock;
454654878   Stefani Seibold   kfifo: move struc...
474
  	struct kfifo fifo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475
476
477
478
479
  	spinlock_t fifo_lock;
  	wait_queue_head_t fifo_proc_list;
  	struct fasync_struct *fifo_async;
  	int open_count;
  	int model;
b416f2e45   Dmitry Torokhov   [PATCH] Input: co...
480
481
  	struct input_dev *input_jog_dev;
  	struct input_dev *input_key_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
  	struct work_struct input_work;
454654878   Stefani Seibold   kfifo: move struc...
483
  	struct kfifo input_fifo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
485
486
487
488
489
490
491
492
493
494
  	spinlock_t input_fifo_lock;
  } sonypi_device;
  
  #define ITERATIONS_LONG		10000
  #define ITERATIONS_SHORT	10
  
  #define wait_on_command(quiet, command, iterations) { \
  	unsigned int n = iterations; \
  	while (--n && (command)) \
  		udelay(1); \
  	if (!n && (verbose || !quiet)) \
bf9d89295   Harvey Harrison   drivers/char: rep...
495
496
  		printk(KERN_WARNING "sonypi command failed at %s : %s (line %d)
  ", __FILE__, __func__, __LINE__); \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
498
499
500
501
502
503
  }
  
  #ifdef CONFIG_ACPI
  #define SONYPI_ACPI_ACTIVE (!acpi_disabled)
  #else
  #define SONYPI_ACPI_ACTIVE 0
  #endif				/* CONFIG_ACPI */
b368fae6a   Ben Collins   [PATCH] sonypi: E...
504
505
  #ifdef CONFIG_ACPI
  static struct acpi_device *sonypi_acpi_device;
e4513a57e   Bjorn Helgaas   ACPI: fix sonypi ...
506
  static int acpi_driver_registered;
b368fae6a   Ben Collins   [PATCH] sonypi: E...
507
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
509
  static int sonypi_ec_write(u8 addr, u8 value)
  {
8950d89ac   Bjorn Helgaas   ACPI: remove CONF...
510
  #ifdef CONFIG_ACPI
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
  	if (SONYPI_ACPI_ACTIVE)
  		return ec_write(addr, value);
  #endif
  	wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3, ITERATIONS_LONG);
  	outb_p(0x81, SONYPI_CST_IOPORT);
  	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
  	outb_p(addr, SONYPI_DATA_IOPORT);
  	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
  	outb_p(value, SONYPI_DATA_IOPORT);
  	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
  	return 0;
  }
  
  static int sonypi_ec_read(u8 addr, u8 *value)
  {
8950d89ac   Bjorn Helgaas   ACPI: remove CONF...
526
  #ifdef CONFIG_ACPI
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
  	if (SONYPI_ACPI_ACTIVE)
  		return ec_read(addr, value);
  #endif
  	wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3, ITERATIONS_LONG);
  	outb_p(0x80, SONYPI_CST_IOPORT);
  	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
  	outb_p(addr, SONYPI_DATA_IOPORT);
  	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
  	*value = inb_p(SONYPI_DATA_IOPORT);
  	return 0;
  }
  
  static int ec_read16(u8 addr, u16 *value)
  {
  	u8 val_lb, val_hb;
  	if (sonypi_ec_read(addr, &val_lb))
  		return -1;
  	if (sonypi_ec_read(addr + 1, &val_hb))
  		return -1;
  	*value = val_lb | (val_hb << 8);
  	return 0;
  }
  
  /* Initializes the device - this comes from the AML code in the ACPI bios */
  static void sonypi_type1_srs(void)
  {
  	u32 v;
  
  	pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
  	v = (v & 0xFFFF0000) | ((u32) sonypi_device.ioport1);
  	pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
  
  	pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
  	v = (v & 0xFFF0FFFF) |
  	    (((u32) sonypi_device.ioport1 ^ sonypi_device.ioport2) << 16);
  	pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
  
  	v = inl(SONYPI_IRQ_PORT);
  	v &= ~(((u32) 0x3) << SONYPI_IRQ_SHIFT);
  	v |= (((u32) sonypi_device.bits) << SONYPI_IRQ_SHIFT);
  	outl(v, SONYPI_IRQ_PORT);
  
  	pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
  	v = (v & 0xFF1FFFFF) | 0x00C00000;
  	pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
  }
  
  static void sonypi_type2_srs(void)
  {
  	if (sonypi_ec_write(SONYPI_SHIB, (sonypi_device.ioport1 & 0xFF00) >> 8))
  		printk(KERN_WARNING "ec_write failed
  ");
  	if (sonypi_ec_write(SONYPI_SLOB, sonypi_device.ioport1 & 0x00FF))
  		printk(KERN_WARNING "ec_write failed
  ");
  	if (sonypi_ec_write(SONYPI_SIRQ, sonypi_device.bits))
  		printk(KERN_WARNING "ec_write failed
  ");
  	udelay(10);
  }
d2052c167   Erik Waling   [PATCH] sonypi SP...
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
  static void sonypi_type3_srs(void)
  {
  	u16 v16;
  	u8  v8;
  
  	/* This model type uses the same initialiazation of
  	 * the embedded controller as the type2 models. */
  	sonypi_type2_srs();
  
  	/* Initialization of PCI config space of the LPC interface bridge. */
  	v16 = (sonypi_device.ioport1 & 0xFFF0) | 0x01;
  	pci_write_config_word(sonypi_device.dev, SONYPI_TYPE3_GID2, v16);
  	pci_read_config_byte(sonypi_device.dev, SONYPI_TYPE3_MISC, &v8);
  	v8 = (v8 & 0xCF) | 0x10;
  	pci_write_config_byte(sonypi_device.dev, SONYPI_TYPE3_MISC, v8);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
  /* Disables the device - this comes from the AML code in the ACPI bios */
  static void sonypi_type1_dis(void)
  {
  	u32 v;
  
  	pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
  	v = v & 0xFF3FFFFF;
  	pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
  
  	v = inl(SONYPI_IRQ_PORT);
  	v |= (0x3 << SONYPI_IRQ_SHIFT);
  	outl(v, SONYPI_IRQ_PORT);
  }
  
  static void sonypi_type2_dis(void)
  {
  	if (sonypi_ec_write(SONYPI_SHIB, 0))
  		printk(KERN_WARNING "ec_write failed
  ");
  	if (sonypi_ec_write(SONYPI_SLOB, 0))
  		printk(KERN_WARNING "ec_write failed
  ");
  	if (sonypi_ec_write(SONYPI_SIRQ, 0))
  		printk(KERN_WARNING "ec_write failed
  ");
  }
d2052c167   Erik Waling   [PATCH] sonypi SP...
629
630
631
632
633
634
  static void sonypi_type3_dis(void)
  {
  	sonypi_type2_dis();
  	udelay(10);
  	pci_write_config_word(sonypi_device.dev, SONYPI_TYPE3_GID2, 0);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
  static u8 sonypi_call1(u8 dev)
  {
  	u8 v1, v2;
  
  	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
  	outb(dev, sonypi_device.ioport2);
  	v1 = inb_p(sonypi_device.ioport2);
  	v2 = inb_p(sonypi_device.ioport1);
  	return v2;
  }
  
  static u8 sonypi_call2(u8 dev, u8 fn)
  {
  	u8 v1;
  
  	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
  	outb(dev, sonypi_device.ioport2);
  	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
  	outb(fn, sonypi_device.ioport1);
  	v1 = inb_p(sonypi_device.ioport1);
  	return v1;
  }
  
  static u8 sonypi_call3(u8 dev, u8 fn, u8 v)
  {
  	u8 v1;
  
  	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
  	outb(dev, sonypi_device.ioport2);
  	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
  	outb(fn, sonypi_device.ioport1);
  	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
  	outb(v, sonypi_device.ioport1);
  	v1 = inb_p(sonypi_device.ioport1);
  	return v1;
  }
  
  #if 0
  /* Get brightness, hue etc. Unreliable... */
  static u8 sonypi_read(u8 fn)
  {
  	u8 v1, v2;
  	int n = 100;
  
  	while (n--) {
  		v1 = sonypi_call2(0x8f, fn);
  		v2 = sonypi_call2(0x8f, fn);
  		if (v1 == v2 && v1 != 0xff)
  			return v1;
  	}
  	return 0xff;
  }
  #endif
  
  /* Set brightness, hue etc */
  static void sonypi_set(u8 fn, u8 v)
  {
  	wait_on_command(0, sonypi_call3(0x90, fn, v), ITERATIONS_SHORT);
  }
  
  /* Tests if the camera is ready */
  static int sonypi_camera_ready(void)
  {
  	u8 v;
  
  	v = sonypi_call2(0x8f, SONYPI_CAMERA_STATUS);
  	return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY));
  }
  
  /* Turns the camera off */
  static void sonypi_camera_off(void)
  {
  	sonypi_set(SONYPI_CAMERA_PICTURE, SONYPI_CAMERA_MUTE_MASK);
  
  	if (!sonypi_device.camera_power)
  		return;
  
  	sonypi_call2(0x91, 0);
  	sonypi_device.camera_power = 0;
  }
  
  /* Turns the camera on */
  static void sonypi_camera_on(void)
  {
  	int i, j;
  
  	if (sonypi_device.camera_power)
  		return;
  
  	for (j = 5; j > 0; j--) {
  
  		while (sonypi_call2(0x91, 0x1))
  			msleep(10);
  		sonypi_call1(0x93);
  
  		for (i = 400; i > 0; i--) {
  			if (sonypi_camera_ready())
  				break;
  			msleep(10);
  		}
  		if (i)
  			break;
  	}
  
  	if (j == 0) {
  		printk(KERN_WARNING "sonypi: failed to power on camera
  ");
  		return;
  	}
  
  	sonypi_set(0x10, 0x5a);
  	sonypi_device.camera_power = 1;
  }
  
  /* sets the bluetooth subsystem power state */
  static void sonypi_setbluetoothpower(u8 state)
  {
  	state = !!state;
  
  	if (sonypi_device.bluetooth_power == state)
  		return;
  
  	sonypi_call2(0x96, state);
  	sonypi_call1(0x82);
  	sonypi_device.bluetooth_power = state;
  }
c4028958b   David Howells   WorkStruct: make ...
761
  static void input_keyrelease(struct work_struct *work)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
762
  {
fb2ce3c00   Dmitry Torokhov   Sonypi: make sure...
763
  	struct sonypi_keypress kp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764

7acd72eb8   Stefani Seibold   kfifo: rename kfi...
765
  	while (kfifo_out_locked(&sonypi_device.input_fifo, (unsigned char *)&kp,
c1e13f256   Stefani Seibold   kfifo: move out s...
766
767
  			 sizeof(kp), &sonypi_device.input_fifo_lock)
  			== sizeof(kp)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768
  		msleep(10);
fb2ce3c00   Dmitry Torokhov   Sonypi: make sure...
769
770
771
772
773
774
775
  		input_report_key(kp.dev, kp.key, 0);
  		input_sync(kp.dev);
  	}
  }
  
  static void sonypi_report_input_event(u8 event)
  {
b416f2e45   Dmitry Torokhov   [PATCH] Input: co...
776
777
  	struct input_dev *jog_dev = sonypi_device.input_jog_dev;
  	struct input_dev *key_dev = sonypi_device.input_key_dev;
fb2ce3c00   Dmitry Torokhov   Sonypi: make sure...
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
  	struct sonypi_keypress kp = { NULL };
  	int i;
  
  	switch (event) {
  	case SONYPI_EVENT_JOGDIAL_UP:
  	case SONYPI_EVENT_JOGDIAL_UP_PRESSED:
  		input_report_rel(jog_dev, REL_WHEEL, 1);
  		input_sync(jog_dev);
  		break;
  
  	case SONYPI_EVENT_JOGDIAL_DOWN:
  	case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED:
  		input_report_rel(jog_dev, REL_WHEEL, -1);
  		input_sync(jog_dev);
  		break;
  
  	case SONYPI_EVENT_JOGDIAL_PRESSED:
  		kp.key = BTN_MIDDLE;
  		kp.dev = jog_dev;
  		break;
  
  	case SONYPI_EVENT_FNKEY_RELEASED:
  		/* Nothing, not all VAIOs generate this event */
  		break;
  
  	default:
  		for (i = 0; sonypi_inputkeys[i].sonypiev; i++)
  			if (event == sonypi_inputkeys[i].sonypiev) {
  				kp.dev = key_dev;
  				kp.key = sonypi_inputkeys[i].inputev;
  				break;
  			}
  		break;
  	}
  
  	if (kp.dev) {
  		input_report_key(kp.dev, kp.key, 1);
  		input_sync(kp.dev);
7acd72eb8   Stefani Seibold   kfifo: rename kfi...
816
  		kfifo_in_locked(&sonypi_device.input_fifo,
c1e13f256   Stefani Seibold   kfifo: move out s...
817
818
  			(unsigned char *)&kp, sizeof(kp),
  			&sonypi_device.input_fifo_lock);
fb2ce3c00   Dmitry Torokhov   Sonypi: make sure...
819
  		schedule_work(&sonypi_device.input_work);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
820
821
822
823
  	}
  }
  
  /* Interrupt handler: some event is available */
7d12e780e   David Howells   IRQ: Maintain reg...
824
  static irqreturn_t sonypi_irq(int irq, void *dev_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
  {
  	u8 v1, v2, event = 0;
  	int i, j;
  
  	v1 = inb_p(sonypi_device.ioport1);
  	v2 = inb_p(sonypi_device.ioport1 + sonypi_device.evtype_offset);
  
  	for (i = 0; sonypi_eventtypes[i].model; i++) {
  		if (sonypi_device.model != sonypi_eventtypes[i].model)
  			continue;
  		if ((v2 & sonypi_eventtypes[i].data) !=
  		    sonypi_eventtypes[i].data)
  			continue;
  		if (!(mask & sonypi_eventtypes[i].mask))
  			continue;
  		for (j = 0; sonypi_eventtypes[i].events[j].event; j++) {
  			if (v1 == sonypi_eventtypes[i].events[j].data) {
  				event = sonypi_eventtypes[i].events[j].event;
  				goto found;
  			}
  		}
  	}
  
  	if (verbose)
  		printk(KERN_WARNING
  		       "sonypi: unknown event port1=0x%02x,port2=0x%02x
  ",
  		       v1, v2);
  	/* We need to return IRQ_HANDLED here because there *are*
  	 * events belonging to the sonypi device we don't know about,
  	 * but we still don't want those to pollute the logs... */
  	return IRQ_HANDLED;
  
  found:
  	if (verbose > 1)
  		printk(KERN_INFO
  		       "sonypi: event port1=0x%02x,port2=0x%02x
  ", v1, v2);
fb2ce3c00   Dmitry Torokhov   Sonypi: make sure...
863
864
  	if (useinput)
  		sonypi_report_input_event(event);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
865

7acd72eb8   Stefani Seibold   kfifo: rename kfi...
866
  	kfifo_in_locked(&sonypi_device.fifo, (unsigned char *)&event,
c1e13f256   Stefani Seibold   kfifo: move out s...
867
  			sizeof(event), &sonypi_device.fifo_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
868
869
870
871
872
  	kill_fasync(&sonypi_device.fifo_async, SIGIO, POLL_IN);
  	wake_up_interruptible(&sonypi_device.fifo_proc_list);
  
  	return IRQ_HANDLED;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
873
874
  static int sonypi_misc_fasync(int fd, struct file *filp, int on)
  {
60aa49243   Jonathan Corbet   Rationalize fasyn...
875
  	return fasync_helper(fd, filp, on, &sonypi_device.fifo_async);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
876
877
878
879
  }
  
  static int sonypi_misc_release(struct inode *inode, struct file *file)
  {
c6c60106b   Matthias Kaehlcke   sonypi: use mutex...
880
  	mutex_lock(&sonypi_device.lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
881
  	sonypi_device.open_count--;
c6c60106b   Matthias Kaehlcke   sonypi: use mutex...
882
  	mutex_unlock(&sonypi_device.lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
883
884
885
886
887
  	return 0;
  }
  
  static int sonypi_misc_open(struct inode *inode, struct file *file)
  {
c6c60106b   Matthias Kaehlcke   sonypi: use mutex...
888
  	mutex_lock(&sonypi_device.lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
889
890
  	/* Flush input queue on first open */
  	if (!sonypi_device.open_count)
454654878   Stefani Seibold   kfifo: move struc...
891
  		kfifo_reset(&sonypi_device.fifo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
892
  	sonypi_device.open_count++;
c6c60106b   Matthias Kaehlcke   sonypi: use mutex...
893
  	mutex_unlock(&sonypi_device.lock);
6432e734c   John Kacur   sony_pi: Remove t...
894

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
895
896
897
898
899
900
901
902
  	return 0;
  }
  
  static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
  				size_t count, loff_t *pos)
  {
  	ssize_t ret;
  	unsigned char c;
454654878   Stefani Seibold   kfifo: move struc...
903
  	if ((kfifo_len(&sonypi_device.fifo) == 0) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
904
905
906
907
  	    (file->f_flags & O_NONBLOCK))
  		return -EAGAIN;
  
  	ret = wait_event_interruptible(sonypi_device.fifo_proc_list,
454654878   Stefani Seibold   kfifo: move struc...
908
  				       kfifo_len(&sonypi_device.fifo) != 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
909
910
911
912
  	if (ret)
  		return ret;
  
  	while (ret < count &&
7acd72eb8   Stefani Seibold   kfifo: rename kfi...
913
  	       (kfifo_out_locked(&sonypi_device.fifo, &c, sizeof(c),
c1e13f256   Stefani Seibold   kfifo: move out s...
914
  				 &sonypi_device.fifo_lock) == sizeof(c))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
915
916
917
918
919
920
  		if (put_user(c, buf++))
  			return -EFAULT;
  		ret++;
  	}
  
  	if (ret > 0) {
496ad9aa8   Al Viro   new helper: file_...
921
  		struct inode *inode = file_inode(file);
c2050a454   Deepa Dinamani   fs: Replace curre...
922
  		inode->i_atime = current_time(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
923
924
925
926
927
928
929
930
  	}
  
  	return ret;
  }
  
  static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait)
  {
  	poll_wait(file, &sonypi_device.fifo_proc_list, wait);
454654878   Stefani Seibold   kfifo: move struc...
931
  	if (kfifo_len(&sonypi_device.fifo))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932
933
934
  		return POLLIN | POLLRDNORM;
  	return 0;
  }
6432e734c   John Kacur   sony_pi: Remove t...
935
  static long sonypi_misc_ioctl(struct file *fp,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
936
937
  			     unsigned int cmd, unsigned long arg)
  {
6432e734c   John Kacur   sony_pi: Remove t...
938
  	long ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939
940
941
  	void __user *argp = (void __user *)arg;
  	u8 val8;
  	u16 val16;
c6c60106b   Matthias Kaehlcke   sonypi: use mutex...
942
  	mutex_lock(&sonypi_device.lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
  	switch (cmd) {
  	case SONYPI_IOCGBRT:
  		if (sonypi_ec_read(SONYPI_LCD_LIGHT, &val8)) {
  			ret = -EIO;
  			break;
  		}
  		if (copy_to_user(argp, &val8, sizeof(val8)))
  			ret = -EFAULT;
  		break;
  	case SONYPI_IOCSBRT:
  		if (copy_from_user(&val8, argp, sizeof(val8))) {
  			ret = -EFAULT;
  			break;
  		}
  		if (sonypi_ec_write(SONYPI_LCD_LIGHT, val8))
  			ret = -EIO;
  		break;
  	case SONYPI_IOCGBAT1CAP:
  		if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
  			ret = -EIO;
  			break;
  		}
  		if (copy_to_user(argp, &val16, sizeof(val16)))
  			ret = -EFAULT;
  		break;
  	case SONYPI_IOCGBAT1REM:
  		if (ec_read16(SONYPI_BAT1_LEFT, &val16)) {
  			ret = -EIO;
  			break;
  		}
  		if (copy_to_user(argp, &val16, sizeof(val16)))
  			ret = -EFAULT;
  		break;
  	case SONYPI_IOCGBAT2CAP:
  		if (ec_read16(SONYPI_BAT2_FULL, &val16)) {
  			ret = -EIO;
  			break;
  		}
  		if (copy_to_user(argp, &val16, sizeof(val16)))
  			ret = -EFAULT;
  		break;
  	case SONYPI_IOCGBAT2REM:
  		if (ec_read16(SONYPI_BAT2_LEFT, &val16)) {
  			ret = -EIO;
  			break;
  		}
  		if (copy_to_user(argp, &val16, sizeof(val16)))
  			ret = -EFAULT;
  		break;
  	case SONYPI_IOCGBATFLAGS:
  		if (sonypi_ec_read(SONYPI_BAT_FLAGS, &val8)) {
  			ret = -EIO;
  			break;
  		}
  		val8 &= 0x07;
  		if (copy_to_user(argp, &val8, sizeof(val8)))
  			ret = -EFAULT;
  		break;
  	case SONYPI_IOCGBLUE:
  		val8 = sonypi_device.bluetooth_power;
  		if (copy_to_user(argp, &val8, sizeof(val8)))
  			ret = -EFAULT;
  		break;
  	case SONYPI_IOCSBLUE:
  		if (copy_from_user(&val8, argp, sizeof(val8))) {
  			ret = -EFAULT;
  			break;
  		}
  		sonypi_setbluetoothpower(val8);
  		break;
  	/* FAN Controls */
  	case SONYPI_IOCGFAN:
  		if (sonypi_ec_read(SONYPI_FAN0_STATUS, &val8)) {
  			ret = -EIO;
  			break;
  		}
0555985d0   Al Viro   [PATCH] sonypi tr...
1019
  		if (copy_to_user(argp, &val8, sizeof(val8)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1020
1021
1022
  			ret = -EFAULT;
  		break;
  	case SONYPI_IOCSFAN:
0555985d0   Al Viro   [PATCH] sonypi tr...
1023
  		if (copy_from_user(&val8, argp, sizeof(val8))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
  			ret = -EFAULT;
  			break;
  		}
  		if (sonypi_ec_write(SONYPI_FAN0_STATUS, val8))
  			ret = -EIO;
  		break;
  	/* GET Temperature (useful under APM) */
  	case SONYPI_IOCGTEMP:
  		if (sonypi_ec_read(SONYPI_TEMP_STATUS, &val8)) {
  			ret = -EIO;
  			break;
  		}
0555985d0   Al Viro   [PATCH] sonypi tr...
1036
  		if (copy_to_user(argp, &val8, sizeof(val8)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1037
1038
1039
1040
1041
  			ret = -EFAULT;
  		break;
  	default:
  		ret = -EINVAL;
  	}
c6c60106b   Matthias Kaehlcke   sonypi: use mutex...
1042
  	mutex_unlock(&sonypi_device.lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1043
1044
  	return ret;
  }
62322d255   Arjan van de Ven   [PATCH] make more...
1045
  static const struct file_operations sonypi_misc_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1046
1047
1048
1049
1050
1051
  	.owner		= THIS_MODULE,
  	.read		= sonypi_misc_read,
  	.poll		= sonypi_misc_poll,
  	.open		= sonypi_misc_open,
  	.release	= sonypi_misc_release,
  	.fasync		= sonypi_misc_fasync,
6432e734c   John Kacur   sony_pi: Remove t...
1052
1053
  	.unlocked_ioctl	= sonypi_misc_ioctl,
  	.llseek		= no_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
  };
  
  static struct miscdevice sonypi_misc_device = {
  	.minor		= MISC_DYNAMIC_MINOR,
  	.name		= "sonypi",
  	.fops		= &sonypi_misc_fops,
  };
  
  static void sonypi_enable(unsigned int camera_on)
  {
d2052c167   Erik Waling   [PATCH] sonypi SP...
1064
1065
  	switch (sonypi_device.model) {
  	case SONYPI_DEVICE_MODEL_TYPE1:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1066
  		sonypi_type1_srs();
d2052c167   Erik Waling   [PATCH] sonypi SP...
1067
1068
1069
1070
1071
1072
1073
1074
  		break;
  	case SONYPI_DEVICE_MODEL_TYPE2:
  		sonypi_type2_srs();
  		break;
  	case SONYPI_DEVICE_MODEL_TYPE3:
  		sonypi_type3_srs();
  		break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
  
  	sonypi_call1(0x82);
  	sonypi_call2(0x81, 0xff);
  	sonypi_call1(compat ? 0x92 : 0x82);
  
  	/* Enable ACPI mode to get Fn key events */
  	if (!SONYPI_ACPI_ACTIVE && fnkeyinit)
  		outb(0xf0, 0xb2);
  
  	if (camera && camera_on)
  		sonypi_camera_on();
  }
  
  static int sonypi_disable(void)
  {
  	sonypi_call2(0x81, 0);	/* make sure we don't get any more events */
  	if (camera)
  		sonypi_camera_off();
  
  	/* disable ACPI mode */
  	if (!SONYPI_ACPI_ACTIVE && fnkeyinit)
  		outb(0xf1, 0xb2);
d2052c167   Erik Waling   [PATCH] sonypi SP...
1097
1098
  	switch (sonypi_device.model) {
  	case SONYPI_DEVICE_MODEL_TYPE1:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1099
  		sonypi_type1_dis();
d2052c167   Erik Waling   [PATCH] sonypi SP...
1100
1101
1102
1103
1104
1105
1106
1107
  		break;
  	case SONYPI_DEVICE_MODEL_TYPE2:
  		sonypi_type2_dis();
  		break;
  	case SONYPI_DEVICE_MODEL_TYPE3:
  		sonypi_type3_dis();
  		break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1108
1109
  	return 0;
  }
b368fae6a   Ben Collins   [PATCH] sonypi: E...
1110
1111
1112
1113
1114
1115
1116
1117
  #ifdef CONFIG_ACPI
  static int sonypi_acpi_add(struct acpi_device *device)
  {
  	sonypi_acpi_device = device;
  	strcpy(acpi_device_name(device), "Sony laptop hotkeys");
  	strcpy(acpi_device_class(device), "sony/hotkey");
  	return 0;
  }
51fac8388   Rafael J. Wysocki   ACPI: Remove usel...
1118
  static int sonypi_acpi_remove(struct acpi_device *device)
b368fae6a   Ben Collins   [PATCH] sonypi: E...
1119
1120
1121
1122
  {
  	sonypi_acpi_device = NULL;
  	return 0;
  }
b0cdb5e11   Tobias Klauser   sonypi: Storage c...
1123
  static const struct acpi_device_id sonypi_device_ids[] = {
f7b88ccb6   Eugene Teo   sonypi: fix ids m...
1124
1125
1126
  	{"SNY6001", 0},
  	{"", 0},
  };
b368fae6a   Ben Collins   [PATCH] sonypi: E...
1127
1128
1129
  static struct acpi_driver sonypi_acpi_driver = {
  	.name           = "sonypi",
  	.class          = "hkey",
f7b88ccb6   Eugene Teo   sonypi: fix ids m...
1130
  	.ids            = sonypi_device_ids,
b368fae6a   Ben Collins   [PATCH] sonypi: E...
1131
1132
1133
1134
1135
1136
  	.ops            = {
  		           .add = sonypi_acpi_add,
  			   .remove = sonypi_acpi_remove,
  	},
  };
  #endif
2223cbec3   Bill Pemberton   char: remove use ...
1137
  static int sonypi_create_input_devices(struct platform_device *pdev)
b416f2e45   Dmitry Torokhov   [PATCH] Input: co...
1138
1139
1140
1141
  {
  	struct input_dev *jog_dev;
  	struct input_dev *key_dev;
  	int i;
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1142
  	int error;
b416f2e45   Dmitry Torokhov   [PATCH] Input: co...
1143
1144
1145
1146
1147
1148
1149
1150
  
  	sonypi_device.input_jog_dev = jog_dev = input_allocate_device();
  	if (!jog_dev)
  		return -ENOMEM;
  
  	jog_dev->name = "Sony Vaio Jogdial";
  	jog_dev->id.bustype = BUS_ISA;
  	jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
dcf65cd41   Dmitry Torokhov   sonypi: fit input...
1151
  	jog_dev->dev.parent = &pdev->dev;
b416f2e45   Dmitry Torokhov   [PATCH] Input: co...
1152

7b19ada2e   Jiri Slaby   get rid of input ...
1153
1154
1155
  	jog_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
  	jog_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_MIDDLE);
  	jog_dev->relbit[0] = BIT_MASK(REL_WHEEL);
b416f2e45   Dmitry Torokhov   [PATCH] Input: co...
1156
1157
1158
  
  	sonypi_device.input_key_dev = key_dev = input_allocate_device();
  	if (!key_dev) {
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1159
1160
  		error = -ENOMEM;
  		goto err_free_jogdev;
b416f2e45   Dmitry Torokhov   [PATCH] Input: co...
1161
1162
1163
1164
1165
  	}
  
  	key_dev->name = "Sony Vaio Keys";
  	key_dev->id.bustype = BUS_ISA;
  	key_dev->id.vendor = PCI_VENDOR_ID_SONY;
dcf65cd41   Dmitry Torokhov   sonypi: fit input...
1166
  	key_dev->dev.parent = &pdev->dev;
b416f2e45   Dmitry Torokhov   [PATCH] Input: co...
1167
1168
  
  	/* Initialize the Input Drivers: special keys */
7b19ada2e   Jiri Slaby   get rid of input ...
1169
  	key_dev->evbit[0] = BIT_MASK(EV_KEY);
b416f2e45   Dmitry Torokhov   [PATCH] Input: co...
1170
1171
1172
  	for (i = 0; sonypi_inputkeys[i].sonypiev; i++)
  		if (sonypi_inputkeys[i].inputev)
  			set_bit(sonypi_inputkeys[i].inputev, key_dev->keybit);
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1173
1174
1175
1176
1177
1178
1179
  	error = input_register_device(jog_dev);
  	if (error)
  		goto err_free_keydev;
  
  	error = input_register_device(key_dev);
  	if (error)
  		goto err_unregister_jogdev;
b416f2e45   Dmitry Torokhov   [PATCH] Input: co...
1180
1181
  
  	return 0;
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
  
   err_unregister_jogdev:
  	input_unregister_device(jog_dev);
  	/* Set to NULL so we don't free it again below */
  	jog_dev = NULL;
   err_free_keydev:
  	input_free_device(key_dev);
  	sonypi_device.input_key_dev = NULL;
   err_free_jogdev:
  	input_free_device(jog_dev);
  	sonypi_device.input_jog_dev = NULL;
  
  	return error;
b416f2e45   Dmitry Torokhov   [PATCH] Input: co...
1195
  }
2223cbec3   Bill Pemberton   char: remove use ...
1196
  static int sonypi_setup_ioports(struct sonypi_device *dev,
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1197
  				const struct sonypi_ioport_list *ioport_list)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1198
  {
1a3e32390   malattia@linux.it   sonypi: try to de...
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
  	/* try to detect if sony-laptop is being used and thus
  	 * has already requested one of the known ioports.
  	 * As in the deprecated check_region this is racy has we have
  	 * multiple ioports available and one of them can be requested
  	 * between this check and the subsequent request. Anyway, as an
  	 * attempt to be some more user-friendly as we currently are,
  	 * this is enough.
  	 */
  	const struct sonypi_ioport_list *check = ioport_list;
  	while (check_ioport && check->port1) {
  		if (!request_region(check->port1,
  				   sonypi_device.region_size,
25985edce   Lucas De Marchi   Fix common misspe...
1211
  				   "Sony Programmable I/O Device Check")) {
1a3e32390   malattia@linux.it   sonypi: try to de...
1212
1213
1214
1215
1216
1217
1218
1219
1220
  			printk(KERN_ERR "sonypi: ioport 0x%.4x busy, using sony-laptop? "
  					"if not use check_ioport=0
  ",
  					check->port1);
  			return -EBUSY;
  		}
  		release_region(check->port1, sonypi_device.region_size);
  		check++;
  	}
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1221
  	while (ioport_list->port1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1222

44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1223
1224
  		if (request_region(ioport_list->port1,
  				   sonypi_device.region_size,
25985edce   Lucas De Marchi   Fix common misspe...
1225
  				   "Sony Programmable I/O Device")) {
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1226
1227
1228
1229
1230
1231
  			dev->ioport1 = ioport_list->port1;
  			dev->ioport2 = ioport_list->port2;
  			return 0;
  		}
  		ioport_list++;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1232

44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1233
1234
  	return -EBUSY;
  }
2223cbec3   Bill Pemberton   char: remove use ...
1235
  static int sonypi_setup_irq(struct sonypi_device *dev,
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1236
1237
1238
1239
1240
  				      const struct sonypi_irq_list *irq_list)
  {
  	while (irq_list->irq) {
  
  		if (!request_irq(irq_list->irq, sonypi_irq,
0f2ed4c6b   Thomas Gleixner   [PATCH] irq-flags...
1241
  				 IRQF_SHARED, "sonypi", sonypi_irq)) {
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1242
1243
1244
1245
1246
1247
1248
1249
1250
  			dev->irq = irq_list->irq;
  			dev->bits = irq_list->bits;
  			return 0;
  		}
  		irq_list++;
  	}
  
  	return -EBUSY;
  }
2223cbec3   Bill Pemberton   char: remove use ...
1251
  static void sonypi_display_info(void)
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
  {
  	printk(KERN_INFO "sonypi: detected type%d model, "
  	       "verbose = %d, fnkeyinit = %s, camera = %s, "
  	       "compat = %s, mask = 0x%08lx, useinput = %s, acpi = %s
  ",
  	       sonypi_device.model,
  	       verbose,
  	       fnkeyinit ? "on" : "off",
  	       camera ? "on" : "off",
  	       compat ? "on" : "off",
  	       mask,
  	       useinput ? "on" : "off",
  	       SONYPI_ACPI_ACTIVE ? "on" : "off");
  	printk(KERN_INFO "sonypi: enabled at irq=%d, port1=0x%x, port2=0x%x
  ",
  	       sonypi_device.irq,
  	       sonypi_device.ioport1, sonypi_device.ioport2);
  
  	if (minor == -1)
  		printk(KERN_INFO "sonypi: device allocated minor is %d
  ",
  		       sonypi_misc_device.minor);
  }
2223cbec3   Bill Pemberton   char: remove use ...
1275
  static int sonypi_probe(struct platform_device *dev)
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1276
1277
1278
1279
1280
  {
  	const struct sonypi_ioport_list *ioport_list;
  	const struct sonypi_irq_list *irq_list;
  	struct pci_dev *pcidev;
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1281

74a882e48   malattia@linux.it   sonypi: suggest s...
1282
1283
1284
1285
  	printk(KERN_WARNING "sonypi: please try the sony-laptop module instead "
  			"and report failures, see also "
  			"http://www.linux.it/~malattia/wiki/index.php/Sony_drivers
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1286
  	spin_lock_init(&sonypi_device.fifo_lock);
c1e13f256   Stefani Seibold   kfifo: move out s...
1287
  	error = kfifo_alloc(&sonypi_device.fifo, SONYPI_BUF_SIZE, GFP_KERNEL);
454654878   Stefani Seibold   kfifo: move struc...
1288
  	if (error) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1289
1290
  		printk(KERN_ERR "sonypi: kfifo_alloc failed
  ");
454654878   Stefani Seibold   kfifo: move struc...
1291
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1292
1293
1294
  	}
  
  	init_waitqueue_head(&sonypi_device.fifo_proc_list);
c6c60106b   Matthias Kaehlcke   sonypi: use mutex...
1295
  	mutex_init(&sonypi_device.lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1296
  	sonypi_device.bluetooth_power = -1;
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1297
1298
1299
1300
1301
1302
  	if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
  				     PCI_DEVICE_ID_INTEL_82371AB_3, NULL)))
  		sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE1;
  	else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
  					  PCI_DEVICE_ID_INTEL_ICH6_1, NULL)))
  		sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3;
bf104e641   Arnaud MAZIN   [PATCH] sonypi: c...
1303
1304
1305
  	else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
  					  PCI_DEVICE_ID_INTEL_ICH7_1, NULL)))
  		sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3;
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1306
1307
  	else
  		sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1308
1309
1310
  	if (pcidev && pci_enable_device(pcidev)) {
  		printk(KERN_ERR "sonypi: pci_enable_device failed
  ");
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1311
1312
  		error = -EIO;
  		goto err_put_pcidev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1313
  	}
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1314
  	sonypi_device.dev = pcidev;
d2052c167   Erik Waling   [PATCH] sonypi SP...
1315
1316
1317
1318
1319
1320
1321
  
  	if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) {
  		ioport_list = sonypi_type1_ioport_list;
  		sonypi_device.region_size = SONYPI_TYPE1_REGION_SIZE;
  		sonypi_device.evtype_offset = SONYPI_TYPE1_EVTYPE_OFFSET;
  		irq_list = sonypi_type1_irq_list;
  	} else if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1322
1323
1324
1325
1326
  		ioport_list = sonypi_type2_ioport_list;
  		sonypi_device.region_size = SONYPI_TYPE2_REGION_SIZE;
  		sonypi_device.evtype_offset = SONYPI_TYPE2_EVTYPE_OFFSET;
  		irq_list = sonypi_type2_irq_list;
  	} else {
d2052c167   Erik Waling   [PATCH] sonypi SP...
1327
1328
1329
1330
  		ioport_list = sonypi_type3_ioport_list;
  		sonypi_device.region_size = SONYPI_TYPE3_REGION_SIZE;
  		sonypi_device.evtype_offset = SONYPI_TYPE3_EVTYPE_OFFSET;
  		irq_list = sonypi_type3_irq_list;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1331
  	}
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1332
1333
1334
1335
1336
  	error = sonypi_setup_ioports(&sonypi_device, ioport_list);
  	if (error) {
  		printk(KERN_ERR "sonypi: failed to request ioports
  ");
  		goto err_disable_pcidev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1337
  	}
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1338
1339
1340
1341
1342
  	error = sonypi_setup_irq(&sonypi_device, irq_list);
  	if (error) {
  		printk(KERN_ERR "sonypi: request_irq failed
  ");
  		goto err_free_ioports;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1343
  	}
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1344
1345
1346
1347
1348
1349
1350
  	if (minor != -1)
  		sonypi_misc_device.minor = minor;
  	error = misc_register(&sonypi_misc_device);
  	if (error) {
  		printk(KERN_ERR "sonypi: misc_register failed
  ");
  		goto err_free_irq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1351
  	}
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1352
  	sonypi_display_info();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1353
  	if (useinput) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1354

dcf65cd41   Dmitry Torokhov   sonypi: fit input...
1355
  		error = sonypi_create_input_devices(dev);
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1356
1357
1358
1359
1360
1361
  		if (error) {
  			printk(KERN_ERR
  				"sonypi: failed to create input devices
  ");
  			goto err_miscdev_unregister;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1362
1363
  
  		spin_lock_init(&sonypi_device.input_fifo_lock);
454654878   Stefani Seibold   kfifo: move struc...
1364
  		error = kfifo_alloc(&sonypi_device.input_fifo, SONYPI_BUF_SIZE,
c1e13f256   Stefani Seibold   kfifo: move out s...
1365
  				GFP_KERNEL);
454654878   Stefani Seibold   kfifo: move struc...
1366
  		if (error) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1367
1368
  			printk(KERN_ERR "sonypi: kfifo_alloc failed
  ");
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1369
  			goto err_inpdev_unregister;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1370
  		}
c4028958b   David Howells   WorkStruct: make ...
1371
  		INIT_WORK(&sonypi_device.input_work, input_keyrelease);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1372
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1373
  	sonypi_enable(0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1374
  	return 0;
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1375
   err_inpdev_unregister:
b416f2e45   Dmitry Torokhov   [PATCH] Input: co...
1376
1377
  	input_unregister_device(sonypi_device.input_key_dev);
  	input_unregister_device(sonypi_device.input_jog_dev);
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1378
1379
1380
   err_miscdev_unregister:
  	misc_deregister(&sonypi_misc_device);
   err_free_irq:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1381
  	free_irq(sonypi_device.irq, sonypi_irq);
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1382
   err_free_ioports:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1383
  	release_region(sonypi_device.ioport1, sonypi_device.region_size);
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1384
   err_disable_pcidev:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1385
1386
  	if (pcidev)
  		pci_disable_device(pcidev);
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1387
1388
   err_put_pcidev:
  	pci_dev_put(pcidev);
454654878   Stefani Seibold   kfifo: move struc...
1389
  	kfifo_free(&sonypi_device.fifo);
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1390
1391
  
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1392
  }
39af33fc4   Bill Pemberton   char: remove use ...
1393
  static int sonypi_remove(struct platform_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1394
1395
  {
  	sonypi_disable();
3cb93db6e   Dmitry Torokhov   Sonypi: use synch...
1396
  	synchronize_irq(sonypi_device.irq);
43829731d   Tejun Heo   workqueue: deprec...
1397
  	flush_work(&sonypi_device.input_work);
fb2ce3c00   Dmitry Torokhov   Sonypi: make sure...
1398

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1399
  	if (useinput) {
b416f2e45   Dmitry Torokhov   [PATCH] Input: co...
1400
1401
  		input_unregister_device(sonypi_device.input_key_dev);
  		input_unregister_device(sonypi_device.input_jog_dev);
454654878   Stefani Seibold   kfifo: move struc...
1402
  		kfifo_free(&sonypi_device.input_fifo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1403
  	}
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1404
  	misc_deregister(&sonypi_misc_device);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1405
1406
  	free_irq(sonypi_device.irq, sonypi_irq);
  	release_region(sonypi_device.ioport1, sonypi_device.region_size);
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1407
1408
  
  	if (sonypi_device.dev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1409
  		pci_disable_device(sonypi_device.dev);
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1410
1411
  		pci_dev_put(sonypi_device.dev);
  	}
454654878   Stefani Seibold   kfifo: move struc...
1412
  	kfifo_free(&sonypi_device.fifo);
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1413
1414
1415
  
  	return 0;
  }
2cb55a2f4   Yuanhan Liu   sonypi: suspend/r...
1416
  #ifdef CONFIG_PM_SLEEP
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1417
  static int old_camera_power;
199ac0529   Rafael J. Wysocki   sonypi: Use struc...
1418
  static int sonypi_suspend(struct device *dev)
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1419
1420
1421
1422
1423
1424
  {
  	old_camera_power = sonypi_device.camera_power;
  	sonypi_disable();
  
  	return 0;
  }
199ac0529   Rafael J. Wysocki   sonypi: Use struc...
1425
  static int sonypi_resume(struct device *dev)
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1426
1427
1428
1429
  {
  	sonypi_enable(old_camera_power);
  	return 0;
  }
199ac0529   Rafael J. Wysocki   sonypi: Use struc...
1430
1431
1432
  
  static SIMPLE_DEV_PM_OPS(sonypi_pm, sonypi_suspend, sonypi_resume);
  #define SONYPI_PM	(&sonypi_pm)
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1433
  #else
199ac0529   Rafael J. Wysocki   sonypi: Use struc...
1434
  #define SONYPI_PM	NULL
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1435
1436
1437
1438
1439
  #endif
  
  static void sonypi_shutdown(struct platform_device *dev)
  {
  	sonypi_disable();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1440
  }
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1441
1442
1443
  static struct platform_driver sonypi_driver = {
  	.driver		= {
  		.name	= "sonypi",
199ac0529   Rafael J. Wysocki   sonypi: Use struc...
1444
  		.pm	= SONYPI_PM,
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1445
1446
  	},
  	.probe		= sonypi_probe,
4dde2d2f3   Bill Pemberton   char: remove use ...
1447
  	.remove		= sonypi_remove,
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1448
  	.shutdown	= sonypi_shutdown,
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1449
1450
1451
  };
  
  static struct platform_device *sonypi_platform_device;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
  static struct dmi_system_id __initdata sonypi_dmi_table[] = {
  	{
  		.ident = "Sony Vaio",
  		.matches = {
  			DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
  			DMI_MATCH(DMI_PRODUCT_NAME, "PCG-"),
  		},
  	},
  	{
  		.ident = "Sony Vaio",
  		.matches = {
  			DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
  			DMI_MATCH(DMI_PRODUCT_NAME, "VGN-"),
  		},
  	},
  	{ }
  };
  
  static int __init sonypi_init(void)
  {
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1472
1473
1474
1475
1476
1477
  	int error;
  
  	printk(KERN_INFO
  		"sonypi: Sony Programmable I/O Controller Driver v%s.
  ",
  		SONYPI_DRIVER_VERSION);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1478
1479
1480
  
  	if (!dmi_check_system(sonypi_dmi_table))
  		return -ENODEV;
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1481
1482
1483
  	error = platform_driver_register(&sonypi_driver);
  	if (error)
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1484

44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1485
1486
1487
1488
1489
  	sonypi_platform_device = platform_device_alloc("sonypi", -1);
  	if (!sonypi_platform_device) {
  		error = -ENOMEM;
  		goto err_driver_unregister;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1490

44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1491
1492
1493
  	error = platform_device_add(sonypi_platform_device);
  	if (error)
  		goto err_free_device;
b368fae6a   Ben Collins   [PATCH] sonypi: E...
1494
  #ifdef CONFIG_ACPI
e4513a57e   Bjorn Helgaas   ACPI: fix sonypi ...
1495
1496
  	if (acpi_bus_register_driver(&sonypi_acpi_driver) >= 0)
  		acpi_driver_registered = 1;
b368fae6a   Ben Collins   [PATCH] sonypi: E...
1497
  #endif
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1498
1499
1500
1501
1502
1503
1504
  	return 0;
  
   err_free_device:
  	platform_device_put(sonypi_platform_device);
   err_driver_unregister:
  	platform_driver_unregister(&sonypi_driver);
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1505
1506
1507
1508
  }
  
  static void __exit sonypi_exit(void)
  {
b368fae6a   Ben Collins   [PATCH] sonypi: E...
1509
  #ifdef CONFIG_ACPI
e4513a57e   Bjorn Helgaas   ACPI: fix sonypi ...
1510
  	if (acpi_driver_registered)
b368fae6a   Ben Collins   [PATCH] sonypi: E...
1511
1512
  		acpi_bus_unregister_driver(&sonypi_acpi_driver);
  #endif
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1513
  	platform_device_unregister(sonypi_platform_device);
3ae5eaec1   Russell King   [DRIVER MODEL] Co...
1514
  	platform_driver_unregister(&sonypi_driver);
44f061033   Dmitry Torokhov   [PATCH] Sonypi: c...
1515
1516
  	printk(KERN_INFO "sonypi: removed.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1517
1518
1519
1520
  }
  
  module_init(sonypi_init);
  module_exit(sonypi_exit);