2005-04-17 02:20:36 +04:00
/*
* video . c - ACPI Video Driver ( $ Revision : $ )
*
* Copyright ( C ) 2004 Luming Yu < luming . yu @ intel . com >
* Copyright ( C ) 2004 Bruno Ducrot < ducrot @ poupinou . org >
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or ( at
* your option ) any later version .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA .
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/types.h>
# include <linux/list.h>
# include <linux/proc_fs.h>
# include <linux/seq_file.h>
# include <asm/uaccess.h>
# include <acpi/acpi_bus.h>
# include <acpi/acpi_drivers.h>
# define ACPI_VIDEO_COMPONENT 0x08000000
# define ACPI_VIDEO_CLASS "video"
# define ACPI_VIDEO_DRIVER_NAME "ACPI Video Driver"
# define ACPI_VIDEO_BUS_NAME "Video Bus"
# define ACPI_VIDEO_DEVICE_NAME "Video Device"
# define ACPI_VIDEO_NOTIFY_SWITCH 0x80
# define ACPI_VIDEO_NOTIFY_PROBE 0x81
# define ACPI_VIDEO_NOTIFY_CYCLE 0x82
# define ACPI_VIDEO_NOTIFY_NEXT_OUTPUT 0x83
# define ACPI_VIDEO_NOTIFY_PREV_OUTPUT 0x84
# define ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS 0x82
# define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x83
# define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x84
# define ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS 0x85
# define ACPI_VIDEO_NOTIFY_DISPLAY_OFF 0x86
# define ACPI_VIDEO_HEAD_INVALID (~0u - 1)
# define ACPI_VIDEO_HEAD_END (~0u)
# define _COMPONENT ACPI_VIDEO_COMPONENT
2005-08-05 08:44:28 +04:00
ACPI_MODULE_NAME ( " acpi_video " )
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
MODULE_AUTHOR ( " Bruno Ducrot " ) ;
2005-04-17 02:20:36 +04:00
MODULE_DESCRIPTION ( ACPI_VIDEO_DRIVER_NAME ) ;
MODULE_LICENSE ( " GPL " ) ;
2005-08-05 08:44:28 +04:00
static int acpi_video_bus_add ( struct acpi_device * device ) ;
static int acpi_video_bus_remove ( struct acpi_device * device , int type ) ;
static int acpi_video_bus_match ( struct acpi_device * device ,
struct acpi_driver * driver ) ;
2005-04-17 02:20:36 +04:00
static struct acpi_driver acpi_video_bus = {
. name = ACPI_VIDEO_DRIVER_NAME ,
. class = ACPI_VIDEO_CLASS ,
. ops = {
. add = acpi_video_bus_add ,
. remove = acpi_video_bus_remove ,
. match = acpi_video_bus_match ,
2005-08-05 08:44:28 +04:00
} ,
2005-04-17 02:20:36 +04:00
} ;
struct acpi_video_bus_flags {
2005-08-05 08:44:28 +04:00
u8 multihead : 1 ; /* can switch video heads */
u8 rom : 1 ; /* can retrieve a video rom */
u8 post : 1 ; /* can configure the head to */
u8 reserved : 5 ;
2005-04-17 02:20:36 +04:00
} ;
struct acpi_video_bus_cap {
2005-08-05 08:44:28 +04:00
u8 _DOS : 1 ; /*Enable/Disable output switching */
u8 _DOD : 1 ; /*Enumerate all devices attached to display adapter */
u8 _ROM : 1 ; /*Get ROM Data */
u8 _GPD : 1 ; /*Get POST Device */
u8 _SPD : 1 ; /*Set POST Device */
u8 _VPO : 1 ; /*Video POST Options */
u8 reserved : 2 ;
2005-04-17 02:20:36 +04:00
} ;
2005-08-05 08:44:28 +04:00
struct acpi_video_device_attrib {
u32 display_index : 4 ; /* A zero-based instance of the Display */
u32 display_port_attachment : 4 ; /*This field differenates displays type */
u32 display_type : 4 ; /*Describe the specific type in use */
u32 vendor_specific : 4 ; /*Chipset Vendor Specifi */
u32 bios_can_detect : 1 ; /*BIOS can detect the device */
u32 depend_on_vga : 1 ; /*Non-VGA output device whose power is related to
the VGA device . */
u32 pipe_id : 3 ; /*For VGA multiple-head devices. */
u32 reserved : 10 ; /*Must be 0 */
u32 device_id_scheme : 1 ; /*Device ID Scheme */
2005-04-17 02:20:36 +04:00
} ;
struct acpi_video_enumerated_device {
union {
u32 int_val ;
2005-08-05 08:44:28 +04:00
struct acpi_video_device_attrib attrib ;
2005-04-17 02:20:36 +04:00
} value ;
struct acpi_video_device * bind_info ;
} ;
struct acpi_video_bus {
2005-08-05 08:44:28 +04:00
acpi_handle handle ;
2006-05-20 00:54:40 +04:00
struct acpi_device * device ;
2005-08-05 08:44:28 +04:00
u8 dos_setting ;
2005-04-17 02:20:36 +04:00
struct acpi_video_enumerated_device * attached_array ;
2005-08-05 08:44:28 +04:00
u8 attached_count ;
struct acpi_video_bus_cap cap ;
2005-04-17 02:20:36 +04:00
struct acpi_video_bus_flags flags ;
2005-08-05 08:44:28 +04:00
struct semaphore sem ;
struct list_head video_device_list ;
struct proc_dir_entry * dir ;
2005-04-17 02:20:36 +04:00
} ;
struct acpi_video_device_flags {
2005-08-05 08:44:28 +04:00
u8 crt : 1 ;
u8 lcd : 1 ;
u8 tvout : 1 ;
u8 bios : 1 ;
u8 unknown : 1 ;
u8 reserved : 3 ;
2005-04-17 02:20:36 +04:00
} ;
struct acpi_video_device_cap {
2005-08-05 08:44:28 +04:00
u8 _ADR : 1 ; /*Return the unique ID */
u8 _BCL : 1 ; /*Query list of brightness control levels supported */
u8 _BCM : 1 ; /*Set the brightness level */
u8 _DDC : 1 ; /*Return the EDID for this device */
u8 _DCS : 1 ; /*Return status of output device */
u8 _DGS : 1 ; /*Query graphics state */
u8 _DSS : 1 ; /*Device state set */
u8 _reserved : 1 ;
2005-04-17 02:20:36 +04:00
} ;
struct acpi_video_device_brightness {
2005-08-05 08:44:28 +04:00
int curr ;
int count ;
int * levels ;
2005-04-17 02:20:36 +04:00
} ;
struct acpi_video_device {
2005-08-05 08:44:28 +04:00
acpi_handle handle ;
unsigned long device_id ;
struct acpi_video_device_flags flags ;
struct acpi_video_device_cap cap ;
struct list_head entry ;
struct acpi_video_bus * video ;
struct acpi_device * dev ;
2005-04-17 02:20:36 +04:00
struct acpi_video_device_brightness * brightness ;
} ;
/* bus */
static int acpi_video_bus_info_open_fs ( struct inode * inode , struct file * file ) ;
static struct file_operations acpi_video_bus_info_fops = {
2005-08-05 08:44:28 +04:00
. open = acpi_video_bus_info_open_fs ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
2005-04-17 02:20:36 +04:00
} ;
static int acpi_video_bus_ROM_open_fs ( struct inode * inode , struct file * file ) ;
static struct file_operations acpi_video_bus_ROM_fops = {
2005-08-05 08:44:28 +04:00
. open = acpi_video_bus_ROM_open_fs ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
2005-04-17 02:20:36 +04:00
} ;
2005-08-05 08:44:28 +04:00
static int acpi_video_bus_POST_info_open_fs ( struct inode * inode ,
struct file * file ) ;
2005-04-17 02:20:36 +04:00
static struct file_operations acpi_video_bus_POST_info_fops = {
2005-08-05 08:44:28 +04:00
. open = acpi_video_bus_POST_info_open_fs ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
2005-04-17 02:20:36 +04:00
} ;
static int acpi_video_bus_POST_open_fs ( struct inode * inode , struct file * file ) ;
static struct file_operations acpi_video_bus_POST_fops = {
2005-08-05 08:44:28 +04:00
. open = acpi_video_bus_POST_open_fs ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
2005-04-17 02:20:36 +04:00
} ;
static int acpi_video_bus_DOS_open_fs ( struct inode * inode , struct file * file ) ;
static struct file_operations acpi_video_bus_DOS_fops = {
2005-08-05 08:44:28 +04:00
. open = acpi_video_bus_DOS_open_fs ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
2005-04-17 02:20:36 +04:00
} ;
/* device */
2005-08-05 08:44:28 +04:00
static int acpi_video_device_info_open_fs ( struct inode * inode ,
struct file * file ) ;
2005-04-17 02:20:36 +04:00
static struct file_operations acpi_video_device_info_fops = {
2005-08-05 08:44:28 +04:00
. open = acpi_video_device_info_open_fs ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
2005-04-17 02:20:36 +04:00
} ;
2005-08-05 08:44:28 +04:00
static int acpi_video_device_state_open_fs ( struct inode * inode ,
struct file * file ) ;
2005-04-17 02:20:36 +04:00
static struct file_operations acpi_video_device_state_fops = {
2005-08-05 08:44:28 +04:00
. open = acpi_video_device_state_open_fs ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
2005-04-17 02:20:36 +04:00
} ;
2005-08-05 08:44:28 +04:00
static int acpi_video_device_brightness_open_fs ( struct inode * inode ,
struct file * file ) ;
2005-04-17 02:20:36 +04:00
static struct file_operations acpi_video_device_brightness_fops = {
2005-08-05 08:44:28 +04:00
. open = acpi_video_device_brightness_open_fs ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
2005-04-17 02:20:36 +04:00
} ;
2005-08-05 08:44:28 +04:00
static int acpi_video_device_EDID_open_fs ( struct inode * inode ,
struct file * file ) ;
2005-04-17 02:20:36 +04:00
static struct file_operations acpi_video_device_EDID_fops = {
2005-08-05 08:44:28 +04:00
. open = acpi_video_device_EDID_open_fs ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
2005-04-17 02:20:36 +04:00
} ;
2005-08-05 08:44:28 +04:00
static char device_decode [ ] [ 30 ] = {
2005-04-17 02:20:36 +04:00
" motherboard VGA device " ,
" PCI VGA device " ,
" AGP VGA device " ,
" UNKNOWN " ,
} ;
2005-08-05 08:44:28 +04:00
static void acpi_video_device_notify ( acpi_handle handle , u32 event , void * data ) ;
static void acpi_video_device_rebind ( struct acpi_video_bus * video ) ;
static void acpi_video_device_bind ( struct acpi_video_bus * video ,
struct acpi_video_device * device ) ;
2005-04-17 02:20:36 +04:00
static int acpi_video_device_enumerate ( struct acpi_video_bus * video ) ;
2005-08-05 08:44:28 +04:00
static int acpi_video_switch_output ( struct acpi_video_bus * video , int event ) ;
static int acpi_video_get_next_level ( struct acpi_video_device * device ,
u32 level_current , u32 event ) ;
static void acpi_video_switch_brightness ( struct acpi_video_device * device ,
int event ) ;
2005-04-17 02:20:36 +04:00
/* --------------------------------------------------------------------------
Video Management
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* device */
static int
2005-08-05 08:44:28 +04:00
acpi_video_device_query ( struct acpi_video_device * device , unsigned long * state )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int status ;
2005-04-17 02:20:36 +04:00
status = acpi_evaluate_integer ( device - > handle , " _DGS " , NULL , state ) ;
2006-06-27 08:41:40 +04:00
return status ;
2005-04-17 02:20:36 +04:00
}
static int
2005-08-05 08:44:28 +04:00
acpi_video_device_get_state ( struct acpi_video_device * device ,
unsigned long * state )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int status ;
2005-04-17 02:20:36 +04:00
status = acpi_evaluate_integer ( device - > handle , " _DCS " , NULL , state ) ;
2006-06-27 08:41:40 +04:00
return status ;
2005-04-17 02:20:36 +04:00
}
static int
2005-08-05 08:44:28 +04:00
acpi_video_device_set_state ( struct acpi_video_device * device , int state )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int status ;
union acpi_object arg0 = { ACPI_TYPE_INTEGER } ;
struct acpi_object_list args = { 1 , & arg0 } ;
2005-08-22 03:17:00 +04:00
unsigned long ret ;
2005-04-17 02:20:36 +04:00
arg0 . integer . value = state ;
2005-08-22 03:17:00 +04:00
status = acpi_evaluate_integer ( device - > handle , " _DSS " , & args , & ret ) ;
2005-04-17 02:20:36 +04:00
2006-06-27 08:41:40 +04:00
return status ;
2005-04-17 02:20:36 +04:00
}
static int
2005-08-05 08:44:28 +04:00
acpi_video_device_lcd_query_levels ( struct acpi_video_device * device ,
union acpi_object * * levels )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int status ;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER , NULL } ;
union acpi_object * obj ;
2005-04-17 02:20:36 +04:00
* levels = NULL ;
status = acpi_evaluate_object ( device - > handle , " _BCL " , NULL , & buffer ) ;
if ( ! ACPI_SUCCESS ( status ) )
2006-06-27 08:41:40 +04:00
return status ;
2005-08-05 08:44:28 +04:00
obj = ( union acpi_object * ) buffer . pointer ;
2006-03-11 18:12:00 +03:00
if ( ! obj | | ( obj - > type ! = ACPI_TYPE_PACKAGE ) ) {
2006-06-27 07:41:38 +04:00
printk ( KERN_ERR PREFIX " Invalid _BCL data \n " ) ;
2005-04-17 02:20:36 +04:00
status = - EFAULT ;
goto err ;
}
* levels = obj ;
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
err :
2005-11-07 12:01:32 +03:00
kfree ( buffer . pointer ) ;
2005-04-17 02:20:36 +04:00
2006-06-27 08:41:40 +04:00
return status ;
2005-04-17 02:20:36 +04:00
}
static int
2005-08-05 08:44:28 +04:00
acpi_video_device_lcd_set_level ( struct acpi_video_device * device , int level )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int status ;
union acpi_object arg0 = { ACPI_TYPE_INTEGER } ;
struct acpi_object_list args = { 1 , & arg0 } ;
2005-04-17 02:20:36 +04:00
arg0 . integer . value = level ;
status = acpi_evaluate_object ( device - > handle , " _BCM " , & args , NULL ) ;
printk ( KERN_DEBUG " set_level status: %x \n " , status ) ;
2006-06-27 08:41:40 +04:00
return status ;
2005-04-17 02:20:36 +04:00
}
static int
2005-08-05 08:44:28 +04:00
acpi_video_device_lcd_get_level_current ( struct acpi_video_device * device ,
unsigned long * level )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int status ;
2005-04-17 02:20:36 +04:00
status = acpi_evaluate_integer ( device - > handle , " _BQC " , NULL , level ) ;
2006-06-27 08:41:40 +04:00
return status ;
2005-04-17 02:20:36 +04:00
}
static int
2005-08-05 08:44:28 +04:00
acpi_video_device_EDID ( struct acpi_video_device * device ,
union acpi_object * * edid , ssize_t length )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int status ;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER , NULL } ;
union acpi_object * obj ;
union acpi_object arg0 = { ACPI_TYPE_INTEGER } ;
struct acpi_object_list args = { 1 , & arg0 } ;
2005-04-17 02:20:36 +04:00
* edid = NULL ;
if ( ! device )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
if ( length = = 128 )
arg0 . integer . value = 1 ;
else if ( length = = 256 )
arg0 . integer . value = 2 ;
else
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
status = acpi_evaluate_object ( device - > handle , " _DDC " , & args , & buffer ) ;
if ( ACPI_FAILURE ( status ) )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
obj = ( union acpi_object * ) buffer . pointer ;
2005-04-17 02:20:36 +04:00
if ( obj & & obj - > type = = ACPI_TYPE_BUFFER )
* edid = obj ;
else {
2006-06-27 07:41:38 +04:00
printk ( KERN_ERR PREFIX " Invalid _DDC data \n " ) ;
2005-04-17 02:20:36 +04:00
status = - EFAULT ;
kfree ( obj ) ;
}
2006-06-27 08:41:40 +04:00
return status ;
2005-04-17 02:20:36 +04:00
}
/* bus */
static int
2005-08-05 08:44:28 +04:00
acpi_video_bus_set_POST ( struct acpi_video_bus * video , unsigned long option )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int status ;
unsigned long tmp ;
union acpi_object arg0 = { ACPI_TYPE_INTEGER } ;
struct acpi_object_list args = { 1 , & arg0 } ;
2005-04-17 02:20:36 +04:00
arg0 . integer . value = option ;
status = acpi_evaluate_integer ( video - > handle , " _SPD " , & args , & tmp ) ;
if ( ACPI_SUCCESS ( status ) )
2005-08-05 08:44:28 +04:00
status = tmp ? ( - EINVAL ) : ( AE_OK ) ;
2005-04-17 02:20:36 +04:00
2006-06-27 08:41:40 +04:00
return status ;
2005-04-17 02:20:36 +04:00
}
static int
2005-08-05 08:44:28 +04:00
acpi_video_bus_get_POST ( struct acpi_video_bus * video , unsigned long * id )
2005-04-17 02:20:36 +04:00
{
int status ;
status = acpi_evaluate_integer ( video - > handle , " _GPD " , NULL , id ) ;
2006-06-27 08:41:40 +04:00
return status ;
2005-04-17 02:20:36 +04:00
}
static int
2005-08-05 08:44:28 +04:00
acpi_video_bus_POST_options ( struct acpi_video_bus * video ,
unsigned long * options )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int status ;
2005-04-17 02:20:36 +04:00
status = acpi_evaluate_integer ( video - > handle , " _VPO " , NULL , options ) ;
* options & = 3 ;
2006-06-27 08:41:40 +04:00
return status ;
2005-04-17 02:20:36 +04:00
}
/*
* Arg :
* video : video bus device pointer
* bios_flag :
* 0. The system BIOS should NOT automatically switch ( toggle )
* the active display output .
* 1. The system BIOS should automatically switch ( toggle ) the
* active display output . No swich event .
* 2. The _DGS value should be locked .
* 3. The system BIOS should not automatically switch ( toggle ) the
* active display output , but instead generate the display switch
* event notify code .
* lcd_flag :
* 0. The system BIOS should automatically control the brightness level
* of the LCD , when the power changes from AC to DC
* 1. The system BIOS should NOT automatically control the brightness
* level of the LCD , when the power changes from AC to DC .
* Return Value :
* - 1 wrong arg .
*/
static int
2005-08-05 08:44:28 +04:00
acpi_video_bus_DOS ( struct acpi_video_bus * video , int bios_flag , int lcd_flag )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
acpi_integer status = 0 ;
union acpi_object arg0 = { ACPI_TYPE_INTEGER } ;
struct acpi_object_list args = { 1 , & arg0 } ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
if ( bios_flag < 0 | | bios_flag > 3 | | lcd_flag < 0 | | lcd_flag > 1 ) {
2005-04-17 02:20:36 +04:00
status = - 1 ;
goto Failed ;
}
arg0 . integer . value = ( lcd_flag < < 2 ) | bios_flag ;
video - > dos_setting = arg0 . integer . value ;
acpi_evaluate_object ( video - > handle , " _DOS " , & args , NULL ) ;
2005-08-05 08:44:28 +04:00
Failed :
2006-06-27 08:41:40 +04:00
return status ;
2005-04-17 02:20:36 +04:00
}
/*
* Arg :
* device : video output device ( LCD , CRT , . . )
*
* Return Value :
* None
*
* Find out all required AML method defined under the output
* device .
*/
2005-08-05 08:44:28 +04:00
static void acpi_video_device_find_cap ( struct acpi_video_device * device )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
acpi_integer status ;
2005-04-17 02:20:36 +04:00
acpi_handle h_dummy1 ;
int i ;
union acpi_object * obj = NULL ;
struct acpi_video_device_brightness * br = NULL ;
2005-08-05 08:44:28 +04:00
memset ( & device - > cap , 0 , 4 ) ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
if ( ACPI_SUCCESS ( acpi_get_handle ( device - > handle , " _ADR " , & h_dummy1 ) ) ) {
2005-04-17 02:20:36 +04:00
device - > cap . _ADR = 1 ;
}
2005-08-05 08:44:28 +04:00
if ( ACPI_SUCCESS ( acpi_get_handle ( device - > handle , " _BCL " , & h_dummy1 ) ) ) {
device - > cap . _BCL = 1 ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
if ( ACPI_SUCCESS ( acpi_get_handle ( device - > handle , " _BCM " , & h_dummy1 ) ) ) {
device - > cap . _BCM = 1 ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
if ( ACPI_SUCCESS ( acpi_get_handle ( device - > handle , " _DDC " , & h_dummy1 ) ) ) {
device - > cap . _DDC = 1 ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
if ( ACPI_SUCCESS ( acpi_get_handle ( device - > handle , " _DCS " , & h_dummy1 ) ) ) {
2005-04-17 02:20:36 +04:00
device - > cap . _DCS = 1 ;
}
2005-08-05 08:44:28 +04:00
if ( ACPI_SUCCESS ( acpi_get_handle ( device - > handle , " _DGS " , & h_dummy1 ) ) ) {
2005-04-17 02:20:36 +04:00
device - > cap . _DGS = 1 ;
}
2005-08-05 08:44:28 +04:00
if ( ACPI_SUCCESS ( acpi_get_handle ( device - > handle , " _DSS " , & h_dummy1 ) ) ) {
2005-04-17 02:20:36 +04:00
device - > cap . _DSS = 1 ;
}
status = acpi_video_device_lcd_query_levels ( device , & obj ) ;
if ( obj & & obj - > type = = ACPI_TYPE_PACKAGE & & obj - > package . count > = 2 ) {
int count = 0 ;
union acpi_object * o ;
2005-08-05 08:44:28 +04:00
2005-03-31 07:39:49 +04:00
br = kmalloc ( sizeof ( * br ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! br ) {
printk ( KERN_ERR " can't allocate memory \n " ) ;
} else {
2005-03-31 07:39:49 +04:00
memset ( br , 0 , sizeof ( * br ) ) ;
br - > levels = kmalloc ( obj - > package . count *
2005-08-05 08:44:28 +04:00
sizeof * ( br - > levels ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! br - > levels )
goto out ;
for ( i = 0 ; i < obj - > package . count ; i + + ) {
2005-08-05 08:44:28 +04:00
o = ( union acpi_object * ) & obj - > package .
elements [ i ] ;
2005-04-17 02:20:36 +04:00
if ( o - > type ! = ACPI_TYPE_INTEGER ) {
2006-06-27 07:41:38 +04:00
printk ( KERN_ERR PREFIX " Invalid data \n " ) ;
2005-04-17 02:20:36 +04:00
continue ;
}
br - > levels [ count ] = ( u32 ) o - > integer . value ;
count + + ;
}
2005-08-05 08:44:28 +04:00
out :
2005-04-17 02:20:36 +04:00
if ( count < 2 ) {
2005-03-31 07:39:49 +04:00
kfree ( br - > levels ) ;
2005-04-17 02:20:36 +04:00
kfree ( br ) ;
} else {
br - > count = count ;
device - > brightness = br ;
2005-08-05 08:44:28 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
" found %d brightness levels \n " ,
count ) ) ;
2005-04-17 02:20:36 +04:00
}
}
}
2005-03-31 07:39:49 +04:00
kfree ( obj ) ;
2005-04-17 02:20:36 +04:00
2006-06-27 08:41:40 +04:00
return ;
2005-04-17 02:20:36 +04:00
}
/*
* Arg :
* device : video output device ( VGA )
*
* Return Value :
* None
*
* Find out all required AML method defined under the video bus device .
*/
2005-08-05 08:44:28 +04:00
static void acpi_video_bus_find_cap ( struct acpi_video_bus * video )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
acpi_handle h_dummy1 ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
memset ( & video - > cap , 0 , 4 ) ;
if ( ACPI_SUCCESS ( acpi_get_handle ( video - > handle , " _DOS " , & h_dummy1 ) ) ) {
2005-04-17 02:20:36 +04:00
video - > cap . _DOS = 1 ;
}
2005-08-05 08:44:28 +04:00
if ( ACPI_SUCCESS ( acpi_get_handle ( video - > handle , " _DOD " , & h_dummy1 ) ) ) {
2005-04-17 02:20:36 +04:00
video - > cap . _DOD = 1 ;
}
2005-08-05 08:44:28 +04:00
if ( ACPI_SUCCESS ( acpi_get_handle ( video - > handle , " _ROM " , & h_dummy1 ) ) ) {
2005-04-17 02:20:36 +04:00
video - > cap . _ROM = 1 ;
}
2005-08-05 08:44:28 +04:00
if ( ACPI_SUCCESS ( acpi_get_handle ( video - > handle , " _GPD " , & h_dummy1 ) ) ) {
2005-04-17 02:20:36 +04:00
video - > cap . _GPD = 1 ;
}
2005-08-05 08:44:28 +04:00
if ( ACPI_SUCCESS ( acpi_get_handle ( video - > handle , " _SPD " , & h_dummy1 ) ) ) {
2005-04-17 02:20:36 +04:00
video - > cap . _SPD = 1 ;
}
2005-08-05 08:44:28 +04:00
if ( ACPI_SUCCESS ( acpi_get_handle ( video - > handle , " _VPO " , & h_dummy1 ) ) ) {
2005-04-17 02:20:36 +04:00
video - > cap . _VPO = 1 ;
}
}
/*
* Check whether the video bus device has required AML method to
* support the desired features
*/
2005-08-05 08:44:28 +04:00
static int acpi_video_bus_check ( struct acpi_video_bus * video )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
acpi_status status = - ENOENT ;
2005-04-17 02:20:36 +04:00
if ( ! video )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
/* Since there is no HID, CID and so on for VGA driver, we have
* to check well known required nodes .
*/
/* Does this device able to support video switching ? */
2005-08-05 08:44:28 +04:00
if ( video - > cap . _DOS ) {
2005-04-17 02:20:36 +04:00
video - > flags . multihead = 1 ;
status = 0 ;
}
/* Does this device able to retrieve a retrieve a video ROM ? */
2005-08-05 08:44:28 +04:00
if ( video - > cap . _ROM ) {
2005-04-17 02:20:36 +04:00
video - > flags . rom = 1 ;
status = 0 ;
}
/* Does this device able to configure which video device to POST ? */
2005-08-05 08:44:28 +04:00
if ( video - > cap . _GPD & & video - > cap . _SPD & & video - > cap . _VPO ) {
2005-04-17 02:20:36 +04:00
video - > flags . post = 1 ;
status = 0 ;
}
2006-06-27 08:41:40 +04:00
return status ;
2005-04-17 02:20:36 +04:00
}
/* --------------------------------------------------------------------------
FS Interface ( / proc )
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2005-08-05 08:44:28 +04:00
static struct proc_dir_entry * acpi_video_dir ;
2005-04-17 02:20:36 +04:00
/* video devices */
2005-08-05 08:44:28 +04:00
static int acpi_video_device_info_seq_show ( struct seq_file * seq , void * offset )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct acpi_video_device * dev =
( struct acpi_video_device * ) seq - > private ;
2005-04-17 02:20:36 +04:00
if ( ! dev )
goto end ;
seq_printf ( seq , " device_id: 0x%04x \n " , ( u32 ) dev - > device_id ) ;
seq_printf ( seq , " type: " ) ;
if ( dev - > flags . crt )
seq_printf ( seq , " CRT \n " ) ;
else if ( dev - > flags . lcd )
seq_printf ( seq , " LCD \n " ) ;
else if ( dev - > flags . tvout )
seq_printf ( seq , " TVOUT \n " ) ;
else
seq_printf ( seq , " UNKNOWN \n " ) ;
2005-08-05 08:44:28 +04:00
seq_printf ( seq , " known by bios: %s \n " , dev - > flags . bios ? " yes " : " no " ) ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
end :
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
static int
2005-08-05 08:44:28 +04:00
acpi_video_device_info_open_fs ( struct inode * inode , struct file * file )
2005-04-17 02:20:36 +04:00
{
return single_open ( file , acpi_video_device_info_seq_show ,
PDE ( inode ) - > data ) ;
}
2005-08-05 08:44:28 +04:00
static int acpi_video_device_state_seq_show ( struct seq_file * seq , void * offset )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int status ;
struct acpi_video_device * dev =
( struct acpi_video_device * ) seq - > private ;
unsigned long state ;
2005-04-17 02:20:36 +04:00
if ( ! dev )
goto end ;
status = acpi_video_device_get_state ( dev , & state ) ;
seq_printf ( seq , " state: " ) ;
if ( ACPI_SUCCESS ( status ) )
seq_printf ( seq , " 0x%02lx \n " , state ) ;
else
seq_printf ( seq , " <not supported> \n " ) ;
status = acpi_video_device_query ( dev , & state ) ;
seq_printf ( seq , " query: " ) ;
if ( ACPI_SUCCESS ( status ) )
seq_printf ( seq , " 0x%02lx \n " , state ) ;
else
seq_printf ( seq , " <not supported> \n " ) ;
2005-08-05 08:44:28 +04:00
end :
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
static int
2005-08-05 08:44:28 +04:00
acpi_video_device_state_open_fs ( struct inode * inode , struct file * file )
2005-04-17 02:20:36 +04:00
{
return single_open ( file , acpi_video_device_state_seq_show ,
PDE ( inode ) - > data ) ;
}
static ssize_t
2005-08-05 08:44:28 +04:00
acpi_video_device_write_state ( struct file * file ,
const char __user * buffer ,
size_t count , loff_t * data )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int status ;
struct seq_file * m = ( struct seq_file * ) file - > private_data ;
struct acpi_video_device * dev = ( struct acpi_video_device * ) m - > private ;
char str [ 12 ] = { 0 } ;
u32 state = 0 ;
2005-04-17 02:20:36 +04:00
if ( ! dev | | count + 1 > sizeof str )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
if ( copy_from_user ( str , buffer , count ) )
2006-06-27 08:41:40 +04:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
str [ count ] = 0 ;
state = simple_strtoul ( str , NULL , 0 ) ;
2005-08-05 08:44:28 +04:00
state & = ( ( 1ul < < 31 ) | ( 1ul < < 30 ) | ( 1ul < < 0 ) ) ;
2005-04-17 02:20:36 +04:00
status = acpi_video_device_set_state ( dev , state ) ;
if ( status )
2006-06-27 08:41:40 +04:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
2006-06-27 08:41:40 +04:00
return count ;
2005-04-17 02:20:36 +04:00
}
static int
2005-08-05 08:44:28 +04:00
acpi_video_device_brightness_seq_show ( struct seq_file * seq , void * offset )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct acpi_video_device * dev =
( struct acpi_video_device * ) seq - > private ;
int i ;
2005-04-17 02:20:36 +04:00
if ( ! dev | | ! dev - > brightness ) {
seq_printf ( seq , " <not supported> \n " ) ;
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
seq_printf ( seq , " levels: " ) ;
for ( i = 0 ; i < dev - > brightness - > count ; i + + )
seq_printf ( seq , " %d " , dev - > brightness - > levels [ i ] ) ;
seq_printf ( seq , " \n current: %d \n " , dev - > brightness - > curr ) ;
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
static int
2005-08-05 08:44:28 +04:00
acpi_video_device_brightness_open_fs ( struct inode * inode , struct file * file )
2005-04-17 02:20:36 +04:00
{
return single_open ( file , acpi_video_device_brightness_seq_show ,
PDE ( inode ) - > data ) ;
}
static ssize_t
2005-08-05 08:44:28 +04:00
acpi_video_device_write_brightness ( struct file * file ,
const char __user * buffer ,
size_t count , loff_t * data )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct seq_file * m = ( struct seq_file * ) file - > private_data ;
struct acpi_video_device * dev = ( struct acpi_video_device * ) m - > private ;
char str [ 4 ] = { 0 } ;
unsigned int level = 0 ;
int i ;
2005-04-17 02:20:36 +04:00
2005-11-08 13:27:00 +03:00
if ( ! dev | | ! dev - > brightness | | count + 1 > sizeof str )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
if ( copy_from_user ( str , buffer , count ) )
2006-06-27 08:41:40 +04:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
str [ count ] = 0 ;
level = simple_strtoul ( str , NULL , 0 ) ;
2005-08-05 08:44:28 +04:00
2005-04-17 02:20:36 +04:00
if ( level > 100 )
2006-06-27 08:41:40 +04:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
/* validate though the list of available levels */
for ( i = 0 ; i < dev - > brightness - > count ; i + + )
if ( level = = dev - > brightness - > levels [ i ] ) {
2005-08-05 08:44:28 +04:00
if ( ACPI_SUCCESS
( acpi_video_device_lcd_set_level ( dev , level ) ) )
2005-04-17 02:20:36 +04:00
dev - > brightness - > curr = level ;
break ;
}
2006-06-27 08:41:40 +04:00
return count ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static int acpi_video_device_EDID_seq_show ( struct seq_file * seq , void * offset )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct acpi_video_device * dev =
( struct acpi_video_device * ) seq - > private ;
int status ;
int i ;
union acpi_object * edid = NULL ;
2005-04-17 02:20:36 +04:00
if ( ! dev )
goto out ;
2005-08-05 08:44:28 +04:00
status = acpi_video_device_EDID ( dev , & edid , 128 ) ;
2005-04-17 02:20:36 +04:00
if ( ACPI_FAILURE ( status ) ) {
2005-08-05 08:44:28 +04:00
status = acpi_video_device_EDID ( dev , & edid , 256 ) ;
2005-04-17 02:20:36 +04:00
}
if ( ACPI_FAILURE ( status ) ) {
goto out ;
}
if ( edid & & edid - > type = = ACPI_TYPE_BUFFER ) {
for ( i = 0 ; i < edid - > buffer . length ; i + + )
seq_putc ( seq , edid - > buffer . pointer [ i ] ) ;
}
2005-08-05 08:44:28 +04:00
out :
2005-04-17 02:20:36 +04:00
if ( ! edid )
seq_printf ( seq , " <not supported> \n " ) ;
else
kfree ( edid ) ;
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
static int
2005-08-05 08:44:28 +04:00
acpi_video_device_EDID_open_fs ( struct inode * inode , struct file * file )
2005-04-17 02:20:36 +04:00
{
return single_open ( file , acpi_video_device_EDID_seq_show ,
PDE ( inode ) - > data ) ;
}
2005-08-05 08:44:28 +04:00
static int acpi_video_device_add_fs ( struct acpi_device * device )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct proc_dir_entry * entry = NULL ;
2005-04-17 02:20:36 +04:00
struct acpi_video_device * vid_dev ;
if ( ! device )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
vid_dev = ( struct acpi_video_device * ) acpi_driver_data ( device ) ;
2005-04-17 02:20:36 +04:00
if ( ! vid_dev )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
if ( ! acpi_device_dir ( device ) ) {
acpi_device_dir ( device ) = proc_mkdir ( acpi_device_bid ( device ) ,
2005-08-05 08:44:28 +04:00
vid_dev - > video - > dir ) ;
2005-04-17 02:20:36 +04:00
if ( ! acpi_device_dir ( device ) )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
acpi_device_dir ( device ) - > owner = THIS_MODULE ;
}
/* 'info' [R] */
entry = create_proc_entry ( " info " , S_IRUGO , acpi_device_dir ( device ) ) ;
if ( ! entry )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
else {
entry - > proc_fops = & acpi_video_device_info_fops ;
entry - > data = acpi_driver_data ( device ) ;
entry - > owner = THIS_MODULE ;
}
/* 'state' [R/W] */
2005-08-05 08:44:28 +04:00
entry =
create_proc_entry ( " state " , S_IFREG | S_IRUGO | S_IWUSR ,
acpi_device_dir ( device ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! entry )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
else {
2006-01-07 00:47:00 +03:00
acpi_video_device_state_fops . write = acpi_video_device_write_state ;
2005-04-17 02:20:36 +04:00
entry - > proc_fops = & acpi_video_device_state_fops ;
entry - > data = acpi_driver_data ( device ) ;
entry - > owner = THIS_MODULE ;
}
/* 'brightness' [R/W] */
2005-08-05 08:44:28 +04:00
entry =
create_proc_entry ( " brightness " , S_IFREG | S_IRUGO | S_IWUSR ,
acpi_device_dir ( device ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! entry )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
else {
2006-01-07 00:47:00 +03:00
acpi_video_device_brightness_fops . write = acpi_video_device_write_brightness ;
2005-04-17 02:20:36 +04:00
entry - > proc_fops = & acpi_video_device_brightness_fops ;
entry - > data = acpi_driver_data ( device ) ;
entry - > owner = THIS_MODULE ;
}
/* 'EDID' [R] */
entry = create_proc_entry ( " EDID " , S_IRUGO , acpi_device_dir ( device ) ) ;
if ( ! entry )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
else {
entry - > proc_fops = & acpi_video_device_EDID_fops ;
entry - > data = acpi_driver_data ( device ) ;
entry - > owner = THIS_MODULE ;
}
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static int acpi_video_device_remove_fs ( struct acpi_device * device )
2005-04-17 02:20:36 +04:00
{
struct acpi_video_device * vid_dev ;
2005-08-05 08:44:28 +04:00
vid_dev = ( struct acpi_video_device * ) acpi_driver_data ( device ) ;
2005-04-17 02:20:36 +04:00
if ( ! vid_dev | | ! vid_dev - > video | | ! vid_dev - > video - > dir )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
if ( acpi_device_dir ( device ) ) {
remove_proc_entry ( " info " , acpi_device_dir ( device ) ) ;
remove_proc_entry ( " state " , acpi_device_dir ( device ) ) ;
remove_proc_entry ( " brightness " , acpi_device_dir ( device ) ) ;
remove_proc_entry ( " EDID " , acpi_device_dir ( device ) ) ;
2005-08-05 08:44:28 +04:00
remove_proc_entry ( acpi_device_bid ( device ) , vid_dev - > video - > dir ) ;
2005-04-17 02:20:36 +04:00
acpi_device_dir ( device ) = NULL ;
}
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
/* video bus */
2005-08-05 08:44:28 +04:00
static int acpi_video_bus_info_seq_show ( struct seq_file * seq , void * offset )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct acpi_video_bus * video = ( struct acpi_video_bus * ) seq - > private ;
2005-04-17 02:20:36 +04:00
if ( ! video )
goto end ;
seq_printf ( seq , " Switching heads: %s \n " ,
2005-08-05 08:44:28 +04:00
video - > flags . multihead ? " yes " : " no " ) ;
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " Video ROM: %s \n " ,
2005-08-05 08:44:28 +04:00
video - > flags . rom ? " yes " : " no " ) ;
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " Device to be POSTed on boot: %s \n " ,
2005-08-05 08:44:28 +04:00
video - > flags . post ? " yes " : " no " ) ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
end :
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static int acpi_video_bus_info_open_fs ( struct inode * inode , struct file * file )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
return single_open ( file , acpi_video_bus_info_seq_show ,
PDE ( inode ) - > data ) ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static int acpi_video_bus_ROM_seq_show ( struct seq_file * seq , void * offset )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct acpi_video_bus * video = ( struct acpi_video_bus * ) seq - > private ;
2005-04-17 02:20:36 +04:00
if ( ! video )
goto end ;
printk ( KERN_INFO PREFIX " Please implement %s \n " , __FUNCTION__ ) ;
seq_printf ( seq , " <TODO> \n " ) ;
2005-08-05 08:44:28 +04:00
end :
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static int acpi_video_bus_ROM_open_fs ( struct inode * inode , struct file * file )
2005-04-17 02:20:36 +04:00
{
return single_open ( file , acpi_video_bus_ROM_seq_show , PDE ( inode ) - > data ) ;
}
2005-08-05 08:44:28 +04:00
static int acpi_video_bus_POST_info_seq_show ( struct seq_file * seq , void * offset )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct acpi_video_bus * video = ( struct acpi_video_bus * ) seq - > private ;
unsigned long options ;
int status ;
2005-04-17 02:20:36 +04:00
if ( ! video )
goto end ;
status = acpi_video_bus_POST_options ( video , & options ) ;
if ( ACPI_SUCCESS ( status ) ) {
if ( ! ( options & 1 ) ) {
2005-08-05 08:44:28 +04:00
printk ( KERN_WARNING PREFIX
" The motherboard VGA device is not listed as a possible POST device. \n " ) ;
printk ( KERN_WARNING PREFIX
" This indicate a BIOS bug. Please contact the manufacturer. \n " ) ;
2005-04-17 02:20:36 +04:00
}
printk ( " %lx \n " , options ) ;
seq_printf ( seq , " can POST: <intgrated video> " ) ;
if ( options & 2 )
seq_printf ( seq , " <PCI video> " ) ;
if ( options & 4 )
seq_printf ( seq , " <AGP video> " ) ;
seq_putc ( seq , ' \n ' ) ;
} else
seq_printf ( seq , " <not supported> \n " ) ;
2005-08-05 08:44:28 +04:00
end :
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
static int
2005-08-05 08:44:28 +04:00
acpi_video_bus_POST_info_open_fs ( struct inode * inode , struct file * file )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
return single_open ( file , acpi_video_bus_POST_info_seq_show ,
PDE ( inode ) - > data ) ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static int acpi_video_bus_POST_seq_show ( struct seq_file * seq , void * offset )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct acpi_video_bus * video = ( struct acpi_video_bus * ) seq - > private ;
int status ;
unsigned long id ;
2005-04-17 02:20:36 +04:00
if ( ! video )
goto end ;
2005-08-05 08:44:28 +04:00
status = acpi_video_bus_get_POST ( video , & id ) ;
2005-04-17 02:20:36 +04:00
if ( ! ACPI_SUCCESS ( status ) ) {
seq_printf ( seq , " <not supported> \n " ) ;
goto end ;
}
2005-08-05 08:44:28 +04:00
seq_printf ( seq , " device posted is <%s> \n " , device_decode [ id & 3 ] ) ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
end :
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static int acpi_video_bus_DOS_seq_show ( struct seq_file * seq , void * offset )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct acpi_video_bus * video = ( struct acpi_video_bus * ) seq - > private ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
seq_printf ( seq , " DOS setting: <%d> \n " , video - > dos_setting ) ;
2005-04-17 02:20:36 +04:00
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static int acpi_video_bus_POST_open_fs ( struct inode * inode , struct file * file )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
return single_open ( file , acpi_video_bus_POST_seq_show ,
PDE ( inode ) - > data ) ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static int acpi_video_bus_DOS_open_fs ( struct inode * inode , struct file * file )
2005-04-17 02:20:36 +04:00
{
return single_open ( file , acpi_video_bus_DOS_seq_show , PDE ( inode ) - > data ) ;
}
static ssize_t
2005-08-05 08:44:28 +04:00
acpi_video_bus_write_POST ( struct file * file ,
const char __user * buffer ,
size_t count , loff_t * data )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int status ;
struct seq_file * m = ( struct seq_file * ) file - > private_data ;
struct acpi_video_bus * video = ( struct acpi_video_bus * ) m - > private ;
char str [ 12 ] = { 0 } ;
unsigned long opt , options ;
2005-04-17 02:20:36 +04:00
if ( ! video | | count + 1 > sizeof str )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
status = acpi_video_bus_POST_options ( video , & options ) ;
if ( ! ACPI_SUCCESS ( status ) )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
if ( copy_from_user ( str , buffer , count ) )
2006-06-27 08:41:40 +04:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
str [ count ] = 0 ;
opt = strtoul ( str , NULL , 0 ) ;
if ( opt > 3 )
2006-06-27 08:41:40 +04:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
/* just in case an OEM 'forget' the motherboard... */
options | = 1 ;
if ( options & ( 1ul < < opt ) ) {
2005-08-05 08:44:28 +04:00
status = acpi_video_bus_set_POST ( video , opt ) ;
2005-04-17 02:20:36 +04:00
if ( ! ACPI_SUCCESS ( status ) )
2006-06-27 08:41:40 +04:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
}
2006-06-27 08:41:40 +04:00
return count ;
2005-04-17 02:20:36 +04:00
}
static ssize_t
2005-08-05 08:44:28 +04:00
acpi_video_bus_write_DOS ( struct file * file ,
const char __user * buffer ,
size_t count , loff_t * data )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int status ;
struct seq_file * m = ( struct seq_file * ) file - > private_data ;
struct acpi_video_bus * video = ( struct acpi_video_bus * ) m - > private ;
char str [ 12 ] = { 0 } ;
unsigned long opt ;
2005-04-17 02:20:36 +04:00
if ( ! video | | count + 1 > sizeof str )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
if ( copy_from_user ( str , buffer , count ) )
2006-06-27 08:41:40 +04:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
str [ count ] = 0 ;
opt = strtoul ( str , NULL , 0 ) ;
if ( opt > 7 )
2006-06-27 08:41:40 +04:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
status = acpi_video_bus_DOS ( video , opt & 0x3 , ( opt & 0x4 ) > > 2 ) ;
2005-04-17 02:20:36 +04:00
if ( ! ACPI_SUCCESS ( status ) )
2006-06-27 08:41:40 +04:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
2006-06-27 08:41:40 +04:00
return count ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static int acpi_video_bus_add_fs ( struct acpi_device * device )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct proc_dir_entry * entry = NULL ;
struct acpi_video_bus * video ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
video = ( struct acpi_video_bus * ) acpi_driver_data ( device ) ;
2005-04-17 02:20:36 +04:00
if ( ! acpi_device_dir ( device ) ) {
acpi_device_dir ( device ) = proc_mkdir ( acpi_device_bid ( device ) ,
2005-08-05 08:44:28 +04:00
acpi_video_dir ) ;
2005-04-17 02:20:36 +04:00
if ( ! acpi_device_dir ( device ) )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
video - > dir = acpi_device_dir ( device ) ;
acpi_device_dir ( device ) - > owner = THIS_MODULE ;
}
/* 'info' [R] */
entry = create_proc_entry ( " info " , S_IRUGO , acpi_device_dir ( device ) ) ;
if ( ! entry )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
else {
entry - > proc_fops = & acpi_video_bus_info_fops ;
entry - > data = acpi_driver_data ( device ) ;
entry - > owner = THIS_MODULE ;
}
/* 'ROM' [R] */
entry = create_proc_entry ( " ROM " , S_IRUGO , acpi_device_dir ( device ) ) ;
if ( ! entry )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
else {
entry - > proc_fops = & acpi_video_bus_ROM_fops ;
entry - > data = acpi_driver_data ( device ) ;
entry - > owner = THIS_MODULE ;
}
/* 'POST_info' [R] */
2005-08-05 08:44:28 +04:00
entry =
create_proc_entry ( " POST_info " , S_IRUGO , acpi_device_dir ( device ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! entry )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
else {
entry - > proc_fops = & acpi_video_bus_POST_info_fops ;
entry - > data = acpi_driver_data ( device ) ;
entry - > owner = THIS_MODULE ;
}
/* 'POST' [R/W] */
2005-08-05 08:44:28 +04:00
entry =
create_proc_entry ( " POST " , S_IFREG | S_IRUGO | S_IRUSR ,
acpi_device_dir ( device ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! entry )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
else {
2006-01-07 00:47:00 +03:00
acpi_video_bus_POST_fops . write = acpi_video_bus_write_POST ;
2005-04-17 02:20:36 +04:00
entry - > proc_fops = & acpi_video_bus_POST_fops ;
entry - > data = acpi_driver_data ( device ) ;
entry - > owner = THIS_MODULE ;
}
/* 'DOS' [R/W] */
2005-08-05 08:44:28 +04:00
entry =
create_proc_entry ( " DOS " , S_IFREG | S_IRUGO | S_IRUSR ,
acpi_device_dir ( device ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! entry )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
else {
2006-01-07 00:47:00 +03:00
acpi_video_bus_DOS_fops . write = acpi_video_bus_write_DOS ;
2005-04-17 02:20:36 +04:00
entry - > proc_fops = & acpi_video_bus_DOS_fops ;
entry - > data = acpi_driver_data ( device ) ;
entry - > owner = THIS_MODULE ;
}
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static int acpi_video_bus_remove_fs ( struct acpi_device * device )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct acpi_video_bus * video ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
video = ( struct acpi_video_bus * ) acpi_driver_data ( device ) ;
2005-04-17 02:20:36 +04:00
if ( acpi_device_dir ( device ) ) {
remove_proc_entry ( " info " , acpi_device_dir ( device ) ) ;
remove_proc_entry ( " ROM " , acpi_device_dir ( device ) ) ;
remove_proc_entry ( " POST_info " , acpi_device_dir ( device ) ) ;
remove_proc_entry ( " POST " , acpi_device_dir ( device ) ) ;
remove_proc_entry ( " DOS " , acpi_device_dir ( device ) ) ;
2005-08-05 08:44:28 +04:00
remove_proc_entry ( acpi_device_bid ( device ) , acpi_video_dir ) ;
2005-04-17 02:20:36 +04:00
acpi_device_dir ( device ) = NULL ;
}
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
/* --------------------------------------------------------------------------
Driver Interface
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* device interface */
static int
2005-08-05 08:44:28 +04:00
acpi_video_bus_get_one_device ( struct acpi_device * device ,
struct acpi_video_bus * video )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
unsigned long device_id ;
2006-04-27 13:25:00 +04:00
int status ;
2005-08-05 08:44:28 +04:00
struct acpi_video_device * data ;
2005-04-17 02:20:36 +04:00
if ( ! device | | ! video )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
status =
acpi_evaluate_integer ( device - > handle , " _ADR " , NULL , & device_id ) ;
2005-04-17 02:20:36 +04:00
if ( ACPI_SUCCESS ( status ) ) {
data = kmalloc ( sizeof ( struct acpi_video_device ) , GFP_KERNEL ) ;
if ( ! data )
2006-06-27 08:41:40 +04:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
memset ( data , 0 , sizeof ( struct acpi_video_device ) ) ;
data - > handle = device - > handle ;
strcpy ( acpi_device_name ( device ) , ACPI_VIDEO_DEVICE_NAME ) ;
strcpy ( acpi_device_class ( device ) , ACPI_VIDEO_CLASS ) ;
acpi_driver_data ( device ) = data ;
data - > device_id = device_id ;
data - > video = video ;
data - > dev = device ;
switch ( device_id & 0xffff ) {
case 0x0100 :
data - > flags . crt = 1 ;
break ;
case 0x0400 :
data - > flags . lcd = 1 ;
break ;
case 0x0200 :
data - > flags . tvout = 1 ;
break ;
default :
data - > flags . unknown = 1 ;
break ;
}
2005-08-05 08:44:28 +04:00
2005-04-17 02:20:36 +04:00
acpi_video_device_bind ( video , data ) ;
acpi_video_device_find_cap ( data ) ;
status = acpi_install_notify_handler ( data - > handle ,
2005-08-05 08:44:28 +04:00
ACPI_DEVICE_NOTIFY ,
acpi_video_device_notify ,
data ) ;
2005-04-17 02:20:36 +04:00
if ( ACPI_FAILURE ( status ) ) {
ACPI_DEBUG_PRINT ( ( ACPI_DB_ERROR ,
2005-08-05 08:44:28 +04:00
" Error installing notify handler \n " ) ) ;
2006-04-27 13:25:00 +04:00
if ( data - > brightness )
kfree ( data - > brightness - > levels ) ;
kfree ( data - > brightness ) ;
kfree ( data ) ;
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
down ( & video - > sem ) ;
list_add_tail ( & data - > entry , & video - > video_device_list ) ;
up ( & video - > sem ) ;
acpi_video_device_add_fs ( device ) ;
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2006-06-27 08:41:40 +04:00
return - ENOENT ;
2005-04-17 02:20:36 +04:00
}
/*
* Arg :
* video : video bus device
*
* Return :
* none
*
* Enumerate the video device list of the video bus ,
* bind the ids with the corresponding video devices
* under the video bus .
2005-08-05 08:44:28 +04:00
*/
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
static void acpi_video_device_rebind ( struct acpi_video_bus * video )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct list_head * node , * next ;
2005-04-17 02:20:36 +04:00
list_for_each_safe ( node , next , & video - > video_device_list ) {
2005-08-05 08:44:28 +04:00
struct acpi_video_device * dev =
container_of ( node , struct acpi_video_device , entry ) ;
acpi_video_device_bind ( video , dev ) ;
2005-04-17 02:20:36 +04:00
}
}
/*
* Arg :
* video : video bus device
* device : video output device under the video
* bus
*
* Return :
* none
*
* Bind the ids with the corresponding video devices
* under the video bus .
2005-08-05 08:44:28 +04:00
*/
2005-04-17 02:20:36 +04:00
static void
2005-08-05 08:44:28 +04:00
acpi_video_device_bind ( struct acpi_video_bus * video ,
struct acpi_video_device * device )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int i ;
2005-04-17 02:20:36 +04:00
# define IDS_VAL(i) video->attached_array[i].value.int_val
# define IDS_BIND(i) video->attached_array[i].bind_info
2005-08-05 08:44:28 +04:00
for ( i = 0 ; IDS_VAL ( i ) ! = ACPI_VIDEO_HEAD_INVALID & &
i < video - > attached_count ; i + + ) {
if ( device - > device_id = = ( IDS_VAL ( i ) & 0xffff ) ) {
2005-04-17 02:20:36 +04:00
IDS_BIND ( i ) = device ;
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " device_bind %d \n " , i ) ) ;
}
}
# undef IDS_VAL
# undef IDS_BIND
}
/*
* Arg :
* video : video bus device
*
* Return :
* < 0 : error
*
* Call _DOD to enumerate all devices attached to display adapter
*
2005-08-05 08:44:28 +04:00
*/
2005-04-17 02:20:36 +04:00
static int acpi_video_device_enumerate ( struct acpi_video_bus * video )
{
2005-08-05 08:44:28 +04:00
int status ;
int count ;
int i ;
2005-04-17 02:20:36 +04:00
struct acpi_video_enumerated_device * active_device_list ;
2005-08-05 08:44:28 +04:00
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER , NULL } ;
union acpi_object * dod = NULL ;
union acpi_object * obj ;
2005-04-17 02:20:36 +04:00
status = acpi_evaluate_object ( video - > handle , " _DOD " , NULL , & buffer ) ;
if ( ! ACPI_SUCCESS ( status ) ) {
2006-06-27 07:58:43 +04:00
ACPI_EXCEPTION ( ( AE_INFO , status , " Evaluating _DOD " ) ) ;
2006-06-27 08:41:40 +04:00
return status ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
dod = ( union acpi_object * ) buffer . pointer ;
2005-04-17 02:20:36 +04:00
if ( ! dod | | ( dod - > type ! = ACPI_TYPE_PACKAGE ) ) {
2006-06-27 07:58:43 +04:00
ACPI_EXCEPTION ( ( AE_INFO , status , " Invalid _DOD data " ) ) ;
2005-04-17 02:20:36 +04:00
status = - EFAULT ;
goto out ;
}
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " Found %d video heads in _DOD \n " ,
2005-08-05 08:44:28 +04:00
dod - > package . count ) ) ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
active_device_list = kmalloc ( ( 1 +
dod - > package . count ) *
sizeof ( struct
acpi_video_enumerated_device ) ,
GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! active_device_list ) {
status = - ENOMEM ;
goto out ;
}
count = 0 ;
for ( i = 0 ; i < dod - > package . count ; i + + ) {
2005-08-05 08:44:28 +04:00
obj = ( union acpi_object * ) & dod - > package . elements [ i ] ;
2005-04-17 02:20:36 +04:00
if ( obj - > type ! = ACPI_TYPE_INTEGER ) {
2006-06-27 07:41:38 +04:00
printk ( KERN_ERR PREFIX " Invalid _DOD data \n " ) ;
2005-08-05 08:44:28 +04:00
active_device_list [ i ] . value . int_val =
ACPI_VIDEO_HEAD_INVALID ;
2005-04-17 02:20:36 +04:00
}
active_device_list [ i ] . value . int_val = obj - > integer . value ;
active_device_list [ i ] . bind_info = NULL ;
2005-08-05 08:44:28 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " dod element[%d] = %d \n " , i ,
( int ) obj - > integer . value ) ) ;
2005-04-17 02:20:36 +04:00
count + + ;
}
active_device_list [ count ] . value . int_val = ACPI_VIDEO_HEAD_END ;
2005-11-07 12:01:32 +03:00
kfree ( video - > attached_array ) ;
2005-08-05 08:44:28 +04:00
2005-04-17 02:20:36 +04:00
video - > attached_array = active_device_list ;
video - > attached_count = count ;
2005-08-05 08:44:28 +04:00
out :
2005-04-17 02:20:36 +04:00
acpi_os_free ( buffer . pointer ) ;
2006-06-27 08:41:40 +04:00
return status ;
2005-04-17 02:20:36 +04:00
}
/*
* Arg :
* video : video bus device
* event : Nontify Event
*
* Return :
* < 0 : error
*
* 1. Find out the current active output device .
* 2. Identify the next output device to switch
* 3. call _DSS to do actual switch .
2005-08-05 08:44:28 +04:00
*/
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
static int acpi_video_switch_output ( struct acpi_video_bus * video , int event )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct list_head * node , * next ;
struct acpi_video_device * dev = NULL ;
struct acpi_video_device * dev_next = NULL ;
struct acpi_video_device * dev_prev = NULL ;
2005-04-17 02:20:36 +04:00
unsigned long state ;
int status = 0 ;
list_for_each_safe ( node , next , & video - > video_device_list ) {
2005-03-31 07:31:35 +04:00
dev = container_of ( node , struct acpi_video_device , entry ) ;
2005-04-17 02:20:36 +04:00
status = acpi_video_device_get_state ( dev , & state ) ;
2005-08-05 08:44:28 +04:00
if ( state & 0x2 ) {
dev_next =
container_of ( node - > next , struct acpi_video_device ,
entry ) ;
dev_prev =
container_of ( node - > prev , struct acpi_video_device ,
entry ) ;
2005-04-17 02:20:36 +04:00
goto out ;
}
}
dev_next = container_of ( node - > next , struct acpi_video_device , entry ) ;
dev_prev = container_of ( node - > prev , struct acpi_video_device , entry ) ;
2005-08-05 08:44:28 +04:00
out :
2005-04-17 02:20:36 +04:00
switch ( event ) {
case ACPI_VIDEO_NOTIFY_CYCLE :
case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT :
acpi_video_device_set_state ( dev , 0 ) ;
acpi_video_device_set_state ( dev_next , 0x80000001 ) ;
break ;
case ACPI_VIDEO_NOTIFY_PREV_OUTPUT :
acpi_video_device_set_state ( dev , 0 ) ;
acpi_video_device_set_state ( dev_prev , 0x80000001 ) ;
default :
break ;
}
2006-06-27 08:41:40 +04:00
return status ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static int
acpi_video_get_next_level ( struct acpi_video_device * device ,
u32 level_current , u32 event )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
/*Fix me */
2005-04-17 02:20:36 +04:00
return level_current ;
}
static void
2005-08-05 08:44:28 +04:00
acpi_video_switch_brightness ( struct acpi_video_device * device , int event )
2005-04-17 02:20:36 +04:00
{
unsigned long level_current , level_next ;
acpi_video_device_lcd_get_level_current ( device , & level_current ) ;
level_next = acpi_video_get_next_level ( device , level_current , event ) ;
acpi_video_device_lcd_set_level ( device , level_next ) ;
}
static int
2005-08-05 08:44:28 +04:00
acpi_video_bus_get_devices ( struct acpi_video_bus * video ,
struct acpi_device * device )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int status = 0 ;
struct list_head * node , * next ;
2005-04-17 02:20:36 +04:00
acpi_video_device_enumerate ( video ) ;
list_for_each_safe ( node , next , & device - > children ) {
2005-08-05 08:44:28 +04:00
struct acpi_device * dev =
list_entry ( node , struct acpi_device , node ) ;
2005-04-17 02:20:36 +04:00
if ( ! dev )
continue ;
status = acpi_video_bus_get_one_device ( dev , video ) ;
if ( ACPI_FAILURE ( status ) ) {
2006-06-27 07:58:43 +04:00
ACPI_EXCEPTION ( ( AE_INFO , status , " Cant attach device " ) ) ;
2005-04-17 02:20:36 +04:00
continue ;
}
}
2006-06-27 08:41:40 +04:00
return status ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static int acpi_video_bus_put_one_device ( struct acpi_video_device * device )
2005-04-17 02:20:36 +04:00
{
2005-07-30 12:18:00 +04:00
acpi_status status ;
2005-04-17 02:20:36 +04:00
struct acpi_video_bus * video ;
if ( ! device | | ! device - > video )
2006-06-27 08:41:40 +04:00
return - ENOENT ;
2005-04-17 02:20:36 +04:00
video = device - > video ;
down ( & video - > sem ) ;
list_del ( & device - > entry ) ;
up ( & video - > sem ) ;
acpi_video_device_remove_fs ( device - > dev ) ;
2005-07-30 12:18:00 +04:00
status = acpi_remove_notify_handler ( device - > handle ,
2005-08-05 08:44:28 +04:00
ACPI_DEVICE_NOTIFY ,
acpi_video_device_notify ) ;
2005-07-30 12:18:00 +04:00
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static int acpi_video_bus_put_devices ( struct acpi_video_bus * video )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int status ;
struct list_head * node , * next ;
2005-04-17 02:20:36 +04:00
list_for_each_safe ( node , next , & video - > video_device_list ) {
2005-08-05 08:44:28 +04:00
struct acpi_video_device * data =
list_entry ( node , struct acpi_video_device , entry ) ;
2005-04-17 02:20:36 +04:00
if ( ! data )
continue ;
status = acpi_video_bus_put_one_device ( data ) ;
2005-08-05 08:44:28 +04:00
if ( ACPI_FAILURE ( status ) )
printk ( KERN_WARNING PREFIX
" hhuuhhuu bug in acpi video driver. \n " ) ;
2005-04-17 02:20:36 +04:00
2006-06-24 08:33:08 +04:00
if ( data - > brightness )
2006-04-27 13:25:00 +04:00
kfree ( data - > brightness - > levels ) ;
2005-11-07 12:01:32 +03:00
kfree ( data - > brightness ) ;
2005-04-17 02:20:36 +04:00
kfree ( data ) ;
}
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
/* acpi_video interface */
2005-08-05 08:44:28 +04:00
static int acpi_video_bus_start_devices ( struct acpi_video_bus * video )
2005-04-17 02:20:36 +04:00
{
return acpi_video_bus_DOS ( video , 1 , 0 ) ;
}
2005-08-05 08:44:28 +04:00
static int acpi_video_bus_stop_devices ( struct acpi_video_bus * video )
2005-04-17 02:20:36 +04:00
{
return acpi_video_bus_DOS ( video , 0 , 1 ) ;
}
2005-08-05 08:44:28 +04:00
static void acpi_video_bus_notify ( acpi_handle handle , u32 event , void * data )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct acpi_video_bus * video = ( struct acpi_video_bus * ) data ;
struct acpi_device * device = NULL ;
2005-04-17 02:20:36 +04:00
printk ( " video bus notify \n " ) ;
if ( ! video )
2006-06-27 08:41:40 +04:00
return ;
2005-04-17 02:20:36 +04:00
2006-05-20 00:54:40 +04:00
device = video - > device ;
2005-04-17 02:20:36 +04:00
switch ( event ) {
case ACPI_VIDEO_NOTIFY_SWITCH : /* User request that a switch occur,
* most likely via hotkey . */
acpi_bus_generate_event ( device , event , 0 ) ;
break ;
case ACPI_VIDEO_NOTIFY_PROBE : /* User plug or remove a video
* connector . */
acpi_video_device_enumerate ( video ) ;
acpi_video_device_rebind ( video ) ;
acpi_video_switch_output ( video , event ) ;
acpi_bus_generate_event ( device , event , 0 ) ;
break ;
2005-08-05 08:44:28 +04:00
case ACPI_VIDEO_NOTIFY_CYCLE : /* Cycle Display output hotkey pressed. */
case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT : /* Next Display output hotkey pressed. */
case ACPI_VIDEO_NOTIFY_PREV_OUTPUT : /* previous Display output hotkey pressed. */
2005-04-17 02:20:36 +04:00
acpi_video_switch_output ( video , event ) ;
acpi_bus_generate_event ( device , event , 0 ) ;
break ;
default :
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
2005-08-05 08:44:28 +04:00
" Unsupported event [0x%x] \n " , event ) ) ;
2005-04-17 02:20:36 +04:00
break ;
}
2006-06-27 08:41:40 +04:00
return ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static void acpi_video_device_notify ( acpi_handle handle , u32 event , void * data )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct acpi_video_device * video_device =
( struct acpi_video_device * ) data ;
struct acpi_device * device = NULL ;
2005-04-17 02:20:36 +04:00
printk ( " video device notify \n " ) ;
if ( ! video_device )
2006-06-27 08:41:40 +04:00
return ;
2005-04-17 02:20:36 +04:00
2006-05-20 00:54:40 +04:00
device = video_device - > dev ;
2005-04-17 02:20:36 +04:00
switch ( event ) {
2005-08-05 08:44:28 +04:00
case ACPI_VIDEO_NOTIFY_SWITCH : /* change in status (cycle output device) */
case ACPI_VIDEO_NOTIFY_PROBE : /* change in status (output device status) */
2005-04-17 02:20:36 +04:00
acpi_bus_generate_event ( device , event , 0 ) ;
break ;
2005-08-05 08:44:28 +04:00
case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS : /* Cycle brightness */
case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS : /* Increase brightness */
case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS : /* Decrease brightness */
case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS : /* zero brightnesss */
case ACPI_VIDEO_NOTIFY_DISPLAY_OFF : /* display device off */
acpi_video_switch_brightness ( video_device , event ) ;
2005-04-17 02:20:36 +04:00
acpi_bus_generate_event ( device , event , 0 ) ;
break ;
default :
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
2005-08-05 08:44:28 +04:00
" Unsupported event [0x%x] \n " , event ) ) ;
2005-04-17 02:20:36 +04:00
break ;
}
2006-06-27 08:41:40 +04:00
return ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static int acpi_video_bus_add ( struct acpi_device * device )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int result = 0 ;
acpi_status status = 0 ;
struct acpi_video_bus * video = NULL ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
2005-04-17 02:20:36 +04:00
if ( ! device )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
video = kmalloc ( sizeof ( struct acpi_video_bus ) , GFP_KERNEL ) ;
if ( ! video )
2006-06-27 08:41:40 +04:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
memset ( video , 0 , sizeof ( struct acpi_video_bus ) ) ;
video - > handle = device - > handle ;
2006-05-20 00:54:40 +04:00
video - > device = device ;
2005-04-17 02:20:36 +04:00
strcpy ( acpi_device_name ( device ) , ACPI_VIDEO_BUS_NAME ) ;
strcpy ( acpi_device_class ( device ) , ACPI_VIDEO_CLASS ) ;
acpi_driver_data ( device ) = video ;
acpi_video_bus_find_cap ( video ) ;
result = acpi_video_bus_check ( video ) ;
if ( result )
goto end ;
result = acpi_video_bus_add_fs ( device ) ;
if ( result )
goto end ;
init_MUTEX ( & video - > sem ) ;
INIT_LIST_HEAD ( & video - > video_device_list ) ;
acpi_video_bus_get_devices ( video , device ) ;
acpi_video_bus_start_devices ( video ) ;
status = acpi_install_notify_handler ( video - > handle ,
2005-08-05 08:44:28 +04:00
ACPI_DEVICE_NOTIFY ,
acpi_video_bus_notify , video ) ;
2005-04-17 02:20:36 +04:00
if ( ACPI_FAILURE ( status ) ) {
ACPI_DEBUG_PRINT ( ( ACPI_DB_ERROR ,
2005-08-05 08:44:28 +04:00
" Error installing notify handler \n " ) ) ;
2006-04-27 13:25:00 +04:00
acpi_video_bus_stop_devices ( video ) ;
acpi_video_bus_put_devices ( video ) ;
kfree ( video - > attached_array ) ;
acpi_video_bus_remove_fs ( device ) ;
2005-04-17 02:20:36 +04:00
result = - ENODEV ;
goto end ;
}
printk ( KERN_INFO PREFIX " %s [%s] (multi-head: %s rom: %s post: %s) \n " ,
2005-08-05 08:44:28 +04:00
ACPI_VIDEO_DEVICE_NAME , acpi_device_bid ( device ) ,
video - > flags . multihead ? " yes " : " no " ,
video - > flags . rom ? " yes " : " no " ,
video - > flags . post ? " yes " : " no " ) ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
end :
2006-04-27 13:25:00 +04:00
if ( result )
2005-04-17 02:20:36 +04:00
kfree ( video ) ;
2006-06-27 08:41:40 +04:00
return result ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static int acpi_video_bus_remove ( struct acpi_device * device , int type )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
acpi_status status = 0 ;
struct acpi_video_bus * video = NULL ;
2005-04-17 02:20:36 +04:00
if ( ! device | | ! acpi_driver_data ( device ) )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
video = ( struct acpi_video_bus * ) acpi_driver_data ( device ) ;
2005-04-17 02:20:36 +04:00
acpi_video_bus_stop_devices ( video ) ;
status = acpi_remove_notify_handler ( video - > handle ,
2005-08-05 08:44:28 +04:00
ACPI_DEVICE_NOTIFY ,
acpi_video_bus_notify ) ;
2005-04-17 02:20:36 +04:00
acpi_video_bus_put_devices ( video ) ;
acpi_video_bus_remove_fs ( device ) ;
2005-11-07 12:01:32 +03:00
kfree ( video - > attached_array ) ;
2005-04-17 02:20:36 +04:00
kfree ( video ) ;
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
static int
2005-08-05 08:44:28 +04:00
acpi_video_bus_match ( struct acpi_device * device , struct acpi_driver * driver )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
acpi_handle h_dummy1 ;
acpi_handle h_dummy2 ;
acpi_handle h_dummy3 ;
2005-04-17 02:20:36 +04:00
if ( ! device | | ! driver )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
/* Since there is no HID, CID for ACPI Video drivers, we have
* to check well known required nodes for each feature we support .
*/
/* Does this device able to support video switching ? */
if ( ACPI_SUCCESS ( acpi_get_handle ( device - > handle , " _DOD " , & h_dummy1 ) ) & &
ACPI_SUCCESS ( acpi_get_handle ( device - > handle , " _DOS " , & h_dummy2 ) ) )
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
/* Does this device able to retrieve a video ROM ? */
if ( ACPI_SUCCESS ( acpi_get_handle ( device - > handle , " _ROM " , & h_dummy1 ) ) )
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
/* Does this device able to configure which video head to be POSTed ? */
if ( ACPI_SUCCESS ( acpi_get_handle ( device - > handle , " _VPO " , & h_dummy1 ) ) & &
ACPI_SUCCESS ( acpi_get_handle ( device - > handle , " _GPD " , & h_dummy2 ) ) & &
ACPI_SUCCESS ( acpi_get_handle ( device - > handle , " _SPD " , & h_dummy3 ) ) )
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static int __init acpi_video_init ( void )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int result = 0 ;
2005-04-17 02:20:36 +04:00
/*
2005-08-05 08:44:28 +04:00
acpi_dbg_level = 0xFFFFFFFF ;
acpi_dbg_layer = 0x08000000 ;
*/
2005-04-17 02:20:36 +04:00
acpi_video_dir = proc_mkdir ( ACPI_VIDEO_CLASS , acpi_root_dir ) ;
if ( ! acpi_video_dir )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
acpi_video_dir - > owner = THIS_MODULE ;
result = acpi_bus_register_driver ( & acpi_video_bus ) ;
if ( result < 0 ) {
remove_proc_entry ( ACPI_VIDEO_CLASS , acpi_root_dir ) ;
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static void __exit acpi_video_exit ( void )
2005-04-17 02:20:36 +04:00
{
acpi_bus_unregister_driver ( & acpi_video_bus ) ;
remove_proc_entry ( ACPI_VIDEO_CLASS , acpi_root_dir ) ;
2006-06-27 08:41:40 +04:00
return ;
2005-04-17 02:20:36 +04:00
}
module_init ( acpi_video_init ) ;
module_exit ( acpi_video_exit ) ;