/* $Header$ */ /* * Copyright 2004 by Costas Stylianou +44(0)7850 394095 * * 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 Costas Sylianou not be used in * advertising or publicity pertaining to distribution of the software without * specific, written prior permission. Costas Stylianou makes no representations * about the suitability of this software for any purpose. It is provided * "as is" without express or implied warranty. * * COSTAS STYLIANOU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL COSTAS STYLIANOU 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. */ /* * epson13806.c - Implementation of hardware accelerated functions for * Epson S1D13806 graphics controller. * * History: * 28-Jan-04 C.Stylianou PRJ NBL: Created from fbdev.c. * 30-Mar-04 Phil Blundell/Peter Naulls Integration with XFree 4.3 * */ #ifdef HAVE_CONFIG_H #include #endif #include #include "epson13806.h" #include "epson13806reg.h" extern int KdTsPhyScreen; Bool epsonInitialize (KdCardInfo *card, EpsonPriv *priv) { int k; unsigned long off; if ((priv->fd = open("/dev/fb0", O_RDWR)) < 0) { perror("Error opening /dev/fb0\n"); return FALSE; } if ((k=ioctl(priv->fd, FBIOGET_FSCREENINFO, &priv->fix)) < 0) { perror("Error with /dev/fb ioctl FIOGET_FSCREENINFO"); close (priv->fd); return FALSE; } if ((k=ioctl(priv->fd, FBIOGET_VSCREENINFO, &priv->var)) < 0) { perror("Error with /dev/fb ioctl FIOGET_VSCREENINFO"); close (priv->fd); return FALSE; } priv->fb_base = KdMapDevice (EPSON13806_PHYSICAL_VMEM_ADDR, EPSON13806_VMEM_SIZE); 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 epsonCardInit (KdCardInfo *card) { EpsonPriv *priv; priv = (EpsonPriv *) xalloc (sizeof (EpsonPriv)); if (!priv) return FALSE; if (!epsonInitialize (card, priv)) { xfree (priv); return FALSE; } card->driver = priv; // Call InitEpson to map onto Epson registers initEpson13806(); return TRUE; } #define FBDEV_KLUDGE_FORMAT #ifdef FBDEV_KLUDGE_FORMAT static Pixel epsonMakeContig (Pixel orig, Pixel others) { Pixel low; low = lowbit (orig) >> 1; while (low && (others & low) == 0) { orig |= low; low >>= 1; } return orig; } #endif Bool epsonScreenInitialize (KdScreenInfo *screen, EpsonScrPriv *scrpriv) { EpsonPriv *priv = screen->card->driver; Pixel allbits; int depth; Bool gray; depth = priv->var.bits_per_pixel; gray = priv->var.grayscale; screen->fb[0].visuals = (1 << TrueColor); #define Mask(o,l) (((1 << l) - 1) << o) screen->fb[0].redMask = Mask (priv->var.red.offset, priv->var.red.length); screen->fb[0].greenMask = Mask (priv->var.green.offset, priv->var.green.length); screen->fb[0].blueMask = Mask (priv->var.blue.offset, priv->var.blue.length); #ifdef FBDEV_KLUDGE_FORMAT /* * This is a kludge so that Render will work -- fill in the gaps * in the pixel */ screen->fb[0].redMask = epsonMakeContig (screen->fb[0].redMask, screen->fb[0].greenMask| screen->fb[0].blueMask); screen->fb[0].greenMask = epsonMakeContig (screen->fb[0].greenMask, screen->fb[0].redMask| screen->fb[0].blueMask); screen->fb[0].blueMask = epsonMakeContig (screen->fb[0].blueMask, screen->fb[0].redMask| screen->fb[0].greenMask); #endif allbits = screen->fb[0].redMask | screen->fb[0].greenMask | screen->fb[0].blueMask; depth = 32; while (depth && !(allbits & (1 << (depth - 1)))) depth--; screen->rate = 60; scrpriv->randr = screen->randr; { screen->fb[0].depth = depth; screen->fb[0].bitsPerPixel = priv->var.bits_per_pixel; screen->width = priv->var.xres; screen->height = priv->var.yres; screen->fb[0].byteStride = priv->fix.line_length; screen->fb[0].pixelStride = (priv->fix.line_length * 8 / priv->var.bits_per_pixel); screen->fb[0].frameBuffer = (CARD8 *) (priv->fb); screen->off_screen_base = screen->fb[0].byteStride * screen->height; screen->memory_base = priv->fb; screen->memory_size = EPSON13806_VMEM_SIZE; } return TRUE; } Bool epsonScreenInit (KdScreenInfo *screen) { EpsonScrPriv *scrpriv; scrpriv = xalloc (sizeof (EpsonScrPriv)); if (!scrpriv) return FALSE; memset (scrpriv, '\0', sizeof (EpsonScrPriv)); screen->driver = scrpriv; if (!epsonScreenInitialize (screen, scrpriv)) { screen->driver = 0; xfree (scrpriv); return FALSE; } return TRUE; } static void * epsonWindowLinear (ScreenPtr pScreen, CARD32 row, CARD32 offset, int mode, CARD32 *size, void *closure) { KdScreenPriv(pScreen); EpsonPriv *priv = pScreenPriv->card->driver; if (!pScreenPriv->enabled) return 0; *size = priv->fix.line_length; return (CARD8 *) priv->fb + row * priv->fix.line_length + offset; } #ifdef RANDR static Bool epsonRandRGetInfo (ScreenPtr pScreen, Rotation *rotations) { KdScreenPriv(pScreen); KdScreenInfo *screen = pScreenPriv->screen; EpsonScrPriv *scrpriv = screen->driver; #if 0 RRVisualGroupPtr pVisualGroup; RRGroupOfVisualGroupPtr pGroupOfVisualGroup; #endif RRScreenSizePtr pSize; Rotation randr; int n; *rotations = RR_Rotate_0|RR_Rotate_90|RR_Rotate_180|RR_Rotate_270; for (n = 0; n < pScreen->numDepths; n++) if (pScreen->allowedDepths[n].numVids) break; if (n == pScreen->numDepths) return FALSE; #if 0 pVisualGroup = RRCreateVisualGroup (pScreen); if (!pVisualGroup) return FALSE; if (!RRAddDepthToVisualGroup (pScreen, pVisualGroup, &pScreen->allowedDepths[n])) { RRDestroyVisualGroup (pScreen, pVisualGroup); return FALSE; } pVisualGroup = RRRegisterVisualGroup (pScreen, pVisualGroup); if (!pVisualGroup) return FALSE; pGroupOfVisualGroup = RRCreateGroupOfVisualGroup (pScreen); if (!RRAddVisualGroupToGroupOfVisualGroup (pScreen, pGroupOfVisualGroup, pVisualGroup)) { RRDestroyGroupOfVisualGroup (pScreen, pGroupOfVisualGroup); /* pVisualGroup left until screen closed */ return FALSE; } pGroupOfVisualGroup = RRRegisterGroupOfVisualGroup (pScreen, pGroupOfVisualGroup); if (!pGroupOfVisualGroup) return FALSE; #endif pSize = RRRegisterSize (pScreen, screen->width, screen->height, screen->width_mm, screen->height_mm); randr = KdSubRotation (scrpriv->randr, screen->randr); RRSetCurrentConfig (pScreen, randr, RR_Rotate_0, pSize); return TRUE; } static Bool epsonRandRSetConfig (ScreenPtr pScreen, Rotation randr, int rate, RRScreenSizePtr pSize) { KdScreenPriv(pScreen); KdScreenInfo *screen = pScreenPriv->screen; EpsonScrPriv *scrpriv = screen->driver; Bool wasEnabled = pScreenPriv->enabled; randr = KdAddRotation (randr, screen->randr); if (scrpriv->randr != randr) { if (wasEnabled) KdDisableScreen (pScreen); scrpriv->randr = randr; if (wasEnabled) KdEnableScreen (pScreen); } return TRUE; } static Bool epsonRandRInit (ScreenPtr pScreen) { rrScrPrivPtr pScrPriv; if (!RRScreenInit (pScreen)) return FALSE; pScrPriv = rrGetScrPriv(pScreen); pScrPriv->rrGetInfo = epsonRandRGetInfo; pScrPriv->rrSetConfig = epsonRandRSetConfig; return TRUE; } #endif static Bool epsonCreateColormap (ColormapPtr pmap) { ScreenPtr pScreen = pmap->pScreen; KdScreenPriv(pScreen); EpsonPriv *priv = pScreenPriv->card->driver; VisualPtr pVisual; int i; int nent; xColorItem *pdefs; switch (priv->fix.visual) { case FB_VISUAL_STATIC_PSEUDOCOLOR: pVisual = pmap->pVisual; nent = pVisual->ColormapEntries; pdefs = ALLOCATE_LOCAL (nent * sizeof (xColorItem)); if (!pdefs) return FALSE; for (i = 0; i < nent; i++) pdefs[i].pixel = i; epsonGetColors (pScreen, 0, 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; } DEALLOCATE_LOCAL (pdefs); return TRUE; default: return fbInitializeColormap (pmap); } } Bool epsonInitScreen (ScreenPtr pScreen) { #ifdef TOUCHSCREEN KdTsPhyScreen = pScreen->myNum; #endif pScreen->CreateColormap = epsonCreateColormap; return TRUE; } static Bool epsonFinishInitScreen (ScreenPtr pScreen) { if (!shadowSetup (pScreen)) return FALSE; #ifdef RANDR if (!epsonRandRInit (pScreen)) return FALSE; #endif return TRUE; } static Bool epsonSetShadow (ScreenPtr pScreen) { KdScreenPriv(pScreen); KdScreenInfo *screen = pScreenPriv->screen; EpsonScrPriv *scrpriv = screen->driver; ShadowUpdateProc update; ShadowWindowProc window; window = epsonWindowLinear; update = shadowUpdatePacked; return KdShadowSet (pScreen, scrpriv->randr, update, window); } static Bool epsonCreateResources (ScreenPtr pScreen) { return epsonSetShadow (pScreen); } void epsonPreserve (KdCardInfo *card) { } Bool epsonEnable (ScreenPtr pScreen) { KdScreenPriv(pScreen); EpsonPriv *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; } k = ioctl (priv->fd, FBIOGET_FSCREENINFO, &priv->fix); if (k < 0) { perror ("FBIOGET_FSCREENINFO"); return FALSE; } if (priv->fix.visual == FB_VISUAL_DIRECTCOLOR) { struct fb_cmap cmap; 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); } cmap.start = 0; cmap.len = i; cmap.red = &priv->red[0]; cmap.green = &priv->green[0]; cmap.blue = &priv->blue[0]; cmap.transp = 0; ioctl (priv->fd, FBIOPUTCMAP, &cmap); } return TRUE; } Bool epsonDPMS (ScreenPtr pScreen, int mode) { KdScreenPriv(pScreen); EpsonPriv *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 epsonDisable (ScreenPtr pScreen) { } void epsonRestore (KdCardInfo *card) { } void epsonScreenFini (KdScreenInfo *screen) { } void epsonCardFini (KdCardInfo *card) { EpsonPriv *priv = card->driver; munmap (priv->fb_base, priv->fix.smem_len); close (priv->fd); xfree (priv); } void epsonGetColors (ScreenPtr pScreen, int fb, int n, xColorItem *pdefs) { KdScreenPriv(pScreen); EpsonPriv *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++; } } void epsonPutColors (ScreenPtr pScreen, int fb, int n, xColorItem *pdefs) { KdScreenPriv(pScreen); EpsonPriv *priv = pScreenPriv->card->driver; struct fb_cmap cmap; 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++; } 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; ioctl (priv->fd, FBIOPUTCMAP, &cmap); } KdCardFuncs epsonFuncs = { epsonCardInit, /* cardinit */ epsonScreenInit, /* scrinit */ epsonInitScreen, /* initScreen */ epsonFinishInitScreen, epsonCreateResources, epsonPreserve, /* preserve */ epsonEnable, /* enable */ epsonDPMS, /* dpms */ epsonDisable, /* disable */ epsonRestore, /* restore */ epsonScreenFini, /* scrfini */ epsonCardFini, /* cardfini */ 0, /* initCursor */ 0, /* enableCursor */ 0, /* disableCursor */ 0, /* finiCursor */ 0, /* recolorCursor */ /* * History: * 28-Jan-04 C.Stylianou NBL: Added the following for h/w accel. * */ epsonDrawInit, /* initAccel */ epsonDrawEnable, /* enableAccel */ epsonDrawSync, /* syncAccel */ epsonDrawDisable, /* disableAccel */ epsonDrawFini, /* finiAccel */ epsonGetColors, /* getColors */ epsonPutColors, /* putColors */ };