1/**
2 * \file
3 * \brief ACPI video hacks
4 */
5
6/*
7 * Copyright (c) 2009, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <stdio.h>
16#include <barrelfish/barrelfish.h>
17#include <acpi.h>
18
19#include "acpi_shared.h"
20#include "acpi_debug.h"
21
22static ACPI_STATUS walk_video_device(ACPI_HANDLE handle, UINT32 level,
23                                     void *context, void **dummy)
24{
25    ACPI_OBJECT_LIST ArgList;
26    ACPI_OBJECT Arg;
27    ACPI_STATUS as;
28    char namebuf[128];
29    ACPI_BUFFER namebufobj = {.Length = sizeof(namebuf), .Pointer = namebuf};
30
31    /* get the node's name */
32    as = AcpiGetName(handle, ACPI_FULL_PATHNAME, &namebufobj);
33    if (ACPI_FAILURE(as)) {
34        return as;
35    }
36    assert(namebufobj.Pointer == namebuf);
37
38#if 1
39    /* Execute the _DOS method (Enable/Disable Output Switching) B.4.1 */
40    ArgList.Count = 1;
41    ArgList.Pointer = &Arg;
42    Arg.Type = ACPI_TYPE_INTEGER;
43    Arg.Integer.Value = 0x1; /* automatically switch outputs */
44    as = AcpiEvaluateObject(handle, "_DOS", &ArgList, NULL);
45    if (ACPI_SUCCESS(as)) {
46        ACPI_DEBUG("%s: successfully enabled video output switching\n", namebuf);
47    }
48#endif
49
50    /* Execute the _DOD method if present (enumerate all devices, B.4.2 */
51    char packagebuf[1024];
52    ACPI_BUFFER retbuf = {.Length = sizeof(packagebuf), .Pointer = packagebuf};
53    as = AcpiEvaluateObjectTyped(handle, "_DOD", NULL, &retbuf, ACPI_TYPE_PACKAGE);
54    if (ACPI_SUCCESS(as)) {
55        ACPI_DEBUG("called %s._DOD ok\n", namebuf);
56    } else if (as != AE_NOT_FOUND) {
57        ACPI_DEBUG("error executing _DOD method on %s: 0x%"PRIx32"\n", namebuf, as);
58    }
59
60    /* Execute the _DCS method if present (output device status) B.6.6 */
61    ACPI_INTEGER retval;
62    as = acpi_eval_integer(handle, "_DCS", &retval);
63    if (ACPI_FAILURE(as)) {
64        if (as != AE_NOT_FOUND) {
65            ACPI_DEBUG("error executing _DCS method on %s: 0x%"PRIx32"\n", namebuf, as);
66        }
67        return AE_OK; // skip the rest
68    }
69
70    ACPI_DEBUG("%s: current video state is 0x%"PRIx64"\n", namebuf, retval);
71
72    /* if connector exists and is ready to switch, enable it! */
73    if ((strstr(namebuf, "CRT0") || strstr(namebuf, "LCD0"))
74        && (retval & 0xf) == 0xd) {
75        ArgList.Count = 1;
76        ArgList.Pointer = &Arg;
77        Arg.Type = ACPI_TYPE_INTEGER;
78        Arg.Integer.Value = 0x80000001;
79        as = AcpiEvaluateObject(handle, "_DSS", &ArgList, NULL);
80        if (ACPI_SUCCESS(as)) {
81            ACPI_DEBUG("%s: successfully enabled video output\n", namebuf);
82        } else {
83            ACPI_DEBUG("%s: enabling video output failed: 0x%"PRIx32"\n", namebuf, as);
84        }
85    }
86
87    return AE_OK;
88}
89
90// XXX: enable video output switching
91void acpi_arch_video_init(void)
92{
93    ACPI_STATUS as;
94
95    /* find all devices with a _DOS method and call it */
96    ACPI_DEBUG("Walking for video devices\n");
97    //as = AcpiGetDevices(NULL, walk_video_device, NULL, NULL);
98    as = AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
99                           walk_video_device, walk_video_device, NULL, NULL);
100    assert(ACPI_SUCCESS(as));
101}
102