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 
35 static void lnxCloseACPI(void);
36 static void *ACPIihPtr = NULL;
37 PMClose lnxACPIOpen(void);
38 
39 /* in milliseconds */
40 #define ACPI_REOPEN_DELAY 1000
41 
42 static CARD32
lnxACPIReopen(OsTimerPtr timer,CARD32 time,void * arg)43 lnxACPIReopen(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 
55 static int
lnxACPIGetEventFromOs(int fd,pmEvent * events,int num)56 lnxACPIGetEventFromOs(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 
122 static pmWait
lnxACPIConfirmEventToOs(int fd,pmEvent event)123 lnxACPIConfirmEventToOs(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 
132 PMClose
lnxACPIOpen(void)133 lnxACPIOpen(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 
169 static void
lnxCloseACPI(void)170 lnxCloseACPI(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