kdrive: bring back Xfbdev

This does most of the work of bringing back Xfbdev
I have a few more patches in my kdrive fork that I'd like to port to Xlibre, but this is a good start.

Signed-off-by: stefan11111 <stefan11111@shitposting.expert>
This commit is contained in:
stefan11111 2025-06-23 22:38:33 +03:00
parent 3f5e4b1d97
commit df42a58be7
25 changed files with 5242 additions and 108 deletions

View File

@ -1435,12 +1435,11 @@ MouseFini(KdPointerInfo * pi)
}
KdPointerDriver EphyrMouseDriver = {
"ephyr",
MouseInit,
MouseEnable,
MouseDisable,
MouseFini,
NULL,
.name = "ephyr",
.Init = MouseInit,
.Enable = MouseEnable,
.Disable = MouseDisable,
.Fini = MouseFini,
};
/* Keyboard */
@ -1509,12 +1508,11 @@ EphyrKeyboardBell(KdKeyboardInfo * ki, int volume, int frequency, int duration)
}
KdKeyboardDriver EphyrKeyboardDriver = {
"ephyr",
EphyrKeyboardInit,
EphyrKeyboardEnable,
EphyrKeyboardLeds,
EphyrKeyboardBell,
EphyrKeyboardDisable,
EphyrKeyboardFini,
NULL,
.name = "ephyr",
.Init = EphyrKeyboardInit,
.Enable = EphyrKeyboardEnable,
.Leds = EphyrKeyboardLeds,
.Bell = EphyrKeyboardBell,
.Disable = EphyrKeyboardDisable,
.Fini = EphyrKeyboardFini,
};

View File

@ -370,6 +370,23 @@ ddxProcessArgument(int argc, char **argv, int i)
return KdProcessArgument(argc, argv, i);
}
static int
EphyrInit(void)
{
/*
* make sure at least one screen
* has been added to the system.
*/
if (!KdCardInfoLast()) {
processScreenArg("640x480", NULL);
}
return hostx_init();
}
KdOsFuncs EphyrOsFuncs = {
.Init = EphyrInit,
};
void
OsVendorInit(void)
{
@ -381,32 +398,23 @@ OsVendorInit(void)
if (hostx_want_host_cursor())
ephyrFuncs.initCursor = &ephyrCursorInit;
if (serverGeneration == 1) {
if (!KdCardInfoLast()) {
processScreenArg("640x480", NULL);
}
hostx_init();
}
KdOsInit(&EphyrOsFuncs);
}
KdCardFuncs ephyrFuncs = {
ephyrCardInit, /* cardinit */
ephyrScreenInitialize, /* scrinit */
ephyrInitScreen, /* initScreen */
ephyrFinishInitScreen, /* finishInitScreen */
ephyrCreateResources, /* createRes */
ephyrScreenFini, /* scrfini */
ephyrCardFini, /* cardfini */
.cardinit = ephyrCardInit,
.scrinit = ephyrScreenInitialize,
.initScreen = ephyrInitScreen,
.finishInitScreen = ephyrFinishInitScreen,
.createRes = ephyrCreateResources,
0, /* initCursor */
.scrfini = ephyrScreenFini,
.cardfini = ephyrCardFini,
0, /* initAccel */
0, /* enableAccel */
0, /* disableAccel */
0, /* finiAccel */
/* no cursor or accel funcs here */
ephyrGetColors, /* getColors */
ephyrPutColors, /* putColors */
.getColors = ephyrGetColors,
.putColors = ephyrPutColors,
ephyrCloseScreen, /* closeScreen */
.closeScreen = ephyrCloseScreen,
};

View File

@ -0,0 +1,28 @@
.\" $RCSId: xc/programs/Xserver/hw/kdrive/fbdev/Xfbdev.man,v 1.4 2001/01/27 18:20:40 dawes Exp $
.\"
.TH Xfbdev 1 __vendorversion__
.SH NAME
Xfbdev \- Linux framebuffer device tiny X server
.SH SYNOPSIS
.B Xfbdev
.RI [ :display ]
.RI [ option ...]
.SH DESCRIPTION
.B Xfbdev
is a generic X server for Linux.
.B Xfbdev
doesn't know about any particular hardware, and uses the framebuffer
provided by the Linux framebuffer device.
.SH OPTIONS
.B Xfbdev
accepts the common options of the Xkdrive family of servers. Please
see Xkdrive(1).
.SH KEYBOARD
To be written.
.SH SEE ALSO
X(__miscmansuffix__), Xserver(1), Xkdrive(1), xdm(1), xinit(1).
.SH AUTHORS
The
.B Xfbdev
server was written by Keith Packard.

895
hw/kdrive/fbdev/fbdev.c Normal file
View File

