1#ifdef HAVE_XORG_CONFIG_H
2#include "xorg-config.h"
3#endif
4
5#include "os.h"
6#include "xf86.h"
7#include "xf86Priv.h"
8#define XF86_OS_PRIVS
9#include "xf86_OSproc.h"
10#include <sys/ioctl.h>
11#include <sys/types.h>
12#include <sys/socket.h>
13#include <sys/un.h>
14#include <unistd.h>
15#include <fcntl.h>
16#include <errno.h>
17
18#define ACPI_SOCKET  "/var/run/acpid.socket"
19
20#define ACPI_VIDEO_NOTIFY_SWITCH	0x80
21#define ACPI_VIDEO_NOTIFY_PROBE		0x81
22#define ACPI_VIDEO_NOTIFY_CYCLE		0x82
23#define ACPI_VIDEO_NOTIFY_NEXT_OUTPUT	0x83
24#define ACPI_VIDEO_NOTIFY_PREV_OUTPUT	0x84
25
26#define ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS	0x85
27#define	ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS	0x86
28#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS	0x87
29#define ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS	0x88
30#define ACPI_VIDEO_NOTIFY_DISPLAY_OFF		0x89
31
32#define ACPI_VIDEO_HEAD_INVALID		(~0u - 1)
33#define ACPI_VIDEO_HEAD_END		(~0u)
34
35static void lnxCloseACPI(void);
36static void *ACPIihPtr = NULL;
37PMClose lnxACPIOpen(void);
38
39/* in milliseconds */
40#define ACPI_REOPEN_DELAY 1000
41
42static CARD32
43lnxACPIReopen(OsTimerPtr timer, CARD32 time, void *arg)
44{
45    if (lnxACPIOpen()) {
46        TimerFree(timer);
47        return 0;
48    }
49
50    return ACPI_REOPEN_DELAY;
51}
52
53#define LINE_LENGTH 80
54
55static int
56lnxACPIGetEventFromOs(int fd, pmEvent * events, int num)
57{
58    char ev[LINE_LENGTH];
59    int n;
60
61    memset(ev, 0, LINE_LENGTH);
62
63    do {
64        n = read(fd, ev, LINE_LENGTH);
65    } while ((n == -1) && (errno == EAGAIN || errno == EINTR));
66
67    if (n <= 0) {
68        lnxCloseACPI();
69        TimerSet(NULL, 0, ACPI_REOPEN_DELAY, lnxACPIReopen, NULL);
70        return 0;
71    }
72    /* FIXME: this only processes the first read ACPI event & might break
73     * with interrupted reads. */
74
75    /* Check that we have a video event */
76    if (!strncmp(ev, "video", 5)) {
77        char *GFX = NULL;
78        char *notify = NULL;
79        char *data = NULL;      /* doesn't appear to be used in the kernel */
80        unsigned long int notify_l;
81
82        strtok(ev, " ");
83
84        if (!(GFX = strtok(NULL, " ")))
85            return 0;
86#if 0
87        ErrorF("GFX: %s\n", GFX);
88#endif
89
90        if (!(notify = strtok(NULL, " ")))
91            return 0;
92        notify_l = strtoul(notify, NULL, 16);
93#if 0
94        ErrorF("notify: 0x%lx\n", notify_l);
95#endif
96
97        if (!(data = strtok(NULL, " ")))
98            return 0;
99#if 0
100        data_l = strtoul(data, NULL, 16);
101        ErrorF("data: 0x%lx\n", data_l);
102#endif
103
104        /* Differentiate between events */
105        switch (notify_l) {
106        case ACPI_VIDEO_NOTIFY_SWITCH:
107        case ACPI_VIDEO_NOTIFY_CYCLE:
108        case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT:
109        case ACPI_VIDEO_NOTIFY_PREV_OUTPUT:
110            events[0] = XF86_APM_CAPABILITY_CHANGED;
111            return 1;
112        case ACPI_VIDEO_NOTIFY_PROBE:
113            return 0;
114        default:
115            return 0;
116        }
117    }
118
119    return 0;
120}
121
122static pmWait
123lnxACPIConfirmEventToOs(int fd, pmEvent event)
124{
125    /* No ability to send back to the kernel in ACPI */
126    switch (event) {
127    default:
128        return PM_NONE;
129    }
130}
131
132PMClose
133lnxACPIOpen(void)
134{
135    int fd;
136    struct sockaddr_un addr;
137    int r = -1;
138    static int warned = 0;
139
140    DebugF("ACPI: OSPMOpen called\n");
141    if (ACPIihPtr || !xf86Info.pmFlag)
142        return NULL;
143
144    DebugF("ACPI: Opening device\n");
145    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) > -1) {
146        memset(&addr, 0, sizeof(addr));
147        addr.sun_family = AF_UNIX;
148        strcpy(addr.sun_path, ACPI_SOCKET);
149        if ((r = connect(fd, (struct sockaddr *) &addr, sizeof(addr))) == -1) {
150            if (!warned)
151                xf86MsgVerb(X_WARNING, 3, "Open ACPI failed (%s) (%s)\n",
152                            ACPI_SOCKET, strerror(errno));
153            warned = 1;
154            shutdown(fd, 2);
155            close(fd);
156            return NULL;
157        }
158    }
159
160    xf86PMGetEventFromOs = lnxACPIGetEventFromOs;
161    xf86PMConfirmEventToOs = lnxACPIConfirmEventToOs;
162    ACPIihPtr = xf86AddGeneralHandler(fd, xf86HandlePMEvents, NULL);
163    xf86MsgVerb(X_INFO, 3, "Open ACPI successful (%s)\n", ACPI_SOCKET);
164    warned = 0;
165
166    return lnxCloseACPI;
167}
168
169static void
170lnxCloseACPI(void)
171{
172    int fd;
173
174    DebugF("ACPI: Closing device\n");
175    if (ACPIihPtr) {
176        fd = xf86RemoveGeneralHandler(ACPIihPtr);
177        shutdown(fd, 2);
178        close(fd);
179        ACPIihPtr = NULL;
180    }
181}
182