PageRenderTime 111ms CodeModel.GetById 9ms app.highlight 89ms RepoModel.GetById 1ms app.codeStats 1ms

/drivers/acpi/video.c

https://bitbucket.org/evzijst/gittest
C | 1989 lines | 1463 code | 366 blank | 160 comment | 188 complexity | 5fc8d624c21760458560ea2ef2fb4fa6 MD5 | raw file
   1/*
   2 *  video.c - ACPI Video Driver ($Revision:$)
   3 *
   4 *  Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
   5 *  Copyright (C) 2004 Bruno Ducrot <ducrot@poupinou.org>
   6 *
   7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   8 *
   9 *  This program is free software; you can redistribute it and/or modify
  10 *  it under the terms of the GNU General Public License as published by
  11 *  the Free Software Foundation; either version 2 of the License, or (at
  12 *  your option) any later version.
  13 *
  14 *  This program is distributed in the hope that it will be useful, but
  15 *  WITHOUT ANY WARRANTY; without even the implied warranty of
  16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 *  General Public License for more details.
  18 *
  19 *  You should have received a copy of the GNU General Public License along
  20 *  with this program; if not, write to the Free Software Foundation, Inc.,
  21 *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  22 *
  23 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  24 */
  25
  26#include <linux/kernel.h>
  27#include <linux/module.h>
  28#include <linux/init.h>
  29#include <linux/types.h>
  30#include <linux/list.h>
  31#include <linux/proc_fs.h>
  32#include <linux/seq_file.h>
  33
  34#include <asm/uaccess.h>
  35
  36#include <acpi/acpi_bus.h>
  37#include <acpi/acpi_drivers.h>
  38
  39#define ACPI_VIDEO_COMPONENT		0x08000000
  40#define ACPI_VIDEO_CLASS		"video"
  41#define ACPI_VIDEO_DRIVER_NAME		"ACPI Video Driver"
  42#define ACPI_VIDEO_BUS_NAME		"Video Bus"
  43#define ACPI_VIDEO_DEVICE_NAME		"Video Device"
  44#define ACPI_VIDEO_NOTIFY_SWITCH	0x80
  45#define ACPI_VIDEO_NOTIFY_PROBE		0x81
  46#define ACPI_VIDEO_NOTIFY_CYCLE		0x82
  47#define ACPI_VIDEO_NOTIFY_NEXT_OUTPUT	0x83
  48#define ACPI_VIDEO_NOTIFY_PREV_OUTPUT	0x84
  49
  50#define ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS	0x82
  51#define	ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS	0x83
  52#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS	0x84
  53#define ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS	0x85
  54#define ACPI_VIDEO_NOTIFY_DISPLAY_OFF		0x86
  55
  56
  57#define ACPI_VIDEO_HEAD_INVALID		(~0u - 1)
  58#define ACPI_VIDEO_HEAD_END		(~0u)
  59
  60
  61#define _COMPONENT		ACPI_VIDEO_COMPONENT
  62ACPI_MODULE_NAME		("acpi_video")
  63
  64MODULE_AUTHOR("Bruno Ducrot");
  65MODULE_DESCRIPTION(ACPI_VIDEO_DRIVER_NAME);
  66MODULE_LICENSE("GPL");
  67
  68static int acpi_video_bus_add (struct acpi_device *device);
  69static int acpi_video_bus_remove (struct acpi_device *device, int type);
  70static int acpi_video_bus_match (struct acpi_device *device, struct acpi_driver *driver);
  71
  72static struct acpi_driver acpi_video_bus = {
  73	.name = ACPI_VIDEO_DRIVER_NAME,
  74	.class = ACPI_VIDEO_CLASS,
  75	.ops = {
  76		.add = acpi_video_bus_add,
  77		.remove = acpi_video_bus_remove,
  78		.match = acpi_video_bus_match,
  79	},
  80};
  81
  82struct acpi_video_bus_flags {
  83	u8	multihead:1;	/* can switch video heads */
  84	u8	rom:1;		/* can retrieve a video rom */
  85	u8	post:1;		/* can configure the head to */
  86	u8	reserved:5;
  87};
  88
  89struct acpi_video_bus_cap {
  90	u8	_DOS:1; /*Enable/Disable output switching*/
  91	u8	_DOD:1; /*Enumerate all devices attached to display adapter*/
  92	u8	_ROM:1; /*Get ROM Data*/
  93	u8	_GPD:1; /*Get POST Device*/
  94	u8	_SPD:1; /*Set POST Device*/
  95	u8	_VPO:1; /*Video POST Options*/
  96	u8	reserved:2;
  97};
  98
  99struct acpi_video_device_attrib{
 100	u32	display_index:4; /* A zero-based instance of the Display*/
 101	u32	display_port_attachment:4; /*This field differenates displays type*/
 102	u32	display_type:4;	/*Describe the specific type in use*/
 103	u32	vendor_specific:4; /*Chipset Vendor Specifi*/ 
 104	u32	bios_can_detect:1; /*BIOS can detect the device*/
 105	u32	depend_on_vga:1; /*Non-VGA output device whose power is related to 
 106				   the VGA device.*/
 107	u32	pipe_id:3; /*For VGA multiple-head devices.*/
 108	u32	reserved:10; /*Must be 0*/
 109	u32	device_id_scheme:1; /*Device ID Scheme*/
 110};
 111
 112struct acpi_video_enumerated_device {
 113	union {
 114		u32 int_val;
 115		struct acpi_video_device_attrib	attrib;
 116	} value;
 117	struct acpi_video_device *bind_info;
 118};
 119
 120struct acpi_video_bus {
 121	acpi_handle	handle;
 122	u8	dos_setting;
 123	struct acpi_video_enumerated_device *attached_array;
 124	u8			attached_count;
 125	struct acpi_video_bus_cap	cap;
 126	struct acpi_video_bus_flags flags;
 127	struct semaphore	sem;
 128	struct list_head	video_device_list;
 129	struct proc_dir_entry 	*dir;
 130};
 131
 132struct acpi_video_device_flags {
 133	u8	crt:1;
 134	u8	lcd:1;
 135	u8	tvout:1;
 136	u8	bios:1;
 137	u8	unknown:1;
 138	u8	reserved:3;
 139};
 140
 141struct acpi_video_device_cap {
 142	u8	_ADR:1;	/*Return the unique ID */
 143	u8	_BCL:1; /*Query list of brightness control levels supported*/
 144	u8	_BCM:1; /*Set the brightness level*/
 145	u8	_DDC:1; /*Return the EDID for this device*/
 146	u8	_DCS:1; /*Return status of output device*/
 147	u8	_DGS:1; /*Query graphics state*/
 148	u8	_DSS:1; /*Device state set*/
 149	u8	_reserved:1;
 150};
 151
 152struct acpi_video_device_brightness {
 153	int	curr;
 154	int	count;
 155	int	*levels;
 156};
 157
 158struct acpi_video_device {
 159	acpi_handle		handle;
 160	unsigned long		device_id;
 161	struct acpi_video_device_flags	flags;
 162	struct acpi_video_device_cap	cap;
 163	struct list_head	entry;
 164	struct acpi_video_bus	*video;
 165	struct acpi_device	*dev;
 166	struct acpi_video_device_brightness *brightness;
 167};
 168
 169
 170/* bus */
 171static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file);
 172static struct file_operations acpi_video_bus_info_fops = {
 173	.open		= acpi_video_bus_info_open_fs,
 174	.read		= seq_read,
 175	.llseek		= seq_lseek,
 176	.release	= single_release,
 177};
 178
 179static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file);
 180static struct file_operations acpi_video_bus_ROM_fops = {
 181	.open		= acpi_video_bus_ROM_open_fs,
 182	.read		= seq_read,
 183	.llseek		= seq_lseek,
 184	.release	= single_release,
 185};
 186
 187static int acpi_video_bus_POST_info_open_fs(struct inode *inode, struct file *file);
 188static struct file_operations acpi_video_bus_POST_info_fops = {
 189	.open		= acpi_video_bus_POST_info_open_fs,
 190	.read		= seq_read,
 191	.llseek		= seq_lseek,
 192	.release	= single_release,
 193};
 194
 195static int acpi_video_bus_POST_open_fs(struct inode *inode, struct file *file);
 196static struct file_operations acpi_video_bus_POST_fops = {
 197	.open		= acpi_video_bus_POST_open_fs,
 198	.read		= seq_read,
 199	.llseek		= seq_lseek,
 200	.release	= single_release,
 201};
 202
 203
 204static int acpi_video_bus_DOS_open_fs(struct inode *inode, struct file *file);
 205static struct file_operations acpi_video_bus_DOS_fops = {
 206	.open		= acpi_video_bus_DOS_open_fs,
 207	.read		= seq_read,
 208	.llseek		= seq_lseek,
 209	.release	= single_release,
 210};
 211
 212/* device */
 213static int acpi_video_device_info_open_fs(struct inode *inode, struct file *file);
 214static struct file_operations acpi_video_device_info_fops = {
 215	.open		= acpi_video_device_info_open_fs,
 216	.read		= seq_read,
 217	.llseek		= seq_lseek,
 218	.release	= single_release,
 219};
 220
 221static int acpi_video_device_state_open_fs(struct inode *inode, struct file *file);
 222static struct file_operations acpi_video_device_state_fops = {
 223	.open		= acpi_video_device_state_open_fs,
 224	.read		= seq_read,
 225	.llseek		= seq_lseek,
 226	.release	= single_release,
 227};
 228
 229static int acpi_video_device_brightness_open_fs(struct inode *inode, struct file *file);
 230static struct file_operations acpi_video_device_brightness_fops = {
 231	.open		= acpi_video_device_brightness_open_fs,
 232	.read		= seq_read,
 233	.llseek		= seq_lseek,
 234	.release	= single_release,
 235};
 236
 237static int acpi_video_device_EDID_open_fs(struct inode *inode, struct file *file);
 238static struct file_operations acpi_video_device_EDID_fops = {
 239	.open		= acpi_video_device_EDID_open_fs,
 240	.read		= seq_read,
 241	.llseek		= seq_lseek,
 242	.release	= single_release,
 243};
 244
 245static char	device_decode[][30] = {
 246	"motherboard VGA device",
 247	"PCI VGA device",
 248	"AGP VGA device",
 249	"UNKNOWN",
 250};
 251
 252static void acpi_video_device_notify ( acpi_handle handle, u32 event, void *data);
 253static void acpi_video_device_rebind( struct acpi_video_bus *video);
 254static void acpi_video_device_bind( struct acpi_video_bus *video, struct acpi_video_device *device);
 255static int acpi_video_device_enumerate(struct acpi_video_bus *video);
 256static int acpi_video_switch_output( struct acpi_video_bus *video, int	event);
 257static int acpi_video_get_next_level( struct acpi_video_device *device, u32 level_current,u32 event);
 258static void acpi_video_switch_brightness ( struct acpi_video_device *device, int event);
 259
 260
 261/* --------------------------------------------------------------------------
 262                               Video Management
 263   -------------------------------------------------------------------------- */
 264
 265/* device */
 266
 267static int
 268acpi_video_device_query (
 269	struct acpi_video_device	*device,
 270	unsigned long			*state)
 271{
 272	int			status;
 273	ACPI_FUNCTION_TRACE("acpi_video_device_query");
 274	status = acpi_evaluate_integer(device->handle, "_DGS", NULL, state);
 275
 276	return_VALUE(status);
 277}
 278
 279static int
 280acpi_video_device_get_state (
 281	struct acpi_video_device	*device,
 282	unsigned long 		*state)
 283{
 284	int			status;
 285
 286	ACPI_FUNCTION_TRACE("acpi_video_device_get_state");
 287
 288	status = acpi_evaluate_integer(device->handle, "_DCS", NULL, state);
 289
 290	return_VALUE(status);
 291}
 292
 293static int
 294acpi_video_device_set_state (
 295	struct acpi_video_device	*device,
 296	int			state)
 297{
 298	int			status;
 299	union acpi_object	arg0 = {ACPI_TYPE_INTEGER};
 300	struct acpi_object_list	args = {1, &arg0};
 301
 302	ACPI_FUNCTION_TRACE("acpi_video_device_set_state");
 303
 304	arg0.integer.value = state;
 305	status = acpi_evaluate_integer(device->handle, "_DSS", &args, NULL);
 306
 307	return_VALUE(status);
 308}
 309
 310static int
 311acpi_video_device_lcd_query_levels (
 312	struct acpi_video_device	*device,
 313	union acpi_object		**levels)
 314{
 315	int			status;
 316	struct acpi_buffer	buffer = {ACPI_ALLOCATE_BUFFER, NULL};
 317	union acpi_object	*obj;
 318
 319
 320	ACPI_FUNCTION_TRACE("acpi_video_device_lcd_query_levels");
 321
 322	*levels = NULL;
 323
 324	status = acpi_evaluate_object(device->handle, "_BCL", NULL, &buffer);
 325	if (!ACPI_SUCCESS(status))
 326		return_VALUE(status);
 327	obj = (union acpi_object *) buffer.pointer;
 328	if (!obj && (obj->type != ACPI_TYPE_PACKAGE)) {
 329		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _BCL data\n"));
 330		status = -EFAULT;
 331		goto err;
 332	}
 333
 334	*levels = obj;
 335
 336	return_VALUE(0);
 337
 338err:
 339	if (buffer.pointer)
 340		kfree(buffer.pointer);
 341
 342	return_VALUE(status);
 343}
 344
 345static int
 346acpi_video_device_lcd_set_level (
 347	struct acpi_video_device	*device,
 348	int				level)
 349{
 350	int			status;
 351	union acpi_object	arg0 = {ACPI_TYPE_INTEGER};
 352	struct acpi_object_list	args = {1, &arg0};
 353
 354	ACPI_FUNCTION_TRACE("acpi_video_device_lcd_set_level");
 355
 356	arg0.integer.value = level;
 357	status = acpi_evaluate_object(device->handle, "_BCM", &args, NULL);
 358
 359	printk(KERN_DEBUG "set_level status: %x\n", status);
 360	return_VALUE(status);
 361}
 362
 363static int
 364acpi_video_device_lcd_get_level_current (
 365	struct acpi_video_device	*device,
 366	unsigned long 	*level)
 367{
 368	int			status;
 369	ACPI_FUNCTION_TRACE("acpi_video_device_lcd_get_level_current");
 370
 371	status = acpi_evaluate_integer(device->handle, "_BQC", NULL, level);
 372
 373	return_VALUE(status);
 374}
 375
 376static int
 377acpi_video_device_EDID (
 378	struct acpi_video_device	*device,
 379	union acpi_object		**edid,
 380	ssize_t				length)
 381{
 382	int			status;
 383	struct acpi_buffer	buffer = {ACPI_ALLOCATE_BUFFER, NULL};
 384	union acpi_object	*obj;
 385	union acpi_object	arg0 = {ACPI_TYPE_INTEGER};
 386	struct acpi_object_list	args = {1, &arg0};
 387
 388	ACPI_FUNCTION_TRACE("acpi_video_device_get_EDID");
 389
 390	*edid = NULL;
 391
 392	if (!device)
 393		return_VALUE(-ENODEV);
 394	if (length == 128)
 395		arg0.integer.value = 1;
 396	else if (length == 256)
 397		arg0.integer.value = 2;
 398	else
 399		return_VALUE(-EINVAL);
 400
 401	status = acpi_evaluate_object(device->handle, "_DDC", &args, &buffer);
 402	if (ACPI_FAILURE(status))
 403		return_VALUE(-ENODEV);
 404
 405	obj = (union acpi_object *) buffer.pointer;
 406
 407	if (obj && obj->type == ACPI_TYPE_BUFFER)
 408		*edid = obj;
 409	else {
 410		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _DDC data\n"));
 411		status = -EFAULT;
 412		kfree(obj);
 413	}
 414
 415	return_VALUE(status);
 416}
 417
 418
 419/* bus */
 420
 421static int
 422acpi_video_bus_set_POST (
 423	struct acpi_video_bus	*video,
 424	unsigned long		option)
 425{
 426	int			status;
 427	unsigned long		tmp;
 428	union acpi_object	arg0 = {ACPI_TYPE_INTEGER};
 429	struct acpi_object_list	args = {1, &arg0};
 430
 431	ACPI_FUNCTION_TRACE("acpi_video_bus_set_POST");
 432
 433	arg0.integer.value = option;
 434
 435	status = acpi_evaluate_integer(video->handle, "_SPD", &args, &tmp);
 436	if (ACPI_SUCCESS(status))
 437		status = tmp ? (-EINVAL):(AE_OK);
 438
 439	return_VALUE(status);
 440}
 441
 442static int
 443acpi_video_bus_get_POST (
 444	struct acpi_video_bus	*video,
 445	unsigned long		*id)
 446{
 447	int status;
 448
 449	ACPI_FUNCTION_TRACE("acpi_video_bus_get_POST");
 450
 451	status = acpi_evaluate_integer(video->handle, "_GPD", NULL, id);
 452
 453	return_VALUE(status);
 454}
 455
 456static int
 457acpi_video_bus_POST_options (
 458	struct acpi_video_bus	*video,
 459	unsigned long		*options)
 460{
 461	int			status;
 462	ACPI_FUNCTION_TRACE("acpi_video_bus_POST_options");
 463
 464	status = acpi_evaluate_integer(video->handle, "_VPO", NULL, options);
 465	*options &= 3;
 466
 467	return_VALUE(status);
 468}
 469
 470/*
 471 *  Arg:
 472 *  	video		: video bus device pointer
 473 *	bios_flag	: 
 474 *		0.	The system BIOS should NOT automatically switch(toggle)
 475 *			the active display output.
 476 *		1.	The system BIOS should automatically switch (toggle) the
 477 *			active display output. No swich event.
 478 *		2.	The _DGS value should be locked.
 479 *		3.	The system BIOS should not automatically switch (toggle) the
 480 *			active display output, but instead generate the display switch
 481 *			event notify code.
 482 *	lcd_flag	:
 483 *		0.	The system BIOS should automatically control the brightness level
 484 *			of the LCD, when the power changes from AC to DC
 485 *		1. 	The system BIOS should NOT automatically control the brightness 
 486 *			level of the LCD, when the power changes from AC to DC.
 487 * Return Value:
 488 * 		-1	wrong arg.
 489 */
 490
 491static int
 492acpi_video_bus_DOS(
 493	struct acpi_video_bus	*video,
 494	int			bios_flag,
 495	int			lcd_flag)
 496{
 497	acpi_integer		status = 0;
 498	union acpi_object	arg0 = {ACPI_TYPE_INTEGER};
 499	struct acpi_object_list	args = {1, &arg0};
 500
 501	ACPI_FUNCTION_TRACE("acpi_video_bus_DOS");
 502
 503	if (bios_flag < 0 || bios_flag >3 || lcd_flag < 0 || lcd_flag > 1){
 504		status = -1;
 505		goto Failed;
 506	}
 507	arg0.integer.value = (lcd_flag << 2) | bios_flag;
 508	video->dos_setting = arg0.integer.value;
 509	acpi_evaluate_object(video->handle, "_DOS", &args, NULL);
 510
 511Failed:
 512	return_VALUE(status);
 513}
 514
 515/*
 516 *  Arg:	
 517 *  	device	: video output device (LCD, CRT, ..)
 518 *
 519 *  Return Value:
 520 *  	None
 521 *
 522 *  Find out all required AML method defined under the output
 523 *  device.
 524 */
 525
 526static void
 527acpi_video_device_find_cap (struct acpi_video_device *device)
 528{
 529	acpi_integer		status;
 530	acpi_handle h_dummy1;
 531	int i;
 532	union acpi_object *obj = NULL;
 533	struct acpi_video_device_brightness *br = NULL;
 534
 535	ACPI_FUNCTION_TRACE("acpi_video_device_find_cap");
 536
 537	memset( &device->cap, 0, 4);
 538
 539    	if( ACPI_SUCCESS(acpi_get_handle(device->handle, "_ADR", &h_dummy1))) {
 540		device->cap._ADR = 1;
 541	}
 542    	if( ACPI_SUCCESS(acpi_get_handle(device->handle, "_BCL", &h_dummy1))) {
 543		device->cap._BCL= 1;
 544	}
 545    	if( ACPI_SUCCESS(acpi_get_handle(device->handle, "_BCM", &h_dummy1))) {
 546		device->cap._BCM= 1;
 547	}
 548    	if( ACPI_SUCCESS(acpi_get_handle(device->handle, "_DDC", &h_dummy1))) {
 549		device->cap._DDC= 1;
 550	}
 551    	if( ACPI_SUCCESS(acpi_get_handle(device->handle, "_DCS", &h_dummy1))) {
 552		device->cap._DCS = 1;
 553	}
 554    	if( ACPI_SUCCESS(acpi_get_handle(device->handle, "_DGS", &h_dummy1))) {
 555		device->cap._DGS = 1;
 556	}
 557    	if( ACPI_SUCCESS(acpi_get_handle(device->handle, "_DSS", &h_dummy1))) {
 558		device->cap._DSS = 1;
 559	}
 560
 561	status = acpi_video_device_lcd_query_levels(device, &obj);
 562
 563	if (obj && obj->type == ACPI_TYPE_PACKAGE && obj->package.count >= 2) {
 564		int count = 0;
 565		union acpi_object *o;
 566		
 567		br = kmalloc(sizeof &br, GFP_KERNEL);
 568		if (!br) {
 569			printk(KERN_ERR "can't allocate memory\n");
 570		} else {
 571			memset(br, 0, sizeof &br);
 572			br->levels = kmalloc(obj->package.count * sizeof &br->levels, GFP_KERNEL);
 573			if (!br->levels)
 574				goto out;
 575
 576			for (i = 0; i < obj->package.count; i++) {
 577				o = (union acpi_object *) &obj->package.elements[i];
 578				if (o->type != ACPI_TYPE_INTEGER) {
 579					ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data\n"));
 580					continue;
 581				}
 582				br->levels[count] = (u32) o->integer.value;
 583				count++;
 584			}
 585out:
 586			if (count < 2) {
 587				if (br->levels)
 588					kfree(br->levels);
 589				kfree(br);
 590			} else {
 591				br->count = count;
 592				device->brightness = br;
 593				ACPI_DEBUG_PRINT((ACPI_DB_INFO, "found %d brightness levels\n", count));
 594			}
 595		}
 596	}
 597
 598	if (obj)
 599		kfree(obj);
 600
 601	return_VOID;
 602}
 603
 604/*
 605 *  Arg:	
 606 *  	device	: video output device (VGA)
 607 *
 608 *  Return Value:
 609 *  	None
 610 *
 611 *  Find out all required AML method defined under the video bus device.
 612 */
 613
 614static void 
 615acpi_video_bus_find_cap (struct acpi_video_bus *video)
 616{
 617	acpi_handle	h_dummy1;
 618
 619	memset(&video->cap ,0, 4);
 620    	if( ACPI_SUCCESS(acpi_get_handle(video->handle, "_DOS", &h_dummy1))) {
 621		video->cap._DOS = 1;
 622	}
 623    	if( ACPI_SUCCESS(acpi_get_handle(video->handle, "_DOD", &h_dummy1))) {
 624		video->cap._DOD = 1;
 625	}
 626    	if( ACPI_SUCCESS(acpi_get_handle(video->handle, "_ROM", &h_dummy1))) {
 627		video->cap._ROM = 1;
 628	}
 629    	if( ACPI_SUCCESS(acpi_get_handle(video->handle, "_GPD", &h_dummy1))) {
 630		video->cap._GPD = 1;
 631	}
 632    	if( ACPI_SUCCESS(acpi_get_handle(video->handle, "_SPD", &h_dummy1))) {
 633		video->cap._SPD = 1;
 634	}
 635    	if( ACPI_SUCCESS(acpi_get_handle(video->handle, "_VPO", &h_dummy1))) {
 636		video->cap._VPO = 1;
 637	}
 638}
 639
 640/*
 641 * Check whether the video bus device has required AML method to
 642 * support the desired features
 643 */
 644
 645static int
 646acpi_video_bus_check (
 647	struct acpi_video_bus	*video)
 648{
 649	acpi_status		status = -ENOENT;
 650
 651
 652	ACPI_FUNCTION_TRACE("acpi_video_bus_check");
 653
 654	if (!video)
 655		return_VALUE(-EINVAL);
 656
 657	/* Since there is no HID, CID and so on for VGA driver, we have
 658	 * to check well known required nodes.
 659	 */
 660
 661	/* Does this device able to support video switching ? */
 662	if(video->cap._DOS){
 663		video->flags.multihead = 1;
 664		status = 0;
 665	}
 666
 667	/* Does this device able to retrieve a retrieve a video ROM ? */
 668	if(video->cap._ROM){
 669		video->flags.rom = 1;
 670		status = 0;
 671	}
 672
 673	/* Does this device able to configure which video device to POST ? */
 674	if(video->cap._GPD && video->cap._SPD && video->cap._VPO){
 675		video->flags.post = 1;
 676		status = 0;
 677	}
 678
 679	return_VALUE(status);
 680}
 681
 682/* --------------------------------------------------------------------------
 683                              FS Interface (/proc)
 684   -------------------------------------------------------------------------- */
 685
 686static struct proc_dir_entry	*acpi_video_dir;
 687
 688/* video devices */
 689
 690static int
 691acpi_video_device_info_seq_show (
 692	struct seq_file		*seq,
 693	void			*offset)
 694{
 695	struct acpi_video_device	*dev = (struct acpi_video_device *) seq->private;
 696
 697	ACPI_FUNCTION_TRACE("acpi_video_device_info_seq_show");
 698
 699	if (!dev)
 700		goto end;
 701
 702	seq_printf(seq, "device_id:    0x%04x\n", (u32) dev->device_id);
 703	seq_printf(seq, "type:         ");
 704	if (dev->flags.crt)
 705		seq_printf(seq, "CRT\n");
 706	else if (dev->flags.lcd)
 707		seq_printf(seq, "LCD\n");
 708	else if (dev->flags.tvout)
 709		seq_printf(seq, "TVOUT\n");
 710	else
 711		seq_printf(seq, "UNKNOWN\n");
 712
 713	seq_printf(seq,"known by bios: %s\n",
 714		   dev->flags.bios ? "yes":"no");
 715
 716end:
 717	return_VALUE(0);
 718}
 719
 720static int
 721acpi_video_device_info_open_fs (
 722	struct inode		*inode,
 723	struct file		*file)
 724{
 725	return single_open(file, acpi_video_device_info_seq_show,
 726			   PDE(inode)->data);
 727}
 728
 729static int  
 730acpi_video_device_state_seq_show (
 731	struct seq_file		*seq,
 732	void			*offset)
 733{
 734	int			status;
 735	struct acpi_video_device	*dev = (struct acpi_video_device *) seq->private;
 736	unsigned long	state;
 737
 738	ACPI_FUNCTION_TRACE("acpi_video_device_state_seq_show");
 739
 740	if (!dev)
 741		goto end;
 742
 743	status = acpi_video_device_get_state(dev, &state);
 744	seq_printf(seq, "state:     ");
 745	if (ACPI_SUCCESS(status))
 746		seq_printf(seq, "0x%02lx\n", state);
 747	else
 748		seq_printf(seq, "<not supported>\n");
 749
 750	status = acpi_video_device_query(dev, &state);
 751	seq_printf(seq, "query:     ");
 752	if (ACPI_SUCCESS(status))
 753		seq_printf(seq, "0x%02lx\n", state);
 754	else
 755		seq_printf(seq, "<not supported>\n");
 756
 757end:
 758	return_VALUE(0);
 759}
 760
 761static int
 762acpi_video_device_state_open_fs (
 763	struct inode		*inode,
 764	struct file		*file)
 765{
 766	return single_open(file, acpi_video_device_state_seq_show,
 767			   PDE(inode)->data);
 768}
 769
 770static ssize_t
 771acpi_video_device_write_state (
 772	struct file		*file,
 773	const char		__user *buffer,
 774	size_t			count,
 775	loff_t			*data)
 776{
 777	int			status;
 778	struct seq_file		*m = (struct seq_file *) file->private_data;
 779	struct acpi_video_device	*dev = (struct acpi_video_device *) m->private;
 780	char			str[12] = {0};
 781	u32			state = 0;
 782
 783	ACPI_FUNCTION_TRACE("acpi_video_device_write_state");
 784
 785	if (!dev || count + 1 > sizeof str)
 786		return_VALUE(-EINVAL);
 787
 788	if (copy_from_user(str, buffer, count))
 789		return_VALUE(-EFAULT);
 790
 791	str[count] = 0;
 792	state = simple_strtoul(str, NULL, 0);
 793	state &= ((1ul<<31) | (1ul<<30) | (1ul<<0));
 794
 795	status = acpi_video_device_set_state(dev, state);
 796
 797	if (status)
 798		return_VALUE(-EFAULT);
 799
 800	return_VALUE(count);
 801}
 802
 803static int
 804acpi_video_device_brightness_seq_show (
 805	struct seq_file		*seq,
 806	void			*offset)
 807{
 808	struct acpi_video_device	*dev = (struct acpi_video_device *) seq->private;
 809	int			i;
 810
 811	ACPI_FUNCTION_TRACE("acpi_video_device_brightness_seq_show");
 812
 813	if (!dev || !dev->brightness) {
 814		seq_printf(seq, "<not supported>\n");
 815		return_VALUE(0);
 816	}
 817
 818	seq_printf(seq, "levels: ");
 819	for (i = 0; i < dev->brightness->count; i++)
 820		seq_printf(seq, " %d", dev->brightness->levels[i]);
 821	seq_printf(seq, "\ncurrent: %d\n", dev->brightness->curr);
 822
 823	return_VALUE(0);
 824}
 825
 826static int
 827acpi_video_device_brightness_open_fs (
 828	struct inode		*inode,
 829	struct file		*file)
 830{
 831	return single_open(file, acpi_video_device_brightness_seq_show,
 832			   PDE(inode)->data);
 833}
 834
 835static ssize_t
 836acpi_video_device_write_brightness (
 837	struct file		*file,
 838	const char		__user *buffer,
 839	size_t			count,
 840	loff_t			*data)
 841{
 842	struct seq_file		*m = (struct seq_file *) file->private_data;
 843	struct acpi_video_device	*dev = (struct acpi_video_device *) m->private;
 844	char			str[4] = {0};
 845	unsigned int		level = 0;
 846	int			i;
 847
 848	ACPI_FUNCTION_TRACE("acpi_video_device_write_brightness");
 849
 850	if (!dev || count + 1 > sizeof str)
 851		return_VALUE(-EINVAL);
 852
 853	if (copy_from_user(str, buffer, count))
 854		return_VALUE(-EFAULT);
 855
 856	str[count] = 0;
 857	level = simple_strtoul(str, NULL, 0);
 858	
 859	if (level > 100)
 860		return_VALUE(-EFAULT);
 861
 862	/* validate though the list of available levels */
 863	for (i = 0; i < dev->brightness->count; i++)
 864		if (level == dev->brightness->levels[i]) {
 865			if (ACPI_SUCCESS(acpi_video_device_lcd_set_level(dev, level)))
 866				dev->brightness->curr = level;
 867			break;
 868		}
 869
 870	return_VALUE(count);
 871}
 872
 873static int
 874acpi_video_device_EDID_seq_show (
 875	struct seq_file		*seq,
 876	void			*offset)
 877{
 878	struct acpi_video_device	*dev = (struct acpi_video_device *) seq->private;
 879	int			status;
 880	int			i;
 881	union acpi_object	*edid = NULL;
 882
 883	ACPI_FUNCTION_TRACE("acpi_video_device_EDID_seq_show");
 884
 885	if (!dev)
 886		goto out;
 887
 888	status = acpi_video_device_EDID (dev, &edid, 128);
 889	if (ACPI_FAILURE(status)) {
 890		status = acpi_video_device_EDID (dev, &edid, 256);
 891	}
 892
 893	if (ACPI_FAILURE(status)) {
 894		goto out;
 895	}
 896
 897	if (edid && edid->type == ACPI_TYPE_BUFFER) {
 898		for (i = 0; i < edid->buffer.length; i++)
 899			seq_putc(seq, edid->buffer.pointer[i]);
 900	}
 901
 902out:
 903	if (!edid)
 904		seq_printf(seq, "<not supported>\n");
 905	else
 906		kfree(edid);
 907
 908	return_VALUE(0);
 909}
 910
 911static int
 912acpi_video_device_EDID_open_fs (
 913	struct inode		*inode,
 914	struct file		*file)
 915{
 916	return single_open(file, acpi_video_device_EDID_seq_show,
 917			   PDE(inode)->data);
 918}
 919
 920
 921static int
 922acpi_video_device_add_fs (
 923	struct acpi_device	*device)
 924{
 925	struct proc_dir_entry	*entry = NULL;
 926	struct acpi_video_device *vid_dev;
 927
 928	ACPI_FUNCTION_TRACE("acpi_video_device_add_fs");
 929
 930	if (!device)
 931		return_VALUE(-ENODEV);
 932
 933	vid_dev = (struct acpi_video_device *) acpi_driver_data(device);
 934	if (!vid_dev)
 935		return_VALUE(-ENODEV);
 936
 937	if (!acpi_device_dir(device)) {
 938		acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
 939				vid_dev->video->dir);
 940		if (!acpi_device_dir(device))
 941			return_VALUE(-ENODEV);
 942		acpi_device_dir(device)->owner = THIS_MODULE;
 943	}
 944
 945	/* 'info' [R] */
 946	entry = create_proc_entry("info", S_IRUGO, acpi_device_dir(device));
 947	if (!entry)
 948		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
 949			"Unable to create 'info' fs entry\n"));
 950	else {
 951		entry->proc_fops = &acpi_video_device_info_fops;
 952		entry->data = acpi_driver_data(device);
 953		entry->owner = THIS_MODULE;
 954	}
 955
 956	/* 'state' [R/W] */
 957	entry = create_proc_entry("state", S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
 958	if (!entry)
 959		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
 960			"Unable to create 'state' fs entry\n"));
 961	else {
 962		entry->proc_fops = &acpi_video_device_state_fops;
 963		entry->proc_fops->write = acpi_video_device_write_state;
 964		entry->data = acpi_driver_data(device);
 965		entry->owner = THIS_MODULE;
 966	}
 967
 968	/* 'brightness' [R/W] */
 969	entry = create_proc_entry("brightness", S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
 970	if (!entry)
 971		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
 972			"Unable to create 'brightness' fs entry\n"));
 973	else {
 974		entry->proc_fops = &acpi_video_device_brightness_fops;
 975		entry->proc_fops->write = acpi_video_device_write_brightness;
 976		entry->data = acpi_driver_data(device);
 977		entry->owner = THIS_MODULE;
 978	}
 979
 980	/* 'EDID' [R] */
 981	entry = create_proc_entry("EDID", S_IRUGO, acpi_device_dir(device));
 982	if (!entry)
 983		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
 984			"Unable to create 'brightness' fs entry\n"));
 985	else {
 986		entry->proc_fops = &acpi_video_device_EDID_fops;
 987		entry->data = acpi_driver_data(device);
 988		entry->owner = THIS_MODULE;
 989	}
 990
 991	return_VALUE(0);
 992}
 993
 994static int
 995acpi_video_device_remove_fs (
 996	struct acpi_device	*device)
 997{
 998	struct acpi_video_device *vid_dev;
 999	ACPI_FUNCTION_TRACE("acpi_video_device_remove_fs");
1000
1001	vid_dev = (struct acpi_video_device *) acpi_driver_data(device);
1002	if (!vid_dev || !vid_dev->video || !vid_dev->video->dir)
1003		return_VALUE(-ENODEV);
1004
1005	if (acpi_device_dir(device)) {
1006		remove_proc_entry("info", acpi_device_dir(device));
1007		remove_proc_entry("state", acpi_device_dir(device));
1008		remove_proc_entry("brightness", acpi_device_dir(device));
1009		remove_proc_entry("EDID", acpi_device_dir(device));
1010		remove_proc_entry(acpi_device_bid(device),
1011				 vid_dev->video->dir);
1012		acpi_device_dir(device) = NULL;
1013	}
1014
1015	return_VALUE(0);
1016}
1017
1018
1019/* video bus */
1020static int
1021acpi_video_bus_info_seq_show (
1022	struct seq_file		*seq,
1023	void			*offset)
1024{
1025	struct acpi_video_bus	*video = (struct acpi_video_bus *) seq->private;
1026
1027	ACPI_FUNCTION_TRACE("acpi_video_bus_info_seq_show");
1028
1029	if (!video)
1030		goto end;
1031
1032	seq_printf(seq, "Switching heads:              %s\n",
1033			video->flags.multihead ? "yes":"no");
1034	seq_printf(seq, "Video ROM:                    %s\n",
1035			video->flags.rom ? "yes":"no");
1036	seq_printf(seq, "Device to be POSTed on boot:  %s\n",
1037			video->flags.post ? "yes":"no");
1038
1039end:
1040	return_VALUE(0);
1041}
1042
1043static int
1044acpi_video_bus_info_open_fs (
1045	struct inode		*inode,
1046	struct file		*file)
1047{
1048	return single_open(file, acpi_video_bus_info_seq_show, PDE(inode)->data);
1049}
1050
1051static int
1052acpi_video_bus_ROM_seq_show (
1053	struct seq_file		*seq,
1054	void			*offset)
1055{
1056	struct acpi_video_bus	*video = (struct acpi_video_bus *) seq->private;
1057
1058	ACPI_FUNCTION_TRACE("acpi_video_bus_ROM_seq_show");
1059
1060	if (!video)
1061		goto end;
1062
1063	printk(KERN_INFO PREFIX "Please implement %s\n", __FUNCTION__);
1064	seq_printf(seq, "<TODO>\n");
1065
1066end:
1067	return_VALUE(0);
1068}
1069
1070static int
1071acpi_video_bus_ROM_open_fs (
1072	struct inode		*inode,
1073	struct file		*file)
1074{
1075	return single_open(file, acpi_video_bus_ROM_seq_show, PDE(inode)->data);
1076}
1077
1078static int
1079acpi_video_bus_POST_info_seq_show (
1080	struct seq_file		*seq,
1081	void			*offset)
1082{
1083	struct acpi_video_bus	*video = (struct acpi_video_bus *) seq->private;
1084	unsigned long		options;
1085	int			status;
1086
1087	ACPI_FUNCTION_TRACE("acpi_video_bus_POST_info_seq_show");
1088
1089	if (!video)
1090		goto end;
1091
1092	status = acpi_video_bus_POST_options(video, &options);
1093	if (ACPI_SUCCESS(status)) {
1094		if (!(options & 1)) {
1095			printk(KERN_WARNING PREFIX "The motherboard VGA device is not listed as a possible POST device.\n");
1096			printk(KERN_WARNING PREFIX "This indicate a BIOS bug.  Please contact the manufacturer.\n");
1097		}
1098		printk("%lx\n", options);
1099		seq_printf(seq, "can POST: <intgrated video>");
1100		if (options & 2)
1101			seq_printf(seq, " <PCI video>");
1102		if (options & 4)
1103			seq_printf(seq, " <AGP video>");
1104		seq_putc(seq, '\n');
1105	} else
1106		seq_printf(seq, "<not supported>\n");
1107end:
1108	return_VALUE(0);
1109}
1110
1111static int
1112acpi_video_bus_POST_info_open_fs (
1113	struct inode		*inode,
1114	struct file		*file)
1115{
1116	return single_open(file, acpi_video_bus_POST_info_seq_show, PDE(inode)->data);
1117}
1118
1119static int
1120acpi_video_bus_POST_seq_show (
1121	struct seq_file		*seq,
1122	void			*offset)
1123{
1124	struct acpi_video_bus	*video = (struct acpi_video_bus *) seq->private;
1125	int			status;
1126	unsigned long		id;
1127
1128	ACPI_FUNCTION_TRACE("acpi_video_bus_POST_seq_show");
1129
1130	if (!video)
1131		goto end;
1132
1133	status = acpi_video_bus_get_POST (video, &id);
1134	if (!ACPI_SUCCESS(status)) {
1135		seq_printf(seq, "<not supported>\n");
1136		goto end;
1137	}
1138	seq_printf(seq, "device posted is <%s>\n",  device_decode[id & 3]);
1139
1140end:
1141	return_VALUE(0);
1142}
1143
1144static int
1145acpi_video_bus_DOS_seq_show (
1146	struct seq_file		*seq,
1147	void			*offset)
1148{
1149	struct acpi_video_bus	*video = (struct acpi_video_bus *) seq->private;
1150
1151	ACPI_FUNCTION_TRACE("acpi_video_bus_DOS_seq_show");
1152
1153	seq_printf(seq, "DOS setting: <%d>\n", video->dos_setting );
1154
1155	return_VALUE(0);
1156}
1157
1158static int
1159acpi_video_bus_POST_open_fs (
1160	struct inode		*inode,
1161	struct file		*file)
1162{
1163	return single_open(file, acpi_video_bus_POST_seq_show, PDE(inode)->data);
1164}
1165
1166static int
1167acpi_video_bus_DOS_open_fs (
1168	struct inode		*inode,
1169	struct file		*file)
1170{
1171	return single_open(file, acpi_video_bus_DOS_seq_show, PDE(inode)->data);
1172}
1173
1174static ssize_t
1175acpi_video_bus_write_POST (
1176	struct file		*file,
1177	const char		__user *buffer,
1178	size_t			count,
1179	loff_t			*data)
1180{
1181	int			status;
1182	struct seq_file		*m = (struct seq_file *) file->private_data;
1183	struct acpi_video_bus	*video = (struct acpi_video_bus *) m->private;
1184	char			str[12] = {0};
1185	unsigned long		opt, options;
1186
1187	ACPI_FUNCTION_TRACE("acpi_video_bus_write_POST");
1188
1189
1190	if (!video || count + 1 > sizeof str)
1191		return_VALUE(-EINVAL);
1192
1193	status = acpi_video_bus_POST_options(video, &options);
1194	if (!ACPI_SUCCESS(status))
1195		return_VALUE(-EINVAL);
1196
1197	if (copy_from_user(str, buffer, count))
1198		return_VALUE(-EFAULT);
1199
1200	str[count] = 0;
1201	opt = strtoul(str, NULL, 0);
1202	if (opt > 3)
1203		return_VALUE(-EFAULT);
1204
1205	/* just in case an OEM 'forget' the motherboard... */
1206	options |= 1;
1207
1208	if (options & (1ul << opt)) {
1209		status = acpi_video_bus_set_POST (video, opt);
1210		if (!ACPI_SUCCESS(status))
1211			return_VALUE(-EFAULT);
1212
1213	}
1214
1215
1216	return_VALUE(count);
1217}
1218
1219static ssize_t
1220acpi_video_bus_write_DOS (
1221	struct file		*file,
1222	const char		__user *buffer,
1223	size_t			count,
1224	loff_t			*data)
1225{
1226	int			status;
1227	struct seq_file		*m = (struct seq_file *) file->private_data;
1228	struct acpi_video_bus	*video = (struct acpi_video_bus *) m->private;
1229	char			str[12] = {0};
1230	unsigned long		opt;
1231
1232	ACPI_FUNCTION_TRACE("acpi_video_bus_write_DOS");
1233
1234
1235	if (!video || count + 1 > sizeof str)
1236		return_VALUE(-EINVAL);
1237
1238	if (copy_from_user(str, buffer, count))
1239		return_VALUE(-EFAULT);
1240
1241	str[count] = 0;
1242	opt = strtoul(str, NULL, 0);
1243	if (opt > 7)
1244		return_VALUE(-EFAULT);
1245
1246	status = acpi_video_bus_DOS (video, opt & 0x3, (opt & 0x4)>>2);
1247
1248	if (!ACPI_SUCCESS(status))
1249		return_VALUE(-EFAULT);
1250
1251	return_VALUE(count);
1252}
1253
1254static int
1255acpi_video_bus_add_fs (
1256	struct acpi_device	*device)
1257{
1258	struct proc_dir_entry	*entry = NULL;
1259	struct acpi_video_bus	*video;
1260
1261	ACPI_FUNCTION_TRACE("acpi_video_bus_add_fs");
1262
1263	video = (struct acpi_video_bus *) acpi_driver_data(device);
1264
1265	if (!acpi_device_dir(device)) {
1266		acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
1267				acpi_video_dir);
1268		if (!acpi_device_dir(device))
1269			return_VALUE(-ENODEV);
1270		video->dir = acpi_device_dir(device);
1271		acpi_device_dir(device)->owner = THIS_MODULE;
1272	}
1273
1274	/* 'info' [R] */
1275	entry = create_proc_entry("info", S_IRUGO, acpi_device_dir(device));
1276	if (!entry)
1277		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to create 'info' fs entry\n"));
1278	else {
1279		entry->proc_fops = &acpi_video_bus_info_fops;
1280		entry->data = acpi_driver_data(device);
1281		entry->owner = THIS_MODULE;
1282	}
1283
1284	/* 'ROM' [R] */
1285	entry = create_proc_entry("ROM", S_IRUGO, acpi_device_dir(device));
1286	if (!entry)
1287		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to create 'ROM' fs entry\n"));
1288	else {
1289		entry->proc_fops = &acpi_video_bus_ROM_fops;
1290		entry->data = acpi_driver_data(device);
1291		entry->owner = THIS_MODULE;
1292	}
1293
1294	/* 'POST_info' [R] */
1295	entry = create_proc_entry("POST_info", S_IRUGO, acpi_device_dir(device));
1296	if (!entry)
1297		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to create 'POST_info' fs entry\n"));
1298	else {
1299		entry->proc_fops = &acpi_video_bus_POST_info_fops;
1300		entry->data = acpi_driver_data(device);
1301		entry->owner = THIS_MODULE;
1302	}
1303
1304	/* 'POST' [R/W] */
1305	entry = create_proc_entry("POST", S_IFREG|S_IRUGO|S_IRUSR, acpi_device_dir(device));
1306	if (!entry)
1307		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to create 'POST' fs entry\n"));
1308	else {
1309		entry->proc_fops = &acpi_video_bus_POST_fops;
1310		entry->proc_fops->write = acpi_video_bus_write_POST;
1311		entry->data = acpi_driver_data(device);
1312		entry->owner = THIS_MODULE;
1313	}
1314
1315	/* 'DOS' [R/W] */
1316	entry = create_proc_entry("DOS", S_IFREG|S_IRUGO|S_IRUSR, acpi_device_dir(device));
1317	if (!entry)
1318		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to create 'DOS' fs entry\n"));
1319	else {
1320		entry->proc_fops = &acpi_video_bus_DOS_fops;
1321		entry->proc_fops->write = acpi_video_bus_write_DOS;
1322		entry->data = acpi_driver_data(device);
1323		entry->owner = THIS_MODULE;
1324	}
1325
1326	return_VALUE(0);
1327}
1328
1329static int
1330acpi_video_bus_remove_fs (
1331	struct acpi_device	*device)
1332{
1333	struct acpi_video_bus	*video;
1334
1335	ACPI_FUNCTION_TRACE("acpi_video_bus_remove_fs");
1336
1337	video = (struct acpi_video_bus *) acpi_driver_data(device);
1338
1339	if (acpi_device_dir(device)) {
1340		remove_proc_entry("info", acpi_device_dir(device));
1341		remove_proc_entry("ROM", acpi_device_dir(device));
1342		remove_proc_entry("POST_info", acpi_device_dir(device));
1343		remove_proc_entry("POST", acpi_device_dir(device));
1344		remove_proc_entry("DOS", acpi_device_dir(device));
1345		remove_proc_entry(acpi_device_bid(device),
1346				acpi_video_dir); 
1347		acpi_device_dir(device) = NULL;
1348	}
1349
1350	return_VALUE(0);
1351}
1352
1353/* --------------------------------------------------------------------------
1354                                 Driver Interface
1355   -------------------------------------------------------------------------- */
1356
1357/* device interface */
1358
1359static int
1360acpi_video_bus_get_one_device (
1361	struct acpi_device	*device,
1362	struct acpi_video_bus	*video)
1363{
1364	unsigned long		device_id;
1365	int			status, result;
1366	struct acpi_video_device	*data;
1367
1368	ACPI_FUNCTION_TRACE("acpi_video_bus_get_one_device");
1369
1370	if (!device || !video)
1371		return_VALUE(-EINVAL);
1372
1373	status = acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
1374	if (ACPI_SUCCESS(status)) {
1375
1376		data = kmalloc(sizeof(struct acpi_video_device), GFP_KERNEL);
1377		if (!data)
1378			return_VALUE(-ENOMEM);
1379
1380		memset(data, 0, sizeof(struct acpi_video_device));
1381
1382		data->handle = device->handle;
1383		strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME);
1384		strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
1385		acpi_driver_data(device) = data;
1386
1387		data->device_id = device_id;
1388		data->video = video;
1389		data->dev = device;
1390
1391		switch (device_id & 0xffff) {
1392		case 0x0100:
1393			data->flags.crt = 1;
1394			break;
1395		case 0x0400:
1396			data->flags.lcd = 1;
1397			break;
1398		case 0x0200:
1399			data->flags.tvout = 1;
1400			break;
1401		default:
1402			data->flags.unknown = 1;
1403			break;
1404		}
1405		
1406		acpi_video_device_bind(video, data);
1407		acpi_video_device_find_cap(data);
1408
1409		status = acpi_install_notify_handler(data->handle,
1410			ACPI_DEVICE_NOTIFY, acpi_video_device_notify, data);
1411		if (ACPI_FAILURE(status)) {
1412			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1413				"Error installing notify handler\n"));
1414			result = -ENODEV;
1415			goto end;
1416		}
1417
1418		down(&video->sem);
1419		list_add_tail(&data->entry, &video->video_device_list);
1420		up(&video->sem);
1421
1422		acpi_video_device_add_fs(device);
1423
1424		return_VALUE(0);
1425	}
1426
1427end:
1428	return_VALUE(-ENOENT);
1429}
1430
1431/*
1432 *  Arg:
1433 *  	video	: video bus device 
1434 *
1435 *  Return:
1436 *  	none
1437 *  
1438 *  Enumerate the video device list of the video bus, 
1439 *  bind the ids with the corresponding video devices
1440 *  under the video bus.
1441 */  
1442
1443static void
1444acpi_video_device_rebind( struct acpi_video_bus *video)
1445{
1446	struct list_head * node, * next;
1447	list_for_each_safe(node, next, &video->video_device_list) {
1448		struct acpi_video_device * dev = container_of(node, struct acpi_video_device, entry);
1449		acpi_video_device_bind( video, dev);
1450	}
1451}
1452
1453/*
1454 *  Arg:
1455 *  	video	: video bus device 
1456 *  	device	: video output device under the video 
1457 *  		bus
1458 *
1459 *  Return:
1460 *  	none
1461 *  
1462 *  Bind the ids with the corresponding video devices
1463 *  under the video bus.
1464 */  
1465
1466static void
1467acpi_video_device_bind( struct acpi_video_bus *video,
1468			struct acpi_video_device *device)
1469{
1470	int	i;
1471	ACPI_FUNCTION_TRACE("acpi_video_device_bind");
1472
1473#define IDS_VAL(i) video->attached_array[i].value.int_val
1474#define IDS_BIND(i) video->attached_array[i].bind_info
1475	
1476	for (i = 0; IDS_VAL(i) != ACPI_VIDEO_HEAD_INVALID && 
1477		i < video->attached_count; i++) {
1478		if (device->device_id == (IDS_VAL(i)& 0xffff)) {
1479			IDS_BIND(i) = device;
1480			ACPI_DEBUG_PRINT((ACPI_DB_INFO, "device_bind %d\n", i));
1481		}
1482	}
1483#undef IDS_VAL
1484#undef IDS_BIND
1485}
1486
1487/*
1488 *  Arg:
1489 *  	video	: video bus device 
1490 *
1491 *  Return:
1492 *  	< 0	: error
1493 *  
1494 *  Call _DOD to enumerate all devices attached to display adapter
1495 *
1496 */  
1497
1498static int acpi_video_device_enumerate(struct acpi_video_bus *video)
1499{
1500	int			status;
1501	int			count;
1502	int			i;
1503	struct acpi_video_enumerated_device *active_device_list;
1504	struct acpi_buffer	buffer = {ACPI_ALLOCATE_BUFFER, NULL};
1505	union acpi_object	*dod = NULL;
1506	union acpi_object	*obj;
1507
1508	ACPI_FUNCTION_TRACE("acpi_video_device_enumerate");
1509
1510	status = acpi_evaluate_object(video->handle, "_DOD", NULL, &buffer);
1511	if (!ACPI_SUCCESS(status)) {
1512		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _DOD\n"));
1513		return_VALUE(status);
1514	}
1515
1516	dod = (union acpi_object *) buffer.pointer;
1517	if (!dod || (dod->type != ACPI_TYPE_PACKAGE)) {
1518		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _DOD data\n"));
1519		status = -EFAULT;
1520		goto out;
1521	}
1522
1523	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d video heads in _DOD\n",
1524		dod->package.count));
1525
1526	active_device_list= kmalloc(
1527 		(1+dod->package.count)*sizeof(struct acpi_video_enumerated_device),
1528	       	GFP_KERNEL);
1529
1530	if (!active_device_list) {
1531		status = -ENOMEM;
1532		goto out;
1533	}
1534
1535	count = 0;
1536	for (i = 0; i < dod->package.count; i++) {
1537		obj = (union acpi_object *) &dod->package.elements[i];
1538
1539		if (obj->type != ACPI_TYPE_INTEGER) {
1540			ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _DOD data\n"));
1541			active_device_list[i].value.int_val = ACPI_VIDEO_HEAD_INVALID;
1542		}
1543		active_device_list[i].value.int_val = obj->integer.value;
1544		active_device_list[i].bind_info = NULL;
1545		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "dod element[%d] = %d\n", i, (int) obj->integer.value));
1546		count++;
1547	}
1548	active_device_list[count].value.int_val = ACPI_VIDEO_HEAD_END;
1549
1550	if(video->attached_array)
1551		kfree(video->attached_array);
1552	
1553	video->attached_array = active_device_list;
1554	video->attached_count = count;
1555out:
1556	acpi_os_free(buffer.pointer);
1557	return_VALUE(status);
1558}
1559
1560/*
1561 *  Arg:
1562 *  	video	: video bus device 
1563 *  	event	: Nontify Event
1564 *
1565 *  Return:
1566 *  	< 0	: error
1567 *  
1568 *	1. Find out the current active output device.
1569 *	2. Identify the next output device to switch
1570 *	3. call _DSS to do actual switch.
1571 */  
1572
1573static int 
1574acpi_video_switch_output(
1575	struct acpi_video_bus *video, 
1576	int	event)
1577{
1578	struct list_head * node, * next;
1579	struct acpi_video_device *dev=NULL;
1580       	struct acpi_video_device *dev_next=NULL;
1581	struct acpi_video_device *dev_prev=NULL;
1582	unsigned long state;
1583	int status = 0;
1584
1585	ACPI_FUNCTION_TRACE("acpi_video_switch_output");
1586
1587	list_for_each_safe(node, next, &video->video_device_list) {
1588		struct acpi_video_device * dev = container_of(node, struct acpi_video_device, entry);
1589		status = acpi_video_device_get_state(dev, &state);
1590		if (state & 0x2){
1591			dev_next = container_of(node->next, struct acpi_video_device, entry);
1592			dev_prev = container_of(node->prev, struct acpi_video_device, entry);
1593			goto out;
1594		}
1595	}
1596	dev_next = container_of(node->next, struct acpi_video_device, entry);
1597	dev_prev = container_of(node->prev, struct acpi_video_device, entry);
1598out:	
1599	switch (event) {
1600	case ACPI_VIDEO_NOTIFY_CYCLE:
1601	case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT:
1602		acpi_video_device_set_state(dev, 0);
1603		acpi_video_device_set_state(dev_next, 0x80000001);
1604		break;
1605	case ACPI_VIDEO_NOTIFY_PREV_OUTPUT:
1606		acpi_video_device_set_state(dev, 0);
1607		acpi_video_device_set_state(dev_prev, 0x80000001);
1608	default:
1609		break;
1610	}
1611
1612	return_VALUE(status);
1613}
1614
1615static int 
1616acpi_video_get_next_level(
1617	struct acpi_video_device *device,
1618	u32	level_current,
1619	u32	event)
1620{
1621	/*Fix me*/
1622	return level_current;
1623}
1624
1625
1626static void
1627acpi_video_switch_brightness (
1628	struct acpi_video_device *device, 
1629	int	event)
1630{
1631	unsigned long level_current, level_next;
1632	acpi_video_device_lcd_get_level_current(device, &level_current);
1633	level_next = acpi_video_get_next_level(device, level_current, event);
1634	acpi_video_device_lcd_set_level(device, level_next);
1635}
1636
1637static int
1638acpi_video_bus_get_devices (
1639	struct acpi_video_bus	*video,
1640	struct acpi_device	*device)
1641{
1642	int			status = 0;
1643	struct list_head	*node, *next;
1644
1645	ACPI_FUNCTION_TRACE("acpi_video_get_devices");
1646
1647	acpi_video_device_enumerate(video);
1648
1649	list_for_each_safe(node, next, &device->children) {
1650		struct acpi_device *dev = list_entry(node, struct acpi_device, node);
1651
1652		if (!dev)
1653			continue;
1654
1655		status = acpi_video_bus_get_one_device(dev, video);
1656		if (ACPI_FAILURE(status)) {
1657			ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Cant attach device\n"));
1658			continue;
1659		}
1660
1661	}
1662	return_VALUE(status);
1663}
1664
1665static int
1666acpi_video_bus_put_one_device(
1667	struct acpi_video_device	*device)
1668{
1669	struct acpi_video_bus *video;
1670
1671	ACPI_FUNCTION_TRACE("acpi_video_bus_put_one_device");
1672
1673	if (!device || !device->video)
1674		return_VALUE(-ENOENT);
1675
1676	video = device->video;
1677
1678	down(&video->sem);
1679	list_del(&device->entry);
1680	up(&video->sem);
1681	acpi_video_device_remove_fs(device->dev);
1682
1683	return_VALUE(0);
1684}
1685
1686static int
1687acpi_video_bus_put_devices (
1688	struct acpi_video_bus	*video)
1689{
1690	int			status;
1691	struct list_head	*node, *next;
1692
1693	ACPI_FUNCTION_TRACE("acpi_video_bus_put_devices");
1694
1695	list_for_each_safe(node, next, &video->video_device_list) {
1696		struct acpi_video_device *data = list_entry(node, struct acpi_video_device, entry);
1697		if (!data)
1698			continue;
1699
1700		status = acpi_video_bus_put_one_device(data);
1701		if(ACPI_FAILURE(status))
1702			printk(KERN_WARNING PREFIX "hhuuhhuu bug in acpi video driver.\n");
1703
1704		if (data->brightness)
1705			kfree(data->brightness);
1706
1707		kfree(data);
1708	}
1709
1710	return_VALUE(0);
1711}
1712
1713/* acpi_video interface */
1714
1715static int
1716acpi_video_bus_start_devices(
1717	struct acpi_video_bus	*video)
1718{
1719	return acpi_video_bus_DOS(video, 1, 0);
1720}
1721
1722static int
1723acpi_video_bus_stop_devices(
1724	struct acpi_video_bus	*video)
1725{
1726	return acpi_video_bus_DOS(video, 0, 1);
1727}
1728
1729static void
1730acpi_video_bus_notify (
1731	acpi_handle		handle,
1732	u32			event,
1733	void			*data)
1734{
1735	struct acpi_video_bus	*video = (struct acpi_video_bus *) data;
1736	struct acpi_device	*device = NULL;
1737
1738	ACPI_FUNCTION_TRACE("acpi_video_bus_notify");
1739	printk("video bus notify\n");
1740
1741	if (!video)
1742		return_VOID;
1743
1744	if (acpi_bus_get_device(handle, &device))
1745		return_VOID;
1746
1747	switch (event) {
1748	case ACPI_VIDEO_NOTIFY_SWITCH:	/* User request that a switch occur,
1749					 * most likely via hotkey. */
1750		acpi_bus_generate_event(device, event, 0);
1751		break;
1752
1753	case ACPI_VIDEO_NOTIFY_PROBE:	/* User plug or remove a video
1754					 * connector. */
1755		acpi_video_device_enumerate(video);
1756		acpi_video_device_rebind(video);
1757		acpi_video_switch_output(video, event);
1758		acpi_bus_generate_event(device, event, 0);
1759		break;
1760
1761	case ACPI_VIDEO_NOTIFY_CYCLE: /* Cycle Display output hotkey pressed.*/
1762	case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT: /* Next Display output hotkey pressed. */
1763	case ACPI_VIDEO_NOTIFY_PREV_OUTPUT: /* previous Display output hotkey pressed. */
1764		acpi_video_switch_output(video, event);
1765		acpi_bus_generate_event(device, event, 0);
1766		break;
1767
1768	default:
1769		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
1770			"Unsupported event [0x%x]\n", event));
1771		break;
1772	}
1773
1774	return_VOID;
1775}
1776
1777static void
1778acpi_video_device_notify (
1779	acpi_handle		handle,
1780	u32			event,
1781	void			*data)
1782{
1783	struct acpi_video_device	*video_device = (struct acpi_video_device *) data;
1784	struct acpi_device	*device = NULL;
1785
1786	ACPI_FUNCTION_TRACE("acpi_video_device_notify");
1787
1788	printk("video device notify\n");
1789	if (!video_device)
1790		return_VOID;
1791
1792	if (acpi_bus_get_device(handle, &device))
1793		return_VOID;
1794
1795	switch (event) {
1796	case ACPI_VIDEO_NOTIFY_SWITCH: /* change in status (cycle output device) */
1797	case ACPI_VIDEO_NOTIFY_PROBE: /* change in status (output device status) */
1798		acpi_bus_generate_event(device, event, 0);
1799		break;
1800	case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: /* Cycle brightness */
1801	case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: /* Increase brightness */
1802	case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: /* Decrease brightness */
1803	case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightnesss */
1804	case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: /* display device off */
1805		acpi_video_switch_brightness (video_device, event);
1806		acpi_bus_generate_event(device, event, 0);
1807		break;
1808	default:
1809		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
1810			"Unsupported event [0x%x]\n", event));
1811		break;
1812	}
1813	return_VOID;
1814}
1815
1816static int
1817acpi_video_bus_add (
1818	struct acpi_device	*device)
1819{
1820	int			result = 0;
1821	acpi_status		status = 0;
1822	struct acpi_video_bus	*video = NULL;
1823
1824	ACPI_FUNCTION_TRACE("acpi_video_bus_add");
1825	
1826	if (!device)
1827		return_VALUE(-EINVAL);
1828
1829	video = kmalloc(sizeof(struct acpi_video_bus), GFP_KERNEL);
1830	if (!video)
1831		return_VALUE(-ENOMEM);
1832	memset(video, 0, sizeof(struct acpi_video_bus));
1833
1834	video->handle = device->handle;
1835	strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME);
1836	strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
1837	acpi_driver_data(device) = video;
1838
1839	acpi_video_bus_find_cap(video);
1840	result = acpi_video_bus_check(video);
1841	if (result)
1842		goto end;
1843
1844	result = acpi_video_bus_add_fs(device);
1845	if (result)
1846		goto end;
1847
1848	init_MUTEX(&video->sem);
1849	INIT_LIST_HEAD(&video->video_device_list);
1850
1851	acpi_video_bus_get_devices(video, device);
1852	acpi_video_bus_start_devices(video);
1853
1854	status = acpi_install_notify_handler(video->handle,
1855		ACPI_DEVICE_NOTIFY, acpi_video_bus_notify, video);
1856	if (ACPI_FAILURE(status)) {
1857		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1858			"Error installing notify handler\n"));
1859		result = -ENODEV;
1860		goto end;
1861	}
1862
1863	printk(KERN_INFO PREFIX "%s [%s] (multi-head: %s  rom: %s  post: %s)\n",
1864		ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device),
1865		video->flags.multihead ? "yes":"no",
1866		video->flags.rom ? "yes":"no",
1867		video->flags.post ? "yes":"no");
1868
1869end:
1870	if (result) {
1871		acpi_video_bus_remove_fs(device);
1872		kfree(video);
1873	}
1874
1875	return_VALUE(result);
1876}
1877
1878static int
1879acpi_video_bus_remove (
1880	struct acpi_device	*device,
1881	int			type)
1882{
1883	acpi_status		status = 0;
1884	struct acpi_video_bus	*video = NULL;
1885
1886	ACPI_FUNCTION_TRACE("acpi_video_bus_remove");
1887
1888	if (!device || !acpi_driver_data(device))
1889		return_VALUE(-EINVAL);
1890
1891	video = (struct acpi_video_bus *) acpi_driver_data(device);
1892
1893	acpi_video_bus_stop_devices(video);
1894
1895	status = acpi_remove_notify_handler(video->handle,
1896		ACPI_DEVICE_NOTIFY, acpi_video_bus_notify);
1897	if (ACPI_FAILURE(status))
1898		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1899			"Error removing notify handler\n"));
1900
1901	acpi_video_bus_put_devices(video);
1902	acpi_video_bus_remove_fs(device);
1903
1904	if (video->attached_array)
1905		kfree(video->attached_array);
1906	kfree(video);
1907
1908	return_VALUE(0);
1909}
1910
1911
1912static int
1913acpi_video_bus_match (
1914	struct acpi_device	*device,
1915	struct acpi_driver	*driver)
1916{
1917	acpi_handle		h_dummy1;
1918	acpi_handle		h_dummy2;
1919	acpi_handle		h_dummy3;
1920
1921	ACPI_FUNCTION_TRACE("acpi_video_bus_match");
1922
1923	if (!device || !driver)
1924		return_VALUE(-EINVAL);
1925
1926	/* Since there is no HID, CID for ACPI Video drivers, we have
1927	 * to check well known required nodes for each feature we support.
1928	 */
1929
1930	/* Does this device able to support video switching ? */
1931	if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) &&
1932	    ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2)))
1933		return_VALUE(0);
1934
1935	/* Does this device able to retrieve a video ROM ? */
1936	if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1)))
1937		return_VALUE(0);
1938
1939	/* Does this device able to configure which video head to be POSTed ? */
1940	if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) &&
1941	    ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) &&
1942	    ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3)))
1943		return_VALUE(0);
1944
1945
1946	return_VALUE(-ENODEV);
1947}
1948
1949
1950static int __init
1951acpi_video_init (void)
1952{
1953	int			result = 0;
1954
1955	ACPI_FUNCTION_TRACE("acpi_video_init");
1956
1957	/*
1958	acpi_dbg_level = 0xFFFFFFFF;
1959	acpi_dbg_layer = 0x08000000;
1960	*/
1961
1962	acpi_video_dir = proc_mkdir(ACPI_VIDEO_CLASS, acpi_root_dir);
1963	if (!acpi_video_dir)
1964		return_VALUE(-ENODEV);
1965	acpi_video_dir->owner = THIS_MODULE;
1966
1967	result = acpi_bus_register_driver(&acpi_video_bus);
1968	if (result < 0) {
1969		remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
1970		return_VALUE(-ENODEV);
1971	}
1972
1973	return_VALUE(0);
1974}
1975
1976static void __exit
1977acpi_video_exit (void)
1978{
1979	ACPI_FUNCTION_TRACE("acpi_video_exit");
1980
1981	acpi_bus_unregister_driver(&acpi_video_bus);
1982
1983	remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
1984
1985	return_VOID;
1986}
1987
1988module_init(acpi_video_init);
1989module_exit(acpi_video_exit);