Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
cfaae3ee
Commit
cfaae3ee
authored
Apr 28, 2007
by
Len Brown
Browse files
Options
Browse Files
Download
Plain Diff
Pull sony into release branch
parents
eaf60d69
c6c60106
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
2073 additions
and
264 deletions
+2073
-264
Documentation/sony-laptop.txt
Documentation/sony-laptop.txt
+18
-7
Documentation/video4linux/meye.txt
Documentation/video4linux/meye.txt
+3
-4
drivers/char/sonypi.c
drivers/char/sonypi.c
+43
-10
drivers/media/video/Kconfig
drivers/media/video/Kconfig
+3
-3
drivers/media/video/meye.c
drivers/media/video/meye.c
+31
-31
drivers/media/video/meye.h
drivers/media/video/meye.h
+1
-1
drivers/misc/Kconfig
drivers/misc/Kconfig
+10
-5
drivers/misc/sony-laptop.c
drivers/misc/sony-laptop.c
+1930
-203
include/linux/sony-laptop.h
include/linux/sony-laptop.h
+34
-0
No files found.
Documentation/sony-laptop.txt
View file @
cfaae3ee
...
@@ -3,12 +3,18 @@ Sony Notebook Control Driver (SNC) Readme
...
@@ -3,12 +3,18 @@ Sony Notebook Control Driver (SNC) Readme
Copyright (C) 2004- 2005 Stelian Pop <stelian@popies.net>
Copyright (C) 2004- 2005 Stelian Pop <stelian@popies.net>
Copyright (C) 2007 Mattia Dongili <malattia@linux.it>
Copyright (C) 2007 Mattia Dongili <malattia@linux.it>
This mini-driver drives the SNC device present in the ACPI BIOS of
This mini-driver drives the SNC and SPIC device present in the ACPI BIOS of the
the Sony Vaio laptops.
Sony Vaio laptops. This driver mixes both devices functions under the same
(hopefully consistent) interface. This also means that the sonypi driver is
obsoleted by sony-laptop now.
It gives access to some extra laptop functionalities. In its current
Fn keys (hotkeys):
form, this driver let the user set or query the screen brightness
------------------
through the backlight subsystem and remove/apply power to some devices.
Some models report hotkeys through the SNC or SPIC devices, such events are
reported both through the ACPI subsystem as acpi events and through the INPUT
subsystem. See the logs of acpid or /proc/acpi/event and
/proc/bus/input/devices to find out what those events are and which input
devices are created by the driver.
Backlight control:
Backlight control:
------------------
------------------
...
@@ -39,6 +45,8 @@ The files are:
...
@@ -39,6 +45,8 @@ The files are:
audiopower power on/off the internal sound card
audiopower power on/off the internal sound card
lanpower power on/off the internal ethernet card
lanpower power on/off the internal ethernet card
(only in debug mode)
(only in debug mode)
bluetoothpower power on/off the internal bluetooth device
fanspeed get/set the fan speed
Note that some files may be missing if they are not supported
Note that some files may be missing if they are not supported
by your particular laptop model.
by your particular laptop model.
...
@@ -76,9 +84,9 @@ The sony-laptop driver creates, for some of those methods (the most
...
@@ -76,9 +84,9 @@ The sony-laptop driver creates, for some of those methods (the most
current ones found on several Vaio models), an entry under
current ones found on several Vaio models), an entry under
/sys/devices/platform/sony-laptop, just like the 'cdpower' one.
/sys/devices/platform/sony-laptop, just like the 'cdpower' one.
You can create other entries corresponding to your own laptop methods by
You can create other entries corresponding to your own laptop methods by
further editing the source (see the 'sony_
acpi
_values' table, and add a new
further editing the source (see the 'sony_
nc
_values' table, and add a new
entry to this table with your get/set method names using the
entry to this table with your get/set method names using the
HANDLE_NAMES macro).
SNC_
HANDLE_NAMES macro).
Your mission, should you accept it, is to try finding out what
Your mission, should you accept it, is to try finding out what
those entries are for, by reading/writing random values from/to those
those entries are for, by reading/writing random values from/to those
...
@@ -87,6 +95,9 @@ files and find out what is the impact on your laptop.
...
@@ -87,6 +95,9 @@ files and find out what is the impact on your laptop.
Should you find anything interesting, please report it back to me,
Should you find anything interesting, please report it back to me,
I will not disavow all knowledge of your actions :)
I will not disavow all knowledge of your actions :)
See also http://www.linux.it/~malattia/wiki/index.php/Sony_drivers for other
useful info.
Bugs/Limitations:
Bugs/Limitations:
-----------------
-----------------
...
...
Documentation/video4linux/meye.txt
View file @
cfaae3ee
...
@@ -5,10 +5,9 @@ Vaio Picturebook Motion Eye Camera Driver Readme
...
@@ -5,10 +5,9 @@ Vaio Picturebook Motion Eye Camera Driver Readme
Copyright (C) 2000 Andrew Tridgell <tridge@samba.org>
Copyright (C) 2000 Andrew Tridgell <tridge@samba.org>
This driver enable the use of video4linux compatible applications with the
This driver enable the use of video4linux compatible applications with the
Motion Eye camera. This driver requires the "Sony Vaio Programmable I/O
Motion Eye camera. This driver requires the "Sony Laptop Extras" driver (which
Control Device" driver (which can be found in the "Character drivers"
can be found in the "Misc devices" section of the kernel configuration utility)
section of the kernel configuration utility) to be compiled and installed
to be compiled and installed (using its "camera=1" parameter).
(using its "camera=1" parameter).
It can do at maximum 30 fps @ 320x240 or 15 fps @ 640x480.
It can do at maximum 30 fps @ 320x240 or 15 fps @ 640x480.
...
...
drivers/char/sonypi.c
View file @
cfaae3ee
/*
/*
* Sony Programmable I/O Control Device driver for VAIO
* Sony Programmable I/O Control Device driver for VAIO
*
*
* Copyright (C) 2007 Mattia Dongili <malattia@linux.it>
*
* Copyright (C) 2001-2005 Stelian Pop <stelian@popies.net>
* Copyright (C) 2001-2005 Stelian Pop <stelian@popies.net>
*
*
* Copyright (C) 2005 Narayanan R S <nars@kadamba.org>
* Copyright (C) 2005 Narayanan R S <nars@kadamba.org>
...
@@ -95,6 +97,11 @@ module_param(useinput, int, 0444);
...
@@ -95,6 +97,11 @@ module_param(useinput, int, 0444);
MODULE_PARM_DESC
(
useinput
,
MODULE_PARM_DESC
(
useinput
,
"set this if you would like sonypi to feed events to the input subsystem"
);
"set this if you would like sonypi to feed events to the input subsystem"
);
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"
);
#define SONYPI_DEVICE_MODEL_TYPE1 1
#define SONYPI_DEVICE_MODEL_TYPE1 1
#define SONYPI_DEVICE_MODEL_TYPE2 2
#define SONYPI_DEVICE_MODEL_TYPE2 2
#define SONYPI_DEVICE_MODEL_TYPE3 3
#define SONYPI_DEVICE_MODEL_TYPE3 3
...
@@ -477,7 +484,7 @@ static struct sonypi_device {
...
@@ -477,7 +484,7 @@ static struct sonypi_device {
u16
evtype_offset
;
u16
evtype_offset
;
int
camera_power
;
int
camera_power
;
int
bluetooth_power
;
int
bluetooth_power
;
struct
semaphore
lock
;
struct
mutex
lock
;
struct
kfifo
*
fifo
;
struct
kfifo
*
fifo
;
spinlock_t
fifo_lock
;
spinlock_t
fifo_lock
;
wait_queue_head_t
fifo_proc_list
;
wait_queue_head_t
fifo_proc_list
;
...
@@ -884,7 +891,7 @@ int sonypi_camera_command(int command, u8 value)
...
@@ -884,7 +891,7 @@ int sonypi_camera_command(int command, u8 value)
if
(
!
camera
)
if
(
!
camera
)
return
-
EIO
;
return
-
EIO
;
down
(
&
sonypi_device
.
lock
);
mutex_lock
(
&
sonypi_device
.
lock
);
switch
(
command
)
{
switch
(
command
)
{
case
SONYPI_COMMAND_SETCAMERA
:
case
SONYPI_COMMAND_SETCAMERA
:
...
@@ -919,7 +926,7 @@ int sonypi_camera_command(int command, u8 value)
...
@@ -919,7 +926,7 @@ int sonypi_camera_command(int command, u8 value)
command
);
command
);
break
;
break
;
}
}
up
(
&
sonypi_device
.
lock
);
mutex_unlock
(
&
sonypi_device
.
lock
);
return
0
;
return
0
;
}
}
...
@@ -938,20 +945,20 @@ static int sonypi_misc_fasync(int fd, struct file *filp, int on)
...
@@ -938,20 +945,20 @@ static int sonypi_misc_fasync(int fd, struct file *filp, int on)
static
int
sonypi_misc_release
(
struct
inode
*
inode
,
struct
file
*
file
)
static
int
sonypi_misc_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
{
sonypi_misc_fasync
(
-
1
,
file
,
0
);
sonypi_misc_fasync
(
-
1
,
file
,
0
);
down
(
&
sonypi_device
.
lock
);
mutex_lock
(
&
sonypi_device
.
lock
);
sonypi_device
.
open_count
--
;
sonypi_device
.
open_count
--
;
up
(
&
sonypi_device
.
lock
);
mutex_unlock
(
&
sonypi_device
.
lock
);
return
0
;
return
0
;
}
}
static
int
sonypi_misc_open
(
struct
inode
*
inode
,
struct
file
*
file
)
static
int
sonypi_misc_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
{
down
(
&
sonypi_device
.
lock
);
mutex_lock
(
&
sonypi_device
.
lock
);
/* Flush input queue on first open */
/* Flush input queue on first open */
if
(
!
sonypi_device
.
open_count
)
if
(
!
sonypi_device
.
open_count
)
kfifo_reset
(
sonypi_device
.
fifo
);
kfifo_reset
(
sonypi_device
.
fifo
);
sonypi_device
.
open_count
++
;
sonypi_device
.
open_count
++
;
up
(
&
sonypi_device
.
lock
);
mutex_unlock
(
&
sonypi_device
.
lock
);
return
0
;
return
0
;
}
}
...
@@ -1001,7 +1008,7 @@ static int sonypi_misc_ioctl(struct inode *ip, struct file *fp,
...
@@ -1001,7 +1008,7 @@ static int sonypi_misc_ioctl(struct inode *ip, struct file *fp,
u8
val8
;
u8
val8
;
u16
val16
;
u16
val16
;
down
(
&
sonypi_device
.
lock
);
mutex_lock
(
&
sonypi_device
.
lock
);
switch
(
cmd
)
{
switch
(
cmd
)
{
case
SONYPI_IOCGBRT
:
case
SONYPI_IOCGBRT
:
if
(
sonypi_ec_read
(
SONYPI_LCD_LIGHT
,
&
val8
))
{
if
(
sonypi_ec_read
(
SONYPI_LCD_LIGHT
,
&
val8
))
{
...
@@ -1101,7 +1108,7 @@ static int sonypi_misc_ioctl(struct inode *ip, struct file *fp,
...
@@ -1101,7 +1108,7 @@ static int sonypi_misc_ioctl(struct inode *ip, struct file *fp,
default:
default:
ret
=
-
EINVAL
;
ret
=
-
EINVAL
;
}
}
up
(
&
sonypi_device
.
lock
);
mutex_unlock
(
&
sonypi_device
.
lock
);
return
ret
;
return
ret
;
}
}
...
@@ -1260,6 +1267,28 @@ static int __devinit sonypi_create_input_devices(void)
...
@@ -1260,6 +1267,28 @@ static int __devinit sonypi_create_input_devices(void)
static
int
__devinit
sonypi_setup_ioports
(
struct
sonypi_device
*
dev
,
static
int
__devinit
sonypi_setup_ioports
(
struct
sonypi_device
*
dev
,
const
struct
sonypi_ioport_list
*
ioport_list
)
const
struct
sonypi_ioport_list
*
ioport_list
)
{
{
/* 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
,
"Sony Programable I/O Device Check"
))
{
printk
(
KERN_ERR
"sonypi: ioport 0x%.4x busy, using sony-laptop? "
"if not use check_ioport=0
\n
"
,
check
->
port1
);
return
-
EBUSY
;
}
release_region
(
check
->
port1
,
sonypi_device
.
region_size
);
check
++
;
}
while
(
ioport_list
->
port1
)
{
while
(
ioport_list
->
port1
)
{
if
(
request_region
(
ioport_list
->
port1
,
if
(
request_region
(
ioport_list
->
port1
,
...
@@ -1321,6 +1350,10 @@ static int __devinit sonypi_probe(struct platform_device *dev)
...
@@ -1321,6 +1350,10 @@ static int __devinit sonypi_probe(struct platform_device *dev)
struct
pci_dev
*
pcidev
;
struct
pci_dev
*
pcidev
;
int
error
;
int
error
;
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
\n
"
);
spin_lock_init
(
&
sonypi_device
.
fifo_lock
);
spin_lock_init
(
&
sonypi_device
.
fifo_lock
);
sonypi_device
.
fifo
=
kfifo_alloc
(
SONYPI_BUF_SIZE
,
GFP_KERNEL
,
sonypi_device
.
fifo
=
kfifo_alloc
(
SONYPI_BUF_SIZE
,
GFP_KERNEL
,
&
sonypi_device
.
fifo_lock
);
&
sonypi_device
.
fifo_lock
);
...
@@ -1330,7 +1363,7 @@ static int __devinit sonypi_probe(struct platform_device *dev)
...
@@ -1330,7 +1363,7 @@ static int __devinit sonypi_probe(struct platform_device *dev)
}
}
init_waitqueue_head
(
&
sonypi_device
.
fifo_proc_list
);
init_waitqueue_head
(
&
sonypi_device
.
fifo_proc_list
);
init_MUTEX
(
&
sonypi_device
.
lock
);
mutex_init
(
&
sonypi_device
.
lock
);
sonypi_device
.
bluetooth_power
=
-
1
;
sonypi_device
.
bluetooth_power
=
-
1
;
if
((
pcidev
=
pci_get_device
(
PCI_VENDOR_ID_INTEL
,
if
((
pcidev
=
pci_get_device
(
PCI_VENDOR_ID_INTEL
,
...
...
drivers/media/video/Kconfig
View file @
cfaae3ee
...
@@ -577,14 +577,14 @@ config VIDEO_ZORAN_AVS6EYES
...
@@ -577,14 +577,14 @@ config VIDEO_ZORAN_AVS6EYES
config VIDEO_MEYE
config VIDEO_MEYE
tristate "Sony Vaio Picturebook Motion Eye Video For Linux"
tristate "Sony Vaio Picturebook Motion Eye Video For Linux"
depends on PCI && SONY
PI
&& VIDEO_V4L1
depends on PCI && SONY
_LAPTOP
&& VIDEO_V4L1
---help---
---help---
This is the video4linux driver for the Motion Eye camera found
This is the video4linux driver for the Motion Eye camera found
in the Vaio Picturebook laptops. Please read the material in
in the Vaio Picturebook laptops. Please read the material in
<file:Documentation/video4linux/meye.txt> for more information.
<file:Documentation/video4linux/meye.txt> for more information.
If you say Y or M here, you need to say Y or M to "Sony
Programmable
If you say Y or M here, you need to say Y or M to "Sony
Laptop
I/O Control Device" in the character
device section.
Extras" in the misc
device section.
To compile this driver as a module, choose M here: the
To compile this driver as a module, choose M here: the
module will be called meye.
module will be called meye.
...
...
drivers/media/video/meye.c
View file @
cfaae3ee
...
@@ -925,13 +925,13 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
...
@@ -925,13 +925,13 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
if
(
p
->
palette
!=
VIDEO_PALETTE_YUV422
&&
p
->
palette
!=
VIDEO_PALETTE_YUYV
)
if
(
p
->
palette
!=
VIDEO_PALETTE_YUV422
&&
p
->
palette
!=
VIDEO_PALETTE_YUYV
)
return
-
EINVAL
;
return
-
EINVAL
;
mutex_lock
(
&
meye
.
lock
);
mutex_lock
(
&
meye
.
lock
);
sony
pi_camera_command
(
SONYPI
_COMMAND_SETCAMERABRIGHTNESS
,
sony
_pic_camera_command
(
SONY_PIC
_COMMAND_SETCAMERABRIGHTNESS
,
p
->
brightness
>>
10
);
p
->
brightness
>>
10
);
sony
pi_camera_command
(
SONYPI
_COMMAND_SETCAMERAHUE
,
sony
_pic_camera_command
(
SONY_PIC
_COMMAND_SETCAMERAHUE
,
p
->
hue
>>
10
);
p
->
hue
>>
10
);
sony
pi_camera_command
(
SONYPI
_COMMAND_SETCAMERACOLOR
,
sony
_pic_camera_command
(
SONY_PIC
_COMMAND_SETCAMERACOLOR
,
p
->
colour
>>
10
);
p
->
colour
>>
10
);
sony
pi_camera_command
(
SONYPI
_COMMAND_SETCAMERACONTRAST
,
sony
_pic_camera_command
(
SONY_PIC
_COMMAND_SETCAMERACONTRAST
,
p
->
contrast
>>
10
);
p
->
contrast
>>
10
);
meye
.
picture
=
*
p
;
meye
.
picture
=
*
p
;
mutex_unlock
(
&
meye
.
lock
);
mutex_unlock
(
&
meye
.
lock
);
...
@@ -1043,11 +1043,11 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
...
@@ -1043,11 +1043,11 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
meye
.
params
.
quality
!=
jp
->
quality
)
meye
.
params
.
quality
!=
jp
->
quality
)
mchip_hic_stop
();
/* need restart */
mchip_hic_stop
();
/* need restart */
meye
.
params
=
*
jp
;
meye
.
params
=
*
jp
;
sony
pi_camera_command
(
SONYPI
_COMMAND_SETCAMERASHARPNESS
,
sony
_pic_camera_command
(
SONY_PIC
_COMMAND_SETCAMERASHARPNESS
,
meye
.
params
.
sharpness
);
meye
.
params
.
sharpness
);
sony
pi_camera_command
(
SONYPI
_COMMAND_SETCAMERAAGC
,
sony
_pic_camera_command
(
SONY_PIC
_COMMAND_SETCAMERAAGC
,
meye
.
params
.
agc
);
meye
.
params
.
agc
);
sony
pi_camera_command
(
SONYPI
_COMMAND_SETCAMERAPICTURE
,
sony
_pic_camera_command
(
SONY_PIC
_COMMAND_SETCAMERAPICTURE
,
meye
.
params
.
picture
);
meye
.
params
.
picture
);
mutex_unlock
(
&
meye
.
lock
);
mutex_unlock
(
&
meye
.
lock
);
break
;
break
;
...
@@ -1287,38 +1287,38 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
...
@@ -1287,38 +1287,38 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
mutex_lock
(
&
meye
.
lock
);
mutex_lock
(
&
meye
.
lock
);
switch
(
c
->
id
)
{
switch
(
c
->
id
)
{
case
V4L2_CID_BRIGHTNESS
:
case
V4L2_CID_BRIGHTNESS
:
sony
pi
_camera_command
(
sony
_pic
_camera_command
(
SONY
PI
_COMMAND_SETCAMERABRIGHTNESS
,
c
->
value
);
SONY
_PIC
_COMMAND_SETCAMERABRIGHTNESS
,
c
->
value
);
meye
.
picture
.
brightness
=
c
->
value
<<
10
;
meye
.
picture
.
brightness
=
c
->
value
<<
10
;
break
;
break
;
case
V4L2_CID_HUE
:
case
V4L2_CID_HUE
:
sony
pi
_camera_command
(
sony
_pic
_camera_command
(
SONY
PI
_COMMAND_SETCAMERAHUE
,
c
->
value
);
SONY
_PIC
_COMMAND_SETCAMERAHUE
,
c
->
value
);
meye
.
picture
.
hue
=
c
->
value
<<
10
;
meye
.
picture
.
hue
=
c
->
value
<<
10
;
break
;
break
;
case
V4L2_CID_CONTRAST
:
case
V4L2_CID_CONTRAST
:
sony
pi
_camera_command
(
sony
_pic
_camera_command
(
SONY
PI
_COMMAND_SETCAMERACONTRAST
,
c
->
value
);
SONY
_PIC
_COMMAND_SETCAMERACONTRAST
,
c
->
value
);
meye
.
picture
.
contrast
=
c
->
value
<<
10
;
meye
.
picture
.
contrast
=
c
->
value
<<
10
;
break
;
break
;
case
V4L2_CID_SATURATION
:
case
V4L2_CID_SATURATION
:
sony
pi
_camera_command
(
sony
_pic
_camera_command
(
SONY
PI
_COMMAND_SETCAMERACOLOR
,
c
->
value
);
SONY
_PIC
_COMMAND_SETCAMERACOLOR
,
c
->
value
);
meye
.
picture
.
colour
=
c
->
value
<<
10
;
meye
.
picture
.
colour
=
c
->
value
<<
10
;
break
;
break
;
case
V4L2_CID_AGC
:
case
V4L2_CID_AGC
:
sony
pi
_camera_command
(
sony
_pic
_camera_command
(
SONY
PI
_COMMAND_SETCAMERAAGC
,
c
->
value
);
SONY
_PIC
_COMMAND_SETCAMERAAGC
,
c
->
value
);
meye
.
params
.
agc
=
c
->
value
;
meye
.
params
.
agc
=
c
->
value
;
break
;
break
;
case
V4L2_CID_SHARPNESS
:
case
V4L2_CID_SHARPNESS
:
sony
pi
_camera_command
(
sony
_pic
_camera_command
(
SONY
PI
_COMMAND_SETCAMERASHARPNESS
,
c
->
value
);
SONY
_PIC
_COMMAND_SETCAMERASHARPNESS
,
c
->
value
);
meye
.
params
.
sharpness
=
c
->
value
;
meye
.
params
.
sharpness
=
c
->
value
;
break
;
break
;
case
V4L2_CID_PICTURE
:
case
V4L2_CID_PICTURE
:
sony
pi
_camera_command
(
sony
_pic
_camera_command
(
SONY
PI
_COMMAND_SETCAMERAPICTURE
,
c
->
value
);
SONY
_PIC
_COMMAND_SETCAMERAPICTURE
,
c
->
value
);
meye
.
params
.
picture
=
c
->
value
;
meye
.
params
.
picture
=
c
->
value
;
break
;
break
;
case
V4L2_CID_JPEGQUAL
:
case
V4L2_CID_JPEGQUAL
:
...
@@ -1848,7 +1848,7 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
...
@@ -1848,7 +1848,7 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
memcpy
(
meye
.
video_dev
,
&
meye_template
,
sizeof
(
meye_template
));
memcpy
(
meye
.
video_dev
,
&
meye_template
,
sizeof
(
meye_template
));
meye
.
video_dev
->
dev
=
&
meye
.
mchip_dev
->
dev
;
meye
.
video_dev
->
dev
=
&
meye
.
mchip_dev
->
dev
;
if
((
ret
=
sony
pi_camera_command
(
SONYPI
_COMMAND_SETCAMERA
,
1
)))
{
if
((
ret
=
sony
_pic_camera_command
(
SONY_PIC
_COMMAND_SETCAMERA
,
1
)))
{
printk
(
KERN_ERR
"meye: unable to power on the camera
\n
"
);
printk
(
KERN_ERR
"meye: unable to power on the camera
\n
"
);
printk
(
KERN_ERR
"meye: did you enable the camera in "
printk
(
KERN_ERR
"meye: did you enable the camera in "
"sonypi using the module options ?
\n
"
);
"sonypi using the module options ?
\n
"
);
...
@@ -1928,13 +1928,13 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
...
@@ -1928,13 +1928,13 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
meye
.
params
.
picture
=
0
;
meye
.
params
.
picture
=
0
;
meye
.
params
.
framerate
=
0
;
meye
.
params
.
framerate
=
0
;
sony
pi_camera_command
(
SONYPI
_COMMAND_SETCAMERABRIGHTNESS
,
32
);
sony
_pic_camera_command
(
SONY_PIC
_COMMAND_SETCAMERABRIGHTNESS
,
32
);
sony
pi_camera_command
(
SONYPI
_COMMAND_SETCAMERAHUE
,
32
);
sony
_pic_camera_command
(
SONY_PIC
_COMMAND_SETCAMERAHUE
,
32
);
sony
pi_camera_command
(
SONYPI
_COMMAND_SETCAMERACOLOR
,
32
);
sony
_pic_camera_command
(
SONY_PIC
_COMMAND_SETCAMERACOLOR
,
32
);
sony
pi_camera_command
(
SONYPI
_COMMAND_SETCAMERACONTRAST
,
32
);
sony
_pic_camera_command
(
SONY_PIC
_COMMAND_SETCAMERACONTRAST
,
32
);
sony
pi_camera_command
(
SONYPI
_COMMAND_SETCAMERASHARPNESS
,
32
);
sony
_pic_camera_command
(
SONY_PIC
_COMMAND_SETCAMERASHARPNESS
,
32
);
sony
pi_camera_command
(
SONYPI
_COMMAND_SETCAMERAPICTURE
,
0
);
sony
_pic_camera_command
(
SONY_PIC
_COMMAND_SETCAMERAPICTURE
,
0
);
sony
pi_camera_command
(
SONYPI
_COMMAND_SETCAMERAAGC
,
48
);
sony
_pic_camera_command
(
SONY_PIC
_COMMAND_SETCAMERAAGC
,
48
);
printk
(
KERN_INFO
"meye: Motion Eye Camera Driver v%s.
\n
"
,
printk
(
KERN_INFO
"meye: Motion Eye Camera Driver v%s.
\n
"
,
MEYE_DRIVER_VERSION
);
MEYE_DRIVER_VERSION
);
...
@@ -1953,7 +1953,7 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
...
@@ -1953,7 +1953,7 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
outregions:
outregions:
pci_disable_device
(
meye
.
mchip_dev
);
pci_disable_device
(
meye
.
mchip_dev
);
outenabledev:
outenabledev:
sony
pi_camera_command
(
SONYPI
_COMMAND_SETCAMERA
,
0
);
sony
_pic_camera_command
(
SONY_PIC
_COMMAND_SETCAMERA
,
0
);
outsonypienable:
outsonypienable:
kfifo_free
(
meye
.
doneq
);
kfifo_free
(
meye
.
doneq
);
outkfifoalloc2:
outkfifoalloc2:
...
@@ -1986,7 +1986,7 @@ static void __devexit meye_remove(struct pci_dev *pcidev)
...
@@ -1986,7 +1986,7 @@ static void __devexit meye_remove(struct pci_dev *pcidev)
pci_disable_device
(
meye
.
mchip_dev
);
pci_disable_device
(
meye
.
mchip_dev
);
sony
pi_camera_command
(
SONYPI
_COMMAND_SETCAMERA
,
0
);
sony
_pic_camera_command
(
SONY_PIC
_COMMAND_SETCAMERA
,
0
);
kfifo_free
(
meye
.
doneq
);
kfifo_free
(
meye
.
doneq
);
kfifo_free
(
meye
.
grabq
);
kfifo_free
(
meye
.
grabq
);
...
...
drivers/media/video/meye.h
View file @
cfaae3ee
...
@@ -255,7 +255,7 @@
...
@@ -255,7 +255,7 @@
/****************************************************************************/
/****************************************************************************/
/* Sony Programmable I/O Controller for accessing the camera commands */
/* Sony Programmable I/O Controller for accessing the camera commands */
#include <linux/sony
pi
.h>
#include <linux/sony
-laptop
.h>
/* private API definitions */
/* private API definitions */
#include <linux/meye.h>
#include <linux/meye.h>
...
...
drivers/misc/Kconfig
View file @
cfaae3ee
...
@@ -112,14 +112,19 @@ config SONY_LAPTOP
...
@@ -112,14 +112,19 @@ config SONY_LAPTOP
depends on X86 && ACPI
depends on X86 && ACPI
select BACKLIGHT_CLASS_DEVICE
select BACKLIGHT_CLASS_DEVICE
---help---
---help---
This mini-driver drives the SNC
device present in the ACPI BIOS of
This mini-driver drives the SNC
and SPIC devices present in the ACPI
the Sony Vaio laptops.
BIOS of
the Sony Vaio laptops.
It gives access to some extra laptop functionalities. In its current
It gives access to some extra laptop functionalities like Bluetooth,
form, this driver let the user set or query the screen brightness
screen brightness control, Fn keys and allows powering on/off some
through the backlight subsystem and remove/apply power to some
devices.
devices.
Read <file:Documentation/sony-laptop.txt> for more information.
Read <file:Documentation/sony-laptop.txt> for more information.
config SONY_LAPTOP_OLD
bool "Sonypi compatibility"
depends on SONY_LAPTOP
---help---
Build the sonypi driver compatibility code into the sony-laptop driver.
endmenu
endmenu
drivers/misc/sony-laptop.c
View file @
cfaae3ee
/*
/*
* ACPI Sony Notebook Control Driver (SNC)
* ACPI Sony Notebook Control Driver (SNC
and SPIC
)
*
*
* Copyright (C) 2004-2005 Stelian Pop <stelian@popies.net>
* Copyright (C) 2004-2005 Stelian Pop <stelian@popies.net>
* Copyright (C) 2007 Mattia Dongili <malattia@linux.it>
* Copyright (C) 2007 Mattia Dongili <malattia@linux.it>
...
@@ -7,6 +7,25 @@
...
@@ -7,6 +7,25 @@
* Parts of this driver inspired from asus_acpi.c and ibm_acpi.c
* Parts of this driver inspired from asus_acpi.c and ibm_acpi.c
* which are copyrighted by their respective authors.
* which are copyrighted by their respective authors.
*
*
* The SNY6001 driver part is based on the sonypi driver which includes
* material from:
*
* Copyright (C) 2001-2005 Stelian Pop <stelian@popies.net>
*
* Copyright (C) 2005 Narayanan R S <nars@kadamba.org>
*
* Copyright (C) 2001-2002 Alcve <www.alcove.com>
*
* 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
* 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* the Free Software Foundation; either version 2 of the License, or
...
@@ -31,40 +50,404 @@
...
@@ -31,40 +50,404 @@
#include <linux/backlight.h>
#include <linux/backlight.h>
#include <linux/platform_device.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/err.h>
#include <linux/dmi.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/kfifo.h>
#include <linux/workqueue.h>
#include <linux/acpi.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_bus.h>
#include <asm/uaccess.h>
#include <asm/uaccess.h>
#include <linux/sonypi.h>
#include <linux/sony-laptop.h>
#ifdef CONFIG_SONY_LAPTOP_OLD
#include <linux/poll.h>
#include <linux/miscdevice.h>
#endif
#define ACPI_SNC_CLASS "sony"
#define DRV_PFX "sony-laptop: "
#define ACPI_SNC_HID "SNY5001"
#define dprintk(msg...) do { \
#define ACPI_SNC_DRIVER_NAME "ACPI Sony Notebook Control Driver v0.4"
if (debug) printk(KERN_WARNING DRV_PFX msg); \
} while (0)
/* the device uses 1-based values, while the backlight subsystem uses
#define SONY_LAPTOP_DRIVER_VERSION "0.5"
0-based values */
#define SONY_MAX_BRIGHTNESS 8
#define LOG_PFX KERN_WARNING "sony-laptop: "
#define SONY_NC_CLASS "sony-nc"
#define SONY_NC_HID "SNY5001"
#define SONY_NC_DRIVER_NAME "Sony Notebook Control Driver"
#define SONY_PIC_CLASS "sony-pic"
#define SONY_PIC_HID "SNY6001"
#define SONY_PIC_DRIVER_NAME "Sony Programmable IO Control Driver"
MODULE_AUTHOR
(
"Stelian Pop, Mattia Dongili"
);
MODULE_AUTHOR
(
"Stelian Pop, Mattia Dongili"
);
MODULE_DESCRIPTION
(
ACPI_SNC_DRIVER_NAME
);
MODULE_DESCRIPTION
(
"Sony laptop extras driver (SPIC and SNC ACPI device)"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_VERSION
(
SONY_LAPTOP_DRIVER_VERSION
);
static
int
debug
;
static
int
debug
;
module_param
(
debug
,
int
,
0
);
module_param
(
debug
,
int
,
0
);
MODULE_PARM_DESC
(
debug
,
"set this to 1 (and RTFM) if you want to help "
MODULE_PARM_DESC
(
debug
,
"set this to 1 (and RTFM) if you want to help "
"the development of this driver"
);
"the development of this driver"
);
static
ssize_t
sony_acpi_show
(
struct
device
*
,
struct
device_attribute
*
,
static
int
no_spic
;
/* = 0 */
module_param
(
no_spic
,
int
,
0444
);
MODULE_PARM_DESC
(
no_spic
,
"set this if you don't want to enable the SPIC device"
);
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
camera
;
/* = 0 */
module_param
(
camera
,
int
,
0444
);
MODULE_PARM_DESC
(
camera
,
"set this to 1 to enable Motion Eye camera controls "
"(only use it if you have a C1VE or C1VN model)"
);
#ifdef CONFIG_SONY_LAPTOP_OLD
static
int
minor
=
-
1
;
module_param
(
minor
,
int
,
0
);
MODULE_PARM_DESC
(
minor
,
"minor number of the misc device for the SPIC compatibility code, "
"default is -1 (automatic)"
);
#endif
/*********** Input Devices ***********/
#define SONY_LAPTOP_BUF_SIZE 128
struct
sony_laptop_input_s
{
atomic_t
users
;
struct
input_dev
*
jog_dev
;
struct
input_dev
*
key_dev
;
struct
kfifo
*
fifo
;
spinlock_t
fifo_lock
;
struct
workqueue_struct
*
wq
;
};
static
struct
sony_laptop_input_s
sony_laptop_input
=
{
.
users
=
ATOMIC_INIT
(
0
),
};
struct
sony_laptop_keypress
{
struct
input_dev
*
dev
;
int
key
;
};
/* Correspondance table between sonypi events and input layer events */
static
struct
{
int
sonypiev
;
int
inputev
;
}
sony_laptop_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
},
};
/* release buttons after a short delay if pressed */
static
void
do_sony_laptop_release_key
(
struct
work_struct
*
work
)
{
struct
sony_laptop_keypress
kp
;
while
(
kfifo_get
(
sony_laptop_input
.
fifo
,
(
unsigned
char
*
)
&
kp
,
sizeof
(
kp
))
==
sizeof
(
kp
))
{
msleep
(
10
);
input_report_key
(
kp
.
dev
,
kp
.
key
,
0
);
input_sync
(
kp
.
dev
);
}
}
static
DECLARE_WORK
(
sony_laptop_release_key_work
,
do_sony_laptop_release_key
);
/* forward event to the input subsytem */
static
void
sony_laptop_report_input_event
(
u8
event
)
{
struct
input_dev
*
jog_dev
=
sony_laptop_input
.
jog_dev
;
struct
input_dev
*
key_dev
=
sony_laptop_input
.
key_dev
;
struct
sony_laptop_keypress
kp
=
{
NULL
};
int
i
;
if
(
event
==
SONYPI_EVENT_FNKEY_RELEASED
)
{
/* Nothing, not all VAIOs generate this event */
return
;
}
/* report events */
switch
(
event
)
{
/* jog_dev events */
case
SONYPI_EVENT_JOGDIAL_UP
:
case
SONYPI_EVENT_JOGDIAL_UP_PRESSED
:
input_report_rel
(
jog_dev
,
REL_WHEEL
,
1
);
input_sync
(
jog_dev
);
return
;
case
SONYPI_EVENT_JOGDIAL_DOWN
:
case
SONYPI_EVENT_JOGDIAL_DOWN_PRESSED
:
input_report_rel
(
jog_dev
,
REL_WHEEL
,
-
1
);
input_sync
(
jog_dev
);
return
;
/* key_dev events */
case
SONYPI_EVENT_JOGDIAL_PRESSED
:
kp
.
key
=
BTN_MIDDLE
;
kp
.
dev
=
jog_dev
;
break
;
default:
for
(
i
=
0
;
sony_laptop_inputkeys
[
i
].
sonypiev
;
i
++
)
if
(
event
==
sony_laptop_inputkeys
[
i
].
sonypiev
)
{
kp
.
dev
=
key_dev
;
kp
.
key
=
sony_laptop_inputkeys
[
i
].
inputev
;
break
;
}
break
;
}
if
(
kp
.
dev
)
{
input_report_key
(
kp
.
dev
,
kp
.
key
,
1
);
input_sync
(
kp
.
dev
);
kfifo_put
(
sony_laptop_input
.
fifo
,
(
unsigned
char
*
)
&
kp
,
sizeof
(
kp
));
if
(
!
work_pending
(
&
sony_laptop_release_key_work
))
queue_work
(
sony_laptop_input
.
wq
,
&
sony_laptop_release_key_work
);
}
else
dprintk
(
"unknown input event %.2x
\n
"
,
event
);
}
static
int
sony_laptop_setup_input
(
void
)
{
struct
input_dev
*
jog_dev
;
struct
input_dev
*
key_dev
;
int
i
;
int
error
;
/* don't run again if already initialized */
if
(
atomic_add_return
(
1
,
&
sony_laptop_input
.
users
)
>
1
)
return
0
;
/* kfifo */
spin_lock_init
(
&
sony_laptop_input
.
fifo_lock
);
sony_laptop_input
.
fifo
=
kfifo_alloc
(
SONY_LAPTOP_BUF_SIZE
,
GFP_KERNEL
,
&
sony_laptop_input
.
fifo_lock
);
if
(
IS_ERR
(
sony_laptop_input
.
fifo
))
{
printk
(
KERN_ERR
DRV_PFX
"kfifo_alloc failed
\n
"
);
error
=
PTR_ERR
(
sony_laptop_input
.
fifo
);
goto
err_dec_users
;
}
/* init workqueue */
sony_laptop_input
.
wq
=
create_singlethread_workqueue
(
"sony-laptop"
);
if
(
!
sony_laptop_input
.
wq
)
{
printk
(
KERN_ERR
DRV_PFX
"Unabe to create workqueue.
\n
"
);
error
=
-
ENXIO
;
goto
err_free_kfifo
;
}
/* input keys */
key_dev
=
input_allocate_device
();
if
(
!
key_dev
)
{
error
=
-
ENOMEM
;
goto
err_destroy_wq
;
}
key_dev
->
name
=
"Sony Vaio Keys"
;
key_dev
->
id
.
bustype
=
BUS_ISA
;
key_dev
->
id
.
vendor
=
PCI_VENDOR_ID_SONY
;
/* Initialize the Input Drivers: special keys */
key_dev
->
evbit
[
0
]
=
BIT
(
EV_KEY
);
for
(
i
=
0
;
sony_laptop_inputkeys
[
i
].
sonypiev
;
i
++
)
if
(
sony_laptop_inputkeys
[
i
].
inputev
)
set_bit
(
sony_laptop_inputkeys
[
i
].
inputev
,
key_dev
->
keybit
);
error
=
input_register_device
(
key_dev
);
if
(
error
)
goto
err_free_keydev
;
sony_laptop_input
.
key_dev
=
key_dev
;
/* jogdial */
jog_dev
=
input_allocate_device
();
if
(
!
jog_dev
)
{
error
=
-
ENOMEM
;
goto
err_unregister_keydev
;
}
jog_dev
->
name
=
"Sony Vaio Jogdial"
;
jog_dev
->
id
.
bustype
=
BUS_ISA
;
jog_dev
->
id
.
vendor
=
PCI_VENDOR_ID_SONY
;
jog_dev
->
evbit
[
0
]
=
BIT
(
EV_KEY
)
|
BIT
(
EV_REL
);
jog_dev
->
keybit
[
LONG
(
BTN_MOUSE
)]
=
BIT
(
BTN_MIDDLE
);
jog_dev
->
relbit
[
0
]
=
BIT
(
REL_WHEEL
);
error
=
input_register_device
(
jog_dev
);
if
(
error
)
goto
err_free_jogdev
;
sony_laptop_input
.
jog_dev
=
jog_dev
;
return
0
;
err_free_jogdev:
input_free_device
(
jog_dev
);
err_unregister_keydev:
input_unregister_device
(
key_dev
);
/* to avoid kref underflow below at input_free_device */
key_dev
=
NULL
;
err_free_keydev:
input_free_device
(
key_dev
);
err_destroy_wq:
destroy_workqueue
(
sony_laptop_input
.
wq
);
err_free_kfifo:
kfifo_free
(
sony_laptop_input
.
fifo
);
err_dec_users:
atomic_dec
(
&
sony_laptop_input
.
users
);
return
error
;
}
static
void
sony_laptop_remove_input
(
void
)
{
/* cleanup only after the last user has gone */
if
(
!
atomic_dec_and_test
(
&
sony_laptop_input
.
users
))
return
;
/* flush workqueue first */
flush_workqueue
(
sony_laptop_input
.
wq
);
/* destroy input devs */
input_unregister_device
(
sony_laptop_input
.
key_dev
);
sony_laptop_input
.
key_dev
=
NULL
;
if
(
sony_laptop_input
.
jog_dev
)
{
input_unregister_device
(
sony_laptop_input
.
jog_dev
);
sony_laptop_input
.
jog_dev
=
NULL
;
}
destroy_workqueue
(
sony_laptop_input
.
wq
);
kfifo_free
(
sony_laptop_input
.
fifo
);
}
/*********** Platform Device ***********/
static
atomic_t
sony_pf_users
=
ATOMIC_INIT
(
0
);
static
struct
platform_driver
sony_pf_driver
=
{
.
driver
=
{
.
name
=
"sony-laptop"
,
.
owner
=
THIS_MODULE
,
}
};
static
struct
platform_device
*
sony_pf_device
;
static
int
sony_pf_add
(
void
)
{
int
ret
=
0
;
/* don't run again if already initialized */
if
(
atomic_add_return
(
1
,
&
sony_pf_users
)
>
1
)
return
0
;
ret
=
platform_driver_register
(
&
sony_pf_driver
);
if
(
ret
)
goto
out
;
sony_pf_device
=
platform_device_alloc
(
"sony-laptop"
,
-
1
);
if
(
!
sony_pf_device
)
{
ret
=
-
ENOMEM
;
goto
out_platform_registered
;
}
ret
=
platform_device_add
(
sony_pf_device
);
if
(
ret
)
goto
out_platform_alloced
;
return
0
;
out_platform_alloced:
platform_device_put
(
sony_pf_device
);
sony_pf_device
=
NULL
;
out_platform_registered:
platform_driver_unregister
(
&
sony_pf_driver
);
out:
atomic_dec
(
&
sony_pf_users
);
return
ret
;
}
static
void
sony_pf_remove
(
void
)
{
/* deregister only after the last user has gone */
if
(
!
atomic_dec_and_test
(
&
sony_pf_users
))
return
;
platform_device_del
(
sony_pf_device
);
platform_device_put
(
sony_pf_device
);
platform_driver_unregister
(
&
sony_pf_driver
);
}
/*********** SNC (SNY5001) Device ***********/
/* the device uses 1-based values, while the backlight subsystem uses
0-based values */
#define SONY_MAX_BRIGHTNESS 8
#define SNC_VALIDATE_IN 0
#define SNC_VALIDATE_OUT 1
static
ssize_t
sony_nc_sysfs_show
(
struct
device
*
,
struct
device_attribute
*
,
char
*
);
char
*
);
static
ssize_t
sony_
acpi
_store
(
struct
device
*
,
struct
device_attribute
*
,
static
ssize_t
sony_
nc_sysfs
_store
(
struct
device
*
,
struct
device_attribute
*
,
const
char
*
,
size_t
);
const
char
*
,
size_t
);
static
int
boolean_validate
(
const
int
,
const
int
);
static
int
boolean_validate
(
const
int
,
const
int
);
static
int
brightness_default_validate
(
const
int
,
const
int
);
static
int
brightness_default_validate
(
const
int
,
const
int
);
#define SNC_VALIDATE_IN 0
struct
sony_nc_value
{
#define SNC_VALIDATE_OUT 1
struct
sony_acpi_value
{
char
*
name
;
/* name of the entry */
char
*
name
;
/* name of the entry */
char
**
acpiget
;
/* names of the ACPI get function */
char
**
acpiget
;
/* names of the ACPI get function */
char
**
acpiset
;
/* names of the ACPI set function */
char
**
acpiset
;
/* names of the ACPI set function */
...
@@ -75,65 +458,65 @@ struct sony_acpi_value {
...
@@ -75,65 +458,65 @@ struct sony_acpi_value {
struct
device_attribute
devattr
;
/* sysfs atribute */
struct
device_attribute
devattr
;
/* sysfs atribute */
};
};
#define HANDLE_NAMES(_name, _values...) \
#define
SNC_
HANDLE_NAMES(_name, _values...) \
static char *snc_##_name[] = { _values, NULL }
static char *snc_##_name[] = { _values, NULL }
#define S
ONY_ACPI_VALU
E(_name, _getters, _setters, _validate, _debug) \
#define S
NC_HANDL
E(_name, _getters, _setters, _validate, _debug) \
{ \
{ \
.name = __stringify(_name), \
.name = __stringify(_name), \
.acpiget = _getters, \
.acpiget = _getters, \
.acpiset = _setters, \
.acpiset = _setters, \
.validate = _validate, \
.validate = _validate, \
.debug = _debug, \
.debug = _debug, \
.devattr = __ATTR(_name, 0, sony_
acpi_show, sony_acpi
_store), \
.devattr = __ATTR(_name, 0, sony_
nc_sysfs_show, sony_nc_sysfs
_store), \
}
}
#define S
ONY_ACPI_VALU
E_NULL { .name = NULL }
#define S
NC_HANDL
E_NULL { .name = NULL }
HANDLE_NAMES
(
fnkey_get
,
"GHKE"
);
SNC_
HANDLE_NAMES
(
fnkey_get
,
"GHKE"
);
HANDLE_NAMES
(
brightness_def_get
,
"GPBR"
);
SNC_
HANDLE_NAMES
(
brightness_def_get
,
"GPBR"
);
HANDLE_NAMES
(
brightness_def_set
,
"SPBR"
);
SNC_
HANDLE_NAMES
(
brightness_def_set
,
"SPBR"
);
HANDLE_NAMES
(
cdpower_get
,
"GCDP"
);
SNC_
HANDLE_NAMES
(
cdpower_get
,
"GCDP"
);
HANDLE_NAMES
(
cdpower_set
,
"SCDP"
,
"CDPW"
);
SNC_
HANDLE_NAMES
(
cdpower_set
,
"SCDP"
,
"CDPW"
);
HANDLE_NAMES
(
audiopower_get
,
"GAZP"
);
SNC_
HANDLE_NAMES
(
audiopower_get
,
"GAZP"
);
HANDLE_NAMES
(
audiopower_set
,
"AZPW"
);
SNC_
HANDLE_NAMES
(
audiopower_set
,
"AZPW"
);
HANDLE_NAMES
(
lanpower_get
,
"GLNP"
);
SNC_
HANDLE_NAMES
(
lanpower_get
,
"GLNP"
);
HANDLE_NAMES
(
lanpower_set
,
"LNPW"
);
SNC_
HANDLE_NAMES
(
lanpower_set
,
"LNPW"
);
HANDLE_NAMES
(
PID_get
,
"GPID"
);
SNC_
HANDLE_NAMES
(
PID_get
,
"GPID"
);
HANDLE_NAMES
(
CTR_get
,
"GCTR"
);
SNC_
HANDLE_NAMES
(
CTR_get
,
"GCTR"
);
HANDLE_NAMES
(
CTR_set
,
"SCTR"
);
SNC_
HANDLE_NAMES
(
CTR_set
,
"SCTR"
);
HANDLE_NAMES
(
PCR_get
,
"GPCR"
);
SNC_
HANDLE_NAMES
(
PCR_get
,
"GPCR"
);
HANDLE_NAMES
(
PCR_set
,
"SPCR"
);
SNC_
HANDLE_NAMES
(
PCR_set
,
"SPCR"
);
HANDLE_NAMES
(
CMI_get
,
"GCMI"
);
SNC_
HANDLE_NAMES
(
CMI_get
,
"GCMI"
);
HANDLE_NAMES
(
CMI_set
,
"SCMI"
);
SNC_
HANDLE_NAMES
(
CMI_set
,
"SCMI"
);
static
struct
sony_
acpi_value
sony_acpi
_values
[]
=
{
static
struct
sony_
nc_value
sony_nc
_values
[]
=
{
S
ONY_ACPI_VALU
E
(
brightness_default
,
snc_brightness_def_get
,
S
NC_HANDL
E
(
brightness_default
,
snc_brightness_def_get
,
snc_brightness_def_set
,
brightness_default_validate
,
0
),
snc_brightness_def_set
,
brightness_default_validate
,
0
),
S
ONY_ACPI_VALU
E
(
fnkey
,
snc_fnkey_get
,
NULL
,
NULL
,
0
),
S
NC_HANDL
E
(
fnkey
,
snc_fnkey_get
,
NULL
,
NULL
,
0
),
S
ONY_ACPI_VALU
E
(
cdpower
,
snc_cdpower_get
,
snc_cdpower_set
,
boolean_validate
,
0
),
S
NC_HANDL
E
(
cdpower
,
snc_cdpower_get
,
snc_cdpower_set
,
boolean_validate
,
0
),
S
ONY_ACPI_VALU
E
(
audiopower
,
snc_audiopower_get
,
snc_audiopower_set
,
S
NC_HANDL
E
(
audiopower
,
snc_audiopower_get
,
snc_audiopower_set
,
boolean_validate
,
0
),
boolean_validate
,
0
),
S
ONY_ACPI_VALU
E
(
lanpower
,
snc_lanpower_get
,
snc_lanpower_set
,
S
NC_HANDL
E
(
lanpower
,
snc_lanpower_get
,
snc_lanpower_set
,
boolean_validate
,
1
),
boolean_validate
,
1
),
/* unknown methods */
/* unknown methods */
S
ONY_ACPI_VALU
E
(
PID
,
snc_PID_get
,
NULL
,
NULL
,
1
),
S
NC_HANDL
E
(
PID
,
snc_PID_get
,
NULL
,
NULL
,
1
),
S
ONY_ACPI_VALU
E
(
CTR
,
snc_CTR_get
,
snc_CTR_set
,
NULL
,
1
),
S
NC_HANDL
E
(
CTR
,
snc_CTR_get
,
snc_CTR_set
,
NULL
,
1
),
S
ONY_ACPI_VALU
E
(
PCR
,
snc_PCR_get
,
snc_PCR_set
,
NULL
,
1
),
S
NC_HANDL
E
(
PCR
,
snc_PCR_get
,
snc_PCR_set
,
NULL
,
1
),
S
ONY_ACPI_VALU
E
(
CMI
,
snc_CMI_get
,
snc_CMI_set
,
NULL
,
1
),
S
NC_HANDL
E
(
CMI
,
snc_CMI_get
,
snc_CMI_set
,
NULL
,
1
),
S
ONY_ACPI_VALU
E_NULL
S
NC_HANDL
E_NULL
};
};
static
acpi_handle
sony_acpi_handle
;
static
acpi_handle
sony_
nc_
acpi_handle
;
static
struct
acpi_device
*
sony_
acpi
_acpi_device
=
NULL
;
static
struct
acpi_device
*
sony_
nc
_acpi_device
=
NULL
;
/*
/*
* acpi_evaluate_object wrappers
* acpi_evaluate_object wrappers
...
@@ -153,7 +536,7 @@ static int acpi_callgetfunc(acpi_handle handle, char *name, int *result)
...
@@ -153,7 +536,7 @@ static int acpi_callgetfunc(acpi_handle handle, char *name, int *result)
return
0
;
return
0
;
}
}
printk
(
LOG
_PFX
"acpi_callreadfunc failed
\n
"
);
printk
(
KERN_WARNING
DRV
_PFX
"acpi_callreadfunc failed
\n
"
);
return
-
1
;
return
-
1
;
}
}
...
@@ -179,7 +562,7 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
...
@@ -179,7 +562,7 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
if
(
status
==
AE_OK
)
{
if
(
status
==
AE_OK
)
{
if
(
result
!=
NULL
)
{
if
(
result
!=
NULL
)
{
if
(
out_obj
.
type
!=
ACPI_TYPE_INTEGER
)
{
if
(
out_obj
.
type
!=
ACPI_TYPE_INTEGER
)
{
printk
(
LOG
_PFX
"acpi_evaluate_object bad "
printk
(
KERN_WARNING
DRV
_PFX
"acpi_evaluate_object bad "
"return type
\n
"
);
"return type
\n
"
);
return
-
1
;
return
-
1
;
}
}
...
@@ -188,13 +571,13 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
...
@@ -188,13 +571,13 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
return
0
;
return
0
;
}
}
printk
(
LOG
_PFX
"acpi_evaluate_object failed
\n
"
);
printk
(
KERN_WARNING
DRV
_PFX
"acpi_evaluate_object failed
\n
"
);
return
-
1
;
return
-
1
;
}
}
/*
/*
* sony_
acpi
_values input/output validate functions
* sony_
nc
_values input/output validate functions
*/
*/
/* brightness_default_validate:
/* brightness_default_validate:
...
@@ -229,19 +612,19 @@ static int boolean_validate(const int direction, const int value)
...
@@ -229,19 +612,19 @@ static int boolean_validate(const int direction, const int value)
}
}
/*
/*
* Sysfs show/store common to all sony_
acpi
_values
* Sysfs show/store common to all sony_
nc
_values
*/
*/
static
ssize_t
sony_
acpi
_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
static
ssize_t
sony_
nc_sysfs
_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buffer
)
char
*
buffer
)
{
{
int
value
;
int
value
;
struct
sony_
acpi
_value
*
item
=
struct
sony_
nc
_value
*
item
=
container_of
(
attr
,
struct
sony_
acpi
_value
,
devattr
);
container_of
(
attr
,
struct
sony_
nc
_value
,
devattr
);
if
(
!*
item
->
acpiget
)
if
(
!*
item
->
acpiget
)
return
-
EIO
;
return
-
EIO
;
if
(
acpi_callgetfunc
(
sony_acpi_handle
,
*
item
->
acpiget
,
&
value
)
<
0
)
if
(
acpi_callgetfunc
(
sony_
nc_
acpi_handle
,
*
item
->
acpiget
,
&
value
)
<
0
)
return
-
EIO
;
return
-
EIO
;
if
(
item
->
validate
)
if
(
item
->
validate
)
...
@@ -250,13 +633,13 @@ static ssize_t sony_acpi_show(struct device *dev, struct device_attribute *attr,
...
@@ -250,13 +633,13 @@ static ssize_t sony_acpi_show(struct device *dev, struct device_attribute *attr,
return
snprintf
(
buffer
,
PAGE_SIZE
,
"%d
\n
"
,
value
);
return
snprintf
(
buffer
,
PAGE_SIZE
,
"%d
\n
"
,
value
);
}
}
static
ssize_t
sony_
acpi
_store
(
struct
device
*
dev
,
static
ssize_t
sony_
nc_sysfs
_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
struct
device_attribute
*
attr
,
const
char
*
buffer
,
size_t
count
)
const
char
*
buffer
,
size_t
count
)
{
{
int
value
;
int
value
;
struct
sony_
acpi
_value
*
item
=
struct
sony_
nc
_value
*
item
=
container_of
(
attr
,
struct
sony_
acpi
_value
,
devattr
);
container_of
(
attr
,
struct
sony_
nc
_value
,
devattr
);
if
(
!
item
->
acpiset
)
if
(
!
item
->
acpiset
)
return
-
EIO
;
return
-
EIO
;
...
@@ -272,118 +655,20 @@ static ssize_t sony_acpi_store(struct device *dev,
...
@@ -272,118 +655,20 @@ static ssize_t sony_acpi_store(struct device *dev,
if
(
value
<
0
)
if
(
value
<
0
)
return
value
;
return
value
;
if
(
acpi_callsetfunc
(
sony_acpi_handle
,
*
item
->
acpiset
,
value
,
NULL
)
<
0
)
if
(
acpi_callsetfunc
(
sony_
nc_
acpi_handle
,
*
item
->
acpiset
,
value
,
NULL
)
<
0
)
return
-
EIO
;
return
-
EIO
;
item
->
value
=
value
;
item
->
value
=
value
;
item
->
valid
=
1
;
item
->
valid
=
1
;
return
count
;
return
count
;
}
}
/*
* Platform device
*/
static
struct
platform_driver
sncpf_driver
=
{
.
driver
=
{
.
name
=
"sony-laptop"
,
.
owner
=
THIS_MODULE
,
}
};
static
struct
platform_device
*
sncpf_device
;
static
int
sony_snc_pf_add
(
void
)
{
acpi_handle
handle
;
struct
sony_acpi_value
*
item
;
int
ret
=
0
;
ret
=
platform_driver_register
(
&
sncpf_driver
);
if
(
ret
)
goto
out
;
sncpf_device
=
platform_device_alloc
(
"sony-laptop"
,
-
1
);
if
(
!
sncpf_device
)
{
ret
=
-
ENOMEM
;
goto
out_platform_registered
;
}
ret
=
platform_device_add
(
sncpf_device
);
if
(
ret
)
goto
out_platform_alloced
;
for
(
item
=
sony_acpi_values
;
item
->
name
;
++
item
)
{
if
(
!
debug
&&
item
->
debug
)
continue
;
/* find the available acpiget as described in the DSDT */
for
(;
item
->
acpiget
&&
*
item
->
acpiget
;
++
item
->
acpiget
)
{
if
(
ACPI_SUCCESS
(
acpi_get_handle
(
sony_acpi_handle
,
*
item
->
acpiget
,
&
handle
)))
{
if
(
debug
)
printk
(
LOG_PFX
"Found %s getter: %s
\n
"
,
item
->
name
,
*
item
->
acpiget
);
item
->
devattr
.
attr
.
mode
|=
S_IRUGO
;
break
;
}
}
/* find the available acpiset as described in the DSDT */
for
(;
item
->
acpiset
&&
*
item
->
acpiset
;
++
item
->
acpiset
)
{
if
(
ACPI_SUCCESS
(
acpi_get_handle
(
sony_acpi_handle
,
*
item
->
acpiset
,
&
handle
)))
{
if
(
debug
)
printk
(
LOG_PFX
"Found %s setter: %s
\n
"
,
item
->
name
,
*
item
->
acpiset
);
item
->
devattr
.
attr
.
mode
|=
S_IWUSR
;
break
;
}
}
if
(
item
->
devattr
.
attr
.
mode
!=
0
)
{
ret
=
device_create_file
(
&
sncpf_device
->
dev
,
&
item
->
devattr
);
if
(
ret
)
goto
out_sysfs
;
}
}
return
0
;
out_sysfs:
for
(
item
=
sony_acpi_values
;
item
->
name
;
++
item
)
{
device_remove_file
(
&
sncpf_device
->
dev
,
&
item
->
devattr
);
}
platform_device_del
(
sncpf_device
);
out_platform_alloced:
platform_device_put
(
sncpf_device
);
out_platform_registered:
platform_driver_unregister
(
&
sncpf_driver
);
out:
return
ret
;
}
static
void
sony_snc_pf_remove
(
void
)
{
struct
sony_acpi_value
*
item
;
for
(
item
=
sony_acpi_values
;
item
->
name
;
++
item
)
{
device_remove_file
(
&
sncpf_device
->
dev
,
&
item
->
devattr
);
}
platform_device_del
(
sncpf_device
);
platform_device_put
(
sncpf_device
);
platform_driver_unregister
(
&
sncpf_driver
);
}
/*
/*
* Backlight device
* Backlight device
*/
*/
static
int
sony_backlight_update_status
(
struct
backlight_device
*
bd
)
static
int
sony_backlight_update_status
(
struct
backlight_device
*
bd
)
{
{
return
acpi_callsetfunc
(
sony_acpi_handle
,
"SBRT"
,
return
acpi_callsetfunc
(
sony_
nc_
acpi_handle
,
"SBRT"
,
bd
->
props
.
brightness
+
1
,
NULL
);
bd
->
props
.
brightness
+
1
,
NULL
);
}
}
...
@@ -391,7 +676,7 @@ static int sony_backlight_get_brightness(struct backlight_device *bd)
...
@@ -391,7 +676,7 @@ static int sony_backlight_get_brightness(struct backlight_device *bd)
{
{
int
value
;
int
value
;
if
(
acpi_callgetfunc
(
sony_acpi_handle
,
"GBRT"
,
&
value
))
if
(
acpi_callgetfunc
(
sony_
nc_
acpi_handle
,
"GBRT"
,
&
value
))
return
0
;
return
0
;
/* brightness levels are 1-based, while backlight ones are 0-based */
/* brightness levels are 1-based, while backlight ones are 0-based */
return
value
-
1
;
return
value
-
1
;
...
@@ -408,9 +693,9 @@ static struct backlight_ops sony_backlight_ops = {
...
@@ -408,9 +693,9 @@ static struct backlight_ops sony_backlight_ops = {
*/
*/
static
void
sony_acpi_notify
(
acpi_handle
handle
,
u32
event
,
void
*
data
)
static
void
sony_acpi_notify
(
acpi_handle
handle
,
u32
event
,
void
*
data
)
{
{
if
(
debug
)
dprintk
(
"sony_acpi_notify, event: %d
\n
"
,
event
);
printk
(
LOG_PFX
"sony_acpi_notify, event: %d
\n
"
,
event
);
sony_laptop_report_input_event
(
event
);
acpi_bus_generate_event
(
sony_
acpi
_acpi_device
,
1
,
event
);
acpi_bus_generate_event
(
sony_
nc
_acpi_device
,
1
,
event
);
}
}
static
acpi_status
sony_walk_callback
(
acpi_handle
handle
,
u32
level
,
static
acpi_status
sony_walk_callback
(
acpi_handle
handle
,
u32
level
,
...
@@ -422,7 +707,7 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
...
@@ -422,7 +707,7 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
node
=
(
struct
acpi_namespace_node
*
)
handle
;
node
=
(
struct
acpi_namespace_node
*
)
handle
;
operand
=
(
union
acpi_operand_object
*
)
node
->
object
;
operand
=
(
union
acpi_operand_object
*
)
node
->
object
;
printk
(
LOG
_PFX
"method: name: %4.4s, args %X
\n
"
,
node
->
name
.
ascii
,
printk
(
KERN_WARNING
DRV
_PFX
"method: name: %4.4s, args %X
\n
"
,
node
->
name
.
ascii
,
(
u32
)
operand
->
method
.
param_count
);
(
u32
)
operand
->
method
.
param_count
);
return
AE_OK
;
return
AE_OK
;
...
@@ -431,16 +716,16 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
...
@@ -431,16 +716,16 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
/*
/*
* ACPI device
* ACPI device
*/
*/
static
int
sony_
acpi
_resume
(
struct
acpi_device
*
device
)
static
int
sony_
nc
_resume
(
struct
acpi_device
*
device
)
{
{
struct
sony_
acpi
_value
*
item
;
struct
sony_
nc
_value
*
item
;
for
(
item
=
sony_
acpi
_values
;
item
->
name
;
item
++
)
{
for
(
item
=
sony_
nc
_values
;
item
->
name
;
item
++
)
{
int
ret
;
int
ret
;
if
(
!
item
->
valid
)
if
(
!
item
->
valid
)
continue
;
continue
;
ret
=
acpi_callsetfunc
(
sony_acpi_handle
,
*
item
->
acpiset
,
ret
=
acpi_callsetfunc
(
sony_
nc_
acpi_handle
,
*
item
->
acpiset
,
item
->
value
,
NULL
);
item
->
value
,
NULL
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
printk
(
"%s: %d
\n
"
,
__FUNCTION__
,
ret
);
printk
(
"%s: %d
\n
"
,
__FUNCTION__
,
ret
);
...
@@ -450,42 +735,55 @@ static int sony_acpi_resume(struct acpi_device *device)
...
@@ -450,42 +735,55 @@ static int sony_acpi_resume(struct acpi_device *device)
return
0
;
return
0
;
}
}
static
int
sony_
acpi
_add
(
struct
acpi_device
*
device
)
static
int
sony_
nc
_add
(
struct
acpi_device
*
device
)
{
{
acpi_status
status
;
acpi_status
status
;
int
result
=
0
;
int
result
=
0
;
acpi_handle
handle
;
acpi_handle
handle
;
struct
sony_nc_value
*
item
;
printk
(
KERN_INFO
DRV_PFX
"%s v%s.
\n
"
,
SONY_NC_DRIVER_NAME
,
SONY_LAPTOP_DRIVER_VERSION
);
sony_acpi_acpi_device
=
device
;
sony_nc_acpi_device
=
device
;
strcpy
(
acpi_device_class
(
device
),
"sony/hotkey"
);
sony_acpi_handle
=
device
->
handle
;
sony_
nc_
acpi_handle
=
device
->
handle
;
if
(
debug
)
{
if
(
debug
)
{
status
=
acpi_walk_namespace
(
ACPI_TYPE_METHOD
,
sony_acpi_handle
,
status
=
acpi_walk_namespace
(
ACPI_TYPE_METHOD
,
sony_
nc_
acpi_handle
,
1
,
sony_walk_callback
,
NULL
,
NULL
);
1
,
sony_walk_callback
,
NULL
,
NULL
);
if
(
ACPI_FAILURE
(
status
))
{
if
(
ACPI_FAILURE
(
status
))
{
printk
(
LOG
_PFX
"unable to walk acpi resources
\n
"
);
printk
(
KERN_WARNING
DRV
_PFX
"unable to walk acpi resources
\n
"
);
result
=
-
ENODEV
;
result
=
-
ENODEV
;
goto
outwalk
;
goto
outwalk
;
}
}
}
}
status
=
acpi_install_notify_handler
(
sony_acpi_handle
,
/* setup input devices and helper fifo */
result
=
sony_laptop_setup_input
();
if
(
result
)
{
printk
(
KERN_ERR
DRV_PFX
"Unabe to create input devices.
\n
"
);
goto
outwalk
;
}
status
=
acpi_install_notify_handler
(
sony_nc_acpi_handle
,
ACPI_DEVICE_NOTIFY
,
ACPI_DEVICE_NOTIFY
,
sony_acpi_notify
,
NULL
);
sony_acpi_notify
,
NULL
);
if
(
ACPI_FAILURE
(
status
))
{
if
(
ACPI_FAILURE
(
status
))
{
printk
(
LOG
_PFX
"unable to install notify handler
\n
"
);
printk
(
KERN_WARNING
DRV
_PFX
"unable to install notify handler
\n
"
);
result
=
-
ENODEV
;
result
=
-
ENODEV
;
goto
out
walk
;
goto
out
input
;
}
}
if
(
ACPI_SUCCESS
(
acpi_get_handle
(
sony_acpi_handle
,
"GBRT"
,
&
handle
)))
{
if
(
ACPI_SUCCESS
(
acpi_get_handle
(
sony_
nc_
acpi_handle
,
"GBRT"
,
&
handle
)))
{
sony_backlight_device
=
backlight_device_register
(
"sony"
,
NULL
,
sony_backlight_device
=
backlight_device_register
(
"sony"
,
NULL
,
NULL
,
NULL
,
&
sony_backlight_ops
);
&
sony_backlight_ops
);
if
(
IS_ERR
(
sony_backlight_device
))
{
if
(
IS_ERR
(
sony_backlight_device
))
{
printk
(
LOG
_PFX
"unable to register backlight device
\n
"
);
printk
(
KERN_WARNING
DRV
_PFX
"unable to register backlight device
\n
"
);
sony_backlight_device
=
NULL
;
sony_backlight_device
=
NULL
;
}
else
{
}
else
{
sony_backlight_device
->
props
.
brightness
=
sony_backlight_device
->
props
.
brightness
=
...
@@ -497,68 +795,1497 @@ static int sony_acpi_add(struct acpi_device *device)
...
@@ -497,68 +795,1497 @@ static int sony_acpi_add(struct acpi_device *device)
}
}
if
(
sony_snc_pf_add
())
result
=
sony_pf_add
();
if
(
result
)
goto
outbacklight
;
goto
outbacklight
;
printk
(
KERN_INFO
ACPI_SNC_DRIVER_NAME
" successfully installed
\n
"
);
/* create sony_pf sysfs attributes related to the SNC device */
for
(
item
=
sony_nc_values
;
item
->
name
;
++
item
)
{
if
(
!
debug
&&
item
->
debug
)
continue
;
/* find the available acpiget as described in the DSDT */
for
(;
item
->
acpiget
&&
*
item
->
acpiget
;
++
item
->
acpiget
)
{
if
(
ACPI_SUCCESS
(
acpi_get_handle
(
sony_nc_acpi_handle
,
*
item
->
acpiget
,
&
handle
)))
{
dprintk
(
"Found %s getter: %s
\n
"
,
item
->
name
,
*
item
->
acpiget
);
item
->
devattr
.
attr
.
mode
|=
S_IRUGO
;
break
;
}
}
/* find the available acpiset as described in the DSDT */
for
(;
item
->
acpiset
&&
*
item
->
acpiset
;
++
item
->
acpiset
)
{
if
(
ACPI_SUCCESS
(
acpi_get_handle
(
sony_nc_acpi_handle
,
*
item
->
acpiset
,
&
handle
)))
{
dprintk
(
"Found %s setter: %s
\n
"
,
item
->
name
,
*
item
->
acpiset
);
item
->
devattr
.
attr
.
mode
|=
S_IWUSR
;
break
;
}
}
if
(
item
->
devattr
.
attr
.
mode
!=
0
)
{
result
=
device_create_file
(
&
sony_pf_device
->
dev
,
&
item
->
devattr
);
if
(
result
)
goto
out_sysfs
;
}
}
return
0
;
return
0
;
out_sysfs:
for
(
item
=
sony_nc_values
;
item
->
name
;
++
item
)
{
device_remove_file
(
&
sony_pf_device
->
dev
,
&
item
->
devattr
);
}
sony_pf_remove
();
outbacklight:
outbacklight:
if
(
sony_backlight_device
)
if
(
sony_backlight_device
)
backlight_device_unregister
(
sony_backlight_device
);
backlight_device_unregister
(
sony_backlight_device
);
status
=
acpi_remove_notify_handler
(
sony_acpi_handle
,
status
=
acpi_remove_notify_handler
(
sony_
nc_
acpi_handle
,
ACPI_DEVICE_NOTIFY
,
ACPI_DEVICE_NOTIFY
,
sony_acpi_notify
);
sony_acpi_notify
);
if
(
ACPI_FAILURE
(
status
))
if
(
ACPI_FAILURE
(
status
))
printk
(
LOG_PFX
"unable to remove notify handler
\n
"
);
printk
(
KERN_WARNING
DRV_PFX
"unable to remove notify handler
\n
"
);
outinput:
sony_laptop_remove_input
();
outwalk:
outwalk:
return
result
;
return
result
;
}
}
static
int
sony_
acpi
_remove
(
struct
acpi_device
*
device
,
int
type
)
static
int
sony_
nc
_remove
(
struct
acpi_device
*
device
,
int
type
)
{
{
acpi_status
status
;
acpi_status
status
;
struct
sony_nc_value
*
item
;
if
(
sony_backlight_device
)
if
(
sony_backlight_device
)
backlight_device_unregister
(
sony_backlight_device
);
backlight_device_unregister
(
sony_backlight_device
);
sony_
acpi
_acpi_device
=
NULL
;
sony_
nc
_acpi_device
=
NULL
;
status
=
acpi_remove_notify_handler
(
sony_acpi_handle
,
status
=
acpi_remove_notify_handler
(
sony_
nc_
acpi_handle
,
ACPI_DEVICE_NOTIFY
,
ACPI_DEVICE_NOTIFY
,
sony_acpi_notify
);
sony_acpi_notify
);
if
(
ACPI_FAILURE
(
status
))
if
(
ACPI_FAILURE
(
status
))
printk
(
LOG
_PFX
"unable to remove notify handler
\n
"
);
printk
(
KERN_WARNING
DRV
_PFX
"unable to remove notify handler
\n
"
);
sony_snc_pf_remove
();
for
(
item
=
sony_nc_values
;
item
->
name
;
++
item
)
{
device_remove_file
(
&
sony_pf_device
->
dev
,
&
item
->
devattr
);
}
printk
(
KERN_INFO
ACPI_SNC_DRIVER_NAME
" successfully removed
\n
"
);
sony_pf_remove
();
sony_laptop_remove_input
();
dprintk
(
SONY_NC_DRIVER_NAME
" removed.
\n
"
);
return
0
;
return
0
;
}
}
static
struct
acpi_driver
sony_acpi_driver
=
{
static
struct
acpi_driver
sony_nc_driver
=
{
.
name
=
ACPI_SNC_DRIVER_NAME
,
.
name
=
SONY_NC_DRIVER_NAME
,
.
class
=
ACPI_SNC_CLASS
,
.
class
=
SONY_NC_CLASS
,
.
ids
=
ACPI_SNC_HID
,
.
ids
=
SONY_NC_HID
,
.
owner
=
THIS_MODULE
,
.
ops
=
{
.
ops
=
{
.
add
=
sony_
acpi
_add
,
.
add
=
sony_
nc
_add
,
.
remove
=
sony_
acpi
_remove
,
.
remove
=
sony_
nc
_remove
,
.
resume
=
sony_
acpi
_resume
,
.
resume
=
sony_
nc
_resume
,
},
},
};
};
static
int
__init
sony_acpi_init
(
void
)
/*********** SPIC (SNY6001) Device ***********/
{
return
acpi_bus_register_driver
(
&
sony_acpi_driver
);
#define SONYPI_DEVICE_TYPE1 0x00000001
#define SONYPI_DEVICE_TYPE2 0x00000002
#define SONYPI_DEVICE_TYPE3 0x00000004
#define SONY_PIC_EV_MASK 0xff
struct
sony_pic_ioport
{
struct
acpi_resource_io
io
;
struct
list_head
list
;
};
struct
sony_pic_irq
{
struct
acpi_resource_irq
irq
;
struct
list_head
list
;
};
struct
sony_pic_dev
{
int
model
;
u8
camera_power
;
u8
bluetooth_power
;
u8
wwan_power
;
struct
acpi_device
*
acpi_dev
;
struct
sony_pic_irq
*
cur_irq
;
struct
sony_pic_ioport
*
cur_ioport
;
struct
list_head
interrupts
;
struct
list_head
ioports
;
struct
mutex
lock
;
};
static
struct
sony_pic_dev
spic_dev
=
{
.
interrupts
=
LIST_HEAD_INIT
(
spic_dev
.
interrupts
),
.
ioports
=
LIST_HEAD_INIT
(
spic_dev
.
ioports
),
};
/* 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
#define SONYPI_WIRELESS_MASK 0x00002000
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
}
};
/* The set of possible wireless events */
static
struct
sonypi_event
sonypi_wlessev
[]
=
{
{
0x59
,
SONYPI_EVENT_WIRELESS_ON
},
{
0x5a
,
SONYPI_EVENT_WIRELESS_OFF
},
{
0
,
0
}
};
/* 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
;
}
sony_pic_eventtypes
[]
=
{
{
SONYPI_DEVICE_TYPE1
,
0
,
0xffffffff
,
sonypi_releaseev
},
{
SONYPI_DEVICE_TYPE1
,
0x70
,
SONYPI_MEYE_MASK
,
sonypi_meyeev
},
{
SONYPI_DEVICE_TYPE1
,
0x30
,
SONYPI_LID_MASK
,
sonypi_lidev
},
{
SONYPI_DEVICE_TYPE1
,
0x60
,
SONYPI_CAPTURE_MASK
,
sonypi_captureev
},
{
SONYPI_DEVICE_TYPE1
,
0x10
,
SONYPI_JOGGER_MASK
,
sonypi_joggerev
},
{
SONYPI_DEVICE_TYPE1
,
0x20
,
SONYPI_FNKEY_MASK
,
sonypi_fnkeyev
},
{
SONYPI_DEVICE_TYPE1
,
0x30
,
SONYPI_BLUETOOTH_MASK
,
sonypi_blueev
},
{
SONYPI_DEVICE_TYPE1
,
0x40
,
SONYPI_PKEY_MASK
,
sonypi_pkeyev
},
{
SONYPI_DEVICE_TYPE1
,
0x30
,
SONYPI_MEMORYSTICK_MASK
,
sonypi_memorystickev
},
{
SONYPI_DEVICE_TYPE1
,
0x40
,
SONYPI_BATTERY_MASK
,
sonypi_batteryev
},
{
SONYPI_DEVICE_TYPE2
,
0
,
0xffffffff
,
sonypi_releaseev
},
{
SONYPI_DEVICE_TYPE2
,
0x38
,
SONYPI_LID_MASK
,
sonypi_lidev
},
{
SONYPI_DEVICE_TYPE2
,
0x11
,
SONYPI_JOGGER_MASK
,
sonypi_joggerev
},
{
SONYPI_DEVICE_TYPE2
,
0x61
,
SONYPI_CAPTURE_MASK
,
sonypi_captureev
},
{
SONYPI_DEVICE_TYPE2
,
0x21
,
SONYPI_FNKEY_MASK
,
sonypi_fnkeyev
},
{
SONYPI_DEVICE_TYPE2
,
0x31
,
SONYPI_BLUETOOTH_MASK
,
sonypi_blueev
},
{
SONYPI_DEVICE_TYPE2
,
0x08
,
SONYPI_PKEY_MASK
,
sonypi_pkeyev
},
{
SONYPI_DEVICE_TYPE2
,
0x11
,
SONYPI_BACK_MASK
,
sonypi_backev
},
{
SONYPI_DEVICE_TYPE2
,
0x21
,
SONYPI_HELP_MASK
,
sonypi_helpev
},
{
SONYPI_DEVICE_TYPE2
,
0x21
,
SONYPI_ZOOM_MASK
,
sonypi_zoomev
},
{
SONYPI_DEVICE_TYPE2
,
0x20
,
SONYPI_THUMBPHRASE_MASK
,
sonypi_thumbphraseev
},
{
SONYPI_DEVICE_TYPE2
,
0x31
,
SONYPI_MEMORYSTICK_MASK
,
sonypi_memorystickev
},
{
SONYPI_DEVICE_TYPE2
,
0x41
,
SONYPI_BATTERY_MASK
,
sonypi_batteryev
},
{
SONYPI_DEVICE_TYPE2
,
0x31
,
SONYPI_PKEY_MASK
,
sonypi_pkeyev
},
{
SONYPI_DEVICE_TYPE3
,
0
,
0xffffffff
,
sonypi_releaseev
},
{
SONYPI_DEVICE_TYPE3
,
0x21
,
SONYPI_FNKEY_MASK
,
sonypi_fnkeyev
},
{
SONYPI_DEVICE_TYPE3
,
0x31
,
SONYPI_WIRELESS_MASK
,
sonypi_wlessev
},
{
SONYPI_DEVICE_TYPE3
,
0x31
,
SONYPI_MEMORYSTICK_MASK
,
sonypi_memorystickev
},
{
SONYPI_DEVICE_TYPE3
,
0x41
,
SONYPI_BATTERY_MASK
,
sonypi_batteryev
},
{
SONYPI_DEVICE_TYPE3
,
0x31
,
SONYPI_PKEY_MASK
,
sonypi_pkeyev
},
{
0
}
};
static
int
sony_pic_detect_device_type
(
void
)
{
struct
pci_dev
*
pcidev
;
int
model
=
0
;
if
((
pcidev
=
pci_get_device
(
PCI_VENDOR_ID_INTEL
,
PCI_DEVICE_ID_INTEL_82371AB_3
,
NULL
)))
model
=
SONYPI_DEVICE_TYPE1
;
else
if
((
pcidev
=
pci_get_device
(
PCI_VENDOR_ID_INTEL
,
PCI_DEVICE_ID_INTEL_ICH6_1
,
NULL
)))
model
=
SONYPI_DEVICE_TYPE3
;
else
if
((
pcidev
=
pci_get_device
(
PCI_VENDOR_ID_INTEL
,
PCI_DEVICE_ID_INTEL_ICH7_1
,
NULL
)))
model
=
SONYPI_DEVICE_TYPE3
;
else
model
=
SONYPI_DEVICE_TYPE2
;
if
(
pcidev
)
pci_dev_put
(
pcidev
);
printk
(
KERN_INFO
DRV_PFX
"detected Type%d model
\n
"
,
model
==
SONYPI_DEVICE_TYPE1
?
1
:
model
==
SONYPI_DEVICE_TYPE2
?
2
:
3
);
return
model
;
}
#define ITERATIONS_LONG 10000
#define ITERATIONS_SHORT 10
#define wait_on_command(command, iterations) { \
unsigned int n = iterations; \
while (--n && (command)) \
udelay(1); \
if (!n) \
dprintk("command failed at %s : %s (line %d)\n", \
__FILE__, __FUNCTION__, __LINE__); \
}
static
u8
sony_pic_call1
(
u8
dev
)
{
u8
v1
,
v2
;
wait_on_command
(
inb_p
(
spic_dev
.
cur_ioport
->
io
.
minimum
+
4
)
&
2
,
ITERATIONS_LONG
);
outb
(
dev
,
spic_dev
.
cur_ioport
->
io
.
minimum
+
4
);
v1
=
inb_p
(
spic_dev
.
cur_ioport
->
io
.
minimum
+
4
);
v2
=
inb_p
(
spic_dev
.
cur_ioport
->
io
.
minimum
);
dprintk
(
"sony_pic_call1: 0x%.4x
\n
"
,
(
v2
<<
8
)
|
v1
);
return
v2
;
}
static
u8
sony_pic_call2
(
u8
dev
,
u8
fn
)
{
u8
v1
;
wait_on_command
(
inb_p
(
spic_dev
.
cur_ioport
->
io
.
minimum
+
4
)
&
2
,
ITERATIONS_LONG
);
outb
(
dev
,
spic_dev
.
cur_ioport
->
io
.
minimum
+
4
);
wait_on_command
(
inb_p
(
spic_dev
.
cur_ioport
->
io
.
minimum
+
4
)
&
2
,
ITERATIONS_LONG
);
outb
(
fn
,
spic_dev
.
cur_ioport
->
io
.
minimum
);
v1
=
inb_p
(
spic_dev
.
cur_ioport
->
io
.
minimum
);
dprintk
(
"sony_pic_call2: 0x%.4x
\n
"
,
v1
);
return
v1
;
}
static
u8
sony_pic_call3
(
u8
dev
,
u8
fn
,
u8
v
)
{
u8
v1
;
wait_on_command
(
inb_p
(
spic_dev
.
cur_ioport
->
io
.
minimum
+
4
)
&
2
,
ITERATIONS_LONG
);
outb
(
dev
,
spic_dev
.
cur_ioport
->
io
.
minimum
+
4
);
wait_on_command
(
inb_p
(
spic_dev
.
cur_ioport
->
io
.
minimum
+
4
)
&
2
,
ITERATIONS_LONG
);
outb
(
fn
,
spic_dev
.
cur_ioport
->
io
.
minimum
);
wait_on_command
(
inb_p
(
spic_dev
.
cur_ioport
->
io
.
minimum
+
4
)
&
2
,
ITERATIONS_LONG
);
outb
(
v
,
spic_dev
.
cur_ioport
->
io
.
minimum
);
v1
=
inb_p
(
spic_dev
.
cur_ioport
->
io
.
minimum
);
dprintk
(
"sony_pic_call3: 0x%.4x
\n
"
,
v1
);
return
v1
;
}
/* camera tests and poweron/poweroff */
#define SONYPI_CAMERA_PICTURE 5
#define SONYPI_CAMERA_CONTROL 0x10
#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_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
static
int
__sony_pic_camera_ready
(
void
)
{
u8
v
;
v
=
sony_pic_call2
(
0x8f
,
SONYPI_CAMERA_STATUS
);
return
(
v
!=
0xff
&&
(
v
&
SONYPI_CAMERA_STATUS_READY
));
}
static
int
__sony_pic_camera_off
(
void
)
{
if
(
!
camera
)
{
printk
(
KERN_WARNING
DRV_PFX
"camera control not enabled
\n
"
);
return
-
ENODEV
;
}
wait_on_command
(
sony_pic_call3
(
0x90
,
SONYPI_CAMERA_PICTURE
,
SONYPI_CAMERA_MUTE_MASK
),
ITERATIONS_SHORT
);
if
(
spic_dev
.
camera_power
)
{
sony_pic_call2
(
0x91
,
0
);
spic_dev
.
camera_power
=
0
;
}
return
0
;
}
static
int
__sony_pic_camera_on
(
void
)
{
int
i
,
j
,
x
;
if
(
!
camera
)
{
printk
(
KERN_WARNING
DRV_PFX
"camera control not enabled
\n
"
);
return
-
ENODEV
;
}
if
(
spic_dev
.
camera_power
)
return
0
;
for
(
j
=
5
;
j
>
0
;
j
--
)
{
for
(
x
=
0
;
x
<
100
&&
sony_pic_call2
(
0x91
,
0x1
);
x
++
)
msleep
(
10
);
sony_pic_call1
(
0x93
);
for
(
i
=
400
;
i
>
0
;
i
--
)
{
if
(
__sony_pic_camera_ready
())
break
;
msleep
(
10
);
}
if
(
i
)
break
;
}
if
(
j
==
0
)
{
printk
(
KERN_WARNING
DRV_PFX
"failed to power on camera
\n
"
);
return
-
ENODEV
;
}
wait_on_command
(
sony_pic_call3
(
0x90
,
SONYPI_CAMERA_CONTROL
,
0x5a
),
ITERATIONS_SHORT
);
spic_dev
.
camera_power
=
1
;
return
0
;
}
/* External camera command (exported to the motion eye v4l driver) */
int
sony_pic_camera_command
(
int
command
,
u8
value
)
{
if
(
!
camera
)
return
-
EIO
;
mutex_lock
(
&
spic_dev
.
lock
);
switch
(
command
)
{
case
SONY_PIC_COMMAND_SETCAMERA
:
if
(
value
)
__sony_pic_camera_on
();
else
__sony_pic_camera_off
();
break
;
case
SONY_PIC_COMMAND_SETCAMERABRIGHTNESS
:
wait_on_command
(
sony_pic_call3
(
0x90
,
SONYPI_CAMERA_BRIGHTNESS
,
value
),
ITERATIONS_SHORT
);
break
;
case
SONY_PIC_COMMAND_SETCAMERACONTRAST
:
wait_on_command
(
sony_pic_call3
(
0x90
,
SONYPI_CAMERA_CONTRAST
,
value
),
ITERATIONS_SHORT
);
break
;
case
SONY_PIC_COMMAND_SETCAMERAHUE
:
wait_on_command
(
sony_pic_call3
(
0x90
,
SONYPI_CAMERA_HUE
,
value
),
ITERATIONS_SHORT
);
break
;
case
SONY_PIC_COMMAND_SETCAMERACOLOR
:
wait_on_command
(
sony_pic_call3
(
0x90
,
SONYPI_CAMERA_COLOR
,
value
),
ITERATIONS_SHORT
);
break
;
case
SONY_PIC_COMMAND_SETCAMERASHARPNESS
:
wait_on_command
(
sony_pic_call3
(
0x90
,
SONYPI_CAMERA_SHARPNESS
,
value
),
ITERATIONS_SHORT
);
break
;
case
SONY_PIC_COMMAND_SETCAMERAPICTURE
:
wait_on_command
(
sony_pic_call3
(
0x90
,
SONYPI_CAMERA_PICTURE
,
value
),
ITERATIONS_SHORT
);
break
;
case
SONY_PIC_COMMAND_SETCAMERAAGC
:
wait_on_command
(
sony_pic_call3
(
0x90
,
SONYPI_CAMERA_AGC
,
value
),
ITERATIONS_SHORT
);
break
;
default:
printk
(
KERN_ERR
DRV_PFX
"sony_pic_camera_command invalid: %d
\n
"
,
command
);
break
;
}
mutex_unlock
(
&
spic_dev
.
lock
);
return
0
;
}
EXPORT_SYMBOL
(
sony_pic_camera_command
);
/* gprs/edge modem (SZ460N and SZ210P), thanks to Joshua Wise */
static
void
sony_pic_set_wwanpower
(
u8
state
)
{
state
=
!!
state
;
mutex_lock
(
&
spic_dev
.
lock
);
if
(
spic_dev
.
wwan_power
==
state
)
{
mutex_unlock
(
&
spic_dev
.
lock
);
return
;
}
sony_pic_call2
(
0xB0
,
state
);
spic_dev
.
wwan_power
=
state
;
mutex_unlock
(
&
spic_dev
.
lock
);
}
static
ssize_t
sony_pic_wwanpower_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buffer
,
size_t
count
)
{
unsigned
long
value
;
if
(
count
>
31
)
return
-
EINVAL
;
value
=
simple_strtoul
(
buffer
,
NULL
,
10
);
sony_pic_set_wwanpower
(
value
);
return
count
;
}
static
ssize_t
sony_pic_wwanpower_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buffer
)
{
ssize_t
count
;
mutex_lock
(
&
spic_dev
.
lock
);
count
=
snprintf
(
buffer
,
PAGE_SIZE
,
"%d
\n
"
,
spic_dev
.
wwan_power
);
mutex_unlock
(
&
spic_dev
.
lock
);
return
count
;
}
/* bluetooth subsystem power state */
static
void
__sony_pic_set_bluetoothpower
(
u8
state
)
{
state
=
!!
state
;
if
(
spic_dev
.
bluetooth_power
==
state
)
return
;
sony_pic_call2
(
0x96
,
state
);
sony_pic_call1
(
0x82
);
spic_dev
.
bluetooth_power
=
state
;
}
static
ssize_t
sony_pic_bluetoothpower_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buffer
,
size_t
count
)
{
unsigned
long
value
;
if
(
count
>
31
)
return
-
EINVAL
;
value
=
simple_strtoul
(
buffer
,
NULL
,
10
);
mutex_lock
(
&
spic_dev
.
lock
);
__sony_pic_set_bluetoothpower
(
value
);
mutex_unlock
(
&
spic_dev
.
lock
);
return
count
;
}
static
ssize_t
sony_pic_bluetoothpower_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buffer
)
{
ssize_t
count
=
0
;
mutex_lock
(
&
spic_dev
.
lock
);
count
=
snprintf
(
buffer
,
PAGE_SIZE
,
"%d
\n
"
,
spic_dev
.
bluetooth_power
);
mutex_unlock
(
&
spic_dev
.
lock
);
return
count
;
}
/* fan speed */
/* FAN0 information (reverse engineered from ACPI tables) */
#define SONY_PIC_FAN0_STATUS 0x93
static
int
sony_pic_set_fanspeed
(
unsigned
long
value
)
{
return
ec_write
(
SONY_PIC_FAN0_STATUS
,
value
);
}
static
int
sony_pic_get_fanspeed
(
u8
*
value
)
{
return
ec_read
(
SONY_PIC_FAN0_STATUS
,
value
);
}
static
ssize_t
sony_pic_fanspeed_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buffer
,
size_t
count
)
{
unsigned
long
value
;
if
(
count
>
31
)
return
-
EINVAL
;
value
=
simple_strtoul
(
buffer
,
NULL
,
10
);
if
(
sony_pic_set_fanspeed
(
value
))
return
-
EIO
;
return
count
;
}
static
ssize_t
sony_pic_fanspeed_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buffer
)
{
u8
value
=
0
;
if
(
sony_pic_get_fanspeed
(
&
value
))
return
-
EIO
;
return
snprintf
(
buffer
,
PAGE_SIZE
,
"%d
\n
"
,
value
);
}
#define SPIC_ATTR(_name, _mode) \
struct device_attribute spic_attr_##_name = __ATTR(_name, \
_mode, sony_pic_## _name ##_show, \
sony_pic_## _name ##_store)
static
SPIC_ATTR
(
bluetoothpower
,
0644
);
static
SPIC_ATTR
(
wwanpower
,
0644
);
static
SPIC_ATTR
(
fanspeed
,
0644
);
static
struct
attribute
*
spic_attributes
[]
=
{
&
spic_attr_bluetoothpower
.
attr
,
&
spic_attr_wwanpower
.
attr
,
&
spic_attr_fanspeed
.
attr
,
NULL
};
static
struct
attribute_group
spic_attribute_group
=
{
.
attrs
=
spic_attributes
};
/******** SONYPI compatibility **********/
#ifdef CONFIG_SONY_LAPTOP_OLD
/* battery / brightness / temperature 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
#define SONYPI_TEMP_STATUS 0xC1
struct
sonypi_compat_s
{
struct
fasync_struct
*
fifo_async
;
struct
kfifo
*
fifo
;
spinlock_t
fifo_lock
;
wait_queue_head_t
fifo_proc_list
;
atomic_t
open_count
;
};
static
struct
sonypi_compat_s
sonypi_compat
=
{
.
open_count
=
ATOMIC_INIT
(
0
),
};
static
int
sonypi_misc_fasync
(
int
fd
,
struct
file
*
filp
,
int
on
)
{
int
retval
;
retval
=
fasync_helper
(
fd
,
filp
,
on
,
&
sonypi_compat
.
fifo_async
);
if
(
retval
<
0
)
return
retval
;
return
0
;
}
static
int
sonypi_misc_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
sonypi_misc_fasync
(
-
1
,
file
,
0
);
atomic_dec
(
&
sonypi_compat
.
open_count
);
return
0
;
}
static
int
sonypi_misc_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
/* Flush input queue on first open */
if
(
atomic_inc_return
(
&
sonypi_compat
.
open_count
)
==
1
)
kfifo_reset
(
sonypi_compat
.
fifo
);
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
;
if
((
kfifo_len
(
sonypi_compat
.
fifo
)
==
0
)
&&
(
file
->
f_flags
&
O_NONBLOCK
))
return
-
EAGAIN
;
ret
=
wait_event_interruptible
(
sonypi_compat
.
fifo_proc_list
,
kfifo_len
(
sonypi_compat
.
fifo
)
!=
0
);
if
(
ret
)
return
ret
;
while
(
ret
<
count
&&
(
kfifo_get
(
sonypi_compat
.
fifo
,
&
c
,
sizeof
(
c
))
==
sizeof
(
c
)))
{
if
(
put_user
(
c
,
buf
++
))
return
-
EFAULT
;
ret
++
;
}
if
(
ret
>
0
)
{
struct
inode
*
inode
=
file
->
f_path
.
dentry
->
d_inode
;
inode
->
i_atime
=
current_fs_time
(
inode
->
i_sb
);
}
return
ret
;
}
static
unsigned
int
sonypi_misc_poll
(
struct
file
*
file
,
poll_table
*
wait
)
{
poll_wait
(
file
,
&
sonypi_compat
.
fifo_proc_list
,
wait
);
if
(
kfifo_len
(
sonypi_compat
.
fifo
))
return
POLLIN
|
POLLRDNORM
;
return
0
;
}
static
int
ec_read16
(
u8
addr
,
u16
*
value
)
{
u8
val_lb
,
val_hb
;
if
(
ec_read
(
addr
,
&
val_lb
))
return
-
1
;
if
(
ec_read
(
addr
+
1
,
&
val_hb
))
return
-
1
;
*
value
=
val_lb
|
(
val_hb
<<
8
);
return
0
;
}
static
int
sonypi_misc_ioctl
(
struct
inode
*
ip
,
struct
file
*
fp
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
int
ret
=
0
;
void
__user
*
argp
=
(
void
__user
*
)
arg
;
u8
val8
;
u16
val16
;
int
value
;
mutex_lock
(
&
spic_dev
.
lock
);
switch
(
cmd
)
{
case
SONYPI_IOCGBRT
:
if
(
sony_backlight_device
==
NULL
)
{
ret
=
-
EIO
;
break
;
}
if
(
acpi_callgetfunc
(
sony_nc_acpi_handle
,
"GBRT"
,
&
value
))
{
ret
=
-
EIO
;
break
;
}
val8
=
((
value
&
0xff
)
-
1
)
<<
5
;
if
(
copy_to_user
(
argp
,
&
val8
,
sizeof
(
val8
)))
ret
=
-
EFAULT
;
break
;
case
SONYPI_IOCSBRT
:
if
(
sony_backlight_device
==
NULL
)
{
ret
=
-
EIO
;
break
;
}
if
(
copy_from_user
(
&
val8
,
argp
,
sizeof
(
val8
)))
{
ret
=
-
EFAULT
;
break
;
}
if
(
acpi_callsetfunc
(
sony_nc_acpi_handle
,
"SBRT"
,
(
val8
>>
5
)
+
1
,
NULL
))
{
ret
=
-
EIO
;
break
;
}
/* sync the backlight device status */
sony_backlight_device
->
props
.
brightness
=
sony_backlight_get_brightness
(
sony_backlight_device
);
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
(
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
=
spic_dev
.
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
;
}
__sony_pic_set_bluetoothpower
(
val8
);
break
;
/* FAN Controls */
case
SONYPI_IOCGFAN
:
if
(
sony_pic_get_fanspeed
(
&
val8
))
{
ret
=
-
EIO
;
break
;
}
if
(
copy_to_user
(
argp
,
&
val8
,
sizeof
(
val8
)))
ret
=
-
EFAULT
;
break
;
case
SONYPI_IOCSFAN
:
if
(
copy_from_user
(
&
val8
,
argp
,
sizeof
(
val8
)))
{
ret
=
-
EFAULT
;
break
;
}
if
(
sony_pic_set_fanspeed
(
val8
))
ret
=
-
EIO
;
break
;
/* GET Temperature (useful under APM) */
case
SONYPI_IOCGTEMP
:
if
(
ec_read
(
SONYPI_TEMP_STATUS
,
&
val8
))
{
ret
=
-
EIO
;
break
;
}
if
(
copy_to_user
(
argp
,
&
val8
,
sizeof
(
val8
)))
ret
=
-
EFAULT
;
break
;
default:
ret
=
-
EINVAL
;
}
mutex_unlock
(
&
spic_dev
.
lock
);
return
ret
;
}
static
const
struct
file_operations
sonypi_misc_fops
=
{
.
owner
=
THIS_MODULE
,
.
read
=
sonypi_misc_read
,
.
poll
=
sonypi_misc_poll
,
.
open
=
sonypi_misc_open
,
.
release
=
sonypi_misc_release
,
.
fasync
=
sonypi_misc_fasync
,
.
ioctl
=
sonypi_misc_ioctl
,
};
static
struct
miscdevice
sonypi_misc_device
=
{
.
minor
=
MISC_DYNAMIC_MINOR
,
.
name
=
"sonypi"
,
.
fops
=
&
sonypi_misc_fops
,
};
static
void
sonypi_compat_report_event
(
u8
event
)
{
kfifo_put
(
sonypi_compat
.
fifo
,
(
unsigned
char
*
)
&
event
,
sizeof
(
event
));
kill_fasync
(
&
sonypi_compat
.
fifo_async
,
SIGIO
,
POLL_IN
);
wake_up_interruptible
(
&
sonypi_compat
.
fifo_proc_list
);
}
static
int
sonypi_compat_init
(
void
)
{
int
error
;
spin_lock_init
(
&
sonypi_compat
.
fifo_lock
);
sonypi_compat
.
fifo
=
kfifo_alloc
(
SONY_LAPTOP_BUF_SIZE
,
GFP_KERNEL
,
&
sonypi_compat
.
fifo_lock
);
if
(
IS_ERR
(
sonypi_compat
.
fifo
))
{
printk
(
KERN_ERR
DRV_PFX
"kfifo_alloc failed
\n
"
);
return
PTR_ERR
(
sonypi_compat
.
fifo
);
}
init_waitqueue_head
(
&
sonypi_compat
.
fifo_proc_list
);
if
(
minor
!=
-
1
)
sonypi_misc_device
.
minor
=
minor
;
error
=
misc_register
(
&
sonypi_misc_device
);
if
(
error
)
{
printk
(
KERN_ERR
DRV_PFX
"misc_register failed
\n
"
);
goto
err_free_kfifo
;
}
if
(
minor
==
-
1
)
printk
(
KERN_INFO
DRV_PFX
"device allocated minor is %d
\n
"
,
sonypi_misc_device
.
minor
);
return
0
;
err_free_kfifo:
kfifo_free
(
sonypi_compat
.
fifo
);
return
error
;
}
static
void
sonypi_compat_exit
(
void
)
{
misc_deregister
(
&
sonypi_misc_device
);
kfifo_free
(
sonypi_compat
.
fifo
);
}
#else
static
int
sonypi_compat_init
(
void
)
{
return
0
;
}
static
void
sonypi_compat_exit
(
void
)
{
}
static
void
sonypi_compat_report_event
(
u8
event
)
{
}
#endif
/* CONFIG_SONY_LAPTOP_OLD */
/*
* ACPI callbacks
*/
static
acpi_status
sony_pic_read_possible_resource
(
struct
acpi_resource
*
resource
,
void
*
context
)
{
u32
i
;
struct
sony_pic_dev
*
dev
=
(
struct
sony_pic_dev
*
)
context
;
switch
(
resource
->
type
)
{
case
ACPI_RESOURCE_TYPE_START_DEPENDENT
:
case
ACPI_RESOURCE_TYPE_END_DEPENDENT
:
return
AE_OK
;
case
ACPI_RESOURCE_TYPE_IRQ
:
{
struct
acpi_resource_irq
*
p
=
&
resource
->
data
.
irq
;
struct
sony_pic_irq
*
interrupt
=
NULL
;
if
(
!
p
||
!
p
->
interrupt_count
)
{
/*
* IRQ descriptors may have no IRQ# bits set,
* particularly those those w/ _STA disabled
*/
dprintk
(
"Blank IRQ resource
\n
"
);
return
AE_OK
;
}
for
(
i
=
0
;
i
<
p
->
interrupt_count
;
i
++
)
{
if
(
!
p
->
interrupts
[
i
])
{
printk
(
KERN_WARNING
DRV_PFX
"Invalid IRQ %d
\n
"
,
p
->
interrupts
[
i
]);
continue
;
}
interrupt
=
kzalloc
(
sizeof
(
*
interrupt
),
GFP_KERNEL
);
if
(
!
interrupt
)
return
AE_ERROR
;
list_add_tail
(
&
interrupt
->
list
,
&
dev
->
interrupts
);
interrupt
->
irq
.
triggering
=
p
->
triggering
;
interrupt
->
irq
.
polarity
=
p
->
polarity
;
interrupt
->
irq
.
sharable
=
p
->
sharable
;
interrupt
->
irq
.
interrupt_count
=
1
;
interrupt
->
irq
.
interrupts
[
0
]
=
p
->
interrupts
[
i
];
}
return
AE_OK
;
}
case
ACPI_RESOURCE_TYPE_IO
:
{
struct
acpi_resource_io
*
io
=
&
resource
->
data
.
io
;
struct
sony_pic_ioport
*
ioport
=
NULL
;
if
(
!
io
)
{
dprintk
(
"Blank IO resource
\n
"
);
return
AE_OK
;
}
ioport
=
kzalloc
(
sizeof
(
*
ioport
),
GFP_KERNEL
);
if
(
!
ioport
)
return
AE_ERROR
;
list_add_tail
(
&
ioport
->
list
,
&
dev
->
ioports
);
memcpy
(
&
ioport
->
io
,
io
,
sizeof
(
*
io
));
return
AE_OK
;
}
default:
dprintk
(
"Resource %d isn't an IRQ nor an IO port
\n
"
,
resource
->
type
);
case
ACPI_RESOURCE_TYPE_END_TAG
:
return
AE_OK
;
}
return
AE_CTRL_TERMINATE
;
}
static
int
sony_pic_possible_resources
(
struct
acpi_device
*
device
)
{
int
result
=
0
;
acpi_status
status
=
AE_OK
;
if
(
!
device
)
return
-
EINVAL
;
/* get device status */
/* see acpi_pci_link_get_current acpi_pci_link_get_possible */
dprintk
(
"Evaluating _STA
\n
"
);
result
=
acpi_bus_get_status
(
device
);
if
(
result
)
{
printk
(
KERN_WARNING
DRV_PFX
"Unable to read status
\n
"
);
goto
end
;
}
if
(
!
device
->
status
.
enabled
)
dprintk
(
"Device disabled
\n
"
);
else
dprintk
(
"Device enabled
\n
"
);
/*
* Query and parse 'method'
*/
dprintk
(
"Evaluating %s
\n
"
,
METHOD_NAME__PRS
);
status
=
acpi_walk_resources
(
device
->
handle
,
METHOD_NAME__PRS
,
sony_pic_read_possible_resource
,
&
spic_dev
);
if
(
ACPI_FAILURE
(
status
))
{
printk
(
KERN_WARNING
DRV_PFX
"Failure evaluating %s
\n
"
,
METHOD_NAME__PRS
);
result
=
-
ENODEV
;
}
end:
return
result
;
}
/*
* Disable the spic device by calling its _DIS method
*/
static
int
sony_pic_disable
(
struct
acpi_device
*
device
)
{
if
(
ACPI_FAILURE
(
acpi_evaluate_object
(
device
->
handle
,
"_DIS"
,
0
,
NULL
)))
return
-
ENXIO
;
dprintk
(
"Device disabled
\n
"
);
return
0
;
}
/*
* Based on drivers/acpi/pci_link.c:acpi_pci_link_set
*
* Call _SRS to set current resources
*/
static
int
sony_pic_enable
(
struct
acpi_device
*
device
,
struct
sony_pic_ioport
*
ioport
,
struct
sony_pic_irq
*
irq
)
{
acpi_status
status
;
int
result
=
0
;
struct
{
struct
acpi_resource
io_res
;
struct
acpi_resource
irq_res
;
struct
acpi_resource
end
;
}
*
resource
;
struct
acpi_buffer
buffer
=
{
0
,
NULL
};
if
(
!
ioport
||
!
irq
)
return
-
EINVAL
;
/* init acpi_buffer */
resource
=
kzalloc
(
sizeof
(
*
resource
)
+
1
,
GFP_KERNEL
);
if
(
!
resource
)
return
-
ENOMEM
;
buffer
.
length
=
sizeof
(
*
resource
)
+
1
;
buffer
.
pointer
=
resource
;
/* setup io resource */
resource
->
io_res
.
type
=
ACPI_RESOURCE_TYPE_IO
;
resource
->
io_res
.
length
=
sizeof
(
struct
acpi_resource
);
memcpy
(
&
resource
->
io_res
.
data
.
io
,
&
ioport
->
io
,
sizeof
(
struct
acpi_resource_io
));
/* setup irq resource */
resource
->
irq_res
.
type
=
ACPI_RESOURCE_TYPE_IRQ
;
resource
->
irq_res
.
length
=
sizeof
(
struct
acpi_resource
);
memcpy
(
&
resource
->
irq_res
.
data
.
irq
,
&
irq
->
irq
,
sizeof
(
struct
acpi_resource_irq
));
/* we requested a shared irq */
resource
->
irq_res
.
data
.
irq
.
sharable
=
ACPI_SHARED
;
resource
->
end
.
type
=
ACPI_RESOURCE_TYPE_END_TAG
;
/* Attempt to set the resource */
dprintk
(
"Evaluating _SRS
\n
"
);
status
=
acpi_set_current_resources
(
device
->
handle
,
&
buffer
);
/* check for total failure */
if
(
ACPI_FAILURE
(
status
))
{
printk
(
KERN_ERR
DRV_PFX
"Error evaluating _SRS"
);
result
=
-
ENODEV
;
goto
end
;
}
/* Necessary device initializations calls (from sonypi) */
sony_pic_call1
(
0x82
);
sony_pic_call2
(
0x81
,
0xff
);
sony_pic_call1
(
compat
?
0x92
:
0x82
);
end:
kfree
(
resource
);
return
result
;
}
/*****************
*
* ISR: some event is available
*
*****************/
static
irqreturn_t
sony_pic_irq
(
int
irq
,
void
*
dev_id
)
{
int
i
,
j
;
u32
port_val
=
0
;
u8
ev
=
0
;
u8
data_mask
=
0
;
u8
device_event
=
0
;
struct
sony_pic_dev
*
dev
=
(
struct
sony_pic_dev
*
)
dev_id
;
acpi_os_read_port
(
dev
->
cur_ioport
->
io
.
minimum
,
&
port_val
,
dev
->
cur_ioport
->
io
.
address_length
);
ev
=
port_val
&
SONY_PIC_EV_MASK
;
data_mask
=
0xff
&
(
port_val
>>
(
dev
->
cur_ioport
->
io
.
address_length
-
8
));
dprintk
(
"event (0x%.8x [%.2x] [%.2x]) at port 0x%.4x
\n
"
,
port_val
,
ev
,
data_mask
,
dev
->
cur_ioport
->
io
.
minimum
);
if
(
ev
==
0x00
||
ev
==
0xff
)
return
IRQ_HANDLED
;
for
(
i
=
0
;
sony_pic_eventtypes
[
i
].
model
;
i
++
)
{
if
(
spic_dev
.
model
!=
sony_pic_eventtypes
[
i
].
model
)
continue
;
if
((
data_mask
&
sony_pic_eventtypes
[
i
].
data
)
!=
sony_pic_eventtypes
[
i
].
data
)
continue
;
if
(
!
(
mask
&
sony_pic_eventtypes
[
i
].
mask
))
continue
;
for
(
j
=
0
;
sony_pic_eventtypes
[
i
].
events
[
j
].
event
;
j
++
)
{
if
(
ev
==
sony_pic_eventtypes
[
i
].
events
[
j
].
data
)
{
device_event
=
sony_pic_eventtypes
[
i
].
events
[
j
].
event
;
goto
found
;
}
}
}
return
IRQ_HANDLED
;
found:
sony_laptop_report_input_event
(
device_event
);
acpi_bus_generate_event
(
spic_dev
.
acpi_dev
,
1
,
device_event
);
sonypi_compat_report_event
(
device_event
);
return
IRQ_HANDLED
;
}
/*****************
*
* ACPI driver
*
*****************/
static
int
sony_pic_remove
(
struct
acpi_device
*
device
,
int
type
)
{
struct
sony_pic_ioport
*
io
,
*
tmp_io
;
struct
sony_pic_irq
*
irq
,
*
tmp_irq
;
sonypi_compat_exit
();
if
(
sony_pic_disable
(
device
))
{
printk
(
KERN_ERR
DRV_PFX
"Couldn't disable device.
\n
"
);
return
-
ENXIO
;
}
free_irq
(
spic_dev
.
cur_irq
->
irq
.
interrupts
[
0
],
&
spic_dev
);
release_region
(
spic_dev
.
cur_ioport
->
io
.
minimum
,
spic_dev
.
cur_ioport
->
io
.
address_length
);
sony_laptop_remove_input
();
/* pf attrs */
sysfs_remove_group
(
&
sony_pf_device
->
dev
.
kobj
,
&
spic_attribute_group
);
sony_pf_remove
();
list_for_each_entry_safe
(
io
,
tmp_io
,
&
spic_dev
.
ioports
,
list
)
{
list_del
(
&
io
->
list
);
kfree
(
io
);
}
list_for_each_entry_safe
(
irq
,
tmp_irq
,
&
spic_dev
.
interrupts
,
list
)
{
list_del
(
&
irq
->
list
);
kfree
(
irq
);
}
spic_dev
.
cur_ioport
=
NULL
;
spic_dev
.
cur_irq
=
NULL
;
dprintk
(
SONY_PIC_DRIVER_NAME
" removed.
\n
"
);
return
0
;
}
static
int
sony_pic_add
(
struct
acpi_device
*
device
)
{
int
result
;
struct
sony_pic_ioport
*
io
,
*
tmp_io
;
struct
sony_pic_irq
*
irq
,
*
tmp_irq
;
printk
(
KERN_INFO
DRV_PFX
"%s v%s.
\n
"
,
SONY_PIC_DRIVER_NAME
,
SONY_LAPTOP_DRIVER_VERSION
);
spic_dev
.
acpi_dev
=
device
;
strcpy
(
acpi_device_class
(
device
),
"sony/hotkey"
);
spic_dev
.
model
=
sony_pic_detect_device_type
();
mutex_init
(
&
spic_dev
.
lock
);
/* read _PRS resources */
result
=
sony_pic_possible_resources
(
device
);
if
(
result
)
{
printk
(
KERN_ERR
DRV_PFX
"Unabe to read possible resources.
\n
"
);
goto
err_free_resources
;
}
/* setup input devices and helper fifo */
result
=
sony_laptop_setup_input
();
if
(
result
)
{
printk
(
KERN_ERR
DRV_PFX
"Unabe to create input devices.
\n
"
);
goto
err_free_resources
;
}
/* request io port */
list_for_each_entry
(
io
,
&
spic_dev
.
ioports
,
list
)
{
if
(
request_region
(
io
->
io
.
minimum
,
io
->
io
.
address_length
,
"Sony Programable I/O Device"
))
{
dprintk
(
"I/O port: 0x%.4x (0x%.4x) + 0x%.2x
\n
"
,
io
->
io
.
minimum
,
io
->
io
.
maximum
,
io
->
io
.
address_length
);
spic_dev
.
cur_ioport
=
io
;
break
;
}
}
if
(
!
spic_dev
.
cur_ioport
)
{
printk
(
KERN_ERR
DRV_PFX
"Failed to request_region.
\n
"
);
result
=
-
ENODEV
;
goto
err_remove_input
;
}
/* request IRQ */
list_for_each_entry
(
irq
,
&
spic_dev
.
interrupts
,
list
)
{
if
(
!
request_irq
(
irq
->
irq
.
interrupts
[
0
],
sony_pic_irq
,
IRQF_SHARED
,
"sony-laptop"
,
&
spic_dev
))
{
dprintk
(
"IRQ: %d - triggering: %d - "
"polarity: %d - shr: %d
\n
"
,
irq
->
irq
.
interrupts
[
0
],
irq
->
irq
.
triggering
,
irq
->
irq
.
polarity
,
irq
->
irq
.
sharable
);
spic_dev
.
cur_irq
=
irq
;
break
;
}
}
if
(
!
spic_dev
.
cur_irq
)
{
printk
(
KERN_ERR
DRV_PFX
"Failed to request_irq.
\n
"
);
result
=
-
ENODEV
;
goto
err_release_region
;
}
/* set resource status _SRS */
result
=
sony_pic_enable
(
device
,
spic_dev
.
cur_ioport
,
spic_dev
.
cur_irq
);
if
(
result
)
{
printk
(
KERN_ERR
DRV_PFX
"Couldn't enable device.
\n
"
);
goto
err_free_irq
;
}
spic_dev
.
bluetooth_power
=
-
1
;
/* create device attributes */
result
=
sony_pf_add
();
if
(
result
)
goto
err_disable_device
;
result
=
sysfs_create_group
(
&
sony_pf_device
->
dev
.
kobj
,
&
spic_attribute_group
);
if
(
result
)
goto
err_remove_pf
;
if
(
sonypi_compat_init
())
goto
err_remove_pf
;
return
0
;
err_remove_pf:
sony_pf_remove
();
err_disable_device:
sony_pic_disable
(
device
);
err_free_irq:
free_irq
(
spic_dev
.
cur_irq
->
irq
.
interrupts
[
0
],
&
spic_dev
);
err_release_region:
release_region
(
spic_dev
.
cur_ioport
->
io
.
minimum
,
spic_dev
.
cur_ioport
->
io
.
address_length
);
err_remove_input:
sony_laptop_remove_input
();
err_free_resources:
list_for_each_entry_safe
(
io
,
tmp_io
,
&
spic_dev
.
ioports
,
list
)
{
list_del
(
&
io
->
list
);
kfree
(
io
);
}
list_for_each_entry_safe
(
irq
,
tmp_irq
,
&
spic_dev
.
interrupts
,
list
)
{
list_del
(
&
irq
->
list
);
kfree
(
irq
);
}
spic_dev
.
cur_ioport
=
NULL
;
spic_dev
.
cur_irq
=
NULL
;
return
result
;
}
static
int
sony_pic_suspend
(
struct
acpi_device
*
device
,
pm_message_t
state
)
{
if
(
sony_pic_disable
(
device
))
return
-
ENXIO
;
return
0
;
}
static
int
sony_pic_resume
(
struct
acpi_device
*
device
)
{
sony_pic_enable
(
device
,
spic_dev
.
cur_ioport
,
spic_dev
.
cur_irq
);
return
0
;
}
static
struct
acpi_driver
sony_pic_driver
=
{
.
name
=
SONY_PIC_DRIVER_NAME
,
.
class
=
SONY_PIC_CLASS
,
.
ids
=
SONY_PIC_HID
,
.
owner
=
THIS_MODULE
,
.
ops
=
{
.
add
=
sony_pic_add
,
.
remove
=
sony_pic_remove
,
.
suspend
=
sony_pic_suspend
,
.
resume
=
sony_pic_resume
,
},
};
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
sony_laptop_init
(
void
)
{
int
result
;
if
(
!
no_spic
&&
dmi_check_system
(
sonypi_dmi_table
))
{
result
=
acpi_bus_register_driver
(
&
sony_pic_driver
);
if
(
result
)
{
printk
(
KERN_ERR
DRV_PFX
"Unable to register SPIC driver."
);
goto
out
;
}
}
result
=
acpi_bus_register_driver
(
&
sony_nc_driver
);
if
(
result
)
{
printk
(
KERN_ERR
DRV_PFX
"Unable to register SNC driver."
);
goto
out_unregister_pic
;
}
return
0
;
out_unregister_pic:
if
(
!
no_spic
)
acpi_bus_unregister_driver
(
&
sony_pic_driver
);
out:
return
result
;
}
}
static
void
__exit
sony_
acpi
_exit
(
void
)
static
void
__exit
sony_
laptop
_exit
(
void
)
{
{
acpi_bus_unregister_driver
(
&
sony_acpi_driver
);
acpi_bus_unregister_driver
(
&
sony_nc_driver
);
if
(
!
no_spic
)
acpi_bus_unregister_driver
(
&
sony_pic_driver
);
}
}
module_init
(
sony_
acpi
_init
);
module_init
(
sony_
laptop
_init
);
module_exit
(
sony_
acpi
_exit
);
module_exit
(
sony_
laptop
_exit
);
include/linux/sony-laptop.h
0 → 100644
View file @
cfaae3ee
#ifndef _SONYLAPTOP_H_
#define _SONYLAPTOP_H_
#include <linux/types.h>
#ifdef __KERNEL__
/* used only for communication between v4l and sony-laptop */
#define SONY_PIC_COMMAND_GETCAMERA 1
/* obsolete */
#define SONY_PIC_COMMAND_SETCAMERA 2
#define SONY_PIC_COMMAND_GETCAMERABRIGHTNESS 3
/* obsolete */
#define SONY_PIC_COMMAND_SETCAMERABRIGHTNESS 4
#define SONY_PIC_COMMAND_GETCAMERACONTRAST 5
/* obsolete */
#define SONY_PIC_COMMAND_SETCAMERACONTRAST 6
#define SONY_PIC_COMMAND_GETCAMERAHUE 7
/* obsolete */
#define SONY_PIC_COMMAND_SETCAMERAHUE 8
#define SONY_PIC_COMMAND_GETCAMERACOLOR 9
/* obsolete */
#define SONY_PIC_COMMAND_SETCAMERACOLOR 10
#define SONY_PIC_COMMAND_GETCAMERASHARPNESS 11
/* obsolete */
#define SONY_PIC_COMMAND_SETCAMERASHARPNESS 12
#define SONY_PIC_COMMAND_GETCAMERAPICTURE 13
/* obsolete */
#define SONY_PIC_COMMAND_SETCAMERAPICTURE 14
#define SONY_PIC_COMMAND_GETCAMERAAGC 15
/* obsolete */
#define SONY_PIC_COMMAND_SETCAMERAAGC 16
#define SONY_PIC_COMMAND_GETCAMERADIRECTION 17
/* obsolete */
#define SONY_PIC_COMMAND_GETCAMERAROMVERSION 18
/* obsolete */
#define SONY_PIC_COMMAND_GETCAMERAREVISION 19
/* obsolete */
int
sony_pic_camera_command
(
int
command
,
u8
value
);
#endif
/* __KERNEL__ */
#endif
/* _SONYLAPTOP_H_ */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment