Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.12-rc2 1989 lines 49 kB view raw
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);