Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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