First import
[xorg_rtime.git] / xorg-server-1.4 / hw / kdrive / linux / linux.c
blob23cd8f59fadc5b25234a7c0fb3acdcc2a44a1d19
1 /*
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.
23 #ifdef HAVE_CONFIG_H
24 #include <kdrive-config.h>
25 #endif
26 #include "kdrive.h"
27 #include "klinux.h"
28 #include <errno.h>
29 #include <signal.h>
30 #include <linux/vt.h>
31 #include <linux/kd.h>
32 #include <sys/stat.h>
33 #include <sys/ioctl.h>
34 #include <X11/keysym.h>
35 #include <linux/apm_bios.h>
37 static int vtno;
38 int LinuxConsoleFd;
39 int LinuxApmFd = -1;
40 static int activeVT;
41 static Bool enabled;
43 static void
44 LinuxVTRequest (int sig)
46 kdSwitchPending = TRUE;
49 /* Check before chowning -- this avoids touching the file system */
50 static void
51 LinuxCheckChown (char *file)
53 struct stat st;
54 __uid_t u;
55 __gid_t g;
57 if (stat (file, &st) < 0)
58 return;
59 u = getuid ();
60 g = getgid ();
61 if (st.st_uid != u || st.st_gid != g)
62 chown (file, u, g);
65 static int
66 LinuxInit (void)
68 int fd = -1;
69 char vtname[11];
70 struct vt_stat vts;
72 LinuxConsoleFd = -1;
73 /* check if we're run with euid==0 */
74 if (geteuid() != 0)
76 FatalError("LinuxInit: Server must be suid root\n");
79 if (kdVirtualTerminal >= 0)
80 vtno = kdVirtualTerminal;
81 else
83 if ((fd = open("/dev/tty0",O_WRONLY,0)) < 0)
85 FatalError(
86 "LinuxInit: Cannot open /dev/tty0 (%s)\n",
87 strerror(errno));
89 if ((ioctl(fd, VT_OPENQRY, &vtno) < 0) ||
90 (vtno == -1))
92 FatalError("xf86OpenConsole: Cannot find a free VT\n");
95 close(fd);
97 sprintf(vtname,"/dev/tty%d",vtno); /* /dev/tty1-64 */
99 if ((LinuxConsoleFd = open(vtname, O_RDWR|O_NDELAY, 0)) < 0)
101 FatalError("LinuxInit: Cannot open %s (%s)\n",
102 vtname, strerror(errno));
105 /* change ownership of the vt */
106 LinuxCheckChown (vtname);
109 * the current VT device we're running on is not "console", we want
110 * to grab all consoles too
112 * Why is this needed?
114 LinuxCheckChown ("/dev/tty0");
116 * Linux doesn't switch to an active vt after the last close of a vt,
117 * so we do this ourselves by remembering which is active now.
119 memset (&vts, '\0', sizeof (vts)); /* valgrind */
120 if (ioctl(LinuxConsoleFd, VT_GETSTATE, &vts) == 0)
122 activeVT = vts.v_active;
125 return 1;
128 Bool
129 LinuxFindPci (CARD16 vendor, CARD16 device, CARD32 count, KdCardAttr *attr)
131 FILE *f;
132 char line[2048], *l, *end;
133 CARD32 bus, id, addr;
134 int n;
135 CARD32 ven_dev;
136 Bool ret = FALSE;
137 int i;
139 attr->vendorID = vendor;
140 attr->deviceID = device;
141 ven_dev = (((CARD32) vendor) << 16) | ((CARD32) device);
142 f = fopen ("/proc/bus/pci/devices", "r");
143 if (!f)
144 return FALSE;
145 attr->io = 0;
146 while (fgets (line, sizeof (line)-1, f))
148 line[sizeof(line)-1] = '\0';
149 l = line;
150 bus = strtoul (l, &end, 16);
151 if (end == l)
152 continue;
153 l = end;
154 id = strtoul (l, &end, 16);
155 if (end == l)
156 continue;
157 l = end;
158 if (id != ven_dev)
159 continue;
160 if (count--)
161 continue;
162 (void) strtoul (l, &end, 16); /* IRQ */
163 if (end == l)
164 continue;
165 l = end;
166 n = 0;
167 for (i = 0; i < 6; i++)
169 addr = strtoul (l, &end, 16);
170 if (end == l)
171 break;
172 if (addr & 1)
173 attr->io = addr & ~0xf;
174 else
176 if (n == KD_MAX_CARD_ADDRESS)
177 break;
178 attr->address[n++] = addr & ~0xf;
180 l = end;
182 while (n > 0)
184 if (attr->address[n-1] != 0)
185 break;
186 n--;
188 attr->naddr = n;
189 attr->domain = 0; /* XXX */
190 attr->bus = (bus >> 8) & 0xff;
191 attr->slot = (bus >> 3) & 0x1f;
192 attr->func = bus & 0x07;
193 ret = TRUE;
194 break;
196 fclose (f);
197 return ret;
200 unsigned char *
201 LinuxGetPciCfg(KdCardAttr *attr)
203 char filename[256];
204 FILE *f;
205 unsigned char *cfg;
206 int r;
208 snprintf(filename, 255, "/proc/bus/pci/%02x/%02x.%x",
209 attr->bus >> 8, (attr->bus & 0xff) >> 3, attr->bus & 7);
210 /* fprintf(stderr,"Find card on path %s\n",filename); */
212 if (!(f=fopen(filename,"r")))
213 return NULL;
215 if (!(cfg=xalloc(256)))
217 fclose(f);
218 return NULL;
221 if (256 != (r=fread(cfg, 1, 256, f)))
223 fprintf(stderr,"LinuxGetPciCfg: read %d, expected 256\n",r);
224 free(cfg);
225 cfg=NULL;
227 fclose(f);
228 /* fprintf(stderr,"LinuxGetPciCfg: success, returning %p\n",cfg); */
229 return cfg;
232 static void
233 LinuxSetSwitchMode (int mode)
235 struct sigaction act;
236 struct vt_mode VT;
238 if (ioctl(LinuxConsoleFd, VT_GETMODE, &VT) < 0)
240 FatalError ("LinuxInit: VT_GETMODE failed\n");
243 if (mode == VT_PROCESS)
245 act.sa_handler = LinuxVTRequest;
246 sigemptyset (&act.sa_mask);
247 act.sa_flags = 0;
248 sigaction (SIGUSR1, &act, 0);
250 VT.mode = mode;
251 VT.relsig = SIGUSR1;
252 VT.acqsig = SIGUSR1;
254 else
256 act.sa_handler = SIG_IGN;
257 sigemptyset (&act.sa_mask);
258 act.sa_flags = 0;
259 sigaction (SIGUSR1, &act, 0);
261 VT.mode = mode;
262 VT.relsig = 0;
263 VT.acqsig = 0;
265 if (ioctl(LinuxConsoleFd, VT_SETMODE, &VT) < 0)
267 FatalError("LinuxInit: VT_SETMODE failed\n");
271 static void
272 LinuxApmBlock (pointer blockData, OSTimePtr pTimeout, pointer pReadmask)
276 static Bool LinuxApmRunning;
278 static void
279 LinuxApmWakeup (pointer blockData, int result, pointer pReadmask)
281 fd_set *readmask = (fd_set *) pReadmask;
283 if (result > 0 && LinuxApmFd >= 0 && FD_ISSET (LinuxApmFd, readmask))
285 apm_event_t event;
286 Bool running = LinuxApmRunning;
287 int cmd = APM_IOC_SUSPEND;
289 while (read (LinuxApmFd, &event, sizeof (event)) == sizeof (event))
291 switch (event) {
292 case APM_SYS_STANDBY:
293 case APM_USER_STANDBY:
294 running = FALSE;
295 cmd = APM_IOC_STANDBY;
296 break;
297 case APM_SYS_SUSPEND:
298 case APM_USER_SUSPEND:
299 case APM_CRITICAL_SUSPEND:
300 running = FALSE;
301 cmd = APM_IOC_SUSPEND;
302 break;
303 case APM_NORMAL_RESUME:
304 case APM_CRITICAL_RESUME:
305 case APM_STANDBY_RESUME:
306 running = TRUE;
307 break;
310 if (running && !LinuxApmRunning)
312 KdResume ();
313 LinuxApmRunning = TRUE;
315 else if (!running && LinuxApmRunning)
317 KdSuspend ();
318 LinuxApmRunning = FALSE;
319 ioctl (LinuxApmFd, cmd, 0);
324 #ifdef FNONBLOCK
325 #define NOBLOCK FNONBLOCK
326 #else
327 #define NOBLOCK FNDELAY
328 #endif
330 static void
331 LinuxEnable (void)
333 if (enabled)
334 return;
335 if (kdSwitchPending)
337 kdSwitchPending = FALSE;
338 ioctl (LinuxConsoleFd, VT_RELDISP, VT_ACKACQ);
341 * Open the APM driver
343 LinuxApmFd = open ("/dev/apm_bios", 2);
344 if (LinuxApmFd < 0 && errno == ENOENT)
345 LinuxApmFd = open ("/dev/misc/apm_bios", 2);
346 if (LinuxApmFd >= 0)
348 LinuxApmRunning = TRUE;
349 fcntl (LinuxApmFd, F_SETFL, fcntl (LinuxApmFd, F_GETFL) | NOBLOCK);
350 RegisterBlockAndWakeupHandlers (LinuxApmBlock, LinuxApmWakeup, 0);
351 AddEnabledDevice (LinuxApmFd);
355 * now get the VT
357 LinuxSetSwitchMode (VT_AUTO);
358 if (ioctl(LinuxConsoleFd, VT_ACTIVATE, vtno) != 0)
360 FatalError("LinuxInit: VT_ACTIVATE failed\n");
362 if (ioctl(LinuxConsoleFd, VT_WAITACTIVE, vtno) != 0)
364 FatalError("LinuxInit: VT_WAITACTIVE failed\n");
366 LinuxSetSwitchMode (VT_PROCESS);
367 if (ioctl(LinuxConsoleFd, KDSETMODE, KD_GRAPHICS) < 0)
369 FatalError("LinuxInit: KDSETMODE KD_GRAPHICS failed\n");
371 enabled = TRUE;
374 static void
375 LinuxDisable (void)
377 ioctl(LinuxConsoleFd, KDSETMODE, KD_TEXT); /* Back to text mode ... */
378 if (kdSwitchPending)
380 kdSwitchPending = FALSE;
381 ioctl (LinuxConsoleFd, VT_RELDISP, 1);
383 enabled = FALSE;
384 if (LinuxApmFd >= 0)
386 RemoveBlockAndWakeupHandlers (LinuxApmBlock, LinuxApmWakeup, 0);
387 RemoveEnabledDevice (LinuxApmFd);
388 close (LinuxApmFd);
389 LinuxApmFd = -1;
393 static void
394 LinuxFini (void)
396 struct vt_mode VT;
397 struct vt_stat vts;
398 int fd;
400 if (LinuxConsoleFd < 0)
401 return;
403 if (ioctl(LinuxConsoleFd, VT_GETMODE, &VT) != -1)
405 VT.mode = VT_AUTO;
406 ioctl(LinuxConsoleFd, VT_SETMODE, &VT); /* set dflt vt handling */
408 memset (&vts, '\0', sizeof (vts)); /* valgrind */
409 ioctl (LinuxConsoleFd, VT_GETSTATE, &vts);
410 if (vtno == vts.v_active)
413 * Find a legal VT to switch to, either the one we started from
414 * or the lowest active one that isn't ours
416 if (activeVT < 0 ||
417 activeVT == vts.v_active ||
418 !(vts.v_state & (1 << activeVT)))
420 for (activeVT = 1; activeVT < 16; activeVT++)
421 if (activeVT != vtno && (vts.v_state & (1 << activeVT)))
422 break;
423 if (activeVT == 16)
424 activeVT = -1;
427 * Perform a switch back to the active VT when we were started
429 if (activeVT >= -1)
431 ioctl (LinuxConsoleFd, VT_ACTIVATE, activeVT);
432 ioctl (LinuxConsoleFd, VT_WAITACTIVE, activeVT);
433 activeVT = -1;
436 close(LinuxConsoleFd); /* make the vt-manager happy */
437 LinuxConsoleFd = -1;
438 fd = open ("/dev/tty0", O_RDWR|O_NDELAY, 0);
439 if (fd >= 0)
441 memset (&vts, '\0', sizeof (vts)); /* valgrind */
442 ioctl (fd, VT_GETSTATE, &vts);
443 if (ioctl (fd, VT_DISALLOCATE, vtno) < 0)
444 fprintf (stderr, "Can't deallocate console %d errno %d\n", vtno, errno);
445 close (fd);
447 return;
450 void
451 KdOsAddInputDrivers ()
453 KdAddPointerDriver(&LinuxMouseDriver);
454 KdAddPointerDriver(&MsMouseDriver);
455 KdAddPointerDriver(&Ps2MouseDriver);
456 #ifdef TSLIB
457 KdAddPointerDriver(&TsDriver);
458 #endif
459 KdAddPointerDriver(&LinuxEvdevMouseDriver);
460 KdAddKeyboardDriver(&LinuxKeyboardDriver);
461 KdAddKeyboardDriver(&LinuxEvdevKeyboardDriver);
464 static void
465 LinuxBell(int volume, int pitch, int duration)
467 if (volume && pitch)
468 ioctl(LinuxConsoleFd, KDMKTONE, ((1193190 / pitch) & 0xffff) |
469 (((unsigned long)duration * volume / 50) << 16));
472 KdOsFuncs LinuxFuncs = {
473 .Init = LinuxInit,
474 .Enable = LinuxEnable,
475 .Disable = LinuxDisable,
476 .Fini = LinuxFini,
477 .Bell = LinuxBell,
480 void
481 OsVendorInit (void)
483 KdOsInit (&LinuxFuncs);