diff --git a/hw/kdrive/ephyr/ephyr.c b/hw/kdrive/ephyr/ephyr.c index 9b00ed11f..cdc22cecf 100644 --- a/hw/kdrive/ephyr/ephyr.c +++ b/hw/kdrive/ephyr/ephyr.c @@ -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, }; diff --git a/hw/kdrive/ephyr/ephyrinit.c b/hw/kdrive/ephyr/ephyrinit.c index ff0d5d0cc..f65cef052 100644 --- a/hw/kdrive/ephyr/ephyrinit.c +++ b/hw/kdrive/ephyr/ephyrinit.c @@ -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, }; diff --git a/hw/kdrive/fbdev/Xfbdev.man b/hw/kdrive/fbdev/Xfbdev.man new file mode 100644 index 000000000..bfdae168f --- /dev/null +++ b/hw/kdrive/fbdev/Xfbdev.man @@ -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. + diff --git a/hw/kdrive/fbdev/fbdev.c b/hw/kdrive/fbdev/fbdev.c new file mode 100644 index 000000000..2603a54df --- /dev/null +++ b/hw/kdrive/fbdev/fbdev.c @@ -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 +#include "fbdev.h" +#include "fb/fb_priv.h" +#include + +#include + +#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); +} diff --git a/hw/kdrive/fbdev/fbdev.h b/hw/kdrive/fbdev/fbdev.h new file mode 100644 index 000000000..ffa548774 --- /dev/null +++ b/hw/kdrive/fbdev/fbdev.h @@ -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 +#include +#include +#include +#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_ */ diff --git a/hw/kdrive/fbdev/fbinit.c b/hw/kdrive/fbdev/fbinit.c new file mode 100644 index 000000000..fd8abd9b9 --- /dev/null +++ b/hw/kdrive/fbdev/fbinit.c @@ -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 +#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 */ +}; diff --git a/hw/kdrive/fbdev/meson.build b/hw/kdrive/fbdev/meson.build new file mode 100644 index 000000000..2c8e6eff0 --- /dev/null +++ b/hw/kdrive/fbdev/meson.build @@ -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) diff --git a/hw/kdrive/linux/evdev.c b/hw/kdrive/linux/evdev.c new file mode 100644 index 000000000..b30981d96 --- /dev/null +++ b/hw/kdrive/linux/evdev.c @@ -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 +#include +#include +#include +#include +#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, +}; diff --git a/hw/kdrive/linux/keyboard.c b/hw/kdrive/linux/keyboard.c new file mode 100644 index 000000000..6b85255b1 --- /dev/null +++ b/hw/kdrive/linux/keyboard.c @@ -0,0 +1,349 @@ +/* + * Copyright © 1999 Keith Packard + * XKB integration © 2006 Nokia Corporation, author: Tomas Frydrych + * + * 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 +#include "kdrive.h" +#include +#include +#define XK_PUBLISHING +#include +#include +#include + +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, +}; diff --git a/hw/kdrive/linux/linux.c b/hw/kdrive/linux/linux.c new file mode 100644 index 000000000..1c4968470 --- /dev/null +++ b/hw/kdrive/linux/linux.c @@ -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 +#include "kdrive.h" +#include +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/hw/kdrive/linux/meson.build b/hw/kdrive/linux/meson.build new file mode 100644 index 000000000..0c81a2929 --- /dev/null +++ b/hw/kdrive/linux/meson.build @@ -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, +) diff --git a/hw/kdrive/linux/mouse.c b/hw/kdrive/linux/mouse.c new file mode 100644 index 000000000..5174c9e21 --- /dev/null +++ b/hw/kdrive/linux/mouse.c @@ -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 +#include +#include +#include +#include +#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, +}; diff --git a/hw/kdrive/linux/ms.c b/hw/kdrive/linux/ms.c new file mode 100644 index 000000000..d4350bf76 --- /dev/null +++ b/hw/kdrive/linux/ms.c @@ -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 +#include +#include +#include "os/xserver_poll.h" +#include +#include +#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, +}; diff --git a/hw/kdrive/linux/ps2.c b/hw/kdrive/linux/ps2.c new file mode 100644 index 000000000..62e451354 --- /dev/null +++ b/hw/kdrive/linux/ps2.c @@ -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 +#include +#include +#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, +}; diff --git a/hw/kdrive/linux/tslib.c b/hw/kdrive/linux/tslib.c new file mode 100644 index 000000000..9df70fb79 --- /dev/null +++ b/hw/kdrive/linux/tslib.c @@ -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 + +#include +#include +#include "inputstr.h" +#include "scrnintstr.h" +#include "kdrive.h" +#include +#include +#include +#include + +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, +}; diff --git a/hw/kdrive/meson.build b/hw/kdrive/meson.build index 16341e228..13cd8b4ad 100644 --- a/hw/kdrive/meson.build +++ b/hw/kdrive/meson.build @@ -1,2 +1,10 @@ subdir('src') -subdir('ephyr') + +if build_xephyr + subdir('ephyr') +endif + +if build_xfbdev + subdir('linux') + subdir('fbdev') +endif diff --git a/hw/kdrive/src/kcmap.c b/hw/kdrive/src/kcmap.c index b19b90b08..9aa29e0ea 100644 --- a/hw/kdrive/src/kcmap.c +++ b/hw/kdrive/src/kcmap.c @@ -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); } diff --git a/hw/kdrive/src/kdrive.c b/hw/kdrive/src/kdrive.c index 36bda4153..d66538841 100644 --- a/hw/kdrive/src/kdrive.c +++ b/hw/kdrive/src/kdrive.c @@ -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) diff --git a/hw/kdrive/src/kdrive.h b/hw/kdrive/src/kdrive.h index a4b7576d0..bae74814c 100644 --- a/hw/kdrive/src/kdrive.h +++ b/hw/kdrive/src/kdrive.h @@ -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_ */ diff --git a/hw/kdrive/src/kinput.c b/hw/kdrive/src/kinput.c index 692c294e3..e56e1da54 100644 --- a/hw/kdrive/src/kinput.c +++ b/hw/kdrive/src/kinput.c @@ -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(); } diff --git a/hw/kdrive/src/kmode.c b/hw/kdrive/src/kmode.c new file mode 100644 index 000000000..333e2a2d1 --- /dev/null +++ b/hw/kdrive/src/kmode.c @@ -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 +#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 diff --git a/hw/kdrive/src/meson.build b/hw/kdrive/src/meson.build index fbc0727e9..8d4e482f6 100644 --- a/hw/kdrive/src/meson.build +++ b/hw/kdrive/src/meson.build @@ -3,6 +3,7 @@ srcs_kdrive = [ 'kdrive.c', 'kinfo.c', 'kinput.c', + 'kmode.c', 'kshadow.c', '../../../mi/miinitext.c', '../../../mi/miinitext.h', diff --git a/hw/meson.build b/hw/meson.build index fb9e5d431..5e292f2e2 100644 --- a/hw/meson.build +++ b/hw/meson.build @@ -1,4 +1,4 @@ -if build_xephyr +if build_xephyr or build_xfbdev subdir('kdrive') endif diff --git a/meson.build b/meson.build index e9e7aa267..8d778fd67 100644 --- a/meson.build +++ b/meson.build @@ -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, diff --git a/meson_options.txt b/meson_options.txt index 26172f147..6c989abbf 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -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')