2 * Copyright 1992 by Rich Murphey <Rich@Rice.edu>
3 * Copyright 1993 by David Wexelblat <dwex@goblin.org>
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the names of Rich Murphey and David Wexelblat
10 * not be used in advertising or publicity pertaining to distribution of
11 * the software without specific, written prior permission. Rich Murphey and
12 * David Wexelblat make no representations about the suitability of this
13 * software for any purpose. It is provided "as is" without express or
16 * RICH MURPHEY AND DAVID WEXELBLAT DISCLAIM ALL WARRANTIES WITH REGARD TO
17 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
18 * FITNESS, IN NO EVENT SHALL RICH MURPHEY OR DAVID WEXELBLAT BE LIABLE FOR
19 * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
20 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
21 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26 #ifdef HAVE_XORG_CONFIG_H
27 #include <xorg-config.h>
36 #include "xf86_OSlib.h"
38 #include <sys/utsname.h>
39 #include <sys/ioctl.h>
43 static Bool KeepTty
= FALSE
;
46 static int devConsoleFd
= -1;
48 #if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT)
49 static int VTnum
= -1;
50 static int initialVT
= -1;
54 /* Stock 0.1 386bsd pccons console driver interface */
55 #define PCCONS_CONSOLE_DEV1 "/dev/ttyv0"
56 #define PCCONS_CONSOLE_DEV2 "/dev/vga"
57 #define PCCONS_CONSOLE_MODE O_RDWR|O_NDELAY
60 #ifdef SYSCONS_SUPPORT
61 /* The FreeBSD 1.1 version syscons driver uses /dev/ttyv0 */
62 #define SYSCONS_CONSOLE_DEV1 "/dev/ttyv0"
63 #define SYSCONS_CONSOLE_DEV2 "/dev/vga"
64 #define SYSCONS_CONSOLE_MODE O_RDWR|O_NDELAY
68 /* Hellmuth Michaelis' pcvt driver */
70 #define PCVT_CONSOLE_DEV "/dev/ttyv0"
72 #define PCVT_CONSOLE_DEV "/dev/ttyC0"
74 #define PCVT_CONSOLE_MODE O_RDWR|O_NDELAY
77 #if defined(WSCONS_SUPPORT) && defined(__NetBSD__)
78 /* NetBSD's new console driver */
79 #define WSCONS_PCVT_COMPAT_CONSOLE_DEV "/dev/ttyE0"
83 #define setpgrp setpgid
86 #define CHECK_DRIVER_MSG \
87 "Check your kernel's console driver configuration and /dev entries"
89 static char *supported_drivers
[] = {
91 "pccons (with X support)",
93 #ifdef SYSCONS_SUPPORT
105 * Functions to probe for the existance of a supported console driver.
106 * Any function returns either a valid file descriptor (driver probed
107 * succesfully), -1 (driver not found), or uses FatalError() if the
108 * driver was found but proved to not support the required mode to run
112 typedef int (*xf86ConsOpen_t
) (void);
114 #ifdef PCCONS_SUPPORT
115 static int xf86OpenPccons(void);
116 #endif /* PCCONS_SUPPORT */
118 #ifdef SYSCONS_SUPPORT
119 static int xf86OpenSyscons(void);
120 #endif /* SYSCONS_SUPPORT */
123 static int xf86OpenPcvt(void);
124 #endif /* PCVT_SUPPORT */
126 #ifdef WSCONS_SUPPORT
127 static int xf86OpenWScons(void);
131 * The sequence of the driver probes is important; start with the
132 * driver that is best distinguishable, and end with the most generic
133 * driver. (Otherwise, pcvt would also probe as syscons, and either
134 * pcvt or syscons might succesfully probe as pccons.)
136 static xf86ConsOpen_t xf86ConsTab
[] = {
140 #ifdef SYSCONS_SUPPORT
143 #ifdef PCCONS_SUPPORT
146 #ifdef WSCONS_SUPPORT
149 (xf86ConsOpen_t
) NULL
156 xf86ConsOpen_t
*driver
;
158 #if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT)
161 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
167 if (serverGeneration
== 1) {
168 /* check if we are run with euid==0 */
169 if (geteuid() != 0) {
170 FatalError("xf86OpenConsole: Server must be suid root");
175 * detaching the controlling tty solves problems of kbd character
176 * loss. This is not interesting for CO driver, because it is
179 setpgrp(0, getpid());
180 if ((i
= open("/dev/tty", O_RDWR
)) >= 0) {
181 ioctl(i
, TIOCNOTTY
, (char *) 0);
186 /* detect which driver we are running on */
187 for (driver
= xf86ConsTab
; *driver
; driver
++) {
188 if ((fd
= (*driver
) ()) >= 0)
192 /* Check that a supported console driver was found */
194 char cons_drivers
[80] = { 0, };
195 for (i
= 0; i
< sizeof(supported_drivers
) / sizeof(char *); i
++) {
197 strcat(cons_drivers
, ", ");
199 strcat(cons_drivers
, supported_drivers
[i
]);
202 ("%s: No console driver found\n\tSupported drivers: %s\n\t%s",
203 "xf86OpenConsole", cons_drivers
, CHECK_DRIVER_MSG
);
205 xf86Info
.consoleFd
= fd
;
207 switch (xf86Info
.consType
) {
208 #ifdef PCCONS_SUPPORT
210 if (ioctl(xf86Info
.consoleFd
, CONSOLE_X_MODE_ON
, 0) < 0) {
211 FatalError("%s: CONSOLE_X_MODE_ON failed (%s)\n%s",
212 "xf86OpenConsole", strerror(errno
),
216 * Hack to prevent keyboard hanging when syslogd closes
219 if ((devConsoleFd
= open("/dev/console", O_WRONLY
, 0)) < 0) {
221 "xf86OpenConsole: couldn't open /dev/console (%s)\n",
226 #if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT)
228 /* as of FreeBSD 2.2.8, syscons driver does not need the #1 vt
229 * switching anymore. Here we check for FreeBSD 3.1 and up.
230 * Add cases for other *BSD that behave the same.
232 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
234 i
= atof(uts
.release
) * 100;
238 /* otherwise fall through */
240 #if !(defined(__NetBSD__) && (__NetBSD_Version__ >= 200000000))
242 * First activate the #1 VT. This is a hack to allow a server
243 * to be started while another one is active. There should be
246 if (initialVT
!= 1) {
248 if (ioctl(xf86Info
.consoleFd
, VT_ACTIVATE
, 1) != 0) {
249 xf86Msg(X_WARNING
, "xf86OpenConsole: VT_ACTIVATE failed\n");
255 if (!xf86Info
.ShareVTs
) {
260 ioctl(xf86Info
.consoleFd
, VT_ACTIVATE
, xf86Info
.vtno
));
262 xf86Msg(X_WARNING
, "xf86OpenConsole: VT_ACTIVATE failed\n");
265 ioctl(xf86Info
.consoleFd
, VT_WAITACTIVE
,
269 "xf86OpenConsole: VT_WAITACTIVE failed\n");
272 signal(SIGUSR1
, xf86VTRequest
);
274 vtmode
.mode
= VT_PROCESS
;
275 vtmode
.relsig
= SIGUSR1
;
276 vtmode
.acqsig
= SIGUSR1
;
277 vtmode
.frsig
= SIGUSR1
;
278 if (ioctl(xf86Info
.consoleFd
, VT_SETMODE
, &vtmode
) < 0) {
279 FatalError("xf86OpenConsole: VT_SETMODE VT_PROCESS failed");
281 #if !defined(__OpenBSD__) && !defined(USE_DEV_IO) && !defined(USE_I386_IOPL)
282 if (ioctl(xf86Info
.consoleFd
, KDENABIO
, 0) < 0) {
283 FatalError("xf86OpenConsole: KDENABIO failed (%s)",
287 if (ioctl(xf86Info
.consoleFd
, KDSETMODE
, KD_GRAPHICS
) < 0) {
288 FatalError("xf86OpenConsole: KDSETMODE KD_GRAPHICS failed");
291 else { /* xf86Info.ShareVTs */
292 close(xf86Info
.consoleFd
);
295 #endif /* SYSCONS_SUPPORT || PCVT_SUPPORT */
296 #ifdef WSCONS_SUPPORT
304 /* serverGeneration != 1 */
305 #if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT)
306 if (!xf86Info
.ShareVTs
&&
307 (xf86Info
.consType
== SYSCONS
|| xf86Info
.consType
== PCVT
)) {
308 if (ioctl(xf86Info
.consoleFd
, VT_ACTIVATE
, xf86Info
.vtno
) != 0) {
309 xf86Msg(X_WARNING
, "xf86OpenConsole: VT_ACTIVATE failed\n");
312 #endif /* SYSCONS_SUPPORT || PCVT_SUPPORT */
317 #ifdef PCCONS_SUPPORT
324 if ((fd
= open(PCCONS_CONSOLE_DEV1
, PCCONS_CONSOLE_MODE
, 0))
325 >= 0 || (fd
= open(PCCONS_CONSOLE_DEV2
, PCCONS_CONSOLE_MODE
, 0))
327 if (ioctl(fd
, CONSOLE_X_MODE_OFF
, 0) < 0) {
328 FatalError("%s: CONSOLE_X_MODE_OFF failed (%s)\n%s\n%s",
331 "Was expecting pccons driver with X support",
334 xf86Info
.consType
= PCCONS
;
335 xf86Msg(X_PROBED
, "Using pccons driver with X support\n");
340 #endif /* PCCONS_SUPPORT */
342 #ifdef SYSCONS_SUPPORT
350 long syscons_version
;
353 /* Check for syscons */
354 if ((fd
= open(SYSCONS_CONSOLE_DEV1
, SYSCONS_CONSOLE_MODE
, 0)) >= 0
355 || (fd
= open(SYSCONS_CONSOLE_DEV2
, SYSCONS_CONSOLE_MODE
, 0)) >= 0) {
356 if (ioctl(fd
, VT_GETMODE
, &vtmode
) >= 0) {
357 /* Get syscons version */
358 if (ioctl(fd
, CONS_GETVERS
, &syscons_version
) < 0) {
362 xf86Info
.vtno
= VTnum
;
366 if (ioctl(fd
, VT_GETACTIVE
, &initialVT
) < 0)
369 if (xf86Info
.ShareVTs
)
370 xf86Info
.vtno
= initialVT
;
372 if (xf86Info
.vtno
== -1) {
374 * For old syscons versions (<0x100), VT_OPENQRY returns
375 * the current VT rather than the next free VT. In this
376 * case, the server gets started on the current VT instead
377 * of the next free VT.
381 /* check for the fixed VT_OPENQRY */
382 if (syscons_version
>= 0x100) {
384 if (ioctl(fd
, VT_OPENQRY
, &xf86Info
.vtno
) < 0) {
392 if (xf86Info
.vtno
== -1) {
394 * All VTs are in use. If initialVT was found, use it.
396 if (initialVT
!= -1) {
397 xf86Info
.vtno
= initialVT
;
400 if (syscons_version
>= 0x100) {
401 FatalError("%s: Cannot find a free VT",
404 /* Should no longer reach here */
405 FatalError("%s: %s %s\n\t%s %s",
407 "syscons versions prior to 1.0 require",
409 "server's stdin be a VT",
410 "or the use of the vtxx server option");
417 snprintf(vtname
, sizeof(vtname
), "/dev/ttyv%01x",
419 if ((fd
= open(vtname
, SYSCONS_CONSOLE_MODE
, 0)) < 0) {
420 FatalError("xf86OpenSyscons: Cannot open %s (%s)",
421 vtname
, strerror(errno
));
423 if (ioctl(fd
, VT_GETMODE
, &vtmode
) < 0) {
424 FatalError("xf86OpenSyscons: VT_GETMODE failed");
426 xf86Info
.consType
= SYSCONS
;
427 xf86Msg(X_PROBED
, "Using syscons driver with X support");
428 if (syscons_version
>= 0x100) {
429 xf86ErrorF(" (version %ld.%ld)\n", syscons_version
>> 8,
430 syscons_version
& 0xFF);
433 xf86ErrorF(" (version 0.x)\n");
435 xf86Msg(from
, "using VT number %d\n\n", xf86Info
.vtno
);
438 /* VT_GETMODE failed, probably not syscons */
446 #endif /* SYSCONS_SUPPORT */
453 /* This looks much like syscons, since pcvt is API compatible */
456 char vtname
[12], *vtprefix
;
457 struct pcvtid pcvt_version
;
460 vtprefix
= "/dev/ttyv";
462 vtprefix
= "/dev/ttyC";
465 fd
= open(PCVT_CONSOLE_DEV
, PCVT_CONSOLE_MODE
, 0);
466 #ifdef WSCONS_PCVT_COMPAT_CONSOLE_DEV
468 fd
= open(WSCONS_PCVT_COMPAT_CONSOLE_DEV
, PCVT_CONSOLE_MODE
, 0);
469 vtprefix
= "/dev/ttyE";
473 if (ioctl(fd
, VGAPCVTID
, &pcvt_version
) >= 0) {
474 if (ioctl(fd
, VT_GETMODE
, &vtmode
) < 0) {
475 FatalError("%s: VT_GETMODE failed\n%s%s\n%s",
477 "Found pcvt driver but X11 seems to be",
478 " not supported.", CHECK_DRIVER_MSG
);
481 xf86Info
.vtno
= VTnum
;
483 if (ioctl(fd
, VT_GETACTIVE
, &initialVT
) < 0)
486 if (xf86Info
.vtno
== -1) {
487 if (ioctl(fd
, VT_OPENQRY
, &xf86Info
.vtno
) < 0) {
492 if (xf86Info
.vtno
== -1) {
494 * All VTs are in use. If initialVT was found, use it.
496 if (initialVT
!= -1) {
497 xf86Info
.vtno
= initialVT
;
500 FatalError("%s: Cannot find a free VT", "xf86OpenPcvt");
506 snprintf(vtname
, sizeof(vtname
), "%s%01x", vtprefix
,
508 if ((fd
= open(vtname
, PCVT_CONSOLE_MODE
, 0)) < 0) {
509 ErrorF("xf86OpenPcvt: Cannot open %s (%s)",
510 vtname
, strerror(errno
));
511 xf86Info
.vtno
= initialVT
;
512 snprintf(vtname
, sizeof(vtname
), "%s%01x", vtprefix
,
514 if ((fd
= open(vtname
, PCVT_CONSOLE_MODE
, 0)) < 0) {
515 FatalError("xf86OpenPcvt: Cannot open %s (%s)",
516 vtname
, strerror(errno
));
519 if (ioctl(fd
, VT_GETMODE
, &vtmode
) < 0) {
520 FatalError("xf86OpenPcvt: VT_GETMODE failed");
522 xf86Info
.consType
= PCVT
;
523 #ifdef WSCONS_SUPPORT
525 "Using wscons driver on %s in pcvt compatibility mode "
526 "(version %d.%d)\n", vtname
,
527 pcvt_version
.rmajor
, pcvt_version
.rminor
);
529 xf86Msg(X_PROBED
, "Using pcvt driver (version %d.%d)\n",
530 pcvt_version
.rmajor
, pcvt_version
.rminor
);
542 #endif /* PCVT_SUPPORT */
544 #ifdef WSCONS_SUPPORT
550 int mode
= WSDISPLAYIO_MODE_MAPPED
;
554 /* XXX Is this ok? */
555 for (i
= 0; i
< 8; i
++) {
556 #if defined(__NetBSD__)
557 snprintf(ttyname
, sizeof(ttyname
), "/dev/ttyE%d", i
);
558 #elif defined(__OpenBSD__)
559 snprintf(ttyname
, sizeof(ttyname
), "/dev/ttyC%x", i
);
561 if ((fd
= open(ttyname
, 2)) != -1)
565 if (ioctl(fd
, WSDISPLAYIO_SMODE
, &mode
) < 0) {
566 FatalError("%s: WSDISPLAYIO_MODE_MAPPED failed (%s)\n%s",
567 "xf86OpenConsole", strerror(errno
), CHECK_DRIVER_MSG
);
569 xf86Info
.consType
= WSCONS
;
570 xf86Msg(X_PROBED
, "Using wscons driver\n");
575 #endif /* WSCONS_SUPPORT */
580 #if defined(SYSCONS_SUPPORT) || defined(PCVT_SUPPORT)
584 if (xf86Info
.ShareVTs
)
587 switch (xf86Info
.consType
) {
588 #ifdef PCCONS_SUPPORT
590 ioctl(xf86Info
.consoleFd
, CONSOLE_X_MODE_OFF
, 0);
592 #endif /* PCCONS_SUPPORT */
593 #if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT)
596 ioctl(xf86Info
.consoleFd
, KDSETMODE
, KD_TEXT
); /* Back to text mode */
597 if (ioctl(xf86Info
.consoleFd
, VT_GETMODE
, &VT
) != -1) {
599 ioctl(xf86Info
.consoleFd
, VT_SETMODE
, &VT
); /* dflt vt handling */
601 #if !defined(__OpenBSD__) && !defined(USE_DEV_IO) && !defined(USE_I386_IOPL)
602 if (ioctl(xf86Info
.consoleFd
, KDDISABIO
, 0) < 0) {
603 xf86FatalError("xf86CloseConsole: KDDISABIO failed (%s)",
608 ioctl(xf86Info
.consoleFd
, VT_ACTIVATE
, initialVT
);
610 #endif /* SYSCONS_SUPPORT || PCVT_SUPPORT */
611 #ifdef WSCONS_SUPPORT
614 int mode
= WSDISPLAYIO_MODE_EMUL
;
616 ioctl(xf86Info
.consoleFd
, WSDISPLAYIO_SMODE
, &mode
);
622 close(xf86Info
.consoleFd
);
623 #ifdef PCCONS_SUPPORT
624 if (devConsoleFd
>= 0)
631 xf86ProcessArgument(int argc
, char *argv
[], int i
)
634 * Keep server from detaching from controlling tty. This is useful
635 * when debugging (so the server can receive keyboard signals.
637 if (!strcmp(argv
[i
], "-keeptty")) {
641 #if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT)
642 if ((argv
[i
][0] == 'v') && (argv
[i
][1] == 't')) {
643 if (sscanf(argv
[i
], "vt%2d", &VTnum
) == 0 || VTnum
< 1 || VTnum
> 12) {
650 #endif /* SYSCONS_SUPPORT || PCVT_SUPPORT */
657 #if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT)
658 ErrorF("vtXX use the specified VT number (1-12)\n");
659 #endif /* SYSCONS_SUPPORT || PCVT_SUPPORT */
661 ErrorF("don't detach controlling tty (for debugging only)\n");