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