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 >
2006-12-19 23:56:14 +03:00
* Copyright ( C ) 2006 Thomas Tuttle < linux - kernel @ ttuttle . net >
2005-04-17 02:20:36 +04:00
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* 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>
2006-11-10 21:40:34 +03:00
# include <linux/backlight.h>
2007-05-09 17:07:05 +04:00
# include <linux/video_output.h>
2005-04-17 02:20:36 +04:00
# 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_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
2006-12-19 23:56:14 +03:00
# define ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS 0x85
# define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x86
# define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87
# define ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS 0x88
# define ACPI_VIDEO_NOTIFY_DISPLAY_OFF 0x89
2005-04-17 02:20:36 +04:00
# define ACPI_VIDEO_HEAD_INVALID (~0u - 1)
# define ACPI_VIDEO_HEAD_END (~0u)
2006-11-10 21:40:34 +03:00
# define MAX_NAME_LEN 20
2005-04-17 02:20:36 +04:00
2007-01-04 07:40:53 +03:00
# define ACPI_VIDEO_DISPLAY_CRT 1
# define ACPI_VIDEO_DISPLAY_TV 2
# define ACPI_VIDEO_DISPLAY_DVI 3
# define ACPI_VIDEO_DISPLAY_LCD 4
2005-04-17 02:20:36 +04:00
# define _COMPONENT ACPI_VIDEO_COMPONENT
2007-02-13 06:42:12 +03:00
ACPI_MODULE_NAME ( " video " ) ;
2005-04-17 02:20:36 +04:00
2007-02-13 06:42:12 +03:00
MODULE_AUTHOR ( " Bruno Ducrot " ) ;
2007-02-13 07:50:02 +03:00
MODULE_DESCRIPTION ( " ACPI Video Driver " ) ;
2005-04-17 02:20:36 +04:00
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 ) ;
2005-04-17 02:20:36 +04:00
2007-07-23 16:44:41 +04:00
static const struct acpi_device_id video_device_ids [ ] = {
{ ACPI_VIDEO_HID , 0 } ,
{ " " , 0 } ,
} ;
MODULE_DEVICE_TABLE ( acpi , video_device_ids ) ;
2005-04-17 02:20:36 +04:00
static struct acpi_driver acpi_video_bus = {
2007-02-13 07:33:40 +03:00
. name = " video " ,
2005-04-17 02:20:36 +04:00
. class = ACPI_VIDEO_CLASS ,
2007-07-23 16:44:41 +04:00
. ids = video_device_ids ,
2005-04-17 02:20:36 +04:00
. ops = {
. add = acpi_video_bus_add ,
. remove = acpi_video_bus_remove ,
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 */
2007-02-20 18:38:40 +03:00
u32 display_port_attachment : 4 ; /*This field differentiates the display type */
2005-08-05 08:44:28 +04:00
u32 display_type : 4 ; /*Describe the specific type in use */
2007-02-20 18:38:40 +03:00
u32 vendor_specific : 4 ; /*Chipset Vendor Specific */
2005-08-05 08:44:28 +04:00
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 {
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 ;
2007-01-04 07:40:53 +03:00
u8 dvi : 1 ;
2005-08-05 08:44:28 +04:00
u8 bios : 1 ;
u8 unknown : 1 ;
2007-01-04 07:40:53 +03:00
u8 reserved : 2 ;
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 */
2006-11-10 21:40:34 +03:00
u8 _BQC : 1 ; /* Get current brightness level */
2005-08-05 08:44:28 +04:00
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 */
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
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 ;
2006-11-10 21:40:34 +03:00
struct backlight_device * backlight ;
2007-05-09 17:07:05 +04:00
struct output_device * output_dev ;
2005-04-17 02:20:36 +04:00
} ;
/* 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 ) ;
2006-11-10 21:40:34 +03:00
static int acpi_video_device_lcd_set_level ( struct acpi_video_device * device ,
int level ) ;
static int acpi_video_device_lcd_get_level_current (
struct acpi_video_device * device ,
unsigned long * level ) ;
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 ) ;
static void acpi_video_switch_brightness ( struct acpi_video_device * device ,
int event ) ;
2007-05-09 17:07:05 +04:00
static int acpi_video_device_get_state ( struct acpi_video_device * device ,
unsigned long * state ) ;
static int acpi_video_output_get ( struct output_device * od ) ;
static int acpi_video_device_set_state ( struct acpi_video_device * device , int state ) ;
2005-04-17 02:20:36 +04:00
2006-11-10 21:40:34 +03:00
/*backlight device sysfs support*/
static int acpi_video_get_brightness ( struct backlight_device * bd )
{
unsigned long cur_level ;
struct acpi_video_device * vd =
2007-07-09 15:17:24 +04:00
( struct acpi_video_device * ) bl_get_data ( bd ) ;
2006-11-10 21:40:34 +03:00
acpi_video_device_lcd_get_level_current ( vd , & cur_level ) ;
return ( int ) cur_level ;
}
static int acpi_video_set_brightness ( struct backlight_device * bd )
{
2007-02-11 02:07:48 +03:00
int request_level = bd - > props . brightness ;
2006-11-10 21:40:34 +03:00
struct acpi_video_device * vd =
2007-07-09 15:17:24 +04:00
( struct acpi_video_device * ) bl_get_data ( bd ) ;
2006-11-10 21:40:34 +03:00
acpi_video_device_lcd_set_level ( vd , request_level ) ;
return 0 ;
}
2007-02-11 02:07:48 +03:00
static struct backlight_ops acpi_backlight_ops = {
. get_brightness = acpi_video_get_brightness ,
. update_status = acpi_video_set_brightness ,
} ;
2007-05-09 17:07:05 +04:00
/*video output device sysfs support*/
static int acpi_video_output_get ( struct output_device * od )
{
unsigned long state ;
struct acpi_video_device * vd =
( struct acpi_video_device * ) class_get_devdata ( & od - > class_dev ) ;
acpi_video_device_get_state ( vd , & state ) ;
return ( int ) state ;
}
static int acpi_video_output_set ( struct output_device * od )
{
unsigned long state = od - > request_state ;
struct acpi_video_device * vd =
( struct acpi_video_device * ) class_get_devdata ( & od - > class_dev ) ;
return acpi_video_device_set_state ( vd , state ) ;
}
static struct output_properties acpi_output_properties = {
. set_state = acpi_video_output_set ,
. get_status = acpi_video_output_get ,
} ;
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 ;
2006-05-20 00:54:48 +04:00
status = acpi_evaluate_integer ( device - > dev - > handle , " _DGS " , NULL , state ) ;
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_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
2006-05-20 00:54:48 +04:00
status = acpi_evaluate_integer ( device - > dev - > handle , " _DCS " , NULL , state ) ;
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_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 ;
2006-05-20 00:54:48 +04:00
status = acpi_evaluate_integer ( device - > dev - > 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 ;
2006-05-20 00:54:48 +04:00
status = acpi_evaluate_object ( device - > dev - > handle , " _BCL " , NULL , & buffer ) ;
2005-04-17 02:20:36 +04:00
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 ;
2006-05-20 00:54:48 +04:00
status = acpi_evaluate_object ( device - > dev - > handle , " _BCM " , & args , NULL ) ;
2005-04-17 02:20:36 +04:00
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
2006-05-20 00:54:48 +04:00
status = acpi_evaluate_integer ( device - > dev - > handle , " _BQC " , NULL , level ) ;
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_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
2006-05-20 00:54:48 +04:00
status = acpi_evaluate_object ( device - > dev - > handle , " _DDC " , & args , & buffer ) ;
2005-04-17 02:20:36 +04:00
if ( ACPI_FAILURE ( status ) )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
2006-10-01 02:28:50 +04:00
obj = 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 ;
2006-05-20 00:54:48 +04:00
status = acpi_evaluate_integer ( video - > device - > handle , " _SPD " , & args , & tmp ) ;
2005-04-17 02:20:36 +04:00
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 ;
2006-05-20 00:54:48 +04:00
status = acpi_evaluate_integer ( video - > device - > handle , " _GPD " , NULL , id ) ;
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_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
2006-05-20 00:54:48 +04:00
status = acpi_evaluate_integer ( video - > device - > handle , " _VPO " , NULL , options ) ;
2005-04-17 02:20:36 +04:00
* 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
2007-02-20 18:38:40 +03:00
* active display output . No switch event .
2005-04-17 02:20:36 +04:00
* 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
2007-02-20 18:38:40 +03:00
* of the LCD when the power changes from AC to DC
2005-04-17 02:20:36 +04:00
* 1. The system BIOS should NOT automatically control the brightness
2007-02-20 18:38:40 +03:00
* level of the LCD when the power changes from AC to DC .
2005-04-17 02:20:36 +04:00
* 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 ;
2006-05-20 00:54:48 +04:00
acpi_evaluate_object ( video - > device - > handle , " _DOS " , & args , NULL ) ;
2005-04-17 02:20:36 +04:00
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
*
2007-02-20 18:38:40 +03:00
* Find out all required AML methods defined under the output
2005-04-17 02:20:36 +04:00
* 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
{
acpi_handle h_dummy1 ;
int i ;
2006-11-10 21:40:34 +03:00
u32 max_level = 0 ;
2005-04-17 02:20:36 +04:00
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
2006-05-20 00:54:48 +04:00
if ( ACPI_SUCCESS ( acpi_get_handle ( device - > dev - > handle , " _ADR " , & h_dummy1 ) ) ) {
2005-04-17 02:20:36 +04:00
device - > cap . _ADR = 1 ;
}
2006-05-20 00:54:48 +04:00
if ( ACPI_SUCCESS ( acpi_get_handle ( device - > dev - > handle , " _BCL " , & h_dummy1 ) ) ) {
2005-08-05 08:44:28 +04:00
device - > cap . _BCL = 1 ;
2005-04-17 02:20:36 +04:00
}
2006-05-20 00:54:48 +04:00
if ( ACPI_SUCCESS ( acpi_get_handle ( device - > dev - > handle , " _BCM " , & h_dummy1 ) ) ) {
2005-08-05 08:44:28 +04:00
device - > cap . _BCM = 1 ;
2005-04-17 02:20:36 +04:00
}
2006-11-10 21:40:34 +03:00
if ( ACPI_SUCCESS ( acpi_get_handle ( device - > dev - > handle , " _BQC " , & h_dummy1 ) ) )
device - > cap . _BQC = 1 ;
2006-05-20 00:54:48 +04:00
if ( ACPI_SUCCESS ( acpi_get_handle ( device - > dev - > handle , " _DDC " , & h_dummy1 ) ) ) {
2005-08-05 08:44:28 +04:00
device - > cap . _DDC = 1 ;
2005-04-17 02:20:36 +04:00
}
2006-05-20 00:54:48 +04:00
if ( ACPI_SUCCESS ( acpi_get_handle ( device - > dev - > handle , " _DCS " , & h_dummy1 ) ) ) {
2005-04-17 02:20:36 +04:00
device - > cap . _DCS = 1 ;
}
2006-05-20 00:54:48 +04:00
if ( ACPI_SUCCESS ( acpi_get_handle ( device - > dev - > handle , " _DGS " , & h_dummy1 ) ) ) {
2005-04-17 02:20:36 +04:00
device - > cap . _DGS = 1 ;
}
2006-05-20 00:54:48 +04:00
if ( ACPI_SUCCESS ( acpi_get_handle ( device - > dev - > handle , " _DSS " , & h_dummy1 ) ) ) {
2005-04-17 02:20:36 +04:00
device - > cap . _DSS = 1 ;
}
2007-07-03 09:33:53 +04:00
if ( ACPI_SUCCESS ( acpi_video_device_lcd_query_levels ( device , & obj ) ) ) {
if ( obj - > package . count > = 2 ) {
int count = 0 ;
union acpi_object * o ;
br = kzalloc ( sizeof ( * br ) , GFP_KERNEL ) ;
if ( ! br ) {
printk ( KERN_ERR " can't allocate memory \n " ) ;
2005-04-17 02:20:36 +04:00
} else {
2007-07-03 09:33:53 +04:00
br - > levels = kmalloc ( obj - > package . count *
sizeof * ( br - > levels ) , GFP_KERNEL ) ;
if ( ! br - > levels )
goto out ;
for ( i = 0 ; i < obj - > package . count ; i + + ) {
o = ( union acpi_object * ) & obj - > package .
elements [ i ] ;
if ( o - > type ! = ACPI_TYPE_INTEGER ) {
printk ( KERN_ERR PREFIX " Invalid data \n " ) ;
continue ;
}
br - > levels [ count ] = ( u32 ) o - > integer . value ;
if ( br - > levels [ count ] > max_level )
max_level = br - > levels [ count ] ;
count + + ;
}
out :
if ( count < 2 ) {
kfree ( br - > levels ) ;
kfree ( br ) ;
} else {
br - > count = count ;
device - > brightness = br ;
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
" found %d brightness levels \n " ,
count ) ) ;
}
2005-04-17 02:20:36 +04:00
}
}
2007-07-03 09:33:53 +04:00
} else {
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " Could not query available LCD brightness level \n " ) ) ;
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
2007-07-03 09:33:53 +04:00
if ( device - > cap . _BCL & & device - > cap . _BCM & & device - > cap . _BQC & & max_level > 0 ) {
2006-11-10 21:40:34 +03:00
unsigned long tmp ;
static int count = 0 ;
char * name ;
name = kzalloc ( MAX_NAME_LEN , GFP_KERNEL ) ;
if ( ! name )
return ;
sprintf ( name , " acpi_video%d " , count + + ) ;
acpi_video_device_lcd_get_level_current ( device , & tmp ) ;
device - > backlight = backlight_device_register ( name ,
2007-02-11 02:07:48 +03:00
NULL , device , & acpi_backlight_ops ) ;
device - > backlight - > props . max_brightness = max_level ;
device - > backlight - > props . brightness = ( int ) tmp ;
backlight_update_status ( device - > backlight ) ;
2006-11-10 21:40:34 +03:00
kfree ( name ) ;
}
2007-05-09 17:07:05 +04:00
if ( device - > cap . _DCS & & device - > cap . _DSS ) {
static int count = 0 ;
char * name ;
name = kzalloc ( MAX_NAME_LEN , GFP_KERNEL ) ;
if ( ! name )
return ;
sprintf ( name , " acpi_video%d " , count + + ) ;
device - > output_dev = video_output_register ( name ,
NULL , device , & acpi_output_properties ) ;
kfree ( name ) ;
}
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
*
2007-02-20 18:38:40 +03:00
* Find out all required AML methods defined under the video bus device .
2005-04-17 02:20:36 +04:00
*/
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 ) ;
2006-05-20 00:54:48 +04:00
if ( ACPI_SUCCESS ( acpi_get_handle ( video - > device - > handle , " _DOS " , & h_dummy1 ) ) ) {
2005-04-17 02:20:36 +04:00
video - > cap . _DOS = 1 ;
}
2006-05-20 00:54:48 +04:00
if ( ACPI_SUCCESS ( acpi_get_handle ( video - > device - > handle , " _DOD " , & h_dummy1 ) ) ) {
2005-04-17 02:20:36 +04:00
video - > cap . _DOD = 1 ;
}
2006-05-20 00:54:48 +04:00
if ( ACPI_SUCCESS ( acpi_get_handle ( video - > device - > handle , " _ROM " , & h_dummy1 ) ) ) {
2005-04-17 02:20:36 +04:00
video - > cap . _ROM = 1 ;
}
2006-05-20 00:54:48 +04:00
if ( ACPI_SUCCESS ( acpi_get_handle ( video - > device - > handle , " _GPD " , & h_dummy1 ) ) ) {
2005-04-17 02:20:36 +04:00
video - > cap . _GPD = 1 ;
}
2006-05-20 00:54:48 +04:00
if ( ACPI_SUCCESS ( acpi_get_handle ( video - > device - > handle , " _SPD " , & h_dummy1 ) ) ) {
2005-04-17 02:20:36 +04:00
video - > cap . _SPD = 1 ;
}
2006-05-20 00:54:48 +04:00
if ( ACPI_SUCCESS ( acpi_get_handle ( video - > device - > 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 .
*/
2007-02-20 18:38:40 +03:00
/* Does this device 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 ;
}
2007-02-20 18:38:40 +03:00
/* Does this device support retrieving 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 ;
}
2007-02-20 18:38:40 +03:00
/* Does this device support configuring 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
{
2006-10-01 02:28:50 +04:00
struct acpi_video_device * dev = 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 " ) ;
2007-01-04 07:40:53 +03:00
else if ( dev - > flags . dvi )
seq_printf ( seq , " DVI \n " ) ;
2005-04-17 02:20:36 +04:00
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 ;
2006-10-01 02:28:50 +04:00
struct acpi_video_device * dev = seq - > private ;
2005-08-05 08:44:28 +04:00
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 ;
2006-10-01 02:28:50 +04:00
struct seq_file * m = file - > private_data ;
struct acpi_video_device * dev = m - > private ;
2005-08-05 08:44:28 +04:00
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
{
2006-10-01 02:28:50 +04:00
struct acpi_video_device * dev = seq - > private ;
2005-08-05 08:44:28 +04:00
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
{
2006-10-01 02:28:50 +04:00
struct seq_file * m = file - > private_data ;
struct acpi_video_device * dev = m - > private ;
2005-08-05 08:44:28 +04:00
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
2007-02-20 18:38:40 +03:00
/* validate through the list of available levels */
2005-04-17 02:20:36 +04:00
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
{
2006-10-01 02:28:50 +04:00
struct acpi_video_device * dev = seq - > private ;
2005-08-05 08:44:28 +04:00
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
2006-10-01 02:28:50 +04:00
vid_dev = 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 ;
2006-10-01 02:28:50 +04:00
vid_dev = 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
{
2006-10-01 02:28:50 +04:00
struct acpi_video_bus * video = 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
{
2006-10-01 02:28:50 +04:00
struct acpi_video_bus * video = 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
{
2006-10-01 02:28:50 +04:00
struct acpi_video_bus * video = seq - > private ;
2005-08-05 08:44:28 +04:00
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
2007-02-20 18:38:40 +03:00
" This indicates a BIOS bug. Please contact the manufacturer. \n " ) ;
2005-04-17 02:20:36 +04:00
}
printk ( " %lx \n " , options ) ;
2007-02-20 18:38:40 +03:00
seq_printf ( seq , " can POST: <integrated video> " ) ;
2005-04-17 02:20:36 +04:00
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
{
2006-10-01 02:28:50 +04:00
struct acpi_video_bus * video = seq - > private ;
2005-08-05 08:44:28 +04:00
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 ;
}
2007-02-20 18:38:40 +03: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
{
2006-10-01 02:28:50 +04:00
struct acpi_video_bus * video = 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 ;
2006-10-01 02:28:50 +04:00
struct seq_file * m = file - > private_data ;
struct acpi_video_bus * video = m - > private ;
2005-08-05 08:44:28 +04:00
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
2007-02-20 18:38:40 +03:00
/* just in case an OEM 'forgot' the motherboard... */
2005-04-17 02:20:36 +04:00
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 ;
2006-10-01 02:28:50 +04:00
struct seq_file * m = file - > private_data ;
struct acpi_video_bus * video = m - > private ;
2005-08-05 08:44:28 +04:00
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
2006-10-01 02:28:50 +04:00
video = 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
2006-10-01 02:28:50 +04:00
video = 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 */
2007-01-04 07:40:53 +03:00
static struct acpi_video_device_attrib *
acpi_video_get_device_attr ( struct acpi_video_bus * video , unsigned long device_id )
{
int count ;
for ( count = 0 ; count < video - > attached_count ; count + + )
if ( ( video - > attached_array [ count ] . value . int_val & 0xffff ) = = device_id )
return & ( video - > attached_array [ count ] . value . attrib ) ;
return NULL ;
}
2005-04-17 02:20:36 +04:00
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 ;
2007-01-04 07:40:53 +03:00
struct acpi_video_device_attrib * attribute ;
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 ) ) {
2006-12-19 23:56:11 +03:00
data = kzalloc ( sizeof ( struct acpi_video_device ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! data )
2006-06-27 08:41:40 +04:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
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 ;
2007-01-04 07:40:53 +03:00
attribute = acpi_video_get_device_attr ( video , device_id ) ;
if ( ( attribute ! = NULL ) & & attribute - > device_id_scheme ) {
switch ( attribute - > display_type ) {
case ACPI_VIDEO_DISPLAY_CRT :
data - > flags . crt = 1 ;
break ;
case ACPI_VIDEO_DISPLAY_TV :
data - > flags . tvout = 1 ;
break ;
case ACPI_VIDEO_DISPLAY_DVI :
data - > flags . dvi = 1 ;
break ;
case ACPI_VIDEO_DISPLAY_LCD :
data - > flags . lcd = 1 ;
break ;
default :
data - > flags . unknown = 1 ;
break ;
}
if ( attribute - > bios_can_detect )
data - > flags . bios = 1 ;
} else
2005-04-17 02:20:36 +04:00
data - > flags . unknown = 1 ;
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 ) ;
2006-05-20 00:54:48 +04:00
status = acpi_install_notify_handler ( device - > 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
2006-05-20 00:54:48 +04:00
status = acpi_evaluate_object ( video - > device - > handle , " _DOD " , NULL , & buffer ) ;
2005-04-17 02:20:36 +04:00
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
}
2006-10-01 02:28:50 +04:00
dod = 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 + + ) {
2006-10-01 02:28:50 +04:00
obj = & 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 :
2006-06-30 11:19:10 +04:00
kfree ( 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
2007-02-20 18:38:40 +03:00
* event : notify event
2005-04-17 02:20:36 +04:00
*
* Return :
* < 0 : error
*
* 1. Find out the current active output device .
2007-02-20 18:38:40 +03:00
* 2. Identify the next output device to switch to .
2005-04-17 02:20:36 +04:00
* 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
{
2006-12-19 23:56:14 +03:00
int min , max , min_above , max_below , i , l ;
max = max_below = 0 ;
min = min_above = 255 ;
for ( i = 0 ; i < device - > brightness - > count ; i + + ) {
l = device - > brightness - > levels [ i ] ;
if ( l < min )
min = l ;
if ( l > max )
max = l ;
if ( l < min_above & & l > level_current )
min_above = l ;
if ( l > max_below & & l < level_current )
max_below = l ;
}
switch ( event ) {
case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS :
return ( level_current < max ) ? min_above : min ;
case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS :
return ( level_current < max ) ? min_above : max ;
case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS :
return ( level_current > min ) ? max_below : min ;
case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS :
case ACPI_VIDEO_NOTIFY_DISPLAY_OFF :
return 0 ;
default :
return level_current ;
}
2005-04-17 02:20:36 +04:00
}
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 ) ;
2006-05-20 00:54:48 +04:00
status = acpi_remove_notify_handler ( device - > dev - > handle ,
2005-08-05 08:44:28 +04:00
ACPI_DEVICE_NOTIFY ,
acpi_video_device_notify ) ;
2007-02-11 02:07:48 +03:00
backlight_device_unregister ( device - > backlight ) ;
2007-05-09 17:07:05 +04:00
video_output_unregister ( device - > output_dev ) ;
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
{
2006-10-01 02:28:50 +04:00
struct acpi_video_bus * video = data ;
2005-08-05 08:44:28 +04:00
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 ) {
2007-02-20 18:38:40 +03:00
case ACPI_VIDEO_NOTIFY_SWITCH : /* User requested a switch,
2005-04-17 02:20:36 +04:00
* most likely via hotkey . */
acpi_bus_generate_event ( device , event , 0 ) ;
break ;
2007-02-20 18:38:40 +03:00
case ACPI_VIDEO_NOTIFY_PROBE : /* User plugged in or removed a video
2005-04-17 02:20:36 +04:00
* 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
{
2006-10-01 02:28:50 +04:00
struct acpi_video_device * video_device = data ;
2005-08-05 08:44:28 +04:00
struct acpi_device * device = NULL ;
2005-04-17 02:20:36 +04:00
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_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
2006-12-19 23:56:11 +03:00
video = kzalloc ( sizeof ( struct acpi_video_bus ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! video )
2006-06-27 08:41:40 +04:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
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 ) ;
2006-05-20 00:54:48 +04:00
status = acpi_install_notify_handler ( device - > 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
2006-10-01 02:28:50 +04:00
video = acpi_driver_data ( device ) ;
2005-04-17 02:20:36 +04:00
acpi_video_bus_stop_devices ( video ) ;
2006-05-20 00:54:48 +04:00
status = acpi_remove_notify_handler ( video - > device - > 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
}
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 ) ;