123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343 |
- /*
- *
- * Copyright © 1999 Keith Packard
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of Keith Packard not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. Keith Packard makes no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
- * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
- #ifdef HAVE_CONFIG_H
- #include <kdrive-config.h>
- #endif
- #include "kdrive.h"
- #include <errno.h>
- #include <signal.h>
- #include <linux/vt.h>
- #include <linux/kd.h>
- #include <sys/stat.h>
- #include <sys/ioctl.h>
- #include <X11/keysym.h>
- #include <linux/apm_bios.h>
- static int vtno;
- int LinuxConsoleFd;
- static int LinuxApmFd;
- static int activeVT;
- static Bool enabled;
- static void LinuxVTRequest(int sig)
- {
- kdSwitchPending = TRUE;
- }
- /* Check before chowning -- this avoids touching the file system */
- static void LinuxCheckChown(char *file)
- {
- struct stat st;
- __uid_t u;
- __gid_t g;
- if (stat(file, &st) < 0)
- return;
- u = getuid();
- g = getgid();
- if (st.st_uid != u || st.st_gid != g)
- chown(file, u, g);
- }
- static int LinuxInit(void)
- {
- int fd = -1;
- LinuxApmFd = -1;
- char vtname[11];
- struct vt_stat vts;
- LinuxConsoleFd = -1;
- /* check if we're run with euid==0 */
- if (geteuid() != 0) {
- FatalError("LinuxInit: Server must be suid root\n");
- }
- if (kdVirtualTerminal >= 0)
- vtno = kdVirtualTerminal;
- else {
- if ((fd = open("/dev/tty0", O_WRONLY, 0)) < 0) {
- FatalError("LinuxInit: Cannot open /dev/tty0 (%s)\n",
- strerror(errno));
- }
- if ((ioctl(fd, VT_OPENQRY, &vtno) < 0) || (vtno == -1)) {
- FatalError("xf86OpenConsole: Cannot find a free VT\n");
- }
- }
- close(fd);
- sprintf(vtname, "/dev/tty%d", vtno); /* /dev/tty1-64 */
- if ((LinuxConsoleFd = open(vtname, O_RDWR | O_NDELAY, 0)) < 0) {
- FatalError("LinuxInit: Cannot open %s (%s)\n",
- vtname, strerror(errno));
- }
- /* change ownership of the vt */
- LinuxCheckChown(vtname);
- /*
- * the current VT device we're running on is not "console", we want
- * to grab all consoles too
- *
- * Why is this needed?
- */
- LinuxCheckChown("/dev/tty0");
- /*
- * Linux doesn't switch to an active vt after the last close of a vt,
- * so we do this ourselves by remembering which is active now.
- */
- memset(&vts, '\0', sizeof(vts)); /* valgrind */
- if (ioctl(LinuxConsoleFd, VT_GETSTATE, &vts) == 0) {
- activeVT = vts.v_active;
- }
- return 1;
- }
- static void LinuxSetSwitchMode(int mode)
- {
- struct sigaction act;
- struct vt_mode VT;
- if (ioctl(LinuxConsoleFd, VT_GETMODE, &VT) < 0) {
- FatalError("LinuxInit: VT_GETMODE failed\n");
- }
- if (mode == VT_PROCESS) {
- act.sa_handler = LinuxVTRequest;
- sigemptyset(&act.sa_mask);
- act.sa_flags = 0;
- sigaction(SIGUSR1, &act, 0);
- VT.mode = mode;
- VT.relsig = SIGUSR1;
- VT.acqsig = SIGUSR1;
- } else {
- act.sa_handler = SIG_IGN;
- sigemptyset(&act.sa_mask);
- act.sa_flags = 0;
- sigaction(SIGUSR1, &act, 0);
- VT.mode = mode;
- VT.relsig = 0;
- VT.acqsig = 0;
- }
- if (ioctl(LinuxConsoleFd, VT_SETMODE, &VT) < 0) {
- FatalError("LinuxInit: VT_SETMODE failed\n");
- }
- }
- static void
- LinuxApmBlock(pointer blockData, OSTimePtr pTimeout, pointer pReadmask)
- {
- }
- static Bool LinuxApmRunning;
- static void LinuxApmWakeup(pointer blockData, int result, pointer pReadmask)
- {
- fd_set *readmask = (fd_set *) pReadmask;
- if (result > 0 && LinuxApmFd >= 0 && FD_ISSET(LinuxApmFd, readmask)) {
- apm_event_t event;
- Bool running = LinuxApmRunning;
- int cmd = APM_IOC_SUSPEND;
- while (read(LinuxApmFd, &event, sizeof(event)) == sizeof(event)) {
- switch (event) {
- case APM_SYS_STANDBY:
- case APM_USER_STANDBY:
- running = FALSE;
- cmd = APM_IOC_STANDBY;
- break;
- case APM_SYS_SUSPEND:
- case APM_USER_SUSPEND:
- case APM_CRITICAL_SUSPEND:
- running = FALSE;
- cmd = APM_IOC_SUSPEND;
- break;
- case APM_NORMAL_RESUME:
- case APM_CRITICAL_RESUME:
- case APM_STANDBY_RESUME:
- running = TRUE;
- break;
- }
- }
- if (running && !LinuxApmRunning) {
- KdResume();
- LinuxApmRunning = TRUE;
- } else if (!running && LinuxApmRunning) {
- KdSuspend();
- LinuxApmRunning = FALSE;
- ioctl(LinuxApmFd, cmd, 0);
- }
- }
- }
- #ifdef FNONBLOCK
- #define NOBLOCK FNONBLOCK
- #else
- #define NOBLOCK FNDELAY
- #endif
- static void LinuxEnable(void)
- {
- if (enabled)
- return;
- if (kdSwitchPending) {
- kdSwitchPending = FALSE;
- ioctl(LinuxConsoleFd, VT_RELDISP, VT_ACKACQ);
- }
- /*
- * Open the APM driver
- */
- LinuxApmFd = open("/dev/apm_bios", 2);
- if (LinuxApmFd < 0 && errno == ENOENT)
- LinuxApmFd = open("/dev/misc/apm_bios", 2);
- if (LinuxApmFd >= 0) {
- LinuxApmRunning = TRUE;
- fcntl(LinuxApmFd, F_SETFL,
- fcntl(LinuxApmFd, F_GETFL) | NOBLOCK);
- RegisterBlockAndWakeupHandlers(LinuxApmBlock, LinuxApmWakeup,
- 0);
- AddEnabledDevice(LinuxApmFd);
- }
- /*
- * now get the VT
- */
- LinuxSetSwitchMode(VT_AUTO);
- if (ioctl(LinuxConsoleFd, VT_ACTIVATE, vtno) != 0) {
- FatalError("LinuxInit: VT_ACTIVATE failed\n");
- }
- if (ioctl(LinuxConsoleFd, VT_WAITACTIVE, vtno) != 0) {
- FatalError("LinuxInit: VT_WAITACTIVE failed\n");
- }
- LinuxSetSwitchMode(VT_PROCESS);
- if (ioctl(LinuxConsoleFd, KDSETMODE, KD_GRAPHICS) < 0) {
- FatalError("LinuxInit: KDSETMODE KD_GRAPHICS failed\n");
- }
- enabled = TRUE;
- }
- static Bool LinuxSpecialKey(KeySym sym)
- {
- struct vt_stat vts;
- int con;
- if (XK_F1 <= sym && sym <= XK_F12) {
- con = sym - XK_F1 + 1;
- memset(&vts, '\0', sizeof(vts)); /* valgrind */
- ioctl(LinuxConsoleFd, VT_GETSTATE, &vts);
- if (con != vts.v_active && (vts.v_state & (1 << con))) {
- ioctl(LinuxConsoleFd, VT_ACTIVATE, con);
- return TRUE;
- }
- }
- return FALSE;
- }
- static void LinuxDisable(void)
- {
- ioctl(LinuxConsoleFd, KDSETMODE, KD_TEXT); /* Back to text mode ... */
- if (kdSwitchPending) {
- kdSwitchPending = FALSE;
- ioctl(LinuxConsoleFd, VT_RELDISP, 1);
- }
- enabled = FALSE;
- if (LinuxApmFd >= 0) {
- RemoveBlockAndWakeupHandlers(LinuxApmBlock, LinuxApmWakeup, 0);
- RemoveEnabledDevice(LinuxApmFd);
- close(LinuxApmFd);
- LinuxApmFd = -1;
- }
- }
- static void LinuxFini(void)
- {
- struct vt_mode VT;
- struct vt_stat vts;
- int fd;
- if (LinuxConsoleFd < 0)
- return;
- if (ioctl(LinuxConsoleFd, VT_GETMODE, &VT) != -1) {
- VT.mode = VT_AUTO;
- ioctl(LinuxConsoleFd, VT_SETMODE, &VT); /* set dflt vt handling */
- }
- memset(&vts, '\0', sizeof(vts)); /* valgrind */
- ioctl(LinuxConsoleFd, VT_GETSTATE, &vts);
- if (vtno == vts.v_active) {
- /*
- * Find a legal VT to switch to, either the one we started from
- * or the lowest active one that isn't ours
- */
- if (activeVT < 0 ||
- activeVT == vts.v_active ||
- !(vts.v_state & (1 << activeVT))) {
- for (activeVT = 1; activeVT < 16; activeVT++)
- if (activeVT != vtno
- && (vts.v_state & (1 << activeVT)))
- break;
- if (activeVT == 16)
- activeVT = -1;
- }
- /*
- * Perform a switch back to the active VT when we were started
- */
- if (activeVT >= -1) {
- ioctl(LinuxConsoleFd, VT_ACTIVATE, activeVT);
- ioctl(LinuxConsoleFd, VT_WAITACTIVE, activeVT);
- activeVT = -1;
- }
- }
- close(LinuxConsoleFd); /* make the vt-manager happy */
- fd = open("/dev/tty0", O_RDWR | O_NDELAY, 0);
- if (fd >= 0) {
- memset(&vts, '\0', sizeof(vts)); /* valgrind */
- ioctl(fd, VT_GETSTATE, &vts);
- if (ioctl(fd, VT_DISALLOCATE, vtno) < 0)
- fprintf(stderr,
- "Can't deallocate console %d errno %d\n", vtno,
- errno);
- close(fd);
- }
- return;
- }
- static const KdOsFuncs LinuxFuncs = {
- LinuxInit,
- LinuxEnable,
- LinuxSpecialKey,
- LinuxDisable,
- LinuxFini,
- 0
- };
- void OsVendorInit(void)
- {
- KdOsInit(&LinuxFuncs);
- }
|