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