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 <linux/sort.h>
  40#include <asm/uaccess.h>
  41
  42#include <acpi/acpi_bus.h>
  43#include <acpi/acpi_drivers.h>
  44
  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 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 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 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 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 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 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 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 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        int state;
 486
 487
 488        arg0.integer.value = level;
 489
 490        if (device->cap._BCM)
 491                status = acpi_evaluate_object(device->dev->handle, "_BCM",
 492                                              &args, NULL);
 493        device->brightness->curr = level;
 494        for (state = 2; state < device->brightness->count; state++)
 495                if (level == device->brightness->levels[state])
 496                        device->backlight->props.brightness = state - 2;
 497
 498        return status;
 499}
 500
 501static int
 502acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
 503                                        unsigned long long *level)
 504{
 505        if (device->cap._BQC)
 506                return acpi_evaluate_integer(device->dev->handle, "_BQC", NULL,
 507                                             level);
 508        *level = device->brightness->curr;
 509        return AE_OK;
 510}
 511
 512static int
 513acpi_video_device_EDID(struct acpi_video_device *device,
 514                       union acpi_object **edid, ssize_t length)
 515{
 516        int status;
 517        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 518        union acpi_object *obj;
 519        union acpi_object arg0 = { ACPI_TYPE_INTEGER };
 520        struct acpi_object_list args = { 1, &arg0 };
 521
 522
 523        *edid = NULL;
 524
 525        if (!device)
 526                return -ENODEV;
 527        if (length == 128)
 528                arg0.integer.value = 1;
 529        else if (length == 256)
 530                arg0.integer.value = 2;
 531        else
 532                return -EINVAL;
 533
 534        status = acpi_evaluate_object(device->dev->handle, "_DDC", &args, &buffer);
 535        if (ACPI_FAILURE(status))
 536                return -ENODEV;
 537
 538        obj = buffer.pointer;
 539
 540        if (obj && obj->type == ACPI_TYPE_BUFFER)
 541                *edid = obj;
 542        else {
 543                printk(KERN_ERR PREFIX "Invalid _DDC data\n");
 544                status = -EFAULT;
 545                kfree(obj);
 546        }
 547
 548        return status;
 549}
 550
 551/* bus */
 552
 553static int
 554acpi_video_bus_set_POST(struct acpi_video_bus *video, unsigned long option)
 555{
 556        int status;
 557        unsigned long long tmp;
 558        union acpi_object arg0 = { ACPI_TYPE_INTEGER };
 559        struct acpi_object_list args = { 1, &arg0 };
 560
 561
 562        arg0.integer.value = option;
 563
 564        status = acpi_evaluate_integer(video->device->handle, "_SPD", &args, &tmp);
 565        if (ACPI_SUCCESS(status))
 566                status = tmp ? (-EINVAL) : (AE_OK);
 567
 568        return status;
 569}
 570
 571static int
 572acpi_video_bus_get_POST(struct acpi_video_bus *video, unsigned long long *id)
 573{
 574        int status;
 575
 576        status = acpi_evaluate_integer(video->device->handle, "_GPD", NULL, id);
 577
 578        return status;
 579}
 580
 581static int
 582acpi_video_bus_POST_options(struct acpi_video_bus *video,
 583                            unsigned long long *options)
 584{
 585        int status;
 586
 587        status = acpi_evaluate_integer(video->device->handle, "_VPO", NULL, options);
 588        *options &= 3;
 589
 590        return status;
 591}
 592
 593/*
 594 *  Arg:
 595 *      video           : video bus device pointer
 596 *      bios_flag       : 
 597 *              0.      The system BIOS should NOT automatically switch(toggle)
 598 *                      the active display output.
 599 *              1.      The system BIOS should automatically switch (toggle) the
 600 *                      active display output. No switch event.
 601 *              2.      The _DGS value should be locked.
 602 *              3.      The system BIOS should not automatically switch (toggle) the
 603 *                      active display output, but instead generate the display switch
 604 *                      event notify code.
 605 *      lcd_flag        :
 606 *              0.      The system BIOS should automatically control the brightness level
 607 *                      of the LCD when the power changes from AC to DC
 608 *              1.      The system BIOS should NOT automatically control the brightness 
 609 *                      level of the LCD when the power changes from AC to DC.
 610 * Return Value:
 611 *              -1      wrong arg.
 612 */
 613
 614static int
 615acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag)
 616{
 617        acpi_integer status = 0;
 618        union acpi_object arg0 = { ACPI_TYPE_INTEGER };
 619        struct acpi_object_list args = { 1, &arg0 };
 620
 621
 622        if (bios_flag < 0 || bios_flag > 3 || lcd_flag < 0 || lcd_flag > 1) {
 623                status = -1;
 624                goto Failed;
 625        }
 626        arg0.integer.value = (lcd_flag << 2) | bios_flag;
 627        video->dos_setting = arg0.integer.value;
 628        acpi_evaluate_object(video->device->handle, "_DOS", &args, NULL);
 629
 630      Failed:
 631        return status;
 632}
 633
 634/*
 635 * Simple comparison function used to sort backlight levels.
 636 */
 637
 638static int
 639acpi_video_cmp_level(const void *a, const void *b)
 640{
 641        return *(int *)a - *(int *)b;
 642}
 643
 644/*
 645 *  Arg:        
 646 *      device  : video output device (LCD, CRT, ..)
 647 *
 648 *  Return Value:
 649 *      Maximum brightness level
 650 *
 651 *  Allocate and initialize device->brightness.
 652 */
 653
 654static int
 655acpi_video_init_brightness(struct acpi_video_device *device)
 656{
 657        union acpi_object *obj = NULL;
 658        int i, max_level = 0, count = 0;
 659        union acpi_object *o;
 660        struct acpi_video_device_brightness *br = NULL;
 661
 662        if (!ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) {
 663                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available "
 664                                                "LCD brightness level\n"));
 665                goto out;
 666        }
 667
 668        if (obj->package.count < 2)
 669                goto out;
 670
 671        br = kzalloc(sizeof(*br), GFP_KERNEL);
 672        if (!br) {
 673                printk(KERN_ERR "can't allocate memory\n");
 674                goto out;
 675        }
 676
 677        br->levels = kmalloc(obj->package.count * sizeof *(br->levels),
 678                                GFP_KERNEL);
 679        if (!br->levels)
 680                goto out_free;
 681
 682        for (i = 0; i < obj->package.count; i++) {
 683                o = (union acpi_object *)&obj->package.elements[i];
 684                if (o->type != ACPI_TYPE_INTEGER) {
 685                        printk(KERN_ERR PREFIX "Invalid data\n");
 686                        continue;
 687                }
 688                br->levels[count] = (u32) o->integer.value;
 689
 690                if (br->levels[count] > max_level)
 691                        max_level = br->levels[count];
 692                count++;
 693        }
 694
 695        /* don't sort the first two brightness levels */
 696        sort(&br->levels[2], count - 2, sizeof(br->levels[2]),
 697                acpi_video_cmp_level, NULL);
 698
 699        if (count < 2)
 700                goto out_free_levels;
 701
 702        br->count = count;
 703        device->brightness = br;
 704        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "found %d brightness levels\n", count));
 705        kfree(obj);
 706        return max_level;
 707
 708out_free_levels:
 709        kfree(br->levels);
 710out_free:
 711        kfree(br);
 712out:
 713        device->brightness = NULL;
 714        kfree(obj);
 715        return 0;
 716}
 717
 718/*
 719 *  Arg:
 720 *      device  : video output device (LCD, CRT, ..)
 721 *
 722 *  Return Value:
 723 *      None
 724 *
 725 *  Find out all required AML methods defined under the output
 726 *  device.
 727 */
 728
 729static void acpi_video_device_find_cap(struct acpi_video_device *device)
 730{
 731        acpi_handle h_dummy1;
 732        u32 max_level = 0;
 733
 734
 735        memset(&device->cap, 0, sizeof(device->cap));
 736
 737        if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_ADR", &h_dummy1))) {
 738                device->cap._ADR = 1;
 739        }
 740        if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCL", &h_dummy1))) {
 741                device->cap._BCL = 1;
 742        }
 743        if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCM", &h_dummy1))) {
 744                device->cap._BCM = 1;
 745        }
 746        if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle,"_BQC",&h_dummy1)))
 747                device->cap._BQC = 1;
 748        if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) {
 749                device->cap._DDC = 1;
 750        }
 751        if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DCS", &h_dummy1))) {
 752                device->cap._DCS = 1;
 753        }
 754        if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DGS", &h_dummy1))) {
 755                device->cap._DGS = 1;
 756        }
 757        if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DSS", &h_dummy1))) {
 758                device->cap._DSS = 1;
 759        }
 760
 761        if (acpi_video_backlight_support())
 762                max_level = acpi_video_init_brightness(device);
 763
 764        if (device->cap._BCL && device->cap._BCM && max_level > 0) {
 765                int result;
 766                static int count = 0;
 767                char *name;
 768                name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
 769                if (!name)
 770                        return;
 771
 772                sprintf(name, "acpi_video%d", count++);
 773                device->backlight = backlight_device_register(name,
 774                        NULL, device, &acpi_backlight_ops);
 775                device->backlight->props.max_brightness = device->brightness->count-3;
 776                /*
 777                 * If there exists the _BQC object, the _BQC object will be
 778                 * called to get the current backlight brightness. Otherwise
 779                 * the brightness will be set to the maximum.
 780                 */
 781                if (device->cap._BQC)
 782                        device->backlight->props.brightness =
 783                                acpi_video_get_brightness(device->backlight);
 784                else
 785                        device->backlight->props.brightness =
 786                                device->backlight->props.max_brightness;
 787                backlight_update_status(device->backlight);
 788                kfree(name);
 789
 790                device->cdev = thermal_cooling_device_register("LCD",
 791                                        device->dev, &video_cooling_ops);
 792                if (IS_ERR(device->cdev))
 793                        return;
 794
 795                dev_info(&device->dev->dev, "registered as cooling_device%d\n",
 796                         device->cdev->id);
 797                result = sysfs_create_link(&device->dev->dev.kobj,
 798                                &device->cdev->device.kobj,
 799                                "thermal_cooling");
 800                if (result)
 801                        printk(KERN_ERR PREFIX "Create sysfs link\n");
 802                result = sysfs_create_link(&device->cdev->device.kobj,
 803                                &device->dev->dev.kobj, "device");
 804                if (result)
 805                        printk(KERN_ERR PREFIX "Create sysfs link\n");
 806
 807        }
 808
 809        if (acpi_video_display_switch_support()) {
 810
 811                if (device->cap._DCS && device->cap._DSS) {
 812                        static int count;
 813                        char *name;
 814                        name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
 815                        if (!name)
 816                                return;
 817                        sprintf(name, "acpi_video%d", count++);
 818                        device->output_dev = video_output_register(name,
 819                                        NULL, device, &acpi_output_properties);
 820                        kfree(name);
 821                }
 822        }
 823}
 824
 825/*
 826 *  Arg:        
 827 *      device  : video output device (VGA)
 828 *
 829 *  Return Value:
 830 *      None
 831 *
 832 *  Find out all required AML methods defined under the video bus device.
 833 */
 834
 835static void acpi_video_bus_find_cap(struct acpi_video_bus *video)
 836{
 837        acpi_handle h_dummy1;
 838
 839        memset(&video->cap, 0, sizeof(video->cap));
 840        if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOS", &h_dummy1))) {
 841                video->cap._DOS = 1;
 842        }
 843        if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOD", &h_dummy1))) {
 844                video->cap._DOD = 1;
 845        }
 846        if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_ROM", &h_dummy1))) {
 847                video->cap._ROM = 1;
 848        }
 849        if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_GPD", &h_dummy1))) {
 850                video->cap._GPD = 1;
 851        }
 852        if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_SPD", &h_dummy1))) {
 853                video->cap._SPD = 1;
 854        }
 855        if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_VPO", &h_dummy1))) {
 856                video->cap._VPO = 1;
 857        }
 858}
 859
 860/*
 861 * Check whether the video bus device has required AML method to
 862 * support the desired features
 863 */
 864
 865static int acpi_video_bus_check(struct acpi_video_bus *video)
 866{
 867        acpi_status status = -ENOENT;
 868        struct device *dev;
 869
 870        if (!video)
 871                return -EINVAL;
 872
 873        dev = acpi_get_physical_pci_device(video->device->handle);
 874        if (!dev)
 875                return -ENODEV;
 876        put_device(dev);
 877
 878        /* Since there is no HID, CID and so on for VGA driver, we have
 879         * to check well known required nodes.
 880         */
 881
 882        /* Does this device support video switching? */
 883        if (video->cap._DOS) {
 884                video->flags.multihead = 1;
 885                status = 0;
 886        }
 887
 888        /* Does this device support retrieving a video ROM? */
 889        if (video->cap._ROM) {
 890                video->flags.rom = 1;
 891                status = 0;
 892        }
 893
 894        /* Does this device support configuring which video device to POST? */
 895        if (video->cap._GPD && video->cap._SPD && video->cap._VPO) {
 896                video->flags.post = 1;
 897                status = 0;
 898        }
 899
 900        return status;
 901}
 902
 903/* --------------------------------------------------------------------------
 904                              FS Interface (/proc)
 905   -------------------------------------------------------------------------- */
 906
 907static struct proc_dir_entry *acpi_video_dir;
 908
 909/* video devices */
 910
 911static int acpi_video_device_info_seq_show(struct seq_file *seq, void *offset)
 912{
 913        struct acpi_video_device *dev = seq->private;
 914
 915
 916        if (!dev)
 917                goto end;
 918
 919        seq_printf(seq, "device_id:    0x%04x\n", (u32) dev->device_id);
 920        seq_printf(seq, "type:         ");
 921        if (dev->flags.crt)
 922                seq_printf(seq, "CRT\n");
 923        else if (dev->flags.lcd)
 924                seq_printf(seq, "LCD\n");
 925        else if (dev->flags.tvout)
 926                seq_printf(seq, "TVOUT\n");
 927        else if (dev->flags.dvi)
 928                seq_printf(seq, "DVI\n");
 929        else
 930                seq_printf(seq, "UNKNOWN\n");
 931
 932        seq_printf(seq, "known by bios: %s\n", dev->flags.bios ? "yes" : "no");
 933
 934      end:
 935        return 0;
 936}
 937
 938static int
 939acpi_video_device_info_open_fs(struct inode *inode, struct file *file)
 940{
 941        return single_open(file, acpi_video_device_info_seq_show,
 942                           PDE(inode)->data);
 943}
 944
 945static int acpi_video_device_state_seq_show(struct seq_file *seq, void *offset)
 946{
 947        int status;
 948        struct acpi_video_device *dev = seq->private;
 949        unsigned long long state;
 950
 951
 952        if (!dev)
 953                goto end;
 954
 955        status = acpi_video_device_get_state(dev, &state);
 956        seq_printf(seq, "state:     ");
 957        if (ACPI_SUCCESS(status))
 958                seq_printf(seq, "0x%02llx\n", state);
 959        else
 960                seq_printf(seq, "<not supported>\n");
 961
 962        status = acpi_video_device_query(dev, &state);
 963        seq_printf(seq, "query:     ");
 964        if (ACPI_SUCCESS(status))
 965                seq_printf(seq, "0x%02llx\n", state);
 966        else
 967                seq_printf(seq, "<not supported>\n");
 968
 969      end:
 970        return 0;
 971}
 972
 973static int
 974acpi_video_device_state_open_fs(struct inode *inode, struct file *file)
 975{
 976        return single_open(file, acpi_video_device_state_seq_show,
 977                           PDE(inode)->data);
 978}
 979
 980static ssize_t
 981acpi_video_device_write_state(struct file *file,
 982                              const char __user * buffer,
 983                              size_t count, loff_t * data)
 984{
 985        int status;
 986        struct seq_file *m = file->private_data;
 987        struct acpi_video_device *dev = m->private;
 988        char str[12] = { 0 };
 989        u32 state = 0;
 990
 991
 992        if (!dev || count + 1 > sizeof str)
 993                return -EINVAL;
 994
 995        if (copy_from_user(str, buffer, count))
 996                return -EFAULT;
 997
 998        str[count] = 0;
 999        state = simple_strtoul(str, NULL, 0);
1000        state &= ((1ul << 31) | (1ul << 30) | (1ul << 0));
1001
1002        status = acpi_video_device_set_state(dev, state);
1003
1004        if (status)
1005                return -EFAULT;
1006
1007        return count;
1008}
1009
1010static int
1011acpi_video_device_brightness_seq_show(struct seq_file *seq, void *offset)
1012{
1013        struct acpi_video_device *dev = seq->private;
1014        int i;
1015
1016
1017        if (!dev || !dev->brightness) {
1018                seq_printf(seq, "<not supported>\n");
1019                return 0;
1020        }
1021
1022        seq_printf(seq, "levels: ");
1023        for (i = 2; i < dev->brightness->count; i++)
1024                seq_printf(seq, " %d", dev->brightness->levels[i]);
1025        seq_printf(seq, "\ncurrent: %d\n", dev->brightness->curr);
1026
1027        return 0;
1028}
1029
1030static int
1031acpi_video_device_brightness_open_fs(struct inode *inode, struct file *file)
1032{
1033        return single_open(file, acpi_video_device_brightness_seq_show,
1034                           PDE(inode)->data);
1035}
1036
1037static ssize_t
1038acpi_video_device_write_brightness(struct file *file,
1039                                   const char __user * buffer,
1040                                   size_t count, loff_t * data)
1041{
1042        struct seq_file *m = file->private_data;
1043        struct acpi_video_device *dev = m->private;
1044        char str[5] = { 0 };
1045        unsigned int level = 0;
1046        int i;
1047
1048
1049        if (!dev || !dev->brightness || count + 1 > sizeof str)
1050                return -EINVAL;
1051
1052        if (copy_from_user(str, buffer, count))
1053                return -EFAULT;
1054
1055        str[count] = 0;
1056        level = simple_strtoul(str, NULL, 0);
1057
1058        if (level > 100)
1059                return -EFAULT;
1060
1061        /* validate through the list of available levels */
1062        for (i = 2; i < dev->brightness->count; i++)
1063                if (level == dev->brightness->levels[i]) {
1064                        if (ACPI_SUCCESS
1065                            (acpi_video_device_lcd_set_level(dev, level)))
1066                                dev->brightness->curr = level;
1067                        break;
1068                }
1069
1070        return count;
1071}
1072
1073static int acpi_video_device_EDID_seq_show(struct seq_file *seq, void *offset)
1074{
1075        struct acpi_video_device *dev = seq->private;
1076        int status;
1077        int i;
1078        union acpi_object *edid = NULL;
1079
1080
1081        if (!dev)
1082                goto out;
1083
1084        status = acpi_video_device_EDID(dev, &edid, 128);
1085        if (ACPI_FAILURE(status)) {
1086                status = acpi_video_device_EDID(dev, &edid, 256);
1087        }
1088
1089        if (ACPI_FAILURE(status)) {
1090                goto out;
1091        }
1092
1093        if (edid && edid->type == ACPI_TYPE_BUFFER) {
1094                for (i = 0; i < edid->buffer.length; i++)
1095                        seq_putc(seq, edid->buffer.pointer[i]);
1096        }
1097
1098      out:
1099        if (!edid)
1100                seq_printf(seq, "<not supported>\n");
1101        else
1102                kfree(edid);
1103
1104        return 0;
1105}
1106
1107static int
1108acpi_video_device_EDID_open_fs(struct inode *inode, struct file *file)
1109{
1110        return single_open(file, acpi_video_device_EDID_seq_show,
1111                           PDE(inode)->data);
1112}
1113
1114static int acpi_video_device_add_fs(struct acpi_device *device)
1115{
1116        struct proc_dir_entry *entry, *device_dir;
1117        struct acpi_video_device *vid_dev;
1118
1119        vid_dev = acpi_driver_data(device);
1120        if (!vid_dev)
1121                return -ENODEV;
1122
1123        device_dir = proc_mkdir(acpi_device_bid(device),
1124                                vid_dev->video->dir);
1125        if (!device_dir)
1126                return -ENOMEM;
1127
1128        device_dir->owner = THIS_MODULE;
1129
1130        /* 'info' [R] */
1131        entry = proc_create_data("info", S_IRUGO, device_dir,
1132                        &acpi_video_device_info_fops, acpi_driver_data(device));
1133        if (!entry)
1134                goto err_remove_dir;
1135
1136        /* 'state' [R/W] */
1137        acpi_video_device_state_fops.write = acpi_video_device_write_state;
1138        entry = proc_create_data("state", S_IFREG | S_IRUGO | S_IWUSR,
1139                                 device_dir,
1140                                 &acpi_video_device_state_fops,
1141                                 acpi_driver_data(device));
1142        if (!entry)
1143                goto err_remove_info;
1144
1145        /* 'brightness' [R/W] */
1146        acpi_video_device_brightness_fops.write =
1147                acpi_video_device_write_brightness;
1148        entry = proc_create_data("brightness", S_IFREG | S_IRUGO | S_IWUSR,
1149                                 device_dir,
1150                                 &acpi_video_device_brightness_fops,
1151                                 acpi_driver_data(device));
1152        if (!entry)
1153                goto err_remove_state;
1154
1155        /* 'EDID' [R] */
1156        entry = proc_create_data("EDID", S_IRUGO, device_dir,
1157                                 &acpi_video_device_EDID_fops,
1158                                 acpi_driver_data(device));
1159        if (!entry)
1160                goto err_remove_brightness;
1161
1162        acpi_device_dir(device) = device_dir;
1163
1164        return 0;
1165
1166 err_remove_brightness:
1167        remove_proc_entry("brightness", device_dir);
1168 err_remove_state:
1169        remove_proc_entry("state", device_dir);
1170 err_remove_info:
1171        remove_proc_entry("info", device_dir);
1172 err_remove_dir:
1173        remove_proc_entry(acpi_device_bid(device), vid_dev->video->dir);
1174        return -ENOMEM;
1175}
1176
1177static int acpi_video_device_remove_fs(struct acpi_device *device)
1178{
1179        struct acpi_video_device *vid_dev;
1180        struct proc_dir_entry *device_dir;
1181
1182        vid_dev = acpi_driver_data(device);
1183        if (!vid_dev || !vid_dev->video || !vid_dev->video->dir)
1184                return -ENODEV;
1185
1186        device_dir = acpi_device_dir(device);
1187        if (device_dir) {
1188                remove_proc_entry("info", device_dir);
1189                remove_proc_entry("state", device_dir);
1190                remove_proc_entry("brightness", device_dir);
1191                remove_proc_entry("EDID", device_dir);
1192                remove_proc_entry(acpi_device_bid(device), vid_dev->video->dir);
1193                acpi_device_dir(device) = NULL;
1194        }
1195
1196        return 0;
1197}
1198
1199/* video bus */
1200static int acpi_video_bus_info_seq_show(struct seq_file *seq, void *offset)
1201{
1202        struct acpi_video_bus *video = seq->private;
1203
1204
1205        if (!video)
1206                goto end;
1207
1208        seq_printf(seq, "Switching heads:              %s\n",
1209                   video->flags.multihead ? "yes" : "no");
1210        seq_printf(seq, "Video ROM:                    %s\n",
1211                   video->flags.rom ? "yes" : "no");
1212        seq_printf(seq, "Device to be POSTed on boot:  %s\n",
1213                   video->flags.post ? "yes" : "no");
1214
1215      end:
1216        return 0;
1217}
1218
1219static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file)
1220{
1221        return single_open(file, acpi_video_bus_info_seq_show,
1222                           PDE(inode)->data);
1223}
1224
1225static int acpi_video_bus_ROM_seq_show(struct seq_file *seq, void *offset)
1226{
1227        struct acpi_video_bus *video = seq->private;
1228
1229
1230        if (!video)
1231                goto end;
1232
1233        printk(KERN_INFO PREFIX "Please implement %s\n", __func__);
1234        seq_printf(seq, "<TODO>\n");
1235
1236      end:
1237        return 0;
1238}
1239
1240static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file)
1241{
1242        return single_open(file, acpi_video_bus_ROM_seq_show, PDE(inode)->data);
1243}
1244
1245static int acpi_video_bus_POST_info_seq_show(struct seq_file *seq, void *offset)
1246{
1247        struct acpi_video_bus *video = seq->private;
1248        unsigned long long options;
1249        int status;
1250
1251
1252        if (!video)
1253                goto end;
1254
1255        status = acpi_video_bus_POST_options(video, &options);
1256        if (ACPI_SUCCESS(status)) {
1257                if (!(options & 1)) {
1258                        printk(KERN_WARNING PREFIX
1259                               "The motherboard VGA device is not listed as a possible POST device.\n");
1260                        printk(KERN_WARNING PREFIX
1261                               "This indicates a BIOS bug. Please contact the manufacturer.\n");
1262                }
1263                printk(KERN_WARNING "%llx\n", options);
1264                seq_printf(seq, "can POST: <integrated video>");
1265                if (options & 2)
1266                        seq_printf(seq, " <PCI video>");
1267                if (options & 4)
1268                        seq_printf(seq, " <AGP video>");
1269                seq_putc(seq, '\n');
1270        } else
1271                seq_printf(seq, "<not supported>\n");
1272      end:
1273        return 0;
1274}
1275
1276static int
1277acpi_video_bus_POST_info_open_fs(struct inode *inode, struct file *file)
1278{
1279        return single_open(file, acpi_video_bus_POST_info_seq_show,
1280                           PDE(inode)->data);
1281}
1282
1283static int acpi_video_bus_POST_seq_show(struct seq_file *seq, void *offset)
1284{
1285        struct acpi_video_bus *video = seq->private;
1286        int status;
1287        unsigned long long id;
1288
1289
1290        if (!video)
1291                goto end;
1292
1293        status = acpi_video_bus_get_POST(video, &id);
1294        if (!ACPI_SUCCESS(status)) {
1295                seq_printf(seq, "<not supported>\n");
1296                goto end;
1297        }
1298        seq_printf(seq, "device POSTed is <%s>\n", device_decode[id & 3]);
1299
1300      end:
1301        return 0;
1302}
1303
1304static int acpi_video_bus_DOS_seq_show(struct seq_file *seq, void *offset)
1305{
1306        struct acpi_video_bus *video = seq->private;
1307
1308
1309        seq_printf(seq, "DOS setting: <%d>\n", video->dos_setting);
1310
1311        return 0;
1312}
1313
1314static int acpi_video_bus_POST_open_fs(struct inode *inode, struct file *file)
1315{
1316        return single_open(file, acpi_video_bus_POST_seq_show,
1317                           PDE(inode)->data);
1318}
1319
1320static int acpi_video_bus_DOS_open_fs(struct inode *inode, struct file *file)
1321{
1322        return single_open(file, acpi_video_bus_DOS_seq_show, PDE(inode)->data);
1323}
1324
1325static ssize_t
1326acpi_video_bus_write_POST(struct file *file,
1327                          const char __user * buffer,
1328                          size_t count, loff_t * data)
1329{
1330        int status;
1331        struct seq_file *m = file->private_data;
1332        struct acpi_video_bus *video = m->private;
1333        char str[12] = { 0 };
1334        unsigned long long opt, options;
1335
1336
1337        if (!video || count + 1 > sizeof str)
1338                return -EINVAL;
1339
1340        status = acpi_video_bus_POST_options(video, &options);
1341        if (!ACPI_SUCCESS(status))
1342                return -EINVAL;
1343
1344        if (copy_from_user(str, buffer, count))
1345                return -EFAULT;
1346
1347        str[count] = 0;
1348        opt = strtoul(str, NULL, 0);
1349        if (opt > 3)
1350                return -EFAULT;
1351
1352        /* just in case an OEM 'forgot' the motherboard... */
1353        options |= 1;
1354
1355        if (options & (1ul << opt)) {
1356                status = acpi_video_bus_set_POST(video, opt);
1357                if (!ACPI_SUCCESS(status))
1358                        return -EFAULT;
1359
1360        }
1361
1362        return count;
1363}
1364
1365static ssize_t
1366acpi_video_bus_write_DOS(struct file *file,
1367                         const char __user * buffer,
1368                         size_t count, loff_t * data)
1369{
1370        int status;
1371        struct seq_file *m = file->private_data;
1372        struct acpi_video_bus *video = m->private;
1373        char str[12] = { 0 };
1374        unsigned long opt;
1375
1376
1377        if (!video || count + 1 > sizeof str)
1378                return -EINVAL;
1379
1380        if (copy_from_user(str, buffer, count))
1381                return -EFAULT;
1382
1383        str[count] = 0;
1384        opt = strtoul(str, NULL, 0);
1385        if (opt > 7)
1386                return -EFAULT;
1387
1388        status = acpi_video_bus_DOS(video, opt & 0x3, (opt & 0x4) >> 2);
1389
1390        if (!ACPI_SUCCESS(status))
1391                return -EFAULT;
1392
1393        return count;
1394}
1395
1396static int acpi_video_bus_add_fs(struct acpi_device *device)
1397{
1398        struct acpi_video_bus *video = acpi_driver_data(device);
1399        struct proc_dir_entry *device_dir;
1400        struct proc_dir_entry *entry;
1401
1402        device_dir = proc_mkdir(acpi_device_bid(device), acpi_video_dir);
1403        if (!device_dir)
1404                return -ENOMEM;
1405
1406        device_dir->owner = THIS_MODULE;
1407
1408        /* 'info' [R] */
1409        entry = proc_create_data("info", S_IRUGO, device_dir,
1410                                 &acpi_video_bus_info_fops,
1411                                 acpi_driver_data(device));
1412        if (!entry)
1413                goto err_remove_dir;
1414
1415        /* 'ROM' [R] */
1416        entry = proc_create_data("ROM", S_IRUGO, device_dir,
1417                                 &acpi_video_bus_ROM_fops,
1418                                 acpi_driver_data(device));
1419        if (!entry)
1420                goto err_remove_info;
1421
1422        /* 'POST_info' [R] */
1423        entry = proc_create_data("POST_info", S_IRUGO, device_dir,
1424                                 &acpi_video_bus_POST_info_fops,
1425                                 acpi_driver_data(device));
1426        if (!entry)
1427                goto err_remove_rom;
1428
1429        /* 'POST' [R/W] */
1430        acpi_video_bus_POST_fops.write = acpi_video_bus_write_POST;
1431        entry = proc_create_data("POST", S_IFREG | S_IRUGO | S_IWUSR,
1432                                 device_dir,
1433                                 &acpi_video_bus_POST_fops,
1434                                 acpi_driver_data(device));
1435        if (!entry)
1436                goto err_remove_post_info;
1437
1438        /* 'DOS' [R/W] */
1439        acpi_video_bus_DOS_fops.write = acpi_video_bus_write_DOS;
1440        entry = proc_create_data("DOS", S_IFREG | S_IRUGO | S_IWUSR,
1441                                 device_dir,
1442                                 &acpi_video_bus_DOS_fops,
1443                                 acpi_driver_data(device));
1444        if (!entry)
1445                goto err_remove_post;
1446
1447        video->dir = acpi_device_dir(device) = device_dir;
1448        return 0;
1449
1450 err_remove_post:
1451        remove_proc_entry("POST", device_dir);
1452 err_remove_post_info:
1453        remove_proc_entry("POST_info", device_dir);
1454 err_remove_rom:
1455        remove_proc_entry("ROM", device_dir);
1456 err_remove_info:
1457        remove_proc_entry("info", device_dir);
1458 err_remove_dir:
1459        remove_proc_entry(acpi_device_bid(device), acpi_video_dir);
1460        return -ENOMEM;
1461}
1462
1463static int acpi_video_bus_remove_fs(struct acpi_device *device)
1464{
1465        struct proc_dir_entry *device_dir = acpi_device_dir(device);
1466
1467        if (device_dir) {
1468                remove_proc_entry("info", device_dir);
1469                remove_proc_entry("ROM", device_dir);
1470                remove_proc_entry("POST_info", device_dir);
1471                remove_proc_entry("POST", device_dir);
1472                remove_proc_entry("DOS", device_dir);
1473                remove_proc_entry(acpi_device_bid(device), acpi_video_dir);
1474                acpi_device_dir(device) = NULL;
1475        }
1476
1477        return 0;
1478}
1479
1480/* --------------------------------------------------------------------------
1481                                 Driver Interface
1482   -------------------------------------------------------------------------- */
1483
1484/* device interface */
1485static struct acpi_video_device_attrib*
1486acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id)
1487{
1488        struct acpi_video_enumerated_device *ids;
1489        int i;
1490
1491        for (i = 0; i < video->attached_count; i++) {
1492                ids = &video->attached_array[i];
1493                if ((ids->value.int_val & 0xffff) == device_id)
1494                        return &ids->value.attrib;
1495        }
1496
1497        return NULL;
1498}
1499
1500static int
1501acpi_video_bus_get_one_device(struct acpi_device *device,
1502                              struct acpi_video_bus *video)
1503{
1504        unsigned long long device_id;
1505        int status;
1506        struct acpi_video_device *data;
1507        struct acpi_video_device_attrib* attribute;
1508
1509        if (!device || !video)
1510                return -EINVAL;
1511
1512        status =
1513            acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
1514        if (ACPI_SUCCESS(status)) {
1515
1516                data = kzalloc(sizeof(struct acpi_video_device), GFP_KERNEL);
1517                if (!data)
1518                        return -ENOMEM;
1519
1520                strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME);
1521                strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
1522                device->driver_data = data;
1523
1524                data->device_id = device_id;
1525                data->video = video;
1526                data->dev = device;
1527
1528                attribute = acpi_video_get_device_attr(video, device_id);
1529
1530                if((attribute != NULL) && attribute->device_id_scheme) {
1531                        switch (attribute->display_type) {
1532                        case ACPI_VIDEO_DISPLAY_CRT:
1533                                data->flags.crt = 1;
1534                                break;
1535                        case ACPI_VIDEO_DISPLAY_TV:
1536                                data->flags.tvout = 1;
1537                                break;
1538                        case ACPI_VIDEO_DISPLAY_DVI:
1539                                data->flags.dvi = 1;
1540                                break;
1541                        case ACPI_VIDEO_DISPLAY_LCD:
1542                                data->flags.lcd = 1;
1543                                break;
1544                        default:
1545                                data->flags.unknown = 1;
1546                                break;
1547                        }
1548                        if(attribute->bios_can_detect)
1549                                data->flags.bios = 1;
1550                } else
1551                        data->flags.unknown = 1;
1552
1553                acpi_video_device_bind(video, data);
1554                acpi_video_device_find_cap(data);
1555
1556                status = acpi_install_notify_handler(device->handle,
1557                                                     ACPI_DEVICE_NOTIFY,
1558                                                     acpi_video_device_notify,
1559                                                     data);
1560                if (ACPI_FAILURE(status)) {
1561                        printk(KERN_ERR PREFIX
1562                                          "Error installing notify handler\n");
1563                        if(data->brightness)
1564                                kfree(data->brightness->levels);
1565                        kfree(data->brightness);
1566                        kfree(data);
1567                        return -ENODEV;
1568                }
1569
1570                mutex_lock(&video->device_list_lock);
1571                list_add_tail(&data->entry, &video->video_device_list);
1572                mutex_unlock(&video->device_list_lock);
1573
1574                acpi_video_device_add_fs(device);
1575
1576                return 0;
1577        }
1578
1579        return -ENOENT;
1580}
1581
1582/*
1583 *  Arg:
1584 *      video   : video bus device 
1585 *
1586 *  Return:
1587 *      none
1588 *  
1589 *  Enumerate the video device list of the video bus, 
1590 *  bind the ids with the corresponding video devices
1591 *  under the video bus.
1592 */
1593
1594static void acpi_video_device_rebind(struct acpi_video_bus *video)
1595{
1596        struct acpi_video_device *dev;
1597
1598        mutex_lock(&video->device_list_lock);
1599
1600        list_for_each_entry(dev, &video->video_device_list, entry)
1601                acpi_video_device_bind(video, dev);
1602
1603        mutex_unlock(&video->device_list_lock);
1604}
1605
1606/*
1607 *  Arg:
1608 *      video   : video bus device 
1609 *      device  : video output device under the video 
1610 *              bus
1611 *
1612 *  Return:
1613 *      none
1614 *  
1615 *  Bind the ids with the corresponding video devices
1616 *  under the video bus.
1617 */
1618
1619static void
1620acpi_video_device_bind(struct acpi_video_bus *video,
1621                       struct acpi_video_device *device)
1622{
1623        struct acpi_video_enumerated_device *ids;
1624        int i;
1625
1626        for (i = 0; i < video->attached_count; i++) {
1627                ids = &video->attached_array[i];
1628                if (device->device_id == (ids->value.int_val & 0xffff)) {
1629                        ids->bind_info = device;
1630                        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "device_bind %d\n", i));
1631                }
1632        }
1633}
1634
1635/*
1636 *  Arg:
1637 *      video   : video bus device 
1638 *
1639 *  Return:
1640 *      < 0     : error
1641 *  
1642 *  Call _DOD to enumerate all devices attached to display adapter
1643 *
1644 */
1645
1646static int acpi_video_device_enumerate(struct acpi_video_bus *video)
1647{
1648        int status;
1649        int count;
1650        int i;
1651        struct acpi_video_enumerated_device *active_list;
1652        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
1653        union acpi_object *dod = NULL;
1654        union acpi_object *obj;
1655
1656        status = acpi_evaluate_object(video->device->handle, "_DOD", NULL, &buffer);
1657        if (!ACPI_SUCCESS(status)) {
1658                ACPI_EXCEPTION((AE_INFO, status, "Evaluating _DOD"));
1659                return status;
1660        }
1661
1662        dod = buffer.pointer;
1663        if (!dod || (dod->type != ACPI_TYPE_PACKAGE)) {
1664                ACPI_EXCEPTION((AE_INFO, status, "Invalid _DOD data"));
1665                status = -EFAULT;
1666                goto out;
1667        }
1668
1669        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d video heads in _DOD\n",
1670                          dod->package.count));
1671
1672        active_list = kcalloc(1 + dod->package.count,
1673                              sizeof(struct acpi_video_enumerated_device),
1674                              GFP_KERNEL);
1675        if (!active_list) {
1676                status = -ENOMEM;
1677                goto out;
1678        }
1679
1680        count = 0;
1681        for (i = 0; i < dod->package.count; i++) {
1682                obj = &dod->package.elements[i];
1683
1684                if (obj->type != ACPI_TYPE_INTEGER) {
1685                        printk(KERN_ERR PREFIX
1686                                "Invalid _DOD data in element %d\n", i);
1687                        continue;
1688                }
1689
1690                active_list[count].value.int_val = obj->integer.value;
1691                active_list[count].bind_info = NULL;
1692                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "dod element[%d] = %d\n", i,
1693                                  (int)obj->integer.value));
1694                count++;
1695        }
1696
1697        kfree(video->attached_array);
1698
1699        video->attached_array = active_list;
1700        video->attached_count = count;
1701
1702 out:
1703        kfree(buffer.pointer);
1704        return status;
1705}
1706
1707static int
1708acpi_video_get_next_level(struct acpi_video_device *device,
1709                          u32 level_current, u32 event)
1710{
1711        int min, max, min_above, max_below, i, l, delta = 255;
1712        max = max_below = 0;
1713        min = min_above = 255;
1714        /* Find closest level to level_current */
1715        for (i = 2; i < device->brightness->count; i++) {
1716                l = device->brightness->levels[i];
1717                if (abs(l - level_current) < abs(delta)) {
1718                        delta = l - level_current;
1719                        if (!delta)
1720                                break;
1721                }
1722        }
1723        /* Ajust level_current to closest available level */
1724        level_current += delta;
1725        for (i = 2; i < device->brightness->count; i++) {
1726                l = device->brightness->levels[i];
1727                if (l < min)
1728                        min = l;
1729                if (l > max)
1730                        max = l;
1731                if (l < min_above && l > level_current)
1732                        min_above = l;
1733                if (l > max_below && l < level_current)
1734                        max_below = l;
1735        }
1736
1737        switch (event) {
1738        case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS:
1739                return (level_current < max) ? min_above : min;
1740        case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS:
1741                return (level_current < max) ? min_above : max;
1742        case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS:
1743                return (level_current > min) ? max_below : min;
1744        case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS:
1745        case ACPI_VIDEO_NOTIFY_DISPLAY_OFF:
1746                return 0;
1747        default:
1748                return level_current;
1749        }
1750}
1751
1752static void
1753acpi_video_switch_brightness(struct acpi_video_device *device, int event)
1754{
1755        unsigned long long level_current, level_next;
1756        if (!device->brightness)
1757                return;
1758        acpi_video_device_lcd_get_level_current(device, &level_current);
1759        level_next = acpi_video_get_next_level(device, level_current, event);
1760        acpi_video_device_lcd_set_level(device, level_next);
1761}
1762
1763static int
1764acpi_video_bus_get_devices(struct acpi_video_bus *video,
1765                           struct acpi_device *device)
1766{
1767        int status = 0;
1768        struct acpi_device *dev;
1769
1770        acpi_video_device_enumerate(video);
1771
1772        list_for_each_entry(dev, &device->children, node) {
1773
1774                status = acpi_video_bus_get_one_device(dev, video);
1775                if (ACPI_FAILURE(status)) {
1776                        printk(KERN_WARNING PREFIX
1777                                        "Cant attach device");
1778                        continue;
1779                }
1780        }
1781        return status;
1782}
1783
1784static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
1785{
1786        acpi_status status;
1787        struct acpi_video_bus *video;
1788
1789
1790        if (!device || !device->video)
1791                return -ENOENT;
1792
1793        video = device->video;
1794
1795        acpi_video_device_remove_fs(device->dev);
1796
1797        status = acpi_remove_notify_handler(device->dev->handle,
1798                                            ACPI_DEVICE_NOTIFY,
1799                                            acpi_video_device_notify);
1800        backlight_device_unregister(device->backlight);
1801        if (device->cdev) {
1802                sysfs_remove_link(&device->dev->dev.kobj,
1803                                  "thermal_cooling");
1804                sysfs_remove_link(&device->cdev->device.kobj,
1805                                  "device");
1806                thermal_cooling_device_unregister(device->cdev);
1807                device->cdev = NULL;
1808        }
1809        video_output_unregister(device->output_dev);
1810
1811        return 0;
1812}
1813
1814static int acpi_video_bus_put_devices(struct acpi_video_bus *video)
1815{
1816        int status;
1817        struct acpi_video_device *dev, *next;
1818
1819        mutex_lock(&video->device_list_lock);
1820
1821        list_for_each_entry_safe(dev, next, &video->video_device_list, entry) {
1822
1823                status = acpi_video_bus_put_one_device(dev);
1824                if (ACPI_FAILURE(status))
1825                        printk(KERN_WARNING PREFIX
1826                               "hhuuhhuu bug in acpi video driver.\n");
1827
1828                if (dev->brightness) {
1829                        kfree(dev->brightness->levels);
1830                        kfree(dev->brightness);
1831                }
1832                list_del(&dev->entry);
1833                kfree(dev);
1834        }
1835
1836        mutex_unlock(&video->device_list_lock);
1837
1838        return 0;
1839}
1840
1841/* acpi_video interface */
1842
1843static int acpi_video_bus_start_devices(struct acpi_video_bus *video)
1844{
1845        return acpi_video_bus_DOS(video, 0, 0);
1846}
1847
1848static int acpi_video_bus_stop_devices(struct acpi_video_bus *video)
1849{
1850        return acpi_video_bus_DOS(video, 0, 1);
1851}
1852
1853static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data)
1854{
1855        struct acpi_video_bus *video = data;
1856        struct acpi_device *device = NULL;
1857        struct input_dev *input;
1858        int keycode;
1859
1860        if (!video)
1861                return;
1862
1863        device = video->device;
1864        input = video->input;
1865
1866        switch (event) {
1867        case ACPI_VIDEO_NOTIFY_SWITCH:  /* User requested a switch,
1868                                         * most likely via hotkey. */
1869                acpi_bus_generate_proc_event(device, event, 0);
1870                keycode = KEY_SWITCHVIDEOMODE;
1871                break;
1872
1873        case ACPI_VIDEO_NOTIFY_PROBE:   /* User plugged in or removed a video
1874                                         * connector. */
1875                acpi_video_device_enumerate(video);
1876                acpi_video_device_rebind(video);
1877                acpi_bus_generate_proc_event(device, event, 0);
1878                keycode = KEY_SWITCHVIDEOMODE;
1879                break;
1880
1881        case ACPI_VIDEO_NOTIFY_CYCLE:   /* Cycle Display output hotkey pressed. */
1882                acpi_bus_generate_proc_event(device, event, 0);
1883                keycode = KEY_SWITCHVIDEOMODE;
1884                break;
1885        case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT:     /* Next Display output hotkey pressed. */
1886                acpi_bus_generate_proc_event(device, event, 0);
1887                keycode = KEY_VIDEO_NEXT;
1888                break;
1889        case ACPI_VIDEO_NOTIFY_PREV_OUTPUT:     /* previous Display output hotkey pressed. */
1890                acpi_bus_generate_proc_event(device, event, 0);
1891                keycode = KEY_VIDEO_PREV;
1892                break;
1893
1894        default:
1895                keycode = KEY_UNKNOWN;
1896                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
1897                                  "Unsupported event [0x%x]\n", event));
1898                break;
1899        }
1900
1901        acpi_notifier_call_chain(device, event, 0);
1902        input_report_key(input, keycode, 1);
1903        input_sync(input);
1904        input_report_key(input, keycode, 0);
1905        input_sync(input);
1906
1907        return;
1908}
1909
1910static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
1911{
1912        struct acpi_video_device *video_device = data;
1913        struct acpi_device *device = NULL;
1914        struct acpi_video_bus *bus;
1915        struct input_dev *input;
1916        int keycode;
1917
1918        if (!video_device)
1919                return;
1920
1921        device = video_device->dev;
1922        bus = video_device->video;
1923        input = bus->input;
1924
1925        switch (event) {
1926        case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS:        /* Cycle brightness */
1927                if (brightness_switch_enabled)
1928                        acpi_video_switch_brightness(video_device, event);
1929                acpi_bus_generate_proc_event(device, event, 0);
1930                keycode = KEY_BRIGHTNESS_CYCLE;
1931                break;
1932        case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS:  /* Increase brightness */
1933                if (brightness_switch_enabled)
1934                        acpi_video_switch_brightness(video_device, event);
1935                acpi_bus_generate_proc_event(device, event, 0);
1936                keycode = KEY_BRIGHTNESSUP;
1937                break;
1938        case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS:  /* Decrease brightness */
1939                if (brightness_switch_enabled)
1940                        acpi_video_switch_brightness(video_device, event);
1941                acpi_bus_generate_proc_event(device, event, 0);
1942                keycode = KEY_BRIGHTNESSDOWN;
1943                break;
1944        case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightnesss */
1945                if (brightness_switch_enabled)
1946                        acpi_video_switch_brightness(video_device, event);
1947                acpi_bus_generate_proc_event(device, event, 0);
1948                keycode = KEY_BRIGHTNESS_ZERO;
1949                break;
1950        case ACPI_VIDEO_NOTIFY_DISPLAY_OFF:     /* display device off */
1951                if (brightness_switch_enabled)
1952                        acpi_video_switch_brightness(video_device, event);
1953                acpi_bus_generate_proc_event(device, event, 0);
1954                keycode = KEY_DISPLAY_OFF;
1955                break;
1956        default:
1957                keycode = KEY_UNKNOWN;
1958                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
1959                                  "Unsupported event [0x%x]\n", event));
1960                break;
1961        }
1962
1963        acpi_notifier_call_chain(device, event, 0);
1964        input_report_key(input, keycode, 1);
1965        input_sync(input);
1966        input_report_key(input, keycode, 0);
1967        input_sync(input);
1968
1969        return;
1970}
1971
1972static int instance;
1973static int acpi_video_resume(struct acpi_device *device)
1974{
1975        struct acpi_video_bus *video;
1976        struct acpi_video_device *video_device;
1977        int i;
1978
1979        if (!device || !acpi_driver_data(device))
1980                return -EINVAL;
1981
1982        video = acpi_driver_data(device);
1983
1984        for (i = 0; i < video->attached_count; i++) {
1985                video_device = video->attached_array[i].bind_info;
1986                if (video_device && video_device->backlight)
1987                        acpi_video_set_brightness(video_device->backlight);
1988        }
1989        return AE_OK;
1990}
1991
1992static int acpi_video_bus_add(struct acpi_device *device)
1993{
1994        acpi_status status;
1995        struct acpi_video_bus *video;
1996        struct input_dev *input;
1997        int error;
1998
1999        video = kzalloc(sizeof(struct acpi_video_bus), GFP_KERNEL);
2000        if (!video)
2001                return -ENOMEM;
2002
2003        /* a hack to fix the duplicate name "VID" problem on T61 */
2004        if (!strcmp(device->pnp.bus_id, "VID")) {
2005                if (instance)
2006                        device->pnp.bus_id[3] = '0' + instance;
2007                instance ++;
2008        }
2009        /* a hack to fix the duplicate name "VGA" problem on Pa 3553 */
2010        if (!strcmp(device->pnp.bus_id, "VGA")) {
2011                if (instance)
2012                        device->pnp.bus_id[3] = '0' + instance;
2013                instance++;
2014        }
2015
2016        video->device = device;
2017        strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME);
2018        strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
2019        device->driver_data = video;
2020
2021        acpi_video_bus_find_cap(video);
2022        error = acpi_video_bus_check(video);
2023        if (error)
2024                goto err_free_video;
2025
2026        error = acpi_video_bus_add_fs(device);
2027        if (error)
2028                goto err_free_video;
2029
2030        mutex_init(&video->device_list_lock);
2031        INIT_LIST_HEAD(&video->video_device_list);
2032
2033        acpi_video_bus_get_devices(video, device);
2034        acpi_video_bus_start_devices(video);
2035
2036        status = acpi_install_notify_handler(device->handle,
2037                                             ACPI_DEVICE_NOTIFY,
2038                                             acpi_video_bus_notify, video);
2039        if (ACPI_FAILURE(status)) {
2040                printk(KERN_ERR PREFIX
2041                                  "Error installing notify handler\n");
2042                error = -ENODEV;
2043                goto err_stop_video;
2044        }
2045
2046        video->input = input = input_allocate_device();
2047        if (!input) {
2048                error = -ENOMEM;
2049                goto err_uninstall_notify;
2050        }
2051
2052        snprintf(video->phys, sizeof(video->phys),
2053                "%s/video/input0", acpi_device_hid(video->device));
2054
2055        input->name = acpi_device_name(video->device);
2056        input->phys = video->phys;
2057        input->id.bustype = BUS_HOST;
2058        input->id.product = 0x06;
2059        input->dev.parent = &device->dev;
2060        input->evbit[0] = BIT(EV_KEY);
2061        set_bit(KEY_SWITCHVIDEOMODE, input->keybit);
2062        set_bit(KEY_VIDEO_NEXT, input->keybit);
2063        set_bit(KEY_VIDEO_PREV, input->keybit);
2064        set_bit(KEY_BRIGHTNESS_CYCLE, input->keybit);
2065        set_bit(KEY_BRIGHTNESSUP, input->keybit);
2066        set_bit(KEY_BRIGHTNESSDOWN, input->keybit);
2067        set_bit(KEY_BRIGHTNESS_ZERO, input->keybit);
2068        set_bit(KEY_DISPLAY_OFF, input->keybit);
2069        set_bit(KEY_UNKNOWN, input->keybit);
2070
2071        error = input_register_device(input);
2072        if (error)
2073                goto err_free_input_dev;
2074
2075        printk(KERN_INFO PREFIX "%s [%s] (multi-head: %s  rom: %s  post: %s)\n",
2076               ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device),
2077               video->flags.multihead ? "yes" : "no",
2078               video->flags.rom ? "yes" : "no",
2079               video->flags.post ? "yes" : "no");
2080
2081        return 0;
2082
2083 err_free_input_dev:
2084        input_free_device(input);
2085 err_uninstall_notify:
2086        acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
2087                                   acpi_video_bus_notify);
2088 err_stop_video:
2089        acpi_video_bus_stop_devices(video);
2090        acpi_video_bus_put_devices(video);
2091        kfree(video->attached_array);
2092        acpi_video_bus_remove_fs(device);
2093 err_free_video:
2094        kfree(video);
2095        device->driver_data = NULL;
2096
2097        return error;
2098}
2099
2100static int acpi_video_bus_remove(struct acpi_device *device, int type)
2101{
2102        acpi_status status = 0;
2103        struct acpi_video_bus *video = NULL;
2104
2105
2106        if (!device || !acpi_driver_data(device))
2107                return -EINVAL;
2108
2109        video = acpi_driver_data(device);
2110
2111        acpi_video_bus_stop_devices(video);
2112
2113        status = acpi_remove_notify_handler(video->device->handle,
2114                                            ACPI_DEVICE_NOTIFY,
2115                                            acpi_video_bus_notify);
2116
2117        acpi_video_bus_put_devices(video);
2118        acpi_video_bus_remove_fs(device);
2119
2120        input_unregister_device(video->input);
2121        kfree(video->attached_array);
2122        kfree(video);
2123
2124        return 0;
2125}
2126
2127static int __init acpi_video_init(void)
2128{
2129        int result = 0;
2130
2131        acpi_video_dir = proc_mkdir(ACPI_VIDEO_CLASS, acpi_root_dir);
2132        if (!acpi_video_dir)
2133                return -ENODEV;
2134        acpi_video_dir->owner = THIS_MODULE;
2135
2136        result = acpi_bus_register_driver(&acpi_video_bus);
2137        if (result < 0) {
2138                remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
2139                return -ENODEV;
2140        }
2141
2142        return 0;
2143}
2144
2145static void __exit acpi_video_exit(void)
2146{
2147
2148        acpi_bus_unregister_driver(&acpi_video_bus);
2149
2150        remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
2151
2152        return;
2153}
2154
2155module_init(acpi_video_init);
2156module_exit(acpi_video_exit);
2157
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.