2 * Copyright © 1999 Keith Packard
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Keith Packard not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission. Keith Packard makes no
11 * representations about the suitability of this software for any purpose. It
12 * is provided "as is" without express or implied warranty.
14 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
24 #include <kdrive-config.h>
32 #include <sys/ioctl.h>
33 #include <X11/keysym.h>
34 #include <linux/apm_bios.h>
37 extern KdPointerDriver LinuxMouseDriver
;
38 extern KdPointerDriver Ps2MouseDriver
;
39 extern KdPointerDriver MsMouseDriver
;
42 extern KdPointerDriver TsDriver
;
45 extern KdPointerDriver LinuxEvdevMouseDriver
;
46 extern KdKeyboardDriver LinuxEvdevKeyboardDriver
;
49 extern KdKeyboardDriver LinuxKeyboardDriver
;
59 LinuxVTRequest(int sig
)
61 kdSwitchPending
= TRUE
;
64 /* Check before chowning -- this avoids touching the file system */
66 LinuxCheckChown(const char *file
)
72 if (stat(file
, &st
) < 0)
76 if (st
.st_uid
!= u
|| st
.st_gid
!= g
)
88 /* check if we're run with euid==0 */
90 FatalError("LinuxInit: Server must be suid root\n");
93 if (kdVirtualTerminal
>= 0)
94 vtno
= kdVirtualTerminal
;
96 if ((fd
= open("/dev/tty0", O_WRONLY
, 0)) < 0) {
97 FatalError("LinuxInit: Cannot open /dev/tty0 (%s)\n",
100 if ((ioctl(fd
, VT_OPENQRY
, &vtno
) < 0) || (vtno
== -1)) {
101 FatalError("xf86OpenConsole: Cannot find a free VT\n");
106 snprintf(vtname
, sizeof(vtname
), "/dev/tty%d", vtno
); /* /dev/tty1-64 */
108 if ((LinuxConsoleFd
= open(vtname
, O_RDWR
| O_NDELAY
, 0)) < 0) {
109 FatalError("LinuxInit: Cannot open %s (%s)\n", vtname
, strerror(errno
));
112 /* change ownership of the vt */
113 LinuxCheckChown(vtname
);
116 * the current VT device we're running on is not "console", we want
117 * to grab all consoles too
119 * Why is this needed?
121 LinuxCheckChown("/dev/tty0");
123 * Linux doesn't switch to an active vt after the last close of a vt,
124 * so we do this ourselves by remembering which is active now.
126 memset(&vts
, '\0', sizeof(vts
)); /* valgrind */
127 if (ioctl(LinuxConsoleFd
, VT_GETSTATE
, &vts
) == 0) {
128 activeVT
= vts
.v_active
;
135 LinuxSetSwitchMode(int mode
)
137 struct sigaction act
;
140 if (ioctl(LinuxConsoleFd
, VT_GETMODE
, &VT
) < 0) {
141 FatalError("LinuxInit: VT_GETMODE failed\n");
144 if (mode
== VT_PROCESS
) {
145 act
.sa_handler
= LinuxVTRequest
;
146 sigemptyset(&act
.sa_mask
);
148 sigaction(SIGUSR1
, &act
, 0);
155 act
.sa_handler
= SIG_IGN
;
156 sigemptyset(&act
.sa_mask
);
158 sigaction(SIGUSR1
, &act
, 0);
164 if (ioctl(LinuxConsoleFd
, VT_SETMODE
, &VT
) < 0) {
165 FatalError("LinuxInit: VT_SETMODE failed\n");
170 LinuxApmBlock(pointer blockData
, OSTimePtr pTimeout
, pointer pReadmask
)
174 static Bool LinuxApmRunning
;
177 LinuxApmWakeup(pointer blockData
, int result
, pointer pReadmask
)
179 fd_set
*readmask
= (fd_set
*) pReadmask
;
181 if (result
> 0 && LinuxApmFd
>= 0 && FD_ISSET(LinuxApmFd
, readmask
)) {
183 Bool running
= LinuxApmRunning
;
184 int cmd
= APM_IOC_SUSPEND
;
186 while (read(LinuxApmFd
, &event
, sizeof(event
)) == sizeof(event
)) {
188 case APM_SYS_STANDBY
:
189 case APM_USER_STANDBY
:
191 cmd
= APM_IOC_STANDBY
;
193 case APM_SYS_SUSPEND
:
194 case APM_USER_SUSPEND
:
195 case APM_CRITICAL_SUSPEND
:
197 cmd
= APM_IOC_SUSPEND
;
199 case APM_NORMAL_RESUME
:
200 case APM_CRITICAL_RESUME
:
201 case APM_STANDBY_RESUME
:
206 if (running
&& !LinuxApmRunning
) {
208 LinuxApmRunning
= TRUE
;
210 else if (!running
&& LinuxApmRunning
) {
212 LinuxApmRunning
= FALSE
;
213 ioctl(LinuxApmFd
, cmd
, 0);
219 #define NOBLOCK FNONBLOCK
221 #define NOBLOCK FNDELAY
229 if (kdSwitchPending
) {
230 kdSwitchPending
= FALSE
;
231 ioctl(LinuxConsoleFd
, VT_RELDISP
, VT_ACKACQ
);
234 * Open the APM driver
236 LinuxApmFd
= open("/dev/apm_bios", 2);
237 if (LinuxApmFd
< 0 && errno
== ENOENT
)
238 LinuxApmFd
= open("/dev/misc/apm_bios", 2);
239 if (LinuxApmFd
>= 0) {
240 LinuxApmRunning
= TRUE
;
241 fcntl(LinuxApmFd
, F_SETFL
, fcntl(LinuxApmFd
, F_GETFL
) | NOBLOCK
);
242 RegisterBlockAndWakeupHandlers(LinuxApmBlock
, LinuxApmWakeup
, 0);
243 AddEnabledDevice(LinuxApmFd
);
249 LinuxSetSwitchMode(VT_AUTO
);
250 if (ioctl(LinuxConsoleFd
, VT_ACTIVATE
, vtno
) != 0) {
251 FatalError("LinuxInit: VT_ACTIVATE failed\n");
253 if (ioctl(LinuxConsoleFd
, VT_WAITACTIVE
, vtno
) != 0) {
254 FatalError("LinuxInit: VT_WAITACTIVE failed\n");
256 LinuxSetSwitchMode(VT_PROCESS
);
257 if (ioctl(LinuxConsoleFd
, KDSETMODE
, KD_GRAPHICS
) < 0) {
258 FatalError("LinuxInit: KDSETMODE KD_GRAPHICS failed\n");
266 ioctl(LinuxConsoleFd
, KDSETMODE
, KD_TEXT
); /* Back to text mode ... */
267 if (kdSwitchPending
) {
268 kdSwitchPending
= FALSE
;
269 ioctl(LinuxConsoleFd
, VT_RELDISP
, 1);
272 if (LinuxApmFd
>= 0) {
273 RemoveBlockAndWakeupHandlers(LinuxApmBlock
, LinuxApmWakeup
, 0);
274 RemoveEnabledDevice(LinuxApmFd
);
287 if (LinuxConsoleFd
< 0)
290 if (ioctl(LinuxConsoleFd
, VT_GETMODE
, &VT
) != -1) {
292 ioctl(LinuxConsoleFd
, VT_SETMODE
, &VT
); /* set dflt vt handling */
294 memset(&vts
, '\0', sizeof(vts
)); /* valgrind */
295 ioctl(LinuxConsoleFd
, VT_GETSTATE
, &vts
);
296 if (vtno
== vts
.v_active
) {
298 * Find a legal VT to switch to, either the one we started from
299 * or the lowest active one that isn't ours
302 activeVT
== vts
.v_active
|| !(vts
.v_state
& (1 << activeVT
))) {
303 for (activeVT
= 1; activeVT
< 16; activeVT
++)
304 if (activeVT
!= vtno
&& (vts
.v_state
& (1 << activeVT
)))
310 * Perform a switch back to the active VT when we were started
312 if (activeVT
>= -1) {
313 ioctl(LinuxConsoleFd
, VT_ACTIVATE
, activeVT
);
314 ioctl(LinuxConsoleFd
, VT_WAITACTIVE
, activeVT
);
318 close(LinuxConsoleFd
); /* make the vt-manager happy */
320 fd
= open("/dev/tty0", O_RDWR
| O_NDELAY
, 0);
322 memset(&vts
, '\0', sizeof(vts
)); /* valgrind */
323 ioctl(fd
, VT_GETSTATE
, &vts
);
324 if (ioctl(fd
, VT_DISALLOCATE
, vtno
) < 0)
325 fprintf(stderr
, "Can't deallocate console %d %s\n", vtno
,
333 KdOsAddInputDrivers(void)
336 KdAddPointerDriver(&LinuxMouseDriver
);
337 KdAddPointerDriver(&MsMouseDriver
);
338 KdAddPointerDriver(&Ps2MouseDriver
);
341 KdAddPointerDriver(&TsDriver
);
344 KdAddPointerDriver(&LinuxEvdevMouseDriver
);
345 KdAddKeyboardDriver(&LinuxEvdevKeyboardDriver
);
348 KdAddKeyboardDriver(&LinuxKeyboardDriver
);
353 LinuxBell(int volume
, int pitch
, int duration
)
356 ioctl(LinuxConsoleFd
, KDMKTONE
, ((1193190 / pitch
) & 0xffff) |
357 (((unsigned long) duration
* volume
/ 50) << 16));
360 KdOsFuncs LinuxFuncs
= {
362 .Enable
= LinuxEnable
,
363 .Disable
= LinuxDisable
,
371 KdOsInit(&LinuxFuncs
);