Showing error 1718

User: Jiri Slaby
Error type: Invalid Pointer Dereference
Error type description: A pointer which is invalid is being dereferenced
File location: drivers/acpi/video.c
Line in file: 755
Project: Linux Kernel
Project version: 2.6.28
Tools: Smatch (1.59)
Entered: 2013-09-10 20:24:52 UTC


Source:

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