@ -0,0 +1,895 @@
/*
* 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.
*/
#include <dix-config.h>
#include "fbdev.h"
#include "fb/fb_priv.h"
#include <sys/ioctl.h>
#include <errno.h>
#ifndef xallocarray
#define xallocarray(num, size) reallocarray(NULL, (num), (size))
#endif
const char *fbdevDevicePath = NULL;
static Bool
fbdevInitialize(KdCardInfo * card, FbdevPriv * priv)
{
unsigned long off;
if (fbdevDevicePath == NULL)
fbdevDevicePath = "/dev/fb0";
if ((priv->fd = open(fbdevDevicePath, O_RDWR)) < 0) {
ErrorF("Error opening framebuffer %s: %s\n",
fbdevDevicePath, strerror(errno));
return FALSE;
}
/* quiet valgrind */
memset(&priv->fix, '\0', sizeof(priv->fix));
if (ioctl(priv->fd, FBIOGET_FSCREENINFO, &priv->fix) < 0) {
perror("Error with /dev/fb ioctl FIOGET_FSCREENINFO");
close(priv->fd);
return FALSE;
}
/* quiet valgrind */
memset(&priv->var, '\0', sizeof(priv->var));
if (ioctl(priv->fd, FBIOGET_VSCREENINFO, &priv->var) < 0) {
perror("Error with /dev/fb ioctl FIOGET_VSCREENINFO");
close(priv->fd);
return FALSE;
}
priv->fb_base = (char *) mmap((caddr_t) NULL,
priv->fix.smem_len,
PROT_READ | PROT_WRITE,
MAP_SHARED, priv->fd, 0);
if (priv->fb_base == (char *) -1) {
perror("ERROR: mmap framebuffer fails!");
close(priv->fd);
return FALSE;
}
off = (unsigned long) priv->fix.smem_start % (unsigned long) getpagesize();
priv->fb = priv->fb_base + off;
return TRUE;
}
Bool
fbdevCardInit(KdCardInfo * card)
{
FbdevPriv *priv;
priv = (FbdevPriv *) malloc(sizeof(FbdevPriv));
if (!priv)
return FALSE;
if (!fbdevInitialize(card, priv)) {
free(priv);
return FALSE;
}
card->driver = priv;
return TRUE;
}
static Pixel
fbdevMakeContig(Pixel orig, Pixel others)
{
Pixel low;
low = lowbit(orig) >> 1;
while (low && (others & low) == 0) {
orig |= low;
low >>= 1;
}
return orig;
}
static Bool
fbdevModeSupported(KdScreenInfo * screen, const KdMonitorTiming * t)
{
return TRUE;
}
static void
fbdevConvertMonitorTiming(const KdMonitorTiming * t,
struct fb_var_screeninfo *var)
{
memset(var, 0, sizeof(struct fb_var_screeninfo));
var->xres = t->horizontal;
var->yres = t->vertical;
var->xres_virtual = t->horizontal;
var->yres_virtual = t->vertical;
var->xoffset = 0;
var->yoffset = 0;
var->pixclock = t->clock ? 1000000000 / t->clock : 0;
var->left_margin = t->hbp;
var->right_margin = t->hfp;
var->upper_margin = t->vbp;
var->lower_margin = t->vfp;
var->hsync_len = t->hblank - t->hfp - t->hbp;
var->vsync_len = t->vblank - t->vfp - t->vbp;
var->sync = 0;
var->vmode = 0;
if (t->hpol == KdSyncPositive)
var->sync |= FB_SYNC_HOR_HIGH_ACT;
if (t->vpol == KdSyncPositive)
var->sync |= FB_SYNC_VERT_HIGH_ACT;
}
static Bool
fbdevScreenInitialize(KdScreenInfo * screen, FbdevScrPriv * scrpriv)
{
FbdevPriv *priv = screen->card->driver;
Pixel allbits;
int depth;
Bool gray;
struct fb_var_screeninfo var;
const KdMonitorTiming *t;
int k;
k = ioctl(priv->fd, FBIOGET_VSCREENINFO, &var);
if (!screen->width || !screen->height) {
if (k >= 0) {
screen->width = var.xres;
screen->height = var.yres;
}
else {
screen->width = 1024;
screen->height = 768;
}
screen->rate = 103; /* FIXME: should get proper value from fb driver */
}
if (!screen->fb.depth) {
if (k >= 0)
screen->fb.depth = var.bits_per_pixel;
else
screen->fb.depth = 16;
}
if ((screen->width != var.xres) || (screen->height != var.yres)) {
t = KdFindMode(screen, fbdevModeSupported);
screen->rate = t->rate;
screen->width = t->horizontal;
screen->height = t->vertical;
/* Now try setting the mode */
if (k < 0 || (t->horizontal != var.xres || t->vertical != var.yres))
fbdevConvertMonitorTiming(t, &var);
}
var.activate = FB_ACTIVATE_NOW;
var.bits_per_pixel = screen->fb.depth;
var.nonstd = 0;
var.grayscale = 0;
k = ioctl(priv->fd, FBIOPUT_VSCREENINFO, &var);
if (k < 0) {
fprintf(stderr, "error: %s\n", strerror(errno));
return FALSE;
}
/* Re-get the "fixed" parameters since they might have changed */
k = ioctl(priv->fd, FBIOGET_FSCREENINFO, &priv->fix);
if (k < 0)
perror("FBIOGET_FSCREENINFO");
/* Now get the new screeninfo */
ioctl(priv->fd, FBIOGET_VSCREENINFO, &priv->var);
depth = priv->var.bits_per_pixel;
gray = priv->var.grayscale;
/* Calculate fix.line_length if it's zero */
if (!priv->fix.line_length)
priv->fix.line_length = (priv->var.xres_virtual * depth + 7) / 8;
switch (priv->fix.visual) {
case FB_VISUAL_MONO01:
case FB_VISUAL_MONO10:
screen->fb.visuals = (1 << StaticGray);
break;
case FB_VISUAL_PSEUDOCOLOR:
screen->fb.visuals = (1 << StaticGray);
if (priv->var.bits_per_pixel == 1) {
/* Override to monochrome, to have preallocated black/white */
priv->fix.visual = FB_VISUAL_MONO01;
} else if (gray) {
/* could also support GrayScale, but what's the point? */
} else {
screen->fb.visuals = ((1 << StaticGray) |
(1 << GrayScale) |
(1 << StaticColor) |
(1 << PseudoColor) |
(1 << TrueColor) | (1 << DirectColor));
}
screen->fb.blueMask = 0x00;
screen->fb.greenMask = 0x00;
screen->fb.redMask = 0x00;
break;
case FB_VISUAL_STATIC_PSEUDOCOLOR:
if (gray) {
screen->fb.visuals = (1 << StaticGray);
}
else {
screen->fb.visuals = (1 << StaticColor);
}
screen->fb.blueMask = 0x00;
screen->fb.greenMask = 0x00;
screen->fb.redMask = 0x00;
break;
case FB_VISUAL_TRUECOLOR:
case FB_VISUAL_DIRECTCOLOR:
screen->fb.visuals = (1 << TrueColor);
#define Mask(o,l) (((1 << l) - 1) << o)
screen->fb.redMask = Mask (priv->var.red.offset, priv->var.red.length);
screen->fb.greenMask =
Mask (priv->var.green.offset, priv->var.green.length);
screen->fb.blueMask =
Mask (priv->var.blue.offset, priv->var.blue.length);
/*
* This is a kludge so that Render will work -- fill in the gaps
* in the pixel
*/
screen->fb.redMask = fbdevMakeContig(screen->fb.redMask,
screen->fb.greenMask |
screen->fb.blueMask);
screen->fb.greenMask = fbdevMakeContig(screen->fb.greenMask,
screen->fb.redMask |
screen->fb.blueMask);
screen->fb.blueMask = fbdevMakeContig(screen->fb.blueMask,
screen->fb.redMask |
screen->fb.greenMask);
allbits =
screen->fb.redMask | screen->fb.greenMask | screen->fb.blueMask;
depth = 32;
while (depth && !(allbits & (1 << (depth - 1))))
depth--;
break;
default:
return FALSE;
break;
}
screen->fb.depth = depth;
screen->fb.bitsPerPixel = priv->var.bits_per_pixel;
scrpriv->randr = screen->randr;
return fbdevMapFramebuffer(screen);
}
Bool
fbdevScreenInit(KdScreenInfo * screen)
{
FbdevScrPriv *scrpriv;
scrpriv = calloc(1, sizeof(FbdevScrPriv));
if (!scrpriv)
return FALSE;
screen->driver = scrpriv;
if (!fbdevScreenInitialize(screen, scrpriv)) {
screen->driver = 0;
free(scrpriv);
return FALSE;
}
return TRUE;
}
static void *
fbdevWindowLinear(ScreenPtr pScreen,
CARD32 row,
CARD32 offset, int mode, CARD32 *size, void *closure)
{
KdScreenPriv(pScreen);
FbdevPriv *priv = pScreenPriv->card->driver;
if (!pScreenPriv->enabled)
return 0;
*size = priv->fix.line_length;
return (CARD8 *) priv->fb + row * priv->fix.line_length + offset;
}
static void *
fbdevWindowAfb(ScreenPtr pScreen,
CARD32 row,
CARD32 offset, int mode, CARD32 *size, void *closure)
{
KdScreenPriv(pScreen);
FbdevPriv *priv = pScreenPriv->card->driver;
if (!pScreenPriv->enabled)
return 0;
/* offset to next plane */
*size = priv->var.yres_virtual * priv->fix.line_length;
return (CARD8 *) priv->fb + row * priv->fix.line_length + offset;
}
Bool
fbdevMapFramebuffer(KdScreenInfo * screen)
{
FbdevScrPriv *scrpriv = screen->driver;
KdPointerMatrix m;
FbdevPriv *priv = screen->card->driver;
if (scrpriv->randr != RR_Rotate_0 ||
priv->fix.type != FB_TYPE_PACKED_PIXELS)
scrpriv->shadow = TRUE;
else
scrpriv->shadow = FALSE;
KdComputePointerMatrix(&m, scrpriv->randr, screen->width, screen->height);
KdSetPointerMatrix(&m);
screen->width = priv->var.xres;
screen->height = priv->var.yres;
if (scrpriv->shadow) {
if (!KdShadowFbAlloc(screen,
scrpriv->randr & (RR_Rotate_90 | RR_Rotate_270)))
return FALSE;
}
else {
screen->fb.byteStride = priv->fix.line_length;
screen->fb.pixelStride = (priv->fix.line_length * 8 /
priv->var.bits_per_pixel);
screen->fb.frameBuffer = (CARD8 *) (priv->fb);
}
return TRUE;
}
static void
fbdevSetScreenSizes(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
FbdevScrPriv *scrpriv = screen->driver;
FbdevPriv *priv = screen->card->driver;
if (scrpriv->randr & (RR_Rotate_0 | RR_Rotate_180)) {
pScreen->width = priv->var.xres;
pScreen->height = priv->var.yres;
pScreen->mmWidth = screen->width_mm;
pScreen->mmHeight = screen->height_mm;
}
else {
pScreen->width = priv->var.yres;
pScreen->height = priv->var.xres;
pScreen->mmWidth = screen->height_mm;
pScreen->mmHeight = screen->width_mm;
}
}
static Bool
fbdevUnmapFramebuffer(KdScreenInfo * screen)
{
KdShadowFbFree(screen);
return TRUE;
}
static Bool
fbdevSetShadow(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
FbdevScrPriv *scrpriv = screen->driver;
FbdevPriv *priv = screen->card->driver;
ShadowUpdateProc update;
ShadowWindowProc window;
int useYX = 0;
#ifdef __arm__
/* Use variant copy routines that always read left to right in the
shadow framebuffer. Reading vertical strips is exceptionally
slow on XScale due to cache effects. */
useYX = 1;
#endif
window = fbdevWindowLinear;
update = 0;
switch (priv->fix.type) {
case FB_TYPE_PACKED_PIXELS:
if (scrpriv->randr)
if (priv->var.bits_per_pixel == 16) {
switch (scrpriv->randr) {
case RR_Rotate_90:
if (useYX)
update = shadowUpdateRotate16_90YX;
else
update = shadowUpdateRotate16_90;
break;
case RR_Rotate_180:
update = shadowUpdateRotate16_180;
break;
case RR_Rotate_270:
if (useYX)
update = shadowUpdateRotate16_270YX;
else
update = shadowUpdateRotate16_270;
break;
default:
update = shadowUpdateRotate16;
break;
}
}
else
update = shadowUpdateRotatePacked;
else
update = shadowUpdatePacked;
break;
case FB_TYPE_PLANES:
window = fbdevWindowAfb;
switch (priv->var.bits_per_pixel) {
case 4:
update = shadowUpdateAfb4;
break;
case 8:
update = shadowUpdateAfb8;
break;
default:
FatalError("Bitplanes with bpp %u are not yet supported\n",
priv->var.bits_per_pixel);
}
break;
case FB_TYPE_INTERLEAVED_PLANES:
if (priv->fix.type_aux == 2) {
switch (priv->var.bits_per_pixel) {
case 4:
update = shadowUpdateIplan2p4;
break;
case 8:
update = shadowUpdateIplan2p8;
break;
default:
FatalError("Atari interleaved bitplanes with bpp %u are not yet supported\n",
priv->var.bits_per_pixel);
}
} else {
FatalError("Interleaved bitplanes with interleave %u are not yet supported\n",
priv->fix.type_aux);
}
break;
case FB_TYPE_TEXT:
FatalError("Text frame buffers are not yet supported\n");
break;
case FB_TYPE_VGA_PLANES:
FatalError("VGA planes are not yet supported\n");
break;
default:
FatalError("Unsupported frame buffer type %u\n", priv->fix.type);
break;
}
return KdShadowSet(pScreen, scrpriv->randr, update, window);
}
#ifdef RANDR
static Bool
fbdevRandRGetInfo(ScreenPtr pScreen, Rotation * rotations)
{
KdScreenPriv(pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
FbdevScrPriv *scrpriv = screen->driver;
RRScreenSizePtr pSize;
Rotation randr;
int n;
*rotations = RR_Rotate_All | RR_Reflect_All;
for (n = 0; n < pScreen->numDepths; n++)
if (pScreen->allowedDepths[n].numVids)
break;
if (n == pScreen->numDepths)
return FALSE;
pSize = RRRegisterSize(pScreen,
screen->width,
screen->height, screen->width_mm, screen->height_mm);
randr = KdSubRotation(scrpriv->randr, screen->randr);
RRSetCurrentConfig(pScreen, randr, 0, pSize);
return TRUE;
}
static Bool
fbdevRandRSetConfig(ScreenPtr pScreen,
Rotation randr, int rate, RRScreenSizePtr pSize)
{
KdScreenPriv(pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
FbdevScrPriv *scrpriv = screen->driver;
Bool wasEnabled = pScreenPriv->enabled;
FbdevScrPriv oldscr;
int oldwidth;
int oldheight;
int oldmmwidth;
int oldmmheight;
int newwidth, newheight, newmmwidth, newmmheight;
if (screen->randr & (RR_Rotate_0 | RR_Rotate_180)) {
newwidth = pSize->width;
newheight = pSize->height;
newmmwidth = pSize->mmWidth;
newmmheight = pSize->mmHeight;
}
else {
newwidth = pSize->height;
newheight = pSize->width;
newmmwidth = pSize->mmHeight;
newmmheight = pSize->mmWidth;
}
if (wasEnabled)
KdDisableScreen(pScreen);
oldscr = *scrpriv;
oldwidth = screen->width;
oldheight = screen->height;
oldmmwidth = pScreen->mmWidth;
oldmmheight = pScreen->mmHeight;
/*
* Set new configuration
*/
scrpriv->randr = KdAddRotation(screen->randr, randr);
pScreen->width = newwidth;
pScreen->height = newheight;
pScreen->mmWidth = newmmwidth;
pScreen->mmHeight = newmmheight;
fbdevUnmapFramebuffer(screen);
if (!fbdevMapFramebuffer(screen))
goto bail4;
KdShadowUnset(screen->pScreen);
if (!fbdevSetShadow(screen->pScreen))
goto bail4;
fbdevSetScreenSizes(screen->pScreen);
/*
* Set frame buffer mapping
*/
(*pScreen->ModifyPixmapHeader) (fbGetScreenPixmap(pScreen),
pScreen->width,
pScreen->height,
screen->fb.depth,
screen->fb.bitsPerPixel,
screen->fb.byteStride,
screen->fb.frameBuffer);
/* set the subpixel order */
KdSetSubpixelOrder(pScreen, scrpriv->randr);
if (wasEnabled)
KdEnableScreen(pScreen);
return TRUE;
bail4:
fbdevUnmapFramebuffer(screen);
*scrpriv = oldscr;
(void) fbdevMapFramebuffer(screen);
pScreen->width = oldwidth;
pScreen->height = oldheight;
pScreen->mmWidth = oldmmwidth;
pScreen->mmHeight = oldmmheight;
if (wasEnabled)
KdEnableScreen(pScreen);
return FALSE;
}
static Bool
fbdevRandRInit(ScreenPtr pScreen)
{
rrScrPrivPtr pScrPriv;
if (!RRScreenInit(pScreen))
return FALSE;
pScrPriv = rrGetScrPriv(pScreen);
pScrPriv->rrGetInfo = fbdevRandRGetInfo;
pScrPriv->rrSetConfig = fbdevRandRSetConfig;
return TRUE;
}
#endif
static Bool
fbdevCreateColormap(ColormapPtr pmap)
{
ScreenPtr pScreen = pmap->pScreen;
KdScreenPriv(pScreen);
FbdevPriv *priv = pScreenPriv->card->driver;
VisualPtr pVisual;
int i;
int nent;
xColorItem *pdefs;
switch (priv->fix.visual) {
case FB_VISUAL_MONO01:
pScreen->whitePixel = 0;
pScreen->blackPixel = 1;
pmap->red[0].co.local.red = 65535;
pmap->red[0].co.local.green = 65535;
pmap->red[0].co.local.blue = 65535;
pmap->red[1].co.local.red = 0;
pmap->red[1].co.local.green = 0;
pmap->red[1].co.local.blue = 0;
return TRUE;
case FB_VISUAL_MONO10:
pScreen->blackPixel = 0;
pScreen->whitePixel = 1;
pmap->red[0].co.local.red = 0;
pmap->red[0].co.local.green = 0;
pmap->red[0].co.local.blue = 0;
pmap->red[1].co.local.red = 65535;
pmap->red[1].co.local.green = 65535;
pmap->red[1].co.local.blue = 65535;
return TRUE;
case FB_VISUAL_STATIC_PSEUDOCOLOR:
pVisual = pmap->pVisual;
nent = pVisual->ColormapEntries;
pdefs = xallocarray(nent, sizeof(xColorItem));
if (!pdefs)
return FALSE;
for (i = 0; i < nent; i++)
pdefs[i].pixel = i;
fbdevGetColors(pScreen, nent, pdefs);
for (i = 0; i < nent; i++) {
pmap->red[i].co.local.red = pdefs[i].red;
pmap->red[i].co.local.green = pdefs[i].green;
pmap->red[i].co.local.blue = pdefs[i].blue;
}
free(pdefs);
return TRUE;
default:
return fbInitializeColormap(pmap);
}
}
Bool
fbdevInitScreen(ScreenPtr pScreen)
{
pScreen->CreateColormap = fbdevCreateColormap;
return TRUE;
}
Bool
fbdevFinishInitScreen(ScreenPtr pScreen)
{
if (!shadowSetup(pScreen))
return FALSE;
#ifdef RANDR
if (!fbdevRandRInit(pScreen))
return FALSE;
#endif
return TRUE;
}
Bool
fbdevCreateResources(ScreenPtr pScreen)
{
return fbdevSetShadow(pScreen);
}
void
fbdevPreserve(KdCardInfo * card)
{
}
static int
fbdevUpdateFbColormap(FbdevPriv * priv, int minidx, int maxidx)
{
struct fb_cmap cmap;
cmap.start = minidx;
cmap.len = maxidx - minidx + 1;
cmap.red = &priv->red[minidx];
cmap.green = &priv->green[minidx];
cmap.blue = &priv->blue[minidx];
cmap.transp = 0;
return ioctl(priv->fd, FBIOPUTCMAP, &cmap);
}
Bool
fbdevEnable(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
FbdevPriv *priv = pScreenPriv->card->driver;
int k;
priv->var.activate = FB_ACTIVATE_NOW | FB_CHANGE_CMAP_VBL;
/* display it on the LCD */
k = ioctl(priv->fd, FBIOPUT_VSCREENINFO, &priv->var);
if (k < 0) {
perror("FBIOPUT_VSCREENINFO");
return FALSE;
}
if (priv->fix.visual == FB_VISUAL_DIRECTCOLOR) {
int i;
for (i = 0;
i < (1 << priv->var.red.length) ||
i < (1 << priv->var.green.length) ||
i < (1 << priv->var.blue.length); i++) {
priv->red[i] = i * 65535 / ((1 << priv->var.red.length) - 1);
priv->green[i] = i * 65535 / ((1 << priv->var.green.length) - 1);
priv->blue[i] = i * 65535 / ((1 << priv->var.blue.length) - 1);
}
fbdevUpdateFbColormap(priv, 0, i);
}
return TRUE;
}
Bool
fbdevDPMS(ScreenPtr pScreen, int mode)
{
KdScreenPriv(pScreen);
FbdevPriv *priv = pScreenPriv->card->driver;
static int oldmode = -1;
if (mode == oldmode)
return TRUE;
#ifdef FBIOPUT_POWERMODE
if (ioctl(priv->fd, FBIOPUT_POWERMODE, &mode) >= 0) {
oldmode = mode;
return TRUE;
}
#endif
#ifdef FBIOBLANK
if (ioctl(priv->fd, FBIOBLANK, mode ? mode + 1 : 0) >= 0) {
oldmode = mode;
return TRUE;
}
#endif
return FALSE;
}
void
fbdevDisable(ScreenPtr pScreen)
{
}
void
fbdevRestore(KdCardInfo * card)
{
}
void
fbdevScreenFini(KdScreenInfo * screen)
{
}
void
fbdevCardFini(KdCardInfo * card)
{
FbdevPriv *priv = card->driver;
munmap(priv->fb_base, priv->fix.smem_len);
close(priv->fd);
free(priv);
}
/*
* Retrieve actual colormap and return selected n entries in pdefs.
*/
void
fbdevGetColors(ScreenPtr pScreen, int n, xColorItem * pdefs)
{
KdScreenPriv(pScreen);
FbdevPriv *priv = pScreenPriv->card->driver;
struct fb_cmap cmap;
int p;
int k;
int min, max;
min = 256;
max = 0;
for (k = 0; k < n; k++) {
if (pdefs[k].pixel < min)
min = pdefs[k].pixel;
if (pdefs[k].pixel > max)
max = pdefs[k].pixel;
}
cmap.start = min;
cmap.len = max - min + 1;
cmap.red = &priv->red[min];
cmap.green = &priv->green[min];
cmap.blue = &priv->blue[min];
cmap.transp = 0;
k = ioctl(priv->fd, FBIOGETCMAP, &cmap);
if (k < 0) {
perror("can't get colormap");
return;
}
while (n--) {
p = pdefs->pixel;
pdefs->red = priv->red[p];
pdefs->green = priv->green[p];
pdefs->blue = priv->blue[p];
pdefs++;
}
}
/*
* Change colormap by updating n entries described in pdefs.
*/
void
fbdevPutColors(ScreenPtr pScreen, int n, xColorItem * pdefs)
{
KdScreenPriv(pScreen);
FbdevPriv *priv = pScreenPriv->card->driver;
int p;
int min, max;
min = 256;
max = 0;
while (n--) {
p = pdefs->pixel;
priv->red[p] = pdefs->red;
priv->green[p] = pdefs->green;
priv->blue[p] = pdefs->blue;
if (p < min)
min = p;
if (p > max)
max = p;
pdefs++;
}
fbdevUpdateFbColormap(priv, min, max);
}

84
hw/kdrive/fbdev/fbdev.h Normal file
View File

@ -0,0 +1,84 @@
/*
* 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.
*/
#ifndef _KDRIVE_FBDEV_H_
#define _KDRIVE_FBDEV_H_
#include <stdio.h>
#include <linux/fb.h>
#include <unistd.h>
#include <sys/mman.h>
#include "kdrive.h"
#ifdef RANDR
#include "randrstr.h"
#endif
typedef struct _fbdevPriv {
struct fb_var_screeninfo var;
struct fb_fix_screeninfo fix;
__u16 red[256];
__u16 green[256];
__u16 blue[256];
int fd;
char *fb;
char *fb_base;
} FbdevPriv;
typedef struct _fbdevScrPriv {
Rotation randr;
Bool shadow;
} FbdevScrPriv;
extern KdCardFuncs fbdevFuncs;
extern const char *fbdevDevicePath;
Bool fbdevCardInit(KdCardInfo * card);
Bool fbdevScreenInit(KdScreenInfo * screen);
Bool fbdevInitScreen(ScreenPtr pScreen);
Bool fbdevFinishInitScreen(ScreenPtr pScreen);
Bool fbdevCreateResources(ScreenPtr pScreen);
void fbdevPreserve(KdCardInfo * card);
Bool fbdevEnable(ScreenPtr pScreen);
Bool fbdevDPMS(ScreenPtr pScreen, int mode);
void fbdevDisable(ScreenPtr pScreen);
void fbdevRestore(KdCardInfo * card);
void fbdevScreenFini(KdScreenInfo * screen);
void fbdevCardFini(KdCardInfo * card);
void fbdevGetColors(ScreenPtr pScreen, int n, xColorItem * pdefs);
void fbdevPutColors(ScreenPtr pScreen, int n, xColorItem * pdefs);
Bool fbdevMapFramebuffer(KdScreenInfo * screen);
#endif /* _KDRIVE_FBDEV_H_ */

122
hw/kdrive/fbdev/fbinit.c Normal file
View File

@ -0,0 +1,122 @@
/*
* 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.
*/
#include <dix-config.h>
#include "fbdev.h"
#include "miext/extinit_priv.h"
#include "os/cmdline.h"
void
InitCard(char *name)
{
KdCardInfoAdd(&fbdevFuncs, 0);
}
static const ExtensionModule ephyrExtensions[] = {
#ifdef GLXEXT
{ GlxExtensionInit, "GLX", &noGlxExtension },
#endif
};
static
void ephyrExtensionInit(void)
{
LoadExtensionList(ephyrExtensions, ARRAY_SIZE(ephyrExtensions), TRUE);
}
#if INPUTTHREAD
/** This function is called in Xserver/os/inputthread.c when starting
the input thread. */
void
ddxInputThreadInit(void)
{
}
#endif
void
InitOutput(ScreenInfo * pScreenInfo, int argc, char **argv)
{
if (serverGeneration == 1)
ephyrExtensionInit();
KdInitOutput(pScreenInfo, argc, argv);
}
void
InitInput(int argc, char **argv)
{
KdOsAddInputDrivers();
KdInitInput();
}
void
CloseInput(void)
{
KdCloseInput();
}
void
ddxUseMsg(void)
{
KdUseMsg();
ErrorF("\nXfbdev Device Usage:\n");
ErrorF
("-fb path Framebuffer device to use. Defaults to /dev/fb0\n");
ErrorF("\n");
}
int
ddxProcessArgument(int argc, char **argv, int i)
{
if (!strcmp(argv[i], "-fb")) {
if (i + 1 < argc) {
fbdevDevicePath = argv[i + 1];
return 2;
}
UseMsg();
exit(1);
}
return KdProcessArgument(argc, argv, i);
}
KdCardFuncs fbdevFuncs = {
.cardinit = fbdevCardInit,
.scrinit = fbdevScreenInit,
.initScreen = fbdevInitScreen,
.finishInitScreen = fbdevFinishInitScreen,
.createRes = fbdevCreateResources,
.preserve = fbdevPreserve,
.enable = fbdevEnable,
.dpms = fbdevDPMS,
.disable = fbdevDisable,
.restore = fbdevRestore,
.scrfini = fbdevScreenFini,
.cardfini = fbdevCardFini,
/* no cursor or accel funcs */
.getColors = fbdevGetColors,
.putColors = fbdevPutColors,
/* no closescreen func */
};

View File

@ -0,0 +1,34 @@
srcs = [
'fbdev.c',
'fbinit.c',
]
xfbdev_server = executable(
'Xfbdev',
srcs,
include_directories: [
inc,
include_directories('../src'),
include_directories('../linux'),
],
dependencies: common_dep,
link_with: [
libxserver_main,
kdrive,
linux,
libxserver_fb,
libxserver,
libxserver_glx,
libxserver_config,
libxserver_xkb_stubs,
libglxvnd,
],
install: true,
)
xfbdev_man = configure_file(
input: 'Xfbdev.man',
output: 'Xfbdev.1',
configuration: manpage_config,
)
install_man(xfbdev_man)

526
hw/kdrive/linux/evdev.c Normal file
View File

@ -0,0 +1,526 @@
/*
* Copyright © 2004 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.
*/
#include <dix-config.h>
#include <errno.h>
#include <linux/input.h>
#include <X11/X.h>
#include <X11/Xproto.h>
#include "inputstr.h"
#include "scrnintstr.h"
#include "kdrive.h"
#define NUM_EVENTS 128
#define ABS_UNSET -65535
#define BITS_PER_LONG (sizeof(long) * 8)
#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
#define ISBITSET(x,y) ((x)[LONG(y)] & BIT(y))
#define OFF(x) ((x)%BITS_PER_LONG)
#define LONG(x) ((x)/BITS_PER_LONG)
#define BIT(x) (1 << OFF(x))
typedef struct _kevdev {
/* current device state */
int rel[REL_MAX + 1];
int abs[ABS_MAX + 1];
int prevabs[ABS_MAX + 1];
long key[NBITS(KEY_MAX + 1)];
/* supported device info */
long relbits[NBITS(REL_MAX + 1)];
long absbits[NBITS(ABS_MAX + 1)];
long keybits[NBITS(KEY_MAX + 1)];
struct input_absinfo absinfo[ABS_MAX + 1];
int max_rel;
int max_abs;
int fd;
} Kevdev;
static void
EvdevPtrBtn(KdPointerInfo * pi, struct input_event *ev)
{
int flags = KD_MOUSE_DELTA | pi->buttonState;
if (ev->code >= BTN_MOUSE && ev->code < BTN_JOYSTICK) {
switch (ev->code) {
case BTN_LEFT:
if (ev->value == 1)
flags |= KD_BUTTON_1;
else
flags &= ~KD_BUTTON_1;
break;
case BTN_MIDDLE:
if (ev->value == 1)
flags |= KD_BUTTON_2;
else
flags &= ~KD_BUTTON_2;
break;
case BTN_RIGHT:
if (ev->value == 1)
flags |= KD_BUTTON_3;
else
flags &= ~KD_BUTTON_3;
break;
default:
/* Unknow button */
break;
}
KdEnqueuePointerEvent(pi, flags, 0, 0, 0);
}
}
static void
EvdevPtrMotion(KdPointerInfo * pi, struct input_event *ev)
{
Kevdev *ke = pi->driverPrivate;
int i;
int flags = KD_MOUSE_DELTA | pi->buttonState;
for (i = 0; i <= ke->max_rel; i++)
if (ke->rel[i]) {
int a;
for (a = 0; a <= ke->max_rel; a++) {
if (ISBITSET(ke->relbits, a)) {
if (a == 0)
KdEnqueuePointerEvent(pi, flags, ke->rel[a], 0, 0);
else if (a == 1)
KdEnqueuePointerEvent(pi, flags, 0, ke->rel[a], 0);
}
ke->rel[a] = 0;
}
break;
}
for (i = 0; i < ke->max_abs; i++)
if (ke->abs[i] != ke->prevabs[i]) {
int a;
ErrorF("abs");
for (a = 0; a <= ke->max_abs; a++) {
if (ISBITSET(ke->absbits, a))
ErrorF(" %d=%d", a, ke->abs[a]);
ke->prevabs[a] = ke->abs[a];
}
ErrorF("\n");
break;
}
if (ev->code == REL_WHEEL) {
for (i = 0; i < abs(ev->value); i++) {
if (ev->value > 0)
flags |= KD_BUTTON_4;
else
flags |= KD_BUTTON_5;
KdEnqueuePointerEvent(pi, flags, 0, 0, 0);
if (ev->value > 0)
flags &= ~KD_BUTTON_4;
else
flags &= ~KD_BUTTON_5;
KdEnqueuePointerEvent(pi, flags, 0, 0, 0);
}
}
}
static void
EvdevPtrRead(int evdevPort, void *closure)
{
KdPointerInfo *pi = closure;
Kevdev *ke = pi->driverPrivate;
int i;
struct input_event events[NUM_EVENTS];
int n;
n = read(evdevPort, &events, NUM_EVENTS * sizeof(struct input_event));
if (n <= 0) {
if (errno == ENODEV)
DeleteInputDeviceRequest(pi->dixdev);
return;
}
n /= sizeof(struct input_event);
for (i = 0; i < n; i++) {
switch (events[i].type) {
case EV_SYN:
break;
case EV_KEY:
EvdevPtrBtn(pi, &events[i]);
break;
case EV_REL:
ke->rel[events[i].code] += events[i].value;
EvdevPtrMotion(pi, &events[i]);
break;
case EV_ABS:
ke->abs[events[i].code] = events[i].value;
EvdevPtrMotion(pi, &events[i]);
break;
}
}
}
const char *kdefaultEvdev[] = {
"/dev/input/event0",
"/dev/input/event1",
"/dev/input/event2",
"/dev/input/event3",
};
#define NUM_DEFAULT_EVDEV (sizeof (kdefaultEvdev) / sizeof (kdefaultEvdev[0]))
static Status
EvdevPtrInit(KdPointerInfo * pi)
{
int i;
int fd;
if (!pi->path) {
for (i = 0; i < NUM_DEFAULT_EVDEV; i++) {
fd = open(kdefaultEvdev[i], 2);
if (fd >= 0) {
pi->path = strdup(kdefaultEvdev[i]);
break;
}
}
}
else {
fd = open(pi->path, O_RDWR);
if (fd < 0) {
ErrorF("Failed to open evdev device %s\n", pi->path);
return BadMatch;
}
}
close(fd);
if (!pi->name)
pi->name = strdup("Evdev mouse");
return Success;
}
static Status
EvdevPtrEnable(KdPointerInfo * pi)
{
int fd;
unsigned long ev[NBITS(EV_MAX)];
Kevdev *ke;
if (!pi || !pi->path)
return BadImplementation;
fd = open(pi->path, 2);
if (fd < 0)
return BadMatch;
if (ioctl(fd, EVIOCGRAB, 1) < 0)
perror("Grabbing evdev mouse device failed");
if (ioctl(fd, EVIOCGBIT(0 /*EV*/, sizeof(ev)), ev) < 0) {
perror("EVIOCGBIT 0");
close(fd);
return BadMatch;
}
ke = calloc(1, sizeof(Kevdev));
if (!ke) {
close(fd);
return BadAlloc;
}
if (ISBITSET(ev, EV_KEY)) {
if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(ke->keybits)), ke->keybits) < 0) {
perror("EVIOCGBIT EV_KEY");
free(ke);
close(fd);
return BadMatch;
}
}
if (ISBITSET(ev, EV_REL)) {
if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(ke->relbits)), ke->relbits) < 0) {
perror("EVIOCGBIT EV_REL");
free(ke);
close(fd);
return BadMatch;
}
for (ke->max_rel = REL_MAX; ke->max_rel >= 0; ke->max_rel--)
if (ISBITSET(ke->relbits, ke->max_rel))
break;
}
if (ISBITSET(ev, EV_ABS)) {
int i;
if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(ke->absbits)), ke->absbits) < 0) {
perror("EVIOCGBIT EV_ABS");
free(ke);
close(fd);
return BadMatch;
}
for (ke->max_abs = ABS_MAX; ke->max_abs >= 0; ke->max_abs--)
if (ISBITSET(ke->absbits, ke->max_abs))
break;
for (i = 0; i <= ke->max_abs; i++) {
if (ISBITSET(ke->absbits, i))
if (ioctl(fd, EVIOCGABS(i), &ke->absinfo[i]) < 0) {
perror("EVIOCGABS");
break;
}
ke->prevabs[i] = ABS_UNSET;
}
if (i <= ke->max_abs) {
free(ke);
close(fd);
return BadValue;
}
}
if (!KdRegisterFd(fd, EvdevPtrRead, pi)) {
free(ke);
close(fd);
return BadAlloc;
}
pi->driverPrivate = ke;
ke->fd = fd;
return Success;
}
static void
EvdevPtrDisable(KdPointerInfo * pi)
{
Kevdev *ke;
ke = pi->driverPrivate;
if (!pi || !pi->driverPrivate)
return;
KdUnregisterFd(pi, ke->fd, TRUE);
if (ioctl(ke->fd, EVIOCGRAB, 0) < 0)
perror("Ungrabbing evdev mouse device failed");
free(ke);
pi->driverPrivate = 0;
}
static void
EvdevPtrFini(KdPointerInfo * pi)
{
}
/*
* Evdev keyboard functions
*/
static void
readMapping(KdKeyboardInfo * ki)
{
if (!ki)
return;
ki->minScanCode = 0;
ki->maxScanCode = 247;
}
static void
EvdevKbdRead(int evdevPort, void *closure)
{
KdKeyboardInfo *ki = closure;
struct input_event events[NUM_EVENTS];
int i, n;
n = read(evdevPort, &events, NUM_EVENTS * sizeof(struct input_event));
if (n <= 0) {
if (errno == ENODEV)
DeleteInputDeviceRequest(ki->dixdev);
return;
}
n /= sizeof(struct input_event);
for (i = 0; i < n; i++) {
if (events[i].type == EV_KEY)
KdEnqueueKeyboardEvent(ki, events[i].code, !events[i].value);
/* FIXME: must implement other types of events
else
ErrorF("Event type (%d) not delivered\n", events[i].type);
*/
}
}
static Status
EvdevKbdInit(KdKeyboardInfo * ki)
{
int fd;
if (!ki->path) {
ErrorF("Couldn't find evdev device path\n");
return BadValue;
}
else {
fd = open(ki->path, O_RDWR);
if (fd < 0) {
ErrorF("Failed to open evdev device %s\n", ki->path);
return BadMatch;
}
}
close(fd);
if (!ki->name)
ki->name = strdup("Evdev keyboard");
readMapping(ki);
return Success;
}
static Status
EvdevKbdEnable(KdKeyboardInfo * ki)
{
unsigned long ev[NBITS(EV_MAX)];
Kevdev *ke;
int fd;
if (!ki || !ki->path)
return BadImplementation;
fd = open(ki->path, O_RDWR);
if (fd < 0)
return BadMatch;
if (ioctl(fd, EVIOCGRAB, 1) < 0)
perror("Grabbing evdev keyboard device failed");
if (ioctl(fd, EVIOCGBIT(0 /*EV*/, sizeof(ev)), ev) < 0) {
perror("EVIOCGBIT 0");
close(fd);
return BadMatch;
}
ke = calloc(1, sizeof(Kevdev));
if (!ke) {
close(fd);
return BadAlloc;
}
if (!KdRegisterFd(fd, EvdevKbdRead, ki)) {
free(ke);
close(fd);
return BadAlloc;
}
ki->driverPrivate = ke;
ke->fd = fd;
return Success;
}
static void
EvdevKbdLeds(KdKeyboardInfo * ki, int leds)
{
struct input_event event;
Kevdev *ke;
int i;
if (!ki)
return;
ke = ki->driverPrivate;
if (!ke)
return;
memset(&event, 0, sizeof(event));
event.type = EV_LED;
event.code = LED_CAPSL;
event.value = leds & (1 << 0) ? 1 : 0;
i = write(ke->fd, (char *) &event, sizeof(event));
(void) i;
event.type = EV_LED;
event.code = LED_NUML;
event.value = leds & (1 << 1) ? 1 : 0;
i = write(ke->fd, (char *) &event, sizeof(event));
(void) i;
event.type = EV_LED;
event.code = LED_SCROLLL;
event.value = leds & (1 << 2) ? 1 : 0;
i = write(ke->fd, (char *) &event, sizeof(event));
(void) i;
event.type = EV_LED;
event.code = LED_COMPOSE;
event.value = leds & (1 << 3) ? 1 : 0;
i = write(ke->fd, (char *) &event, sizeof(event));
(void) i;
}
static void
EvdevKbdBell(KdKeyboardInfo * ki, int volume, int frequency, int duration)
{
}
static void
EvdevKbdDisable(KdKeyboardInfo * ki)
{
Kevdev *ke;
ke = ki->driverPrivate;
if (!ki || !ki->driverPrivate)
return;
KdUnregisterFd(ki, ke->fd, TRUE);
if (ioctl(ke->fd, EVIOCGRAB, 0) < 0)
perror("Ungrabbing evdev keyboard device failed");
free(ke);
ki->driverPrivate = 0;
}
static void
EvdevKbdFini(KdKeyboardInfo * ki)
{
}
KdPointerDriver LinuxEvdevMouseDriver = {
.name = "evdev",
.Init = EvdevPtrInit,
.Enable = EvdevPtrEnable,
.Disable = EvdevPtrDisable,
.Fini = EvdevPtrFini,
};
KdKeyboardDriver LinuxEvdevKeyboardDriver = {
.name = "evdev",
.Init = EvdevKbdInit,
.Enable = EvdevKbdEnable,
.Leds = EvdevKbdLeds,
.Bell = EvdevKbdBell,
.Disable = EvdevKbdDisable,
.Fini = EvdevKbdFini,
};

349
hw/kdrive/linux/keyboard.c Normal file
View File

@ -0,0 +1,349 @@
/*
* Copyright © 1999 Keith Packard
* XKB integration © 2006 Nokia Corporation, author: Tomas Frydrych <tf@o-hand.com>
*
* LinuxKeyboardRead() XKB code based on xf86KbdLnx.c:
* Copyright © 1990,91 by Thomas Roell, Dinkelscherben, Germany.
* Copyright © 1994-2001 by The XFree86 Project, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name of the copyright holder(s)
* and author(s) shall not be used in advertising or otherwise to promote
* the sale, use or other dealings in this Software without prior written
* authorization from the copyright holder(s) and author(s).
*/
#include <dix-config.h>
#include "kdrive.h"
#include <linux/keyboard.h>
#include <linux/kd.h>
#define XK_PUBLISHING
#include <X11/keysym.h>
#include <termios.h>
#include <sys/ioctl.h>
extern int LinuxConsoleFd;
/*
* We need these to handle extended scancodes correctly (I could just use the
* numbers below, but this makes the code more readable
*/
/* The prefix codes */
#define KEY_Prefix0 /* special 0x60 */ 96
#define KEY_Prefix1 /* special 0x61 */ 97
/* The raw scancodes */
#define KEY_Enter /* Enter 0x1c */ 28
#define KEY_LCtrl /* Ctrl(left) 0x1d */ 29
#define KEY_Slash /* / (Slash) ? 0x35 */ 53
#define KEY_KP_Multiply /* * 0x37 */ 55
#define KEY_Alt /* Alt(left) 0x38 */ 56
#define KEY_F3 /* F3 0x3d */ 61
#define KEY_F4 /* F4 0x3e */ 62
#define KEY_F5 /* F5 0x3f */ 63
#define KEY_F6 /* F6 0x40 */ 64
#define KEY_F7 /* F7 0x41 */ 65
#define KEY_ScrollLock /* ScrollLock 0x46 */ 70
#define KEY_KP_7 /* 7 Home 0x47 */ 71
#define KEY_KP_8 /* 8 Up 0x48 */ 72
#define KEY_KP_9 /* 9 PgUp 0x49 */ 73
#define KEY_KP_Minus /* - (Minus) 0x4a */ 74
#define KEY_KP_4 /* 4 Left 0x4b */ 75
#define KEY_KP_5 /* 5 0x4c */ 76
#define KEY_KP_6 /* 6 Right 0x4d */ 77
#define KEY_KP_Plus /* + (Plus) 0x4e */ 78
#define KEY_KP_1 /* 1 End 0x4f */ 79
#define KEY_KP_2 /* 2 Down 0x50 */ 80
#define KEY_KP_3 /* 3 PgDown 0x51 */ 81
#define KEY_KP_0 /* 0 Insert 0x52 */ 82
#define KEY_KP_Decimal /* . (Decimal) Delete 0x53 */ 83
#define KEY_Home /* Home 0x59 */ 89
#define KEY_Up /* Up 0x5a */ 90
#define KEY_PgUp /* PgUp 0x5b */ 91
#define KEY_Left /* Left 0x5c */ 92
#define KEY_Begin /* Begin 0x5d */ 93
#define KEY_Right /* Right 0x5e */ 94
#define KEY_End /* End 0x5f */ 95
#define KEY_Down /* Down 0x60 */ 96
#define KEY_PgDown /* PgDown 0x61 */ 97
#define KEY_Insert /* Insert 0x62 */ 98
#define KEY_Delete /* Delete 0x63 */ 99
#define KEY_KP_Enter /* Enter 0x64 */ 100
#define KEY_RCtrl /* Ctrl(right) 0x65 */ 101
#define KEY_Pause /* Pause 0x66 */ 102
#define KEY_Print /* Print 0x67 */ 103
#define KEY_KP_Divide /* Divide 0x68 */ 104
#define KEY_AltLang /* AtlLang(right) 0x69 */ 105
#define KEY_Break /* Break 0x6a */ 106
#define KEY_LMeta /* Left Meta 0x6b */ 107
#define KEY_RMeta /* Right Meta 0x6c */ 108
#define KEY_Menu /* Menu 0x6d */ 109
#define KEY_F13 /* F13 0x6e */ 110
#define KEY_F14 /* F14 0x6f */ 111
#define KEY_F15 /* F15 0x70 */ 112
#define KEY_F16 /* F16 0x71 */ 113
#define KEY_F17 /* F17 0x72 */ 114
#define KEY_KP_DEC /* KP_DEC 0x73 */ 115
static void
LinuxKeyboardRead(int fd, void *closure)
{
unsigned char buf[256], *b;
int n;
unsigned char prefix = 0, scancode = 0;
while ((n = read(fd, buf, sizeof(buf))) > 0) {
b = buf;
while (n--) {
/*
* With xkb we use RAW mode for reading the console, which allows us
* process extended scancodes.
*
* See if this is a prefix extending the following keycode
*/
if (!prefix && ((b[0] & 0x7f) == KEY_Prefix0)) {
prefix = KEY_Prefix0;
/* swallow this up */
b++;
continue;
}
else if (!prefix && ((b[0] & 0x7f) == KEY_Prefix1)) {
prefix = KEY_Prefix1;
/* swallow this up */
b++;
continue;
}
scancode = b[0] & 0x7f;
switch (prefix) {
/* from xf86Events.c */
case KEY_Prefix0:
{
switch (scancode) {
case KEY_KP_7:
scancode = KEY_Home;
break; /* curs home */
case KEY_KP_8:
scancode = KEY_Up;
break; /* curs up */
case KEY_KP_9:
scancode = KEY_PgUp;
break; /* curs pgup */
case KEY_KP_4:
scancode = KEY_Left;
break; /* curs left */
case KEY_KP_5:
scancode = KEY_Begin;
break; /* curs begin */
case KEY_KP_6:
scancode = KEY_Right;
break; /* curs right */
case KEY_KP_1:
scancode = KEY_End;
break; /* curs end */
case KEY_KP_2:
scancode = KEY_Down;
break; /* curs down */
case KEY_KP_3:
scancode = KEY_PgDown;
break; /* curs pgdown */
case KEY_KP_0:
scancode = KEY_Insert;
break; /* curs insert */
case KEY_KP_Decimal:
scancode = KEY_Delete;
break; /* curs delete */
case KEY_Enter:
scancode = KEY_KP_Enter;
break; /* keypad enter */
case KEY_LCtrl:
scancode = KEY_RCtrl;
break; /* right ctrl */
case KEY_KP_Multiply:
scancode = KEY_Print;
break; /* print */
case KEY_Slash:
scancode = KEY_KP_Divide;
break; /* keyp divide */
case KEY_Alt:
scancode = KEY_AltLang;
break; /* right alt */
case KEY_ScrollLock:
scancode = KEY_Break;
break; /* curs break */
case 0x5b:
scancode = KEY_LMeta;
break;
case 0x5c:
scancode = KEY_RMeta;
break;
case 0x5d:
scancode = KEY_Menu;
break;
case KEY_F3:
scancode = KEY_F13;
break;
case KEY_F4:
scancode = KEY_F14;
break;
case KEY_F5:
scancode = KEY_F15;
break;
case KEY_F6:
scancode = KEY_F16;
break;
case KEY_F7:
scancode = KEY_F17;
break;
case KEY_KP_Plus:
scancode = KEY_KP_DEC;
break;
/* Ignore virtual shifts (E0 2A, E0 AA, E0 36, E0 B6) */
case 0x2A:
case 0x36:
b++;
prefix = 0;
continue;
default:
/*
* "Internet" keyboards are generating lots of new
* codes. Let them pass. There is little consistency
* between them, so don't bother with symbolic names at
* this level.
*/
scancode += 0x78;
}
break;
}
case KEY_Prefix1:
{
/* we do no handle these */
b++;
prefix = 0;
continue;
}
default: /* should not happen */
case 0: /* do nothing */
;
}
prefix = 0;
KdEnqueueKeyboardEvent(closure, scancode, b[0] & 0x80);
b++;
}
}
}
static int LinuxKbdTrans;
static struct termios LinuxTermios;
static Status
LinuxKeyboardEnable(KdKeyboardInfo * ki)
{
struct termios nTty;
unsigned char buf[256];
int n;
int fd;
if (!ki)
return !Success;
fd = LinuxConsoleFd;
ki->driverPrivate = (void *) (intptr_t) fd;
ioctl(fd, KDGKBMODE, &LinuxKbdTrans);
tcgetattr(fd, &LinuxTermios);
ioctl(fd, KDSKBMODE, K_RAW);
nTty = LinuxTermios;
nTty.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP);
nTty.c_oflag = 0;
nTty.c_cflag = CREAD | CS8;
nTty.c_lflag = 0;
nTty.c_cc[VTIME] = 0;
nTty.c_cc[VMIN] = 1;
cfsetispeed(&nTty, 9600);
cfsetospeed(&nTty, 9600);
tcsetattr(fd, TCSANOW, &nTty);
/*
* Flush any pending keystrokes
*/
while ((n = read(fd, buf, sizeof(buf))) > 0);
KdRegisterFd(fd, LinuxKeyboardRead, ki);
return Success;
}
static void
LinuxKeyboardDisable(KdKeyboardInfo * ki)
{
int fd;
if (!ki)
return;
fd = (int) (intptr_t) ki->driverPrivate;
KdUnregisterFd(ki, fd, FALSE);
ioctl(fd, KDSKBMODE, LinuxKbdTrans);
tcsetattr(fd, TCSANOW, &LinuxTermios);
}
static Status
LinuxKeyboardPreInit(KdKeyboardInfo * ki)
{
ki->xkbRules = strdup("base");
return Success;
}
static Status
LinuxKeyboardInit(KdKeyboardInfo * ki)
{
if (!ki)
return !Success;
free(ki->path);
ki->path = strdup("console");
free(ki->name);
ki->name = strdup("Linux console keyboard");
ki->maxScanCode = 0;
ki->maxScanCode = 255;
return Success;
}
static void
LinuxKeyboardLeds(KdKeyboardInfo * ki, int leds)
{
if (!ki)
return;
ioctl((int) (intptr_t) ki->driverPrivate, KDSETLED, leds & 7);
}
KdKeyboardDriver LinuxKeyboardDriver = {
.name = "keyboard",
.PreInit = LinuxKeyboardPreInit,
.Init = LinuxKeyboardInit,
.Enable = LinuxKeyboardEnable,
.Leds = LinuxKeyboardLeds,
.Disable = LinuxKeyboardDisable,
};

361
hw/kdrive/linux/linux.c Normal file
View File

@ -0,0 +1,361 @@
/*
* 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.
*/
#include <dix-config.h>
#include "kdrive.h"
#include <errno.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>
#ifdef KDRIVE_MOUSE
extern KdPointerDriver LinuxMouseDriver;
extern KdPointerDriver Ps2MouseDriver;
extern KdPointerDriver MsMouseDriver;
#endif
#ifdef KDRIVE_TSLIB
extern KdPointerDriver TsDriver;
#endif
#ifdef KDRIVE_EVDEV
extern KdPointerDriver LinuxEvdevMouseDriver;
extern KdKeyboardDriver LinuxEvdevKeyboardDriver;
#endif
#ifdef KDRIVE_KBD
extern KdKeyboardDriver LinuxKeyboardDriver;
#endif
static int vtno;
int LinuxConsoleFd;
int LinuxApmFd = -1;
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(const char *file)
{
struct stat st;
__uid_t u;
__gid_t g;
int r;
if (stat(file, &st) < 0)
return;
u = getuid();
g = getgid();
if (st.st_uid != u || st.st_gid != g) {
r = chown(file, u, g);
(void) r;
}
}
static int
LinuxInit(void)
{
int fd = -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);
}
snprintf(vtname, sizeof(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 Bool LinuxApmRunning;
static void
LinuxApmNotify(int fd, int mask, void *blockData)
{
apm_event_t event;
Bool running = LinuxApmRunning;
int cmd = APM_IOC_SUSPEND;
while (read(fd, &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(fd, 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);
SetNotifyFd(LinuxApmFd, LinuxApmNotify, X_NOTIFY_READ, NULL);
}
/*
* 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 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) {
RemoveNotifyFd(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 */
LinuxConsoleFd = -1;
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 %s\n", vtno,
strerror(errno));
close(fd);
}
return;
}
void
KdOsAddInputDrivers(void)
{
#ifdef KDRIVE_MOUSE
KdAddPointerDriver(&LinuxMouseDriver);
KdAddPointerDriver(&MsMouseDriver);
KdAddPointerDriver(&Ps2MouseDriver);
#endif
#ifdef KDRIVE_TSLIB
KdAddPointerDriver(&TsDriver);
#endif
#ifdef KDRIVE_EVDEV
KdAddPointerDriver(&LinuxEvdevMouseDriver);
KdAddKeyboardDriver(&LinuxEvdevKeyboardDriver);
#endif
#ifdef KDRIVE_KBD
KdAddKeyboardDriver(&LinuxKeyboardDriver);
#endif
}
static void
LinuxBell(int volume, int pitch, int duration)
{
if (volume && pitch)
ioctl(LinuxConsoleFd, KDMKTONE, ((1193190 / pitch) & 0xffff) |
(((unsigned long) duration * volume / 50) << 16));
}
KdOsFuncs LinuxFuncs = {
.Init = LinuxInit,
.Enable = LinuxEnable,
.Disable = LinuxDisable,
.Fini = LinuxFini,
.Bell = LinuxBell,
};
void
OsVendorInit(void)
{
KdOsInit(&LinuxFuncs);
}

View File

@ -0,0 +1,30 @@
srcs_linux = [
'linux.c'
]
if build_kdrive_kbd
srcs_linux += 'keyboard.c'
endif
if build_kdrive_mouse
srcs_linux += 'mouse.c'
srcs_linux += 'ms.c'
srcs_linux += 'ps2.c'
endif
if build_kdrive_evdev
srcs_linux += 'evdev.c'
endif
if build_kdrive_tslib
srcs_linux += 'tslib.c'
endif
linux = static_library('linux',
srcs_linux,
include_directories: [
inc,
include_directories('../src'),
],
dependencies: common_dep,
)

978
hw/kdrive/linux/mouse.c Normal file
View File

@ -0,0 +1,978 @@
/*
* Copyright © 2001 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.
*/
#include <dix-config.h>
#include <errno.h>
#include <termios.h>
#include <X11/X.h>
#include <X11/Xproto.h>
#include "os/xserver_poll.h"
#include "inputstr.h"
#include "scrnintstr.h"
#include "kdrive.h"
#undef DEBUG
#undef DEBUG_BYTES
#define KBUFIO_SIZE 256
#define MOUSE_TIMEOUT 100
typedef struct _kbufio {
int fd;
unsigned char buf[KBUFIO_SIZE];
int avail;
int used;
} Kbufio;
static Bool
MouseWaitForReadable(int fd, int timeout)
{
struct pollfd poll_fd;
int n;
CARD32 done;
done = GetTimeInMillis() + timeout;
poll_fd.fd = fd;
poll_fd.events = POLLIN;
for (;;) {
n = xserver_poll(&poll_fd, 1, timeout);
if (n > 0)
return TRUE;
if (n < 0 && (errno == EAGAIN || errno == EINTR)) {
timeout = (int) (done - GetTimeInMillis());
if (timeout > 0)
continue;
}
break;
}
return FALSE;
}
static int
MouseReadByte(Kbufio * b, int timeout)
{
int n;
if (b->avail <= b->used) {
if (timeout && !MouseWaitForReadable(b->fd, timeout)) {
#ifdef DEBUG_BYTES
ErrorF("\tTimeout %d\n", timeout);
#endif
return -1;
}
n = read(b->fd, b->buf, KBUFIO_SIZE);
if (n <= 0)
return -1;
b->avail = n;
b->used = 0;
}
#ifdef DEBUG_BYTES
ErrorF("\tget %02x\n", b->buf[b->used]);
#endif
return b->buf[b->used++];
}
#if NOTUSED
static int
MouseFlush(Kbufio * b, char *buf, int size)
{
CARD32 now = GetTimeInMillis();
CARD32 done = now + 100;
int c;
int n = 0;
while ((c = MouseReadByte(b, done - now)) != -1) {
if (buf) {
if (n == size) {
memmove(buf, buf + 1, size - 1);
n--;
}
buf[n++] = c;
}
now = GetTimeInMillis();
if ((INT32) (now - done) >= 0)
break;
}
return n;
}
static int
MousePeekByte(Kbufio * b, int timeout)
{
int c;
c = MouseReadByte(b, timeout);
if (c != -1)
--b->used;
return c;
}
#endif /* NOTUSED */
static Bool
MouseWaitForWritable(int fd, int timeout)
{
struct pollfd poll_fd;
int n;
poll_fd.fd = fd;
poll_fd.events = POLLOUT;
n = xserver_poll(&poll_fd, 1, timeout);
if (n > 0)
return TRUE;
return FALSE;
}
static Bool
MouseWriteByte(int fd, unsigned char c, int timeout)
{
int ret;
#ifdef DEBUG_BYTES
ErrorF("\tput %02x\n", c);
#endif
for (;;) {
ret = write(fd, &c, 1);
if (ret == 1)
return TRUE;
if (ret == 0)
return FALSE;
if (errno != EWOULDBLOCK)
return FALSE;
if (!MouseWaitForWritable(fd, timeout))
return FALSE;
}
}
static Bool
MouseWriteBytes(int fd, unsigned char *c, int n, int timeout)
{
while (n--)
if (!MouseWriteByte(fd, *c++, timeout))
return FALSE;
return TRUE;
}
#define MAX_MOUSE 10 /* maximum length of mouse protocol */
#define MAX_SKIP 16 /* number of error bytes before switching */
#define MAX_VALID 4 /* number of valid packets before accepting */
typedef struct _kmouseProt {
const char *name;
Bool (*Complete) (KdPointerInfo * pi, unsigned char *ev, int ne);
int (*Valid) (KdPointerInfo * pi, unsigned char *ev, int ne);
Bool (*Parse) (KdPointerInfo * pi, unsigned char *ev, int ne);
Bool (*Init) (KdPointerInfo * pi);
unsigned char headerMask, headerValid;
unsigned char dataMask, dataValid;
Bool tty;
unsigned int c_iflag;
unsigned int c_oflag;
unsigned int c_lflag;
unsigned int c_cflag;
unsigned int speed;
unsigned char *init;
unsigned long state;
} KmouseProt;
typedef enum _kmouseStage {
MouseBroken, MouseTesting, MouseWorking
} KmouseStage;
typedef struct _kmouse {
Kbufio iob;
const KmouseProt *prot;
int i_prot;
KmouseStage stage; /* protocol verification stage */
Bool tty; /* mouse device is a tty */
int valid; /* sequential valid events */
int tested; /* bytes scanned during Testing phase */
int invalid; /* total invalid bytes for this protocol */
unsigned long state; /* private per protocol, init to prot->state */
} Kmouse;
static int
mouseValid(KdPointerInfo * pi, unsigned char *ev, int ne)
{
Kmouse *km = pi->driverPrivate;
const KmouseProt *prot = km->prot;
int i;
for (i = 0; i < ne; i++)
if ((ev[i] & prot->headerMask) == prot->headerValid)
break;
if (i != 0)
return i;
for (i = 1; i < ne; i++)
if ((ev[i] & prot->dataMask) != prot->dataValid)
return -1;
return 0;
}
static Bool
threeComplete(KdPointerInfo * pi, unsigned char *ev, int ne)
{
return ne == 3;
}
static Bool
fourComplete(KdPointerInfo * pi, unsigned char *ev, int ne)
{
return ne == 4;
}
static Bool
fiveComplete(KdPointerInfo * pi, unsigned char *ev, int ne)
{
return ne == 5;
}
static Bool
MouseReasonable(KdPointerInfo * pi, unsigned long flags, int dx, int dy)
{
Kmouse *km = pi->driverPrivate;
if (km->stage == MouseWorking)
return TRUE;
if (dx < -50 || dx > 50) {
#ifdef DEBUG
ErrorF("Large X %d\n", dx);
#endif
return FALSE;
}
if (dy < -50 || dy > 50) {
#ifdef DEBUG
ErrorF("Large Y %d\n", dy);
#endif
return FALSE;
}
return TRUE;
}
/*
* Standard PS/2 mouse protocol
*/
static Bool
ps2Parse(KdPointerInfo * pi, unsigned char *ev, int ne)
{
Kmouse *km = pi->driverPrivate;
int dx, dy, dz;
unsigned long flags;
unsigned long flagsrelease = 0;
flags = KD_MOUSE_DELTA;
if (ev[0] & 4)
flags |= KD_BUTTON_2;
if (ev[0] & 2)
flags |= KD_BUTTON_3;
if (ev[0] & 1)
flags |= KD_BUTTON_1;
if (ne > 3) {
dz = (int) (signed char) ev[3];
if (dz < 0) {
flags |= KD_BUTTON_4;
flagsrelease = KD_BUTTON_4;
}
else if (dz > 0) {
flags |= KD_BUTTON_5;
flagsrelease = KD_BUTTON_5;
}
}
dx = ev[1];
if (ev[0] & 0x10)
dx -= 256;
dy = ev[2];
if (ev[0] & 0x20)
dy -= 256;
dy = -dy;
if (!MouseReasonable(pi, flags, dx, dy))
return FALSE;
if (km->stage == MouseWorking) {
KdEnqueuePointerEvent(pi, flags, dx, dy, 0);
if (flagsrelease) {
flags &= ~flagsrelease;
KdEnqueuePointerEvent(pi, flags, dx, dy, 0);
}
}
return TRUE;
}
static Bool ps2Init(KdPointerInfo * pi);
static const KmouseProt ps2Prot = {
"ps/2",
threeComplete, mouseValid, ps2Parse, ps2Init,
0x08, 0x08, 0x00, 0x00,
FALSE
};
static const KmouseProt imps2Prot = {
"imps/2",
fourComplete, mouseValid, ps2Parse, ps2Init,
0x08, 0x08, 0x00, 0x00,
FALSE
};
static const KmouseProt exps2Prot = {
"exps/2",
fourComplete, mouseValid, ps2Parse, ps2Init,
0x08, 0x08, 0x00, 0x00,
FALSE
};
/*
* Once the mouse is known to speak ps/2 protocol, go and find out
* what advanced capabilities it has and turn them on
*/
/* these extracted from FreeBSD 4.3 sys/dev/kbd/atkbdcreg.h */
/* aux device commands (sent to KBD_DATA_PORT) */
#define PSMC_SET_SCALING11 0x00e6
#define PSMC_SET_SCALING21 0x00e7
#define PSMC_SET_RESOLUTION 0x00e8
#define PSMC_SEND_DEV_STATUS 0x00e9
#define PSMC_SET_STREAM_MODE 0x00ea
#define PSMC_SEND_DEV_DATA 0x00eb
#define PSMC_SET_REMOTE_MODE 0x00f0
#define PSMC_SEND_DEV_ID 0x00f2
#define PSMC_SET_SAMPLING_RATE 0x00f3
#define PSMC_ENABLE_DEV 0x00f4
#define PSMC_DISABLE_DEV 0x00f5
#define PSMC_SET_DEFAULTS 0x00f6
#define PSMC_RESET_DEV 0x00ff
/* PSMC_SET_RESOLUTION argument */
#define PSMD_RES_LOW 0 /* typically 25ppi */
#define PSMD_RES_MEDIUM_LOW 1 /* typically 50ppi */
#define PSMD_RES_MEDIUM_HIGH 2 /* typically 100ppi (default) */
#define PSMD_RES_HIGH 3 /* typically 200ppi */
#define PSMD_MAX_RESOLUTION PSMD_RES_HIGH
/* PSMC_SET_SAMPLING_RATE */
#define PSMD_MAX_RATE 255 /* FIXME: not sure if it's possible */
/* aux device ID */
#define PSM_MOUSE_ID 0
#define PSM_BALLPOINT_ID 2
#define PSM_INTELLI_ID 3
#define PSM_EXPLORER_ID 4
#define PSM_4DMOUSE_ID 6
#define PSM_4DPLUS_ID 8
static unsigned char ps2_init[] = {
PSMC_ENABLE_DEV
};
#define NINIT_PS2 1
static unsigned char wheel_3button_init[] = {
PSMC_SET_SAMPLING_RATE, 200,
PSMC_SET_SAMPLING_RATE, 100,
PSMC_SET_SAMPLING_RATE, 80,
PSMC_SEND_DEV_ID,
};
#define NINIT_IMPS2 4
static unsigned char wheel_5button_init[] = {
PSMC_SET_SAMPLING_RATE, 200,
PSMC_SET_SAMPLING_RATE, 100,
PSMC_SET_SAMPLING_RATE, 80,
PSMC_SET_SAMPLING_RATE, 200,
PSMC_SET_SAMPLING_RATE, 200,
PSMC_SET_SAMPLING_RATE, 80,
PSMC_SEND_DEV_ID,
};
#define NINIT_EXPS2 7
static unsigned char intelli_init[] = {
PSMC_SET_SAMPLING_RATE, 200,
PSMC_SET_SAMPLING_RATE, 100,
PSMC_SET_SAMPLING_RATE, 80,
};
#define NINIT_INTELLI 3
static int
ps2SkipInit(KdPointerInfo * pi, int ninit, Bool ret_next)
{
Kmouse *km = pi->driverPrivate;
int c = -1;
Bool waiting;
waiting = FALSE;
while (ninit || ret_next) {
c = MouseReadByte(&km->iob, 1); /* Minimum timeout like in xf86-input-mouse and tinyx */
if (c == -1)
break;
/* look for ACK */
if (c == 0xfa) {
ninit--;
if (ret_next)
waiting = TRUE;
}
/* look for packet start -- not the response */
else if ((c & 0x08) == 0x08)
waiting = FALSE;
else if (waiting)
break;
}
return c;
}
static Bool
ps2Init(KdPointerInfo * pi)
{
Kmouse *km = pi->driverPrivate;
int id;
unsigned char *init;
int ninit;
int len;
/* Send Intellimouse initialization sequence */
MouseWriteBytes(km->iob.fd, intelli_init, sizeof(intelli_init),
100);
/*
* Send ID command
*/
if (!MouseWriteByte(km->iob.fd, PSMC_SEND_DEV_ID, 100))
return FALSE;
id = ps2SkipInit(pi, 0, TRUE);
switch (id) {
case 3:
init = wheel_3button_init;
ninit = NINIT_IMPS2;
km->prot = &imps2Prot;
len = sizeof(wheel_3button_init);
break;
case 4:
init = wheel_5button_init;
ninit = NINIT_EXPS2;
km->prot = &exps2Prot;
len = sizeof(wheel_5button_init);
break;
default:
init = ps2_init;
ninit = NINIT_PS2;
km->prot = &ps2Prot;
len = sizeof(ps2_init);
break;
}
if (init)
MouseWriteBytes(km->iob.fd, init, len, 100);
/*
* Flush out the available data to eliminate responses to the
* initialization string. Make sure any partial event is
* skipped
*/
(void) ps2SkipInit(pi, ninit, FALSE);
return TRUE;
}
static Bool
busParse(KdPointerInfo * pi, unsigned char *ev, int ne)
{
Kmouse *km = pi->driverPrivate;
int dx, dy;
unsigned long flags;
flags = KD_MOUSE_DELTA;
dx = (signed char) ev[1];
dy = -(signed char) ev[2];
if ((ev[0] & 4) == 0)
flags |= KD_BUTTON_1;
if ((ev[0] & 2) == 0)
flags |= KD_BUTTON_2;
if ((ev[0] & 1) == 0)
flags |= KD_BUTTON_3;
if (!MouseReasonable(pi, flags, dx, dy))
return FALSE;
if (km->stage == MouseWorking)
KdEnqueuePointerEvent(pi, flags, dx, dy, 0);
return TRUE;
}
static const KmouseProt busProt = {
"bus",
threeComplete, mouseValid, busParse, 0,
0xf8, 0x00, 0x00, 0x00,
FALSE
};
/*
* Standard MS serial protocol, three bytes
*/
static Bool
msParse(KdPointerInfo * pi, unsigned char *ev, int ne)
{
Kmouse *km = pi->driverPrivate;
int dx, dy;
unsigned long flags;
flags = KD_MOUSE_DELTA;
if (ev[0] & 0x20)
flags |= KD_BUTTON_1;
if (ev[0] & 0x10)
flags |= KD_BUTTON_3;
dx = (signed char) (((ev[0] & 0x03) << 6) | (ev[1] & 0x3F));
dy = (signed char) (((ev[0] & 0x0C) << 4) | (ev[2] & 0x3F));
if (!MouseReasonable(pi, flags, dx, dy))
return FALSE;
if (km->stage == MouseWorking)
KdEnqueuePointerEvent(pi, flags, dx, dy, 0);
return TRUE;
}
static const KmouseProt msProt = {
"ms",
threeComplete, mouseValid, msParse, 0,
0xc0, 0x40, 0xc0, 0x00,
TRUE,
IGNPAR,
0,
0,
CS7 | CSTOPB | CREAD | CLOCAL,
B1200,
};
/*
* Logitech mice send 3 or 4 bytes, the only way to tell is to look at the
* first byte of a synchronized protocol stream and see if it's got
* any bits turned on that can't occur in that fourth byte
*/
static Bool
logiComplete(KdPointerInfo * pi, unsigned char *ev, int ne)
{
Kmouse *km = pi->driverPrivate;
if ((ev[0] & 0x40) == 0x40)
return ne == 3;
if (km->stage != MouseBroken && (ev[0] & ~0x23) == 0)
return ne == 1;
return FALSE;
}
static int
logiValid(KdPointerInfo * pi, unsigned char *ev, int ne)
{
Kmouse *km = pi->driverPrivate;
const KmouseProt *prot = km->prot;
int i;
for (i = 0; i < ne; i++) {
if ((ev[i] & 0x40) == 0x40)
break;
if (km->stage != MouseBroken && (ev[i] & ~0x23) == 0)
break;
}
if (i != 0)
return i;
for (i = 1; i < ne; i++)
if ((ev[i] & prot->dataMask) != prot->dataValid)
return -1;
return 0;
}
static Bool
logiParse(KdPointerInfo * pi, unsigned char *ev, int ne)
{
Kmouse *km = pi->driverPrivate;
int dx, dy;
unsigned long flags;
flags = KD_MOUSE_DELTA;
if (ne == 3) {
if (ev[0] & 0x20)
flags |= KD_BUTTON_1;
if (ev[0] & 0x10)
flags |= KD_BUTTON_3;
dx = (signed char) (((ev[0] & 0x03) << 6) | (ev[1] & 0x3F));
dy = (signed char) (((ev[0] & 0x0C) << 4) | (ev[2] & 0x3F));
flags |= km->state & KD_BUTTON_2;
}
else {
if (ev[0] & 0x20)
flags |= KD_BUTTON_2;
dx = 0;
dy = 0;
flags |= km->state & (KD_BUTTON_1 | KD_BUTTON_3);
}
if (!MouseReasonable(pi, flags, dx, dy))
return FALSE;
if (km->stage == MouseWorking)
KdEnqueuePointerEvent(pi, flags, dx, dy, 0);
return TRUE;
}
static const KmouseProt logiProt = {
"logitech",
logiComplete, logiValid, logiParse, 0,
0xc0, 0x40, 0xc0, 0x00,
TRUE,
IGNPAR,
0,
0,
CS7 | CSTOPB | CREAD | CLOCAL,
B1200,
};
/*
* Mouse systems protocol, 5 bytes
*/
static Bool
mscParse(KdPointerInfo * pi, unsigned char *ev, int ne)
{
Kmouse *km = pi->driverPrivate;
int dx, dy;
unsigned long flags;
flags = KD_MOUSE_DELTA;
if (!(ev[0] & 0x4))
flags |= KD_BUTTON_1;
if (!(ev[0] & 0x2))
flags |= KD_BUTTON_2;
if (!(ev[0] & 0x1))
flags |= KD_BUTTON_3;
dx = (signed char) (ev[1]) + (signed char) (ev[3]);
dy = -((signed char) (ev[2]) + (signed char) (ev[4]));
if (!MouseReasonable(pi, flags, dx, dy))
return FALSE;
if (km->stage == MouseWorking)
KdEnqueuePointerEvent(pi, flags, dx, dy, 0);
return TRUE;
}
static const KmouseProt mscProt = {
"msc",
fiveComplete, mouseValid, mscParse, 0,
0xf8, 0x80, 0x00, 0x00,
TRUE,
IGNPAR,
0,
0,
CS8 | CSTOPB | CREAD | CLOCAL,
B1200,
};
/*
* Use logitech before ms -- they're the same except that
* logitech sometimes has a fourth byte
*/
static const KmouseProt *kmouseProts[] = {
&ps2Prot, &imps2Prot, &exps2Prot, &busProt, &logiProt, &msProt, &mscProt,
};
#define NUM_PROT (sizeof (kmouseProts) / sizeof (kmouseProts[0]))
static void
MouseInitProtocol(Kmouse * km)
{
int ret;
struct termios t;
if (km->prot->tty) {
ret = tcgetattr(km->iob.fd, &t);
if (ret >= 0) {
t.c_iflag = km->prot->c_iflag;
t.c_oflag = km->prot->c_oflag;
t.c_lflag = km->prot->c_lflag;
t.c_cflag = km->prot->c_cflag;
cfsetispeed(&t, km->prot->speed);
cfsetospeed(&t, km->prot->speed);
ret = tcsetattr(km->iob.fd, TCSANOW, &t);
}
}
km->stage = MouseBroken;
km->valid = 0;
km->tested = 0;
km->invalid = 0;
km->state = km->prot->state;
}
static void
MouseFirstProtocol(Kmouse * km, const char *prot)
{
if (prot) {
for (km->i_prot = 0; km->i_prot < NUM_PROT; km->i_prot++)
if (!strcmp(prot, kmouseProts[km->i_prot]->name))
break;
if (km->i_prot == NUM_PROT) {
int i;
ErrorF("Unknown mouse protocol \"%s\". Pick one of:", prot);
for (i = 0; i < NUM_PROT; i++)
ErrorF(" %s", kmouseProts[i]->name);
ErrorF("\n");
km->i_prot = 0;
km->prot = kmouseProts[km->i_prot];
ErrorF("Falling back to %s\n", km->prot->name);
}
else {
km->prot = kmouseProts[km->i_prot];
if (km->tty && !km->prot->tty)
ErrorF
("Mouse device is serial port, protocol %s is not serial protocol\n",
prot);
else if (!km->tty && km->prot->tty)
ErrorF
("Mouse device is not serial port, protocol %s is serial protocol\n",
prot);
}
}
if (!km->prot) {
for (km->i_prot = 0; kmouseProts[km->i_prot]->tty != km->tty;
km->i_prot++);
km->prot = kmouseProts[km->i_prot];
}
MouseInitProtocol(km);
}
static void
MouseNextProtocol(Kmouse * km)
{
do {
if (!km->prot)
km->i_prot = 0;
else if (++km->i_prot >= NUM_PROT)
km->i_prot = 0;
km->prot = kmouseProts[km->i_prot];
} while (km->prot->tty != km->tty);
MouseInitProtocol(km);
ErrorF("Switching to mouse protocol \"%s\"\n", km->prot->name);
}
static void
MouseRead(int mousePort, void *closure)
{
KdPointerInfo *pi = closure;
Kmouse *km = pi->driverPrivate;
unsigned char event[MAX_MOUSE];
int ne;
int c;
int i;
int timeout;
timeout = 0;
ne = 0;
for (;;) {
c = MouseReadByte(&km->iob, timeout);
if (c == -1) {
if (ne) {
km->invalid += ne + km->tested;
km->valid = 0;
km->tested = 0;
km->stage = MouseBroken;
}
break;
}
event[ne++] = c;
i = (*km->prot->Valid) (pi, event, ne);
if (i != 0) {
#ifdef DEBUG
ErrorF("Mouse protocol %s broken %d of %d bytes bad\n",
km->prot->name, i > 0 ? i : ne, ne);
#endif
if (i > 0 && i < ne) {
ne -= i;
memmove(event, event + i, ne);
}
else {
i = ne;
ne = 0;
}
km->invalid += i + km->tested;
km->valid = 0;
km->tested = 0;
if (km->stage == MouseWorking)
km->i_prot--;
km->stage = MouseBroken;
if (km->invalid > MAX_SKIP) {
MouseNextProtocol(km);
ne = 0;
}
timeout = 0;
}
else {
if ((*km->prot->Complete) (pi, event, ne)) {
if ((*km->prot->Parse) (pi, event, ne)) {
switch (km->stage) {
case MouseBroken:
#ifdef DEBUG
ErrorF("Mouse protocol %s seems OK\n", km->prot->name);
#endif
/* do not zero invalid to accumulate invalid bytes */
km->valid = 0;
km->tested = 0;
km->stage = MouseTesting;
/* fall through ... */
case MouseTesting:
km->valid++;
km->tested += ne;
if (km->valid > MAX_VALID) {
#ifdef DEBUG
ErrorF("Mouse protocol %s working\n",
km->prot->name);
#endif
km->stage = MouseWorking;
km->invalid = 0;
km->tested = 0;
km->valid = 0;
if (km->prot->Init && !(*km->prot->Init) (pi))
km->stage = MouseBroken;
}
break;
case MouseWorking:
break;
}
}
else {
km->invalid += ne + km->tested;
km->valid = 0;
km->tested = 0;
km->stage = MouseBroken;
}
ne = 0;
timeout = 0;
}
else
timeout = MOUSE_TIMEOUT;
}
}
}
const char *kdefaultMouse[] = {
"/dev/input/mice",
"/dev/mouse",
"/dev/psaux",
"/dev/adbmouse",
"/dev/ttyS0",
"/dev/ttyS1",
};
#define NUM_DEFAULT_MOUSE (sizeof (kdefaultMouse) / sizeof (kdefaultMouse[0]))
static Status
MouseInit(KdPointerInfo * pi)
{
int i;
int fd;
Kmouse *km;
if (!pi)
return BadImplementation;
if (!pi->path || strcmp(pi->path, "auto") == 0) {
for (i = 0; i < NUM_DEFAULT_MOUSE; i++) {
fd = open(kdefaultMouse[i], 2);
if (fd >= 0) {
pi->path = strdup(kdefaultMouse[i]);
break;
}
}
}
else {
fd = open(pi->path, 2);
}
if (fd < 0)
return BadMatch;
km = (Kmouse *) malloc(sizeof(Kmouse));
if (km) {
km->iob.avail = km->iob.used = 0;
MouseFirstProtocol(km, pi->protocol ? pi->protocol : "ps/2");
/* MouseFirstProtocol sets state to MouseBroken for later protocol
* checks. Skip these checks if a protocol was supplied */
if (pi->protocol)
km->state = MouseWorking;
km->i_prot = 0;
km->tty = isatty(fd);
km->iob.fd = fd;
pi->driverPrivate = km;
}
else {
close(fd);
return BadAlloc;
}
return Success;
}
static Status
MouseEnable(KdPointerInfo * pi)
{
Kmouse *km;
if (!pi || !pi->driverPrivate || !pi->path)
return BadImplementation;
km = pi->driverPrivate;
km->iob.fd = open(pi->path, 2);
if (km->iob.fd < 0)
return BadMatch;
if (!KdRegisterFd(km->iob.fd, MouseRead, pi)) {
close(km->iob.fd);
return BadAlloc;
}
return Success;
}
static void
MouseDisable(KdPointerInfo * pi)
{
Kmouse *km;
if (!pi || !pi->driverPrivate)
return;
km = pi->driverPrivate;
KdUnregisterFd(pi, km->iob.fd, TRUE);
}
static void
MouseFini(KdPointerInfo * pi)
{
free(pi->driverPrivate);
pi->driverPrivate = NULL;
}
KdPointerDriver LinuxMouseDriver = {
.name = "mouse",
.Init = MouseInit,
.Enable = MouseEnable,
.Disable = MouseDisable,
.Fini = MouseFini,
};

172
hw/kdrive/linux/ms.c Normal file
View File

@ -0,0 +1,172 @@
/*
Copyright (c) 2001 by Juliusz Chroboczek
Copyright (c) 1999 by Keith Packard
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <dix-config.h>
#include <errno.h>
#include <termios.h>
#include "os/xserver_poll.h"
#include <X11/X.h>
#include <X11/Xproto.h>
#include "inputstr.h"
#include "scrnintstr.h"
#include "kdrive.h"
static int
MsReadBytes(int fd, char *buf, int len, int min)
{
int n, tot;
struct pollfd poll_fd;
poll_fd.fd = fd;
poll_fd.events = POLLIN;
tot = 0;
while (len) {
n = read(fd, buf, len);
if (n > 0) {
tot += n;
buf += n;
len -= n;
}
if (tot % min == 0)
break;
n = xserver_poll(&poll_fd, 1, 100);
if (n <= 0)
break;
}
return tot;
}
static void
MsRead(int port, void *closure)
{
unsigned char buf[3 * 200];
unsigned char *b;
int n;
int dx, dy;
unsigned long flags;
while ((n = MsReadBytes(port, (char *) buf, sizeof(buf), 3)) > 0) {
b = buf;
while (n >= 3) {
flags = KD_MOUSE_DELTA;
if (b[0] & 0x20)
flags |= KD_BUTTON_1;
if (b[0] & 0x10)
flags |= KD_BUTTON_3;
dx = (char) (((b[0] & 0x03) << 6) | (b[1] & 0x3F));
dy = (char) (((b[0] & 0x0C) << 4) | (b[2] & 0x3F));
n -= 3;
b += 3;
KdEnqueuePointerEvent(closure, flags, dx, dy, 0);
}
}
}
static Status
MsInit(KdPointerInfo * pi)
{
if (!pi)
return BadImplementation;
if (!pi->path || strcmp(pi->path, "auto"))
pi->path = strdup("/dev/mouse");
if (!pi->name)
pi->name = strdup("Microsoft protocol mouse");
return Success;
}
static Status
MsEnable(KdPointerInfo * pi)
{
int port;
struct termios t;
int ret;
port = open(pi->path, O_RDWR | O_NONBLOCK);
if (port < 0) {
ErrorF("Couldn't open %s (%d)\n", pi->path, (int) errno);
return 0;
}
else if (port == 0) {
ErrorF("Opening %s returned 0! Please complain to Keith.\n", pi->path);
goto bail;
}
if (!isatty(port)) {
ErrorF("%s is not a tty\n", pi->path);
goto bail;
}
ret = tcgetattr(port, &t);
if (ret < 0) {
ErrorF("Couldn't tcgetattr(%s): %d\n", pi->path, errno);
goto bail;
}
t.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR |
IGNCR | ICRNL | IXON | IXOFF);
t.c_oflag &= ~OPOST;
t.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
t.c_cflag &= ~(CSIZE | PARENB);
t.c_cflag |= CS8 | CLOCAL | CSTOPB;
cfsetispeed(&t, B1200);
cfsetospeed(&t, B1200);
t.c_cc[VMIN] = 1;
t.c_cc[VTIME] = 0;
ret = tcsetattr(port, TCSANOW, &t);
if (ret < 0) {
ErrorF("Couldn't tcsetattr(%s): %d\n", pi->path, errno);
goto bail;
}
if (KdRegisterFd(port, MsRead, pi))
return TRUE;
pi->driverPrivate = (void *) (intptr_t) port;
return Success;
bail:
close(port);
return BadMatch;
}
static void
MsDisable(KdPointerInfo * pi)
{
KdUnregisterFd(pi, (int) (intptr_t) pi->driverPrivate, TRUE);
}
static void
MsFini(KdPointerInfo * pi)
{
}
KdPointerDriver MsMouseDriver = {
.name = "ms",
.Init = MsInit,
.Enable = MsEnable,
.Disable = MsDisable,
.Fini = MsFini,
};

174
hw/kdrive/linux/ps2.c Normal file
View File

@ -0,0 +1,174 @@
/*
* 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.
*/
#include <dix-config.h>
#include <X11/X.h>
#include <X11/Xproto.h>
#include "os/xserver_poll.h"
#include "inputstr.h"
#include "scrnintstr.h"
#include "kdrive.h"
static int
Ps2ReadBytes(int fd, char *buf, int len, int min)
{
int n, tot;
struct pollfd poll_fd;
tot = 0;
poll_fd.fd = fd;
poll_fd.events = POLLIN;
while (len) {
n = read(fd, buf, len);
if (n > 0) {
tot += n;
buf += n;
len -= n;
}
if (tot % min == 0)
break;
n = xserver_poll(&poll_fd, 1, 100);
if (n <= 0)
break;
}
return tot;
}
const char *Ps2Names[] = {
"/dev/psaux",
/* "/dev/mouse", */
"/dev/input/mice",
};
#define NUM_PS2_NAMES (sizeof (Ps2Names) / sizeof (Ps2Names[0]))
static void
Ps2Read(int ps2Port, void *closure)
{
unsigned char buf[3 * 200];
unsigned char *b;
int n;
int dx, dy;
unsigned long flags;
unsigned long left_button = KD_BUTTON_1;
unsigned long right_button = KD_BUTTON_3;
#undef SWAP_USB
#ifdef SWAP_USB
if (id == 2) {
left_button = KD_BUTTON_3;
right_button = KD_BUTTON_1;
}
#endif
while ((n = Ps2ReadBytes(ps2Port, (char *) buf, sizeof(buf), 3)) > 0) {
b = buf;
while (n >= 3) {
flags = KD_MOUSE_DELTA;
if (b[0] & 4)
flags |= KD_BUTTON_2;
if (b[0] & 2)
flags |= right_button;
if (b[0] & 1)
flags |= left_button;
dx = b[1];
if (b[0] & 0x10)
dx -= 256;
dy = b[2];
if (b[0] & 0x20)
dy -= 256;
dy = -dy;
n -= 3;
b += 3;
KdEnqueuePointerEvent(closure, flags, dx, dy, 0);
}
}
}
static Status
Ps2Init(KdPointerInfo * pi)
{
int ps2Port, i;
if (!pi->path) {
for (i = 0; i < NUM_PS2_NAMES; i++) {
ps2Port = open(Ps2Names[i], 0);
if (ps2Port >= 0) {
pi->path = strdup(Ps2Names[i]);
break;
}
}
}
else {
ps2Port = open(pi->path, 0);
}
if (ps2Port < 0)
return BadMatch;
close(ps2Port);
if (!pi->name)
pi->name = strdup("PS/2 Mouse");
return Success;
}
static Status
Ps2Enable(KdPointerInfo * pi)
{
int fd;
if (!pi)
return BadImplementation;
fd = open(pi->path, 0);
if (fd < 0)
return BadMatch;
if (!KdRegisterFd(fd, Ps2Read, pi)) {
close(fd);
return BadAlloc;
}
pi->driverPrivate = (void *) (intptr_t) fd;
return Success;
}
static void
Ps2Disable(KdPointerInfo * pi)
{
KdUnregisterFd(pi, (int) (intptr_t) pi->driverPrivate, TRUE);
}
static void
Ps2Fini(KdPointerInfo * pi)
{
}
KdPointerDriver Ps2MouseDriver = {
.name = "ps2",
.Init = Ps2Init,
.Enable = Ps2Enable,
.Disable = Ps2Disable,
.Fini = Ps2Fini,
};

191
hw/kdrive/linux/tslib.c Normal file
View File

@ -0,0 +1,191 @@
/*
* TSLIB based touchscreen driver for KDrive
* Porting to new input API and event queueing by Daniel Stone.
* Derived from ts.c by Keith Packard
* Derived from ps2.c by Jim Gettys
*
* Copyright © 1999 Keith Packard
* Copyright © 2000 Compaq Computer Corporation
* Copyright © 2002 MontaVista Software Inc.
* Copyright © 2005 OpenedHand Ltd.
* Copyright © 2006 Nokia Corporation
*
* 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 the authors and/or copyright holders
* not be used in advertising or publicity pertaining to distribution of the
* software without specific, written prior permission. The authors and/or
* copyright holders make no representations about the suitability of this
* software for any purpose. It is provided "as is" without express or
* implied warranty.
*
* THE AUTHORS AND/OR COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL THE AUTHORS AND/OR COPYRIGHT HOLDERS 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.
*/
#include <dix-config.h>
#include <X11/X.h>
#include <X11/Xproto.h>
#include "inputstr.h"
#include "scrnintstr.h"
#include "kdrive.h"
#include <sys/ioctl.h>
#include <tslib.h>
#include <dirent.h>
#include <linux/input.h>
struct TslibPrivate {
int fd;
int lastx, lasty;
struct tsdev *tsDev;
void (*raw_event_hook) (int x, int y, int pressure, void *closure);
void *raw_event_closure;
int phys_screen;
};
static void
TsRead(int fd, void *closure)
{
KdPointerInfo *pi = closure;
struct TslibPrivate *private = pi->driverPrivate;
struct ts_sample event;
long x = 0, y = 0;
unsigned long flags;
if (private->raw_event_hook) {
while (ts_read_raw(private->tsDev, &event, 1) == 1)
private->raw_event_hook(event.x, event.y, event.pressure,
private->raw_event_closure);
return;
}
while (ts_read(private->tsDev, &event, 1) == 1) {
if (event.pressure) {
flags = KD_BUTTON_1;
/*
* Here we test for the touch screen driver actually being on the
* touch screen, if it is we send absolute coordinates. If not,
* then we send delta's so that we can track the entire vga screen.
*/
if (KdCurScreen == private->phys_screen) {
x = event.x;
y = event.y;
}
else {
flags |= KD_MOUSE_DELTA;
if ((private->lastx == 0) || (private->lasty == 0)) {
x = event.x;
y = event.y;
}
else {
x = event.x - private->lastx;
y = event.y - private->lasty;
}
}
private->lastx = event.x;
private->lasty = event.y;
}
else {
flags = 0;
x = private->lastx;
y = private->lasty;
}
KdEnqueuePointerEvent(pi, flags, x, y, event.pressure);
}
}
static Status
TslibEnable(KdPointerInfo * pi)
{
struct TslibPrivate *private = pi->driverPrivate;
private->raw_event_hook = NULL;
private->raw_event_closure = NULL;
if (!pi->path) {
pi->path = strdup("/dev/input/touchscreen0");
ErrorF("[tslib/TslibEnable] no device path given, trying %s\n",
pi->path);
}
private->tsDev = ts_open(pi->path, 0);
if (!private->tsDev) {
ErrorF("[tslib/TslibEnable] failed to open %s\n", pi->path);
return BadAlloc;
}
if (ts_config(private->tsDev)) {
ErrorF("[tslib/TslibEnable] failed to load configuration\n");
ts_close(private->tsDev);
private->tsDev = NULL;
return BadValue;
}
private->fd = ts_fd(private->tsDev);
KdRegisterFd(private->fd, TsRead, pi);
return Success;
}
static void
TslibDisable(KdPointerInfo * pi)
{
struct TslibPrivate *private = pi->driverPrivate;
if (private->fd)
KdUnregisterFd(pi, private->fd, TRUE);
if (private->tsDev)
ts_close(private->tsDev);
private->fd = 0;
private->tsDev = NULL;
}
static Status
TslibInit(KdPointerInfo * pi)
{
struct TslibPrivate *private = NULL;
if (!pi || !pi->dixdev)
return !Success;
pi->driverPrivate = (struct TslibPrivate *)
calloc(sizeof(struct TslibPrivate), 1);
if (!pi->driverPrivate)
return !Success;
private = pi->driverPrivate;
/* hacktastic */
private->phys_screen = 0;
pi->nAxes = 3;
pi->name = strdup("Touchscreen");
pi->inputClass = KD_TOUCHSCREEN;
return Success;
}
static void
TslibFini(KdPointerInfo * pi)
{
free(pi->driverPrivate);
pi->driverPrivate = NULL;
}
KdPointerDriver TsDriver = {
.name = "tslib",
.Init = TslibInit,
.Enable = TslibEnable,
.Disable = TslibDisable,
.Fini = TslibFini,
};

View File

@ -1,2 +1,10 @@
subdir('src')
subdir('ephyr')
if build_xephyr
subdir('ephyr')
endif
if build_xfbdev
subdir('linux')
subdir('fbdev')
endif

View File

@ -29,7 +29,7 @@
* Put the entire colormap into the DAC
*/
static void
void
KdSetColormap(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
@ -72,6 +72,10 @@ KdSetColormap(ScreenPtr pScreen)
(*pScreenPriv->card->cfuncs->putColors) (pCmap->pScreen,
(1 << pScreenPriv->screen->fb.
depth), defs);
/* recolor hardware cursor */
if (pScreenPriv->card->cfuncs->recolorCursor)
(*pScreenPriv->card->cfuncs->recolorCursor) (pCmap->pScreen, 0, 0);
}
/*
@ -231,4 +235,9 @@ KdStoreColors(ColormapPtr pCmap, int ndef, xColorItem * pdefs)
}
(*pScreenPriv->card->cfuncs->putColors) (pCmap->pScreen, ndef, pdefs);
/* recolor hardware cursor */
if (pScreenPriv->card->cfuncs->recolorCursor)
(*pScreenPriv->card->cfuncs->recolorCursor) (pCmap->pScreen, ndef,
pdefs);
}

View File

@ -74,15 +74,20 @@ KdDepths kdDepths[] = {
#define KD_DEFAULT_BUTTONS 5
DevPrivateKeyRec kdScreenPrivateKeyRec;
static unsigned long kdGeneration;
unsigned long kdGeneration;
Bool kdVideoTest;
unsigned long kdVideoTestTime;
Bool kdEmulateMiddleButton;
Bool kdRawPointerCoordinates;
Bool kdDisableZaphod;
static Bool kdEnabled;
static int kdSubpixelOrder;
static char *kdSwitchCmd;
static DDXPointRec kdOrigin;
Bool kdAllowZap;
Bool kdEnabled;
int kdSubpixelOrder;
int kdVirtualTerminal = -1;
Bool kdSwitchPending;
char *kdSwitchCmd;
DDXPointRec kdOrigin;
Bool kdHasPointer = FALSE;
Bool kdHasKbd = FALSE;
const char *kdGlobalXkbRules = NULL;
@ -91,6 +96,15 @@ const char *kdGlobalXkbLayout = NULL;
const char *kdGlobalXkbVariant = NULL;
const char *kdGlobalXkbOptions = NULL;
static Bool kdCaughtSignal = FALSE;
/*
* Carry arguments from InitOutput through driver initialization
* to KdScreenInit
*/
KdOsFuncs *kdOsFuncs;
void
KdDisableScreen(ScreenPtr pScreen)
{
@ -103,7 +117,14 @@ KdDisableScreen(ScreenPtr pScreen)
KdDisableColormap(pScreen);
if (!pScreenPriv->screen->dumb && pScreenPriv->card->cfuncs->disableAccel)
(*pScreenPriv->card->cfuncs->disableAccel) (pScreen);
if (!pScreenPriv->screen->softCursor &&
pScreenPriv->card->cfuncs->disableCursor)
(*pScreenPriv->card->cfuncs->disableCursor) (pScreen);
if (pScreenPriv->card->cfuncs->dpms)
(*pScreenPriv->card->cfuncs->dpms) (pScreen, KD_DPMS_NORMAL);
pScreenPriv->enabled = FALSE;
if (pScreenPriv->card->cfuncs->disable)
(*pScreenPriv->card->cfuncs->disable) (pScreen);
}
static void
@ -126,7 +147,7 @@ KdDoSwitchCmd(const char *reason)
}
}
static void
void
KdSuspend(void)
{
KdCardInfo *card;
@ -137,17 +158,23 @@ KdSuspend(void)
for (screen = card->screenList; screen; screen = screen->next)
if (screen->mynum == card->selected && screen->pScreen)
KdDisableScreen(screen->pScreen);
if (card->driver && card->cfuncs->restore)
(*card->cfuncs->restore) (card);
}
KdDisableInput();
KdDoSwitchCmd("suspend");
}
}
static void
void
KdDisableScreens(void)
{
KdSuspend();
kdEnabled = FALSE;
if (kdEnabled) {
if (kdOsFuncs->Disable)
(*kdOsFuncs->Disable) ();
kdEnabled = FALSE;
}
}
Bool
@ -157,24 +184,88 @@ KdEnableScreen(ScreenPtr pScreen)
if (pScreenPriv->enabled)
return TRUE;
if (pScreenPriv->card->cfuncs->enable)
if (!(*pScreenPriv->card->cfuncs->enable) (pScreen))
return FALSE;
pScreenPriv->enabled = TRUE;
pScreenPriv->dpmsState = KD_DPMS_NORMAL;
pScreenPriv->card->selected = pScreenPriv->screen->mynum;
if (!pScreenPriv->screen->softCursor &&
pScreenPriv->card->cfuncs->enableCursor)
(*pScreenPriv->card->cfuncs->enableCursor) (pScreen);
if (!pScreenPriv->screen->dumb && pScreenPriv->card->cfuncs->enableAccel)
(*pScreenPriv->card->cfuncs->enableAccel) (pScreen);
KdEnableColormap(pScreen);
SetRootClip(pScreen, ROOT_CLIP_FULL);
if (pScreenPriv->card->cfuncs->dpms)
(*pScreenPriv->card->cfuncs->dpms) (pScreen, pScreenPriv->dpmsState);
return TRUE;
}
void
KdResume(void)
{
KdCardInfo *card;
KdScreenInfo *screen;
if (kdEnabled) {
KdDoSwitchCmd("resume");
for (card = kdCardInfo; card; card = card->next) {
if (card->cfuncs->preserve)
(*card->cfuncs->preserve) (card);
for (screen = card->screenList; screen; screen = screen->next)
if (screen->mynum == card->selected && screen->pScreen)
KdEnableScreen(screen->pScreen);
}
KdEnableInput();
KdReleaseAllKeys();
}
}
void
KdEnableScreens(void)
{
if (!kdEnabled) {
kdEnabled = TRUE;
if (kdOsFuncs->Enable)
(*kdOsFuncs->Enable) ();
}
KdResume();
}
void
KdProcessSwitch(void)
{
if (kdEnabled)
KdDisableScreens();
else
KdEnableScreens();
}
void
AbortDDX(enum ExitCode error)
{
KdDisableScreens();
if (kdOsFuncs) {
if (kdEnabled && kdOsFuncs->Disable)
(*kdOsFuncs->Disable) ();
if (kdOsFuncs->Fini)
(*kdOsFuncs->Fini) ();
KdDoSwitchCmd("stop");
}
if (kdCaughtSignal)
OsAbort();
}
void
ddxGiveUp(enum ExitCode error)
{
KdDisableScreens();
AbortDDX(error);
}
static Bool kdDumbDriver;
static Bool kdSoftCursor;
Bool kdDumbDriver;
Bool kdSoftCursor;
const char *
KdParseFindNext(const char *cur, const char *delim, char *save, char *last)
@ -330,7 +421,18 @@ KdParseScreen(KdScreenInfo * screen, const char *arg)
}
}
static void
/*
* Mouse argument syntax:
*
* device,protocol,options...
*
* Options are any of:
* 1-5 n button mouse
* 2button emulate middle button
* {NMO} Reorder buttons
*/
void
KdParseRgba(char *rgba)
{
if (!strcmp(rgba, "rgb"))
@ -356,7 +458,7 @@ KdUseMsg(void)
ErrorF
("-rgba rgb/bgr/vrgb/vbgr/none Specify subpixel ordering for LCD panels\n");
ErrorF
("-mouse driver [,n,options] Specify the pointer driver and its options (n is the number of buttons)\n");
("-mouse driver [,n,,options] Specify the pointer driver and its options (n is the number of buttons)\n");
ErrorF
("-keybd driver [,,options] Specify the keyboard driver and its options\n");
ErrorF("-xkb-rules Set default XkbRules value (can be overridden by -keybd options)\n");
@ -375,6 +477,7 @@ KdUseMsg(void)
ErrorF
("-origin X,Y Locates the next screen in the virtual screen (Xinerama)\n");
ErrorF("-switchCmd Command to execute on vt switch\n");
ErrorF("-zap Terminate server on Ctrl+Alt+Backspace\n");
ErrorF
("vtxx Use virtual terminal xx instead of the next available\n");
}
@ -407,6 +510,10 @@ KdProcessArgument(int argc, char **argv, int i)
kdDisableZaphod = TRUE;
return 1;
}
if (!strcmp(argv[i], "-zap")) {
kdAllowZap = TRUE;
return 1;
}
if (!strcmp(argv[i], "-3button")) {
kdEmulateMiddleButton = FALSE;
return 1;
@ -427,6 +534,10 @@ KdProcessArgument(int argc, char **argv, int i)
kdSoftCursor = TRUE;
return 1;
}
if (!strcmp(argv[i], "-videoTest")) {
kdVideoTest = TRUE;
return 1;
}
if (!strcmp(argv[i], "-origin")) {
if ((i + 1) < argc) {
char *x = argv[i + 1];
@ -459,6 +570,10 @@ KdProcessArgument(int argc, char **argv, int i)
UseMsg();
return 2;
}
if (!strncmp(argv[i], "vt", 2) &&
sscanf(argv[i], "vt%2d", &kdVirtualTerminal) == 1) {
return 1;
}
if (!strcmp(argv[i], "-xkb-rules")) {
if (i + 1 >= argc) {
UseMsg();
@ -517,7 +632,25 @@ KdProcessArgument(int argc, char **argv, int i)
return 0;
}
static Bool
/*
* These are getting tossed in here until I can think of where
* they really belong
*/
void
KdOsInit(KdOsFuncs * pOsFuncs)
{
kdOsFuncs = pOsFuncs;
if (pOsFuncs) {
if (serverGeneration == 1) {
KdDoSwitchCmd("start");
if (pOsFuncs->Init)
(*pOsFuncs->Init) ();
}
}
}
Bool
KdAllocatePrivates(ScreenPtr pScreen)
{
KdPrivScreenPtr pScreenPriv;
@ -535,40 +668,65 @@ KdAllocatePrivates(ScreenPtr pScreen)
return TRUE;
}
static Bool
Bool
KdCreateScreenResources(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
KdCardInfo *card = pScreenPriv->card;
Bool ret;
if (!miCreateScreenResources(pScreen))
return FALSE;
pScreen->CreateScreenResources = pScreenPriv->CreateScreenResources;
if (pScreen->CreateScreenResources)
ret = (*pScreen->CreateScreenResources) (pScreen);
else
ret = -1;
pScreenPriv->CreateScreenResources = pScreen->CreateScreenResources;
pScreen->CreateScreenResources = KdCreateScreenResources;
if (ret && card->cfuncs->createRes)
ret = (*card->cfuncs->createRes) (pScreen);
return ret;
if (card->cfuncs->createRes)
return card->cfuncs->createRes(pScreen);
return TRUE;
}
Bool KdCloseScreen(ScreenPtr pScreen)
Bool
KdCloseScreen(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
KdCardInfo *card = pScreenPriv->card;
Bool ret;
if (card->cfuncs->closeScreen)
(*card->cfuncs->closeScreen)(pScreen);
pScreenPriv->closed = TRUE;
pScreen->CloseScreen = pScreenPriv->CloseScreen;
Bool ret = fbCloseScreen(pScreen);
if (pScreen->CloseScreen)
ret = (*pScreen->CloseScreen) (pScreen);
else
ret = TRUE;
if (pScreenPriv->dpmsState != KD_DPMS_NORMAL)
(*card->cfuncs->dpms) (pScreen, KD_DPMS_NORMAL);
if (screen->mynum == card->selected)
KdDisableScreen(pScreen);
/*
* Restore video hardware when last screen is closed
*/
if (screen == card->screenList) {
if (kdEnabled && card->cfuncs->restore)
(*card->cfuncs->restore) (card);
}
if (!pScreenPriv->screen->dumb && card->cfuncs->finiAccel)
(*card->cfuncs->finiAccel) (pScreen);
if (!pScreenPriv->screen->softCursor && card->cfuncs->finiCursor)
(*card->cfuncs->finiCursor) (pScreen);
if (card->cfuncs->scrfini)
(*card->cfuncs->scrfini) (screen);
@ -583,7 +741,11 @@ Bool KdCloseScreen(ScreenPtr pScreen)
* Clean up OS when last card is closed
*/
if (card == kdCardInfo) {
kdEnabled = FALSE;
if (kdEnabled) {
kdEnabled = FALSE;
if (kdOsFuncs->Disable)
(*kdOsFuncs->Disable) ();
}
}
}
@ -593,12 +755,40 @@ Bool KdCloseScreen(ScreenPtr pScreen)
return ret;
}
static Bool
Bool
KdSaveScreen(ScreenPtr pScreen, int on)
{
return FALSE;
KdScreenPriv(pScreen);
int dpmsState;
if (!pScreenPriv->card->cfuncs->dpms)
return FALSE;
dpmsState = pScreenPriv->dpmsState;
switch (on) {
case SCREEN_SAVER_OFF:
dpmsState = KD_DPMS_NORMAL;
break;
case SCREEN_SAVER_ON:
if (dpmsState == KD_DPMS_NORMAL)
dpmsState = KD_DPMS_NORMAL + 1;
break;
case SCREEN_SAVER_CYCLE:
if (dpmsState < KD_DPMS_MAX)
dpmsState++;
break;
case SCREEN_SAVER_FORCER:
break;
}
if (dpmsState != pScreenPriv->dpmsState) {
if (pScreenPriv->enabled)
(*pScreenPriv->card->cfuncs->dpms) (pScreen, dpmsState);
pScreenPriv->dpmsState = dpmsState;
}
return TRUE;
}
static Bool
KdCreateWindow(WindowPtr pWin)
{
@ -671,7 +861,7 @@ KdSetSubpixelOrder(ScreenPtr pScreen, Rotation randr)
/* Pass through AddScreen, which doesn't take any closure */
static KdScreenInfo *kdCurrentScreen;
static Bool
Bool
KdScreenInit(ScreenPtr pScreen, int argc, char **argv)
{
KdScreenInfo *screen = kdCurrentScreen;
@ -778,7 +968,16 @@ KdScreenInit(ScreenPtr pScreen, int argc, char **argv)
if (!(*card->cfuncs->finishInitScreen) (pScreen))
return FALSE;
/*
* Wrap CloseScreen, the order now is:
* KdCloseScreen
* miBSCloseScreen
* fbCloseScreen
*/
pScreenPriv->CloseScreen = pScreen->CloseScreen;
pScreen->CloseScreen = KdCloseScreen;
pScreenPriv->CreateScreenResources = pScreen->CreateScreenResources;
pScreen->CreateScreenResources = KdCreateScreenResources;
if (screen->softCursor ||
@ -797,10 +996,21 @@ KdScreenInit(ScreenPtr pScreen, int argc, char **argv)
/*
* Enable the hardware
*/
kdEnabled = TRUE;
if (!kdEnabled) {
kdEnabled = TRUE;
if (kdOsFuncs->Enable)
(*kdOsFuncs->Enable) ();
}
if (screen->mynum == card->selected) {
if (card->cfuncs->preserve)
(*card->cfuncs->preserve) (card);
if (card->cfuncs->enable)
if (!(*card->cfuncs->enable) (pScreen))
return FALSE;
pScreenPriv->enabled = TRUE;
if (!screen->softCursor && card->cfuncs->enableCursor)
(*card->cfuncs->enableCursor) (pScreen);
KdEnableColormap(pScreen);
if (!screen->dumb && card->cfuncs->enableAccel)
(*card->cfuncs->enableAccel) (pScreen);
@ -809,7 +1019,7 @@ KdScreenInit(ScreenPtr pScreen, int argc, char **argv)
return TRUE;
}
static void
void
KdInitScreen(ScreenInfo * pScreenInfo,
KdScreenInfo * screen, int argc, char **argv)
{
@ -911,6 +1121,27 @@ KdAddScreen(ScreenInfo * pScreenInfo,
AddScreen(KdScreenInit, argc, argv);
}
#if 0 /* This function is not used currently */
int
KdDepthToFb(ScreenPtr pScreen, int depth)
{
KdScreenPriv(pScreen);
for (fb = 0; fb <= KD_MAX_FB && pScreenPriv->screen->fb.frameBuffer; fb++)
if (pScreenPriv->screen->fb.depth == depth)
return fb;
}
#endif
static int
KdSignalWrapper(int signum)
{
kdCaughtSignal = TRUE;
return 1; /* use generic OS layer cleanup & abort */
}
void
KdInitOutput(ScreenInfo * pScreenInfo, int argc, char **argv)
{
@ -952,6 +1183,7 @@ KdInitOutput(ScreenInfo * pScreenInfo, int argc, char **argv)
for (screen = card->screenList; screen; screen = screen->next)
KdAddScreen(pScreenInfo, screen, argc, argv);
OsRegisterSigWrapper(KdSignalWrapper);
xorgGlxCreateVendor();
#if defined(CONFIG_UDEV) || defined(CONFIG_HAL)

View File

@ -35,6 +35,7 @@
#include "pixmapstr.h"
#include "windowstr.h"
#include "servermd.h"
#include "colormapst.h"
#include "gcstruct.h"
#include "input.h"
#include "mipointer.h"
@ -112,10 +113,19 @@ typedef struct _KdCardFuncs {
Bool (*initScreen) (ScreenPtr); /* initialize ScreenRec */
Bool (*finishInitScreen) (ScreenPtr pScreen);
Bool (*createRes) (ScreenPtr); /* create screen resources */
void (*preserve) (KdCardInfo *); /* save graphics card state */
Bool (*enable) (ScreenPtr); /* set up for rendering */
Bool (*dpms) (ScreenPtr, int); /* set DPMS screen saver */
void (*disable) (ScreenPtr); /* turn off rendering */
void (*restore) (KdCardInfo *); /* restore graphics card state */
void (*scrfini) (KdScreenInfo *); /* close down screen */
void (*cardfini) (KdCardInfo *); /* close down */
Bool (*initCursor) (ScreenPtr); /* detect and map cursor */
void (*enableCursor) (ScreenPtr); /* enable cursor */
void (*disableCursor) (ScreenPtr); /* disable cursor */
void (*finiCursor) (ScreenPtr); /* close down */
void (*recolorCursor) (ScreenPtr, int, xColorItem *);
Bool (*initAccel) (ScreenPtr);
void (*enableAccel) (ScreenPtr);
@ -143,6 +153,9 @@ typedef struct {
ColormapPtr pInstalledmap; /* current colormap */
xColorItem systemPalette[KD_MAX_PSEUDO_SIZE]; /* saved windows colors */
CreateScreenResourcesProcPtr CreateScreenResources;
CloseScreenProcPtr CloseScreen;
} KdPrivScreenRec, *KdPrivScreenPtr;
typedef enum _kdPointerState {
@ -212,12 +225,14 @@ struct _KdPointerInfo {
struct _KdPointerInfo *next;
};
extern int KdCurScreen;
void KdAddPointerDriver(KdPointerDriver * driver);
void KdRemovePointerDriver(KdPointerDriver * driver);
KdPointerInfo *KdNewPointer(void);
void KdFreePointer(KdPointerInfo *);
int KdAddPointer(KdPointerInfo * ki);
int KdAddConfigPointer(char *pointer);
int KdAddConfigPointer(const char *pointer);
void KdRemovePointer(KdPointerInfo * ki);
#define KD_KEY_COUNT 248
@ -235,6 +250,7 @@ typedef struct _KdKeyboardInfo KdKeyboardInfo;
typedef struct _KdKeyboardDriver {
const char *name;
Bool (*PreInit) (KdKeyboardInfo *);
Bool (*Init) (KdKeyboardInfo *);
Bool (*Enable) (KdKeyboardInfo *);
void (*Leds) (KdKeyboardInfo *, int);
@ -274,10 +290,46 @@ void KdAddKeyboardDriver(KdKeyboardDriver * driver);
void KdRemoveKeyboardDriver(KdKeyboardDriver * driver);
KdKeyboardInfo *KdNewKeyboard(void);
void KdFreeKeyboard(KdKeyboardInfo * ki);
int KdAddConfigKeyboard(char *pointer);
int KdAddConfigKeyboard(const char *pointer);
int KdAddKeyboard(KdKeyboardInfo * ki);
void KdRemoveKeyboard(KdKeyboardInfo * ki);
typedef struct _KdOsFuncs {
int (*Init) (void);
void (*Enable) (void);
Bool (*SpecialKey) (KeySym);
void (*Disable) (void);
void (*Fini) (void);
void (*pollEvents) (void);
void (*Bell) (int, int, int);
} KdOsFuncs;
typedef enum _KdSyncPolarity {
KdSyncNegative, KdSyncPositive
} KdSyncPolarity;
typedef struct _KdMonitorTiming {
/* label */
int horizontal;
int vertical;
int rate;
/* pixel clock */
int clock; /* in KHz */
/* horizontal timing */
int hfp; /* front porch */
int hbp; /* back porch */
int hblank; /* blanking */
KdSyncPolarity hpol; /* polarity */
/* vertical timing */
int vfp; /* front porch */
int vbp; /* back porch */
int vblank; /* blanking */
KdSyncPolarity vpol; /* polarity */
} KdMonitorTiming;
extern const KdMonitorTiming kdMonitorTimings[];
extern const int kdNumMonitorTimings;
typedef struct _KdPointerMatrix {
int matrix[2][3];
} KdPointerMatrix;
@ -286,8 +338,15 @@ extern DevPrivateKeyRec kdScreenPrivateKeyRec;
#define kdScreenPrivateKey (&kdScreenPrivateKeyRec)
extern unsigned long kdGeneration;
extern Bool kdEnabled;
extern Bool kdSwitchPending;
extern Bool kdEmulateMiddleButton;
extern Bool kdDisableZaphod;
extern Bool kdAllowZap;
extern int kdVirtualTerminal;
extern char *kdSwitchCmd;
extern KdOsFuncs *kdOsFuncs;
#define KdGetScreenPriv(pScreen) ((KdPrivScreenPtr) \
dixLookupPrivate(&(pScreen)->devPrivates, kdScreenPrivateKey))
@ -296,6 +355,9 @@ extern Bool kdDisableZaphod;
#define KdScreenPriv(pScreen) KdPrivScreenPtr pScreenPriv = KdGetScreenPriv(pScreen)
/* kcmap.c */
void
KdSetColormap(ScreenPtr pScreen);
void
KdEnableColormap(ScreenPtr pScreen);
@ -320,12 +382,21 @@ extern miPointerScreenFuncRec kdPointerScreenFuncs;
void
KdDisableScreen(ScreenPtr pScreen);
void
KdDisableScreens(void);
Bool
KdEnableScreen(ScreenPtr pScreen);
void
KdEnableScreens(void);
void
KdSuspend(void);
void
KdResume(void);
void
KdProcessSwitch(void);
@ -336,18 +407,48 @@ Rotation KdSubRotation(Rotation a, Rotation b);
void
KdParseScreen(KdScreenInfo * screen, const char *arg);
KdPointerInfo *KdParsePointer(const char *arg);
KdKeyboardInfo *KdParseKeyboard(const char *arg);
const char *
KdParseFindNext(const char *cur, const char *delim, char *save, char *last);
void
KdParseRgba(char *rgba);
void
KdUseMsg(void);
int
KdProcessArgument(int argc, char **argv, int i);
void
KdOsInit(KdOsFuncs * pOsFuncs);
void
KdOsAddInputDrivers(void);
Bool
KdAllocatePrivates(ScreenPtr pScreen);
Bool
KdCreateScreenResources(ScreenPtr pScreen);
Bool
KdCloseScreen(ScreenPtr pScreen);
Bool
KdSaveScreen(ScreenPtr pScreen, int on);
Bool
KdScreenInit(ScreenPtr pScreen, int argc, char **argv);
void
KdInitScreen(ScreenInfo * pScreenInfo,
KdScreenInfo * screen, int argc, char **argv);
void
KdInitCard(ScreenInfo * pScreenInfo, KdCardInfo * card, int argc, char **argv);
@ -379,6 +480,15 @@ void
void
KdCloseInput(void);
Bool
KdRegisterFd(int fd, void (*read) (int fd, void *closure), void *closure);
void
KdUnregisterFds(void *closure, Bool do_close);
void
KdUnregisterFd(void *closure, int fd, Bool do_close);
void
KdEnqueueKeyboardEvent(KdKeyboardInfo * ki, unsigned char scan_code,
unsigned char is_up);
@ -396,6 +506,17 @@ void
KdEnqueuePointerEvent(KdPointerInfo * pi, unsigned long flags, int rx, int ry,
int rz);
void
_KdEnqueuePointerEvent(KdPointerInfo * pi, int type, int x, int y, int z,
int b, int absrel, Bool force);
void
KdReleaseAllKeys(void);
void
KdSetLed(KdKeyboardInfo * ki, int led, Bool on);
void
KdSetPointerMatrix(KdPointerMatrix *pointer);
@ -403,6 +524,9 @@ void
KdComputePointerMatrix(KdPointerMatrix *pointer, Rotation randr, int width,
int height);
void
KdScreenToPointerCoords(int *x, int *y);
void
KdBlockHandler(ScreenPtr pScreen, void *timeout);
@ -415,6 +539,34 @@ void
void
KdEnableInput(void);
void
KdRingBell(KdKeyboardInfo * ki, int volume, int pitch, int duration);
/* kmode.c */
const KdMonitorTiming *KdFindMode(KdScreenInfo * screen,
Bool (*supported) (KdScreenInfo *,
const KdMonitorTiming *));
Bool
KdTuneMode(KdScreenInfo * screen,
Bool (*usable) (KdScreenInfo *),
Bool (*supported) (KdScreenInfo *, const KdMonitorTiming *));
#ifdef RANDR
Bool
KdRandRGetInfo(ScreenPtr pScreen,
int randr,
Bool (*supported) (ScreenPtr pScreen, const KdMonitorTiming *));
const KdMonitorTiming *KdRandRGetTiming(ScreenPtr pScreen,
Bool (*supported) (ScreenPtr pScreen,
const KdMonitorTiming
*), int rate,
RRScreenSizePtr pSize);
#endif
/* kshadow.c */
Bool
KdShadowFbAlloc(KdScreenInfo * screen, Bool rotate);
@ -434,6 +586,4 @@ void
void
InitCard(char *name);
Bool KdCloseScreen(ScreenPtr pScreen);
#endif /* _KDRIVE_H_ */

View File

@ -46,12 +46,22 @@
#include "xkbsrv.h"
#include "XIstubs.h" /* even though we don't use stubs. cute, no? */
#include "exevents.h"
#include "extinit.h"
#include "exglobals.h"
#include "eventstr.h"
#include "xserver-properties.h"
#include "inpututils.h"
#include "optionstr.h"
#if defined(CONFIG_UDEV) || defined(CONFIG_HAL)
#include "hotplug.h"
#endif
#ifdef KDRIVE_EVDEV
#define DEV_INPUT_EVENT_PREFIX "/dev/input/event"
#define DEV_INPUT_EVENT_PREFIX_LEN (sizeof(DEV_INPUT_EVENT_PREFIX) - 1)
#endif
#define AtomFromName(x) MakeAtom(x, strlen(x), 1)
struct KdConfigDevice {
@ -77,6 +87,21 @@ static KdPointerMatrix kdPointerMatrix = {
{0, 1, 0}}
};
void KdResetInputMachine(void);
#define KD_MAX_INPUT_FDS 8
typedef struct _kdInputFd {
int fd;
void (*read) (int fd, void *closure);
int (*enable) (int fd, void *closure);
void (*disable) (int fd, void *closure);
void *closure;
} KdInputFd;
static KdInputFd kdInputFds[KD_MAX_INPUT_FDS];
static int kdNumInputFds;
extern Bool kdRawPointerCoordinates;
extern const char *kdGlobalXkbRules;
@ -85,13 +110,62 @@ extern const char *kdGlobalXkbLayout;
extern const char *kdGlobalXkbVariant;
extern const char *kdGlobalXkbOptions;
#ifdef KDRIVE_KBD
static void KdSigio(int sig)
{
int i;
for (i = 0; i < kdNumInputFds; i++)
(*kdInputFds[i].read) (kdInputFds[i].fd, kdInputFds[i].closure);
}
static void KdBlockSigio(void)
{
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGIO);
sigprocmask(SIG_BLOCK, &set, 0);
}
static void KdUnblockSigio(void)
{
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGIO);
sigprocmask(SIG_UNBLOCK, &set, 0);
}
#undef VERIFY_SIGIO
#ifdef VERIFY_SIGIO
void KdAssertSigioBlocked(char *where)
{
sigset_t set, old;
sigemptyset(&set);
sigprocmask(SIG_BLOCK, &set, &old);
if (!sigismember(&old, SIGIO))
ErrorF("SIGIO not blocked at %s\n", where);
}
#else
#define KdAssertSigioBlocked(s)
#endif
static int kdnFds;
#endif
#ifdef FNONBLOCK
#define NOBLOCK FNONBLOCK
#else
#define NOBLOCK FNDELAY
#endif
static void
void
KdResetInputMachine(void)
{
KdPointerInfo *pi;
@ -102,13 +176,126 @@ KdResetInputMachine(void)
}
}
static void
KdNonBlockFd(int fd)
{
int flags;
flags = fcntl(fd, F_GETFL);
flags |= FASYNC | NOBLOCK;
fcntl(fd, F_SETFL, flags);
}
static void
KdNotifyFd(int fd, int ready, void *data)
{
int i = (int) (intptr_t) data;
(*kdInputFds[i].read)(fd, kdInputFds[i].closure);
}
static void
KdAddFd(int fd, int i)
{
#ifdef KDRIVE_KBD
struct sigaction act;
sigset_t set;
kdnFds++;
fcntl(fd, F_SETOWN, getpid());
#endif
KdNonBlockFd(fd);
InputThreadRegisterDev(fd, KdNotifyFd, (void *) (intptr_t) i);
#ifdef KDRIVE_KBD
/* AddEnabledDevice(fd); */
memset(&act, '\0', sizeof act);
act.sa_handler = KdSigio;
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask, SIGIO);
sigaddset(&act.sa_mask, SIGALRM);
sigaddset(&act.sa_mask, SIGVTALRM);
sigaction(SIGIO, &act, 0);
sigemptyset(&set);
sigprocmask(SIG_SETMASK, &set, 0);
#endif
}
static void
KdRemoveFd(int fd)
{
int flags;
InputThreadUnregisterDev(fd);
flags = fcntl(fd, F_GETFL);
flags &= ~(FASYNC | NOBLOCK);
fcntl(fd, F_SETFL, flags);
#ifdef KDRIVE_KBD
struct sigaction act;
kdnFds--;
if (kdnFds == 0) {
memset(&act, '\0', sizeof act);
act.sa_handler = SIG_IGN;
sigemptyset(&act.sa_mask);
sigaction(SIGIO, &act, 0);
}
#endif
}
Bool
KdRegisterFd(int fd, void (*read) (int fd, void *closure), void *closure)
{
if (kdNumInputFds == KD_MAX_INPUT_FDS)
return FALSE;
kdInputFds[kdNumInputFds].fd = fd;
kdInputFds[kdNumInputFds].read = read;
kdInputFds[kdNumInputFds].enable = 0;
kdInputFds[kdNumInputFds].disable = 0;
kdInputFds[kdNumInputFds].closure = closure;
if (kdInputEnabled)
KdAddFd(fd, kdNumInputFds);
kdNumInputFds++;
return TRUE;
}
void
KdUnregisterFd(void *closure, int fd, Bool do_close)
{
int i, j;
for (i = 0; i < kdNumInputFds; i++) {
if (kdInputFds[i].closure == closure &&
(fd == -1 || kdInputFds[i].fd == fd)) {
if (kdInputEnabled)
KdRemoveFd(kdInputFds[i].fd);
if (do_close)
close(kdInputFds[i].fd);
for (j = i; j < (kdNumInputFds - 1); j++)
kdInputFds[j] = kdInputFds[j + 1];
kdNumInputFds--;
break;
}
}
}
void
KdUnregisterFds(void *closure, Bool do_close)
{
KdUnregisterFd(closure, -1, do_close);
}
void
KdDisableInput(void)
{
KdKeyboardInfo *ki;
KdPointerInfo *pi;
int found = 0, i = 0;
#ifndef KDRIVE_KBD
input_lock();
#else
KdBlockSigio();
#endif
for (ki = kdKeyboards; ki; ki = ki->next) {
if (ki->driver && ki->driver->Disable)
@ -120,6 +307,49 @@ KdDisableInput(void)
(*pi->driver->Disable) (pi);
}
if (kdNumInputFds) {
ErrorF("[KdDisableInput] Buggy drivers: still %d input fds left!",
kdNumInputFds);
i = 0;
while (i < kdNumInputFds) {
found = 0;
for (ki = kdKeyboards; ki; ki = ki->next) {
if (ki == kdInputFds[i].closure) {
ErrorF(" fd %d belongs to keybd driver %s\n",
kdInputFds[i].fd,
ki->driver && ki->driver->name ?
ki->driver->name : "(unnamed!)");
found = 1;
break;
}
}
if (found) {
i++;
continue;
}
for (pi = kdPointers; pi; pi = pi->next) {
if (pi == kdInputFds[i].closure) {
ErrorF(" fd %d belongs to pointer driver %s\n",
kdInputFds[i].fd,
pi->driver && pi->driver->name ?
pi->driver->name : "(unnamed!)");
break;
}
}
if (found) {
i++;
continue;
}
ErrorF(" fd %d not claimed by any active device!\n",
kdInputFds[i].fd);
KdUnregisterFd(kdInputFds[i].closure, kdInputFds[i].fd, TRUE);
}
}
kdInputEnabled = FALSE;
}
@ -147,8 +377,11 @@ KdEnableInput(void)
/* reset screen saver */
NoticeEventTime (&ev, pi->dixdev);
}
#ifndef KDRIVE_KBD
input_unlock();
#else
KdUnblockSigio();
#endif
}
static KdKeyboardDriver *
@ -351,14 +584,10 @@ KdPointerProc(DeviceIntPtr pDevice, int onoff)
return BadImplementation;
}
static void
KdRingBell(KdKeyboardInfo * ki, int volume, int pitch, int duration)
Bool
LegalModifier(unsigned int key, DeviceIntPtr pDev)
{
if (!ki || !ki->driver || !ki->driver->Bell)
return;
if (kdInputEnabled)
(*ki->driver->Bell) (ki, volume, pitch, duration);
return TRUE;
}
static void
@ -383,10 +612,25 @@ DDXRingBell(int volume, int pitch, int duration)
{
KdKeyboardInfo *ki = NULL;
for (ki = kdKeyboards; ki; ki = ki->next) {
if (ki->dixdev->coreEvents)
KdRingBell(ki, volume, pitch, duration);
if (kdOsFuncs->Bell) {
(*kdOsFuncs->Bell) (volume, pitch, duration);
}
else {
for (ki = kdKeyboards; ki; ki = ki->next) {
if (ki->dixdev->coreEvents)
KdRingBell(ki, volume, pitch, duration);
}
}
}
void
KdRingBell(KdKeyboardInfo * ki, int volume, int pitch, int duration)
{
if (!ki || !ki->driver || !ki->driver->Bell)
return;
if (kdInputEnabled)
(*ki->driver->Bell) (ki, volume, pitch, duration);
}
static void
@ -401,7 +645,7 @@ KdSetLeds(KdKeyboardInfo * ki, int leds)
}
}
static void
void
KdSetLed(KdKeyboardInfo * ki, int led, Bool on)
{
if (!ki || !ki->dixdev || !ki->dixdev->kbdfeed)
@ -465,6 +709,20 @@ KdComputePointerMatrix(KdPointerMatrix * m, Rotation randr, int width,
}
}
void
KdScreenToPointerCoords(int *x, int *y)
{
int (*m)[3] = kdPointerMatrix.matrix;
int div = m[0][1] * m[1][0] - m[1][1] * m[0][0];
int sx = *x;
int sy = *y;
*x = (m[0][1] * sy - m[0][1] * m[1][2] + m[1][1] * m[0][2] -
m[1][1] * sx) / div;
*y = (m[1][0] * sx + m[0][0] * m[1][2] - m[1][0] * m[0][2] -
m[0][0] * sy) / div;
}
static void
KdKbdCtrl(DeviceIntPtr pDevice, KeybdCtrl * ctrl)
{
@ -532,6 +790,10 @@ KdKeyboardProc(DeviceIntPtr pDevice, int onoff)
return BadImplementation;
}
if (ki->driver->PreInit) {
(*ki->driver->PreInit)(ki);
}
memset(&rmlvo, 0, sizeof(rmlvo));
rmlvo.rules = ki->xkbRules;
rmlvo.model = ki->xkbModel;
@ -698,7 +960,7 @@ KdNewKeyboard(void)
}
int
KdAddConfigKeyboard(char *keyboard)
KdAddConfigKeyboard(const char *keyboard)
{
struct KdConfigDevice **prev, *new;
@ -762,7 +1024,7 @@ KdRemoveKeyboard(KdKeyboardInfo * ki)
}
int
KdAddConfigPointer(char *pointer)
KdAddConfigPointer(const char *pointer)
{
struct KdConfigDevice **prev, *new;
@ -923,9 +1185,18 @@ KdParseKbdOptions(KdKeyboardInfo * ki)
ErrorF("Kbd option key (%s) of value (%s) not assigned!\n",
key, value);
}
}
static KdKeyboardInfo *
#ifdef KDRIVE_EVDEV
if (!ki->driver && ki->path != NULL &&
strncasecmp(ki->path,
DEV_INPUT_EVENT_PREFIX,
DEV_INPUT_EVENT_PREFIX_LEN) == 0) {
ki->driver = KdFindKeyboardDriver("evdev");
ki->options = input_option_new(ki->options, "driver", "evdev");
}
#endif
}
KdKeyboardInfo *
KdParseKeyboard(const char *arg)
{
char save[1024];
@ -1033,9 +1304,19 @@ KdParsePointerOptions(KdPointerInfo * pi)
ErrorF("Pointer option key (%s) of value (%s) not assigned!\n",
key, value);
}
#ifdef KDRIVE_EVDEV
if (!pi->driver && pi->path != NULL &&
strncasecmp(pi->path,
DEV_INPUT_EVENT_PREFIX,
DEV_INPUT_EVENT_PREFIX_LEN) == 0) {
pi->driver = KdFindPointerDriver("evdev");
pi->options = input_option_new(pi->options, "driver", "evdev");
}
#endif
}
static KdPointerInfo *
KdPointerInfo *
KdParsePointer(const char *arg)
{
char save[1024];
@ -1119,11 +1400,26 @@ KdInitInput(void)
KdKeyboardInfo *ki;
struct KdConfigDevice *dev;
#ifndef KDRIVE_KBD
if (kdConfigPointers || kdConfigKeyboards)
InputThreadPreInit();
#else
InputThreadEnable = FALSE;
#endif
kdInputEnabled = TRUE;
#ifdef KDRIVE_KBD
if (!kdConfigKeyboards) {
KdAddConfigKeyboard("keyboard");
}
#endif
#ifdef KDRIVE_MOUSE
if (!kdConfigPointers) {
KdAddConfigPointer("mouse");
}
#endif
for (dev = kdConfigPointers; dev; dev = dev->next) {
pi = KdParsePointer(dev->line);
if (!pi)
@ -1511,9 +1807,6 @@ KdClassifyInput(KdPointerInfo * pi, int type, int x, int y, int z, int b)
return keyboard;
}
static void
_KdEnqueuePointerEvent(KdPointerInfo * pi, int type, int x, int y, int z,
int b, int absrel, Bool force);
/* We return true if we're stealing the event. */
static Bool
KdRunMouseMachine(KdPointerInfo * pi, KdInputClass c, int type, int x, int y,
@ -1587,30 +1880,55 @@ KdHandlePointerEvent(KdPointerInfo * pi, int type, int x, int y, int z, int b,
return FALSE;
}
static void
_KdEnqueuePointerEvent(KdPointerInfo * pi, int type, int x, int y, int z,
int b, int absrel, Bool force)
{
int valuators[3] = { x, y, z };
ValuatorMask mask;
/* TRUE from KdHandlePointerEvent, means 'we swallowed the event'. */
if (!force && KdHandlePointerEvent(pi, type, x, y, z, b, absrel))
return;
valuator_mask_set_range(&mask, 0, 3, valuators);
QueuePointerEvents(pi->dixdev, type, b, absrel, &mask);
}
static void
KdReceiveTimeout(KdPointerInfo * pi)
{
KdRunMouseMachine(pi, timeout, 0, 0, 0, 0, 0, 0);
}
/*
* kdCheckTermination
*
* This function checks for the key sequence that terminates the server. When
* detected, it sets the dispatchException flag and returns. The key sequence
* is:
* Control-Alt
* It's assumed that the server will be waken up by the caller when this
* function returns.
*/
extern int nClients;
void
KdReleaseAllKeys(void)
{
#if 0
int key;
KdKeyboardInfo *ki;
#ifndef KDRIVE_KBD
input_lock();
#else
KdBlockSigio();
#endif
for (ki = kdKeyboards; ki; ki = ki->next) {
for (key = ki->keySyms.minKeyCode; key < ki->keySyms.maxKeyCode; key++) {
if (key_is_down(ki->dixdev, key, KEY_POSTED | KEY_PROCESSED)) {
KdHandleKeyboardEvent(ki, KeyRelease, key);
QueueGetKeyboardEvents(ki->dixdev, KeyRelease, key, NULL);
}
}
}
#ifndef KDRIVE_KBD
input_unlock();
#else
KdUnblockSigio();
#endif
#endif
}
static void
KdCheckLock(void)
{
@ -1744,6 +2062,22 @@ KdEnqueuePointerEvent(KdPointerInfo * pi, unsigned long flags, int rx, int ry,
pi->buttonState = buttons;
}
void
_KdEnqueuePointerEvent(KdPointerInfo * pi, int type, int x, int y, int z,
int b, int absrel, Bool force)
{
int valuators[3] = { x, y, z };
ValuatorMask mask;
/* TRUE from KdHandlePointerEvent, means 'we swallowed the event'. */
if (!force && KdHandlePointerEvent(pi, type, x, y, z, b, absrel))
return;
valuator_mask_set_range(&mask, 0, 3, valuators);
QueuePointerEvents(pi->dixdev, type, b, absrel, &mask);
}
void
KdBlockHandler(ScreenPtr pScreen, void *timeo)
{
@ -1761,6 +2095,11 @@ KdBlockHandler(ScreenPtr pScreen, void *timeo)
myTimeout = ms;
}
}
/* if we need to poll for events, do that */
if (kdOsFuncs->pollEvents) {
(*kdOsFuncs->pollEvents) ();
myTimeout = 20;
}
if (myTimeout > 0)
AdjustWaitForDelay(timeo, myTimeout);
}
@ -1774,12 +2113,22 @@ KdWakeupHandler(ScreenPtr pScreen, int result)
if (pi->timeoutPending) {
if ((long) (GetTimeInMillis() - pi->emulationTimeout) >= 0) {
pi->timeoutPending = FALSE;
#ifndef KDRIVE_KBD
input_lock();
#else
KdBlockSigio();
#endif
KdReceiveTimeout(pi);
#ifndef KDRIVE_KBD
input_unlock();
#else
KdUnblockSigio();
#endif
}
}
}
if (kdSwitchPending)
KdProcessSwitch();
}
#define KdScreenOrigin(pScreen) (&(KdGetScreenPriv(pScreen)->screen->origin))
@ -1866,12 +2215,23 @@ KdCrossScreen(ScreenPtr pScreen, Bool entering)
{
}
int KdCurScreen; /* current event screen */
static void
KdWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
{
#ifndef KDRIVE_KBD
input_lock();
#else
KdBlockSigio();
#endif
KdCurScreen = pScreen->myNum;
miPointerWarpCursor(pDev, pScreen, x, y);
#ifndef KDRIVE_KBD
input_unlock();
#else
KdUnblockSigio();
#endif
}
miPointerScreenFuncRec kdPointerScreenFuncs = {
@ -1884,6 +2244,8 @@ void
ProcessInputEvents(void)
{
mieqProcessInputEvents();
if (kdSwitchPending)
KdProcessSwitch();
KdCheckLock();
}

376
hw/kdrive/src/kmode.c Normal file
View File

@ -0,0 +1,376 @@
/*
* Copyright 1999 SuSE, Inc.
*
* 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 SuSE not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. SuSE makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
* 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.
*
* Author: Keith Packard, SuSE, Inc.
*/
#include <dix-config.h>
#include "kdrive.h"
const KdMonitorTiming kdMonitorTimings[] = {
/* H V Hz KHz */
/* FP BP BLANK POLARITY */
/* IPAQ modeline:
*
* Modeline "320x240" 5.7222 320 337 340 352 240 241 244 254"
*/
{320, 240, 64, 16256,
17, 12, 32, KdSyncNegative,
1, 11, 14, KdSyncNegative,
},
/* Other VESA modes */
{640, 350, 85, 31500, /* VESA */
32, 96, 192, KdSyncPositive, /* 26.413 */
32, 60, 95, KdSyncNegative, /* 59.354 */
},
{640, 400, 60, 31500, /* VESA */
32, 96, 192, KdSyncNegative, /* 26.413 */
1, 41, 45, KdSyncPositive, /* 59.354 */
},
{720, 400, 85, 35500, /* VESA */
36, 108, 216, KdSyncNegative, /* 37.927 */
1, 42, 46, KdSyncPositive, /* 85.039 */
},
/* Modeline "720x576" 29.000 720 736 800 880 576 577 580 625 */
{
720, 576, 52, 32954, /* PAL Video */
16, 80, 160, KdSyncPositive, /* 32.954 */
1, 45, 49, KdSyncPositive, /* 52.727 */
},
/* 640x480 modes */
{640, 480, 85, 36000, /* VESA */
56, 80, 192, KdSyncNegative, /* 43.269 */
1, 25, 29, KdSyncNegative, /* 85.008 */
},
{640, 480, 75, 31500, /* VESA */
16, 120, 200, KdSyncNegative, /* 37.500 */
1, 16, 20, KdSyncNegative, /* 75.000 */
},
{640, 480, 72, 31500, /* VESA */
16, 120, 176, KdSyncNegative, /* 37.861 */
1, 20, 24, KdSyncNegative, /* 72.809 */
},
{640, 480, 60, 25175, /* VESA */
16, 48, 160, KdSyncNegative, /* 31.469 */
10, 33, 45, KdSyncNegative, /* 59.940 */
},
/* 800x600 modes */
{800, 600, 85, 56250, /* VESA */
32, 152, 248, KdSyncPositive, /* 53.674 */
1, 27, 31, KdSyncPositive, /* 85.061 */
},
{800, 600, 75, 49500, /* VESA */
16, 160, 256, KdSyncPositive, /* 46.875 */
1, 21, 25, KdSyncPositive, /* 75.000 */
},
/* DEFAULT */
#define MONITOR_TIMING_DEFAULT 9
{800, 600, 72, 50000, /* VESA */
56, 64, 240, KdSyncPositive, /* 48.077 */
37, 23, 66, KdSyncPositive, /* 72.188 */
},
{800, 600, 60, 40000, /* VESA */
40, 88, 256, KdSyncPositive, /* 37.879 */
1, 23, 28, KdSyncPositive, /* 60.317 */
},
{800, 600, 56, 36000, /* VESA */
24, 128, 224, KdSyncPositive, /* 35.156 */
1, 22, 25, KdSyncPositive, /* 56.250 */
},
/* 1024x768 modes */
{1024, 768, 85, 94500, /* VESA */
48, 208, 352, KdSyncPositive, /* 68.677 */
1, 36, 40, KdSyncPositive, /* 84.997 */
},
{1024, 768, 75, 78750, /* VESA */
16, 176, 288, KdSyncPositive, /* 60.023 */
1, 28, 32, KdSyncPositive, /* 75.029 */
},
{1024, 768, 70, 75000, /* VESA */
24, 144, 304, KdSyncNegative, /* 56.476 */
3, 29, 38, KdSyncNegative, /* 70.069 */
},
{1024, 768, 60, 65000, /* VESA */
24, 160, 320, KdSyncNegative, /* 48.363 */
3, 29, 38, KdSyncNegative, /* 60.004 */
},
/* 1152x864 mode */
{1152, 864, 75, 108000, /* VESA */
64, 256, 448, KdSyncPositive, /* 67.500 */
1, 32, 36, KdSyncPositive, /* 75.000 */
},
/* 1152x900 modes */
{1152, 900, 85, 122500, /* ADDED */
48, 208, 384, KdSyncPositive, /* 79.753 */
1, 32, 38, KdSyncPositive, /* 85.024 */
},
{1152, 900, 75, 108250, /* ADDED */
32, 208, 384, KdSyncPositive, /* 70.475 */
1, 32, 38, KdSyncPositive, /* 75.133 */
},
{1152, 900, 70, 100250, /* ADDED */
32, 208, 384, KdSyncPositive, /* 65.267 */
2, 32, 38, KdSyncPositive, /* 69.581 */
},
{1152, 900, 66, 95000, /* ADDED */
32, 208, 384, KdSyncPositive, /* 61.849 */
1, 32, 38, KdSyncPositive, /* 65.937 */
},
/* 1280x854 modes */
{1280, 854, 103, 12500, /* ADDED */
56, 16, 128, KdSyncPositive, /* 102.554 */
1, 216, 12, KdSyncPositive,
},
/* 1280x960 modes */
{1280, 960, 85, 148500, /* VESA */
64, 224, 448, KdSyncPositive, /* 85.938 */
1, 47, 51, KdSyncPositive, /* 85.002 */
},
{1280, 960, 60, 108000, /* VESA */
96, 312, 520, KdSyncPositive, /* 60.000 */
1, 36, 40, KdSyncPositive, /* 60.000 */
},
/* 1280x1024 modes */
{1280, 1024, 85, 157500, /* VESA */
64, 224, 448, KdSyncPositive, /* 91.146 */
1, 44, 48, KdSyncPositive, /* 85.024 */
},
{1280, 1024, 75, 135000, /* VESA */
16, 248, 408, KdSyncPositive, /* 79.976 */
1, 38, 42, KdSyncPositive, /* 75.025 */
},
{1280, 1024, 60, 108000, /* VESA */
48, 248, 408, KdSyncPositive, /* 63.981 */
1, 38, 42, KdSyncPositive, /* 60.020 */
},
/* 1600x1200 modes */
{1600, 1200, 85, 229500, /* VESA */
64, 304, 560, KdSyncPositive, /* 106.250 */
1, 46, 50, KdSyncPositive, /* 85.000 */
},
{1600, 1200, 75, 202500, /* VESA */
64, 304, 560, KdSyncPositive, /* 93.750 */
1, 46, 50, KdSyncPositive, /* 75.000 */
},
{1600, 1200, 70, 189000, /* VESA */
64, 304, 560, KdSyncPositive, /* 87.500 */
1, 46, 50, KdSyncPositive, /* 70.000 */
},
{1600, 1200, 65, 175500, /* VESA */
64, 304, 560, KdSyncPositive, /* 81.250 */
1, 46, 50, KdSyncPositive, /* 65.000 */
},
{1600, 1200, 60, 162000, /* VESA */
64, 304, 560, KdSyncPositive, /* 75.000 */
1, 46, 50, KdSyncPositive, /* 60.000 */
},
/* 1792x1344 modes */
{1792, 1344, 85, 301500, /* ADDED */
96, 352, 672, KdSyncNegative, /* 122.362 */
1, 92, 96, KdSyncPositive, /* 84.974 */
},
{1792, 1344, 75, 261000, /* VESA */
96, 352, 664, KdSyncNegative, /* 106.270 */
1, 69, 73, KdSyncPositive, /* 74.997 */
},
{1792, 1344, 60, 204750, /* VESA */
128, 328, 656, KdSyncNegative, /* 83.640 */
1, 46, 50, KdSyncPositive, /* 60.000 */
},
#if 0
{1800, 1012, 75},
{1906, 1072, 68},
#endif
/* 1856x1392 modes */
{1856, 1392, 85, 330500, /* ADDED */
160, 352, 736, KdSyncNegative, /* 127.508 */
1, 104, 108, KdSyncPositive, /* 85.001 */
},
{1856, 1392, 75, 288000, /* VESA */
128, 352, 704, KdSyncNegative, /* 112.500 */
1, 104, 108, KdSyncPositive, /* 75.000 */
},
{1856, 1392, 60, 218250, /* VESA */
96, 352, 672, KdSyncNegative, /* 86.333 */
1, 43, 47, KdSyncPositive, /* 59.995 */
},
/* 1920x1440 modes */
{1920, 1440, 85, 341750, /* ADDED */
160, 352, 760, KdSyncNegative, /* 127.512 */
1, 56, 60, KdSyncPositive, /* 85.012 */
},
{1920, 1440, 75, 297000, /* VESA */
144, 352, 720, KdSyncNegative, /* 112.500 */
1, 56, 60, KdSyncPositive, /* 75.000 */
},
{1920, 1440, 60, 234000, /* VESA */
128, 244, 680, KdSyncNegative, /* 90.000 */
1, 56, 60, KdSyncPositive, /* 60.000 */
},
};
#define NUM_MONITOR_TIMINGS (sizeof kdMonitorTimings/sizeof kdMonitorTimings[0])
const int kdNumMonitorTimings = NUM_MONITOR_TIMINGS;
const KdMonitorTiming *
KdFindMode(KdScreenInfo * screen,
Bool (*supported) (KdScreenInfo *, const KdMonitorTiming *))
{
int i;
const KdMonitorTiming *t;
for (i = 0, t = kdMonitorTimings; i < NUM_MONITOR_TIMINGS; i++, t++) {
if ((*supported) (screen, t) &&
t->horizontal == screen->width &&
t->vertical == screen->height &&
(!screen->rate || t->rate <= screen->rate)) {
return t;
}
}
ErrorF("Warning: mode not found, using default\n");
return &kdMonitorTimings[MONITOR_TIMING_DEFAULT];
}
static const KdMonitorTiming *
kdFindPrevSize(const KdMonitorTiming * old)
{
const KdMonitorTiming *new, *prev;
if (old == kdMonitorTimings)
return 0;
new = old;
/*
* Search for the previous size
*/
while (new != kdMonitorTimings) {
new--;
if (new->horizontal != old->horizontal &&
new->vertical != old->vertical) {
break;
}
}
/*
* Match the refresh rate (<=)
*/
while (new != kdMonitorTimings) {
prev = new - 1;
if (prev->horizontal == new->horizontal &&
prev->vertical == new->vertical && prev->rate > old->rate) {
break;
}
new--;
}
return new;
}
Bool
KdTuneMode(KdScreenInfo * screen,
Bool (*usable) (KdScreenInfo *),
Bool (*supported) (KdScreenInfo *, const KdMonitorTiming *))
{
const KdMonitorTiming *t;
while (!(*usable) (screen)) {
/*
* Fix requested depth and geometry until it works
*/
if (screen->fb.depth > 16)
screen->fb.depth = 16;
else if (screen->fb.depth > 8)
screen->fb.depth = 8;
else {
t = kdFindPrevSize(KdFindMode(screen, supported));
if (!t)
return FALSE;
screen->width = t->horizontal;
screen->height = t->vertical;
screen->rate = t->rate;
}
}
return TRUE;
}
#ifdef RANDR
Bool
KdRandRGetInfo(ScreenPtr pScreen,
int randr,
Bool (*supported) (ScreenPtr pScreen, const KdMonitorTiming *))
{
KdScreenPriv(pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
int i;
const KdMonitorTiming *t;
for (i = 0, t = kdMonitorTimings; i < NUM_MONITOR_TIMINGS; i++, t++) {
if ((*supported) (pScreen, t)) {
RRScreenSizePtr pSize;
pSize = RRRegisterSize(pScreen,
t->horizontal,
t->vertical,
screen->width_mm, screen->height_mm);
if (!pSize)
return FALSE;
if (!RRRegisterRate(pScreen, pSize, t->rate))
return FALSE;
if (t->horizontal == screen->width &&
t->vertical == screen->height && t->rate == screen->rate)
RRSetCurrentConfig(pScreen, randr, t->rate, pSize);
}
}
return TRUE;
}
const KdMonitorTiming *
KdRandRGetTiming(ScreenPtr pScreen,
Bool (*supported) (ScreenPtr pScreen,
const KdMonitorTiming *),
int rate, RRScreenSizePtr pSize)
{
int i;
const KdMonitorTiming *t;
for (i = 0, t = kdMonitorTimings; i < NUM_MONITOR_TIMINGS; i++, t++) {
if (t->horizontal == pSize->width &&
t->vertical == pSize->height &&
t->rate == rate && (*supported) (pScreen, t))
return t;
}
return 0;
}
#endif

View File

@ -3,6 +3,7 @@ srcs_kdrive = [
'kdrive.c',
'kinfo.c',
'kinput.c',
'kmode.c',
'kshadow.c',
'../../../mi/miinitext.c',
'../../../mi/miinitext.h',

View File

@ -1,4 +1,4 @@
if build_xephyr
if build_xephyr or build_xfbdev
subdir('kdrive')
endif

View File

@ -238,14 +238,49 @@ if build_xquartz
endif
build_xephyr = get_option('xephyr')
build_xfbdev = get_option('xfbdev')
build_xvfb = get_option('xvfb')
build_kdrive_kbd = false
build_kdrive_mouse = false
build_kdrive_evdev = false
build_kdrive_tslib = false
if build_xfbdev
build_kdrive_kbd = get_option('kdrive_kbd')
build_kdrive_mouse = get_option('kdrive_mouse')
build_kdrive_evdev = get_option('kdrive_evdev')
build_kdrive_tslib = get_option('kdrive_tslib')
endif
if build_kdrive_kbd
add_project_arguments('-DKDRIVE_KBD=1', language : 'c')
endif
if build_kdrive_mouse
add_project_arguments('-DKDRIVE_MOUSE=1', language : 'c')
endif
if build_kdrive_evdev
add_project_arguments('-DKDRIVE_EVDEV=1', language : 'c')
endif
if build_kdrive_tslib
add_project_arguments('-DKDRIVE_TSLIB=1', language : 'c')
endif
summary({
'Xorg': build_xorg,
'Xnest': build_xnest,
'Xvfb': build_xvfb,
'Xwin': build_xwin,
'Xquartz': build_xquartz,
'Xfbdev': build_xfbdev,
'Xfbdev-kbd': build_kdrive_kbd,
'Xfbdev-mouse': build_kdrive_mouse,
'Xfbdev-evdev': build_kdrive_evdev,
'Xfbdev-tslib': build_kdrive_tslib,
},
section: 'DDX',
bool_yn: true,

View File

@ -2,6 +2,8 @@ option('xorg', type: 'combo', choices: ['true', 'false', 'auto'], value: 'auto',
description: 'Enable Xorg X Server')
option('xephyr', type: 'boolean', value: false,
description: 'Enable Xephyr nested X server')
option('xfbdev', type: 'boolean', value: false,
description: 'Enable the kdrive framebuffer device server')
option('glamor', type: 'combo', choices: ['true', 'false', 'auto'], value: 'auto',
description: 'Enable glamor (default yes for Xorg builds)')
option('xnest', type: 'combo', choices: ['true', 'false', 'auto'], value: 'auto',
@ -13,6 +15,15 @@ option('xwin', type: 'combo', choices: ['true', 'false', 'auto'], value: 'auto',
option('xquartz', type: 'combo', choices: ['true', 'false', 'auto'], value: 'auto',
description: 'Enable Xquartz X server')
option('kdrive_kbd', type: 'boolean', value: true,
description: 'Build kbd driver for kdrive')
option('kdrive_mouse', type: 'boolean', value: true,
description: 'Build mouse driver for kdrive')
option('kdrive_evdev', type: 'boolean', value: true,
description: 'Build evdev driver for kdrive')
option('kdrive_tslib', type: 'boolean', value: false,
description: 'Build kdrive tslib touchscreen support')
option('builder_addr', type: 'string', description: 'Builder address', value: 'xorg@lists.freedesktop.org')
option('builder_string', type: 'string', description: 'Additional builder string')