Home | History | Annotate | Line # | Download | only in fbdev
      1 /*
      2  * Copyright  1999 Keith Packard
      3  *
      4  * Permission to use, copy, modify, distribute, and sell this software and its
      5  * documentation for any purpose is hereby granted without fee, provided that
      6  * the above copyright notice appear in all copies and that both that
      7  * copyright notice and this permission notice appear in supporting
      8  * documentation, and that the name of Keith Packard not be used in
      9  * advertising or publicity pertaining to distribution of the software without
     10  * specific, written prior permission.  Keith Packard makes no
     11  * representations about the suitability of this software for any purpose.  It
     12  * is provided "as is" without express or implied warranty.
     13  *
     14  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     16  * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
     20  * PERFORMANCE OF THIS SOFTWARE.
     21  */
     22 
     23 #ifdef HAVE_CONFIG_H
     24 #include <kdrive-config.h>
     25 #endif
     26 #include "fbdev.h"
     27 #include <sys/ioctl.h>
     28 
     29 #include <errno.h>
     30 
     31 extern int KdTsPhyScreen;
     32 
     33 char *fbdevDevicePath = NULL;
     34 
     35 static Bool
     36 fbdevInitialize (KdCardInfo *card, FbdevPriv *priv)
     37 {
     38     unsigned long   off;
     39 
     40     if (fbdevDevicePath == NULL)
     41       fbdevDevicePath = "/dev/fb0";
     42 
     43     if ((priv->fd = open(fbdevDevicePath, O_RDWR)) < 0)
     44       {
     45 	ErrorF("Error opening framebuffer %s: %s\n",
     46 	       fbdevDevicePath, strerror(errno));
     47         return FALSE;
     48       }
     49 
     50     /* quiet valgrind */
     51     memset (&priv->fix, '\0', sizeof (priv->fix));
     52     if (ioctl(priv->fd, FBIOGET_FSCREENINFO, &priv->fix) < 0) {
     53 	perror("Error with /dev/fb ioctl FIOGET_FSCREENINFO");
     54 	close (priv->fd);
     55 	return FALSE;
     56     }
     57     /* quiet valgrind */
     58     memset (&priv->var, '\0', sizeof (priv->var));
     59     if (ioctl(priv->fd, FBIOGET_VSCREENINFO, &priv->var) < 0) {
     60 	perror("Error with /dev/fb ioctl FIOGET_VSCREENINFO");
     61 	close (priv->fd);
     62 	return FALSE;
     63     }
     64 
     65     priv->fb_base = (char *) mmap ((caddr_t) NULL,
     66 				   priv->fix.smem_len,
     67 				   PROT_READ|PROT_WRITE,
     68 				   MAP_SHARED,
     69 				   priv->fd, 0);
     70 
     71     if (priv->fb_base == (char *)-1)
     72     {
     73         perror("ERROR: mmap framebuffer fails!");
     74 	close (priv->fd);
     75 	return FALSE;
     76     }
     77     off = (unsigned long) priv->fix.smem_start % (unsigned long) getpagesize();
     78     priv->fb = priv->fb_base + off;
     79     return TRUE;
     80 }
     81 
     82 Bool
     83 fbdevCardInit (KdCardInfo *card)
     84 {
     85     FbdevPriv	*priv;
     86 
     87     priv = (FbdevPriv *) malloc(sizeof (FbdevPriv));
     88     if (!priv)
     89 	return FALSE;
     90 
     91     if (!fbdevInitialize (card, priv))
     92     {
     93 	free(priv);
     94 	return FALSE;
     95     }
     96     card->driver = priv;
     97 
     98     return TRUE;
     99 }
    100 
    101 static Pixel
    102 fbdevMakeContig (Pixel orig, Pixel others)
    103 {
    104     Pixel   low;
    105 
    106     low = lowbit (orig) >> 1;
    107     while (low && (others & low) == 0)
    108     {
    109 	orig |= low;
    110 	low >>= 1;
    111     }
    112     return orig;
    113 }
    114 
    115 static Bool
    116 fbdevModeSupported (KdScreenInfo		*screen,
    117 		    const KdMonitorTiming	*t)
    118 {
    119     return TRUE;
    120 }
    121 
    122 static void
    123 fbdevConvertMonitorTiming (const KdMonitorTiming *t, struct fb_var_screeninfo *var)
    124 {
    125     memset (var, 0, sizeof (struct fb_var_screeninfo));
    126 
    127     var->xres = t->horizontal;
    128     var->yres = t->vertical;
    129     var->xres_virtual = t->horizontal;
    130     var->yres_virtual = t->vertical;
    131     var->xoffset = 0;
    132     var->yoffset = 0;
    133     var->pixclock = t->clock ? 1000000000 / t->clock : 0;
    134     var->left_margin = t->hbp;
    135     var->right_margin = t->hfp;
    136     var->upper_margin = t->vbp;
    137     var->lower_margin = t->vfp;
    138     var->hsync_len = t->hblank - t->hfp - t->hbp;
    139     var->vsync_len = t->vblank - t->vfp - t->vbp;
    140 
    141     var->sync = 0;
    142     var->vmode = 0;
    143 
    144     if (t->hpol == KdSyncPositive)
    145       var->sync |= FB_SYNC_HOR_HIGH_ACT;
    146     if (t->vpol == KdSyncPositive)
    147       var->sync |= FB_SYNC_VERT_HIGH_ACT;
    148 }
    149 
    150 static Bool
    151 fbdevScreenInitialize (KdScreenInfo *screen, FbdevScrPriv *scrpriv)
    152 {
    153     FbdevPriv	*priv = screen->card->driver;
    154     Pixel	allbits;
    155     int		depth;
    156     Bool	gray;
    157     struct fb_var_screeninfo var;
    158     const KdMonitorTiming *t;
    159     int k;
    160 
    161     k = ioctl (priv->fd, FBIOGET_VSCREENINFO, &var);
    162 
    163     if (!screen->width || !screen->height)
    164     {
    165 	if (k >= 0)
    166 	{
    167 	    screen->width = var.xres;
    168 	    screen->height = var.yres;
    169 	}
    170 	else
    171 	{
    172 	    screen->width = 1024;
    173 	    screen->height = 768;
    174 	}
    175 	screen->rate = 103; /* FIXME: should get proper value from fb driver */
    176     }
    177     if (!screen->fb.depth)
    178     {
    179 	if (k >= 0)
    180 	    screen->fb.depth = var.bits_per_pixel;
    181 	else
    182 	    screen->fb.depth = 16;
    183     }
    184 
    185     if ((screen->width != var.xres) || (screen->height != var.yres))
    186     {
    187       t = KdFindMode (screen, fbdevModeSupported);
    188       screen->rate = t->rate;
    189       screen->width = t->horizontal;
    190       screen->height = t->vertical;
    191 
    192       /* Now try setting the mode */
    193       if (k < 0 || (t->horizontal != var.xres || t->vertical != var.yres))
    194           fbdevConvertMonitorTiming (t, &var);
    195     }
    196 
    197     var.activate = FB_ACTIVATE_NOW;
    198     var.bits_per_pixel = screen->fb.depth;
    199     var.nonstd = 0;
    200     var.grayscale = 0;
    201 
    202     k = ioctl (priv->fd, FBIOPUT_VSCREENINFO, &var);
    203 
    204     if (k < 0)
    205     {
    206 	fprintf (stderr, "error: %s\n", strerror (errno));
    207 	return FALSE;
    208     }
    209 
    210     /* Re-get the "fixed" parameters since they might have changed */
    211     k = ioctl (priv->fd, FBIOGET_FSCREENINFO, &priv->fix);
    212     if (k < 0)
    213         perror ("FBIOGET_FSCREENINFO");
    214 
    215     /* Now get the new screeninfo */
    216     ioctl (priv->fd, FBIOGET_VSCREENINFO, &priv->var);
    217     depth = priv->var.bits_per_pixel;
    218     gray = priv->var.grayscale;
    219 
    220     switch (priv->fix.visual) {
    221     case FB_VISUAL_PSEUDOCOLOR:
    222 	if (gray)
    223 	{
    224 	    screen->fb.visuals = (1 << StaticGray);
    225 	    /* could also support GrayScale, but what's the point? */
    226 	}
    227 	else
    228 	{
    229 	    screen->fb.visuals = ((1 << StaticGray) |
    230 			       (1 << GrayScale) |
    231 			       (1 << StaticColor) |
    232 			       (1 << PseudoColor) |
    233 			       (1 << TrueColor) |
    234 			       (1 << DirectColor));
    235 	}
    236 	screen->fb.blueMask  = 0x00;
    237 	screen->fb.greenMask = 0x00;
    238 	screen->fb.redMask   = 0x00;
    239 	break;
    240     case FB_VISUAL_STATIC_PSEUDOCOLOR:
    241 	if (gray)
    242 	{
    243 	    screen->fb.visuals = (1 << StaticGray);
    244 	}
    245 	else
    246 	{
    247 	    screen->fb.visuals = (1 << StaticColor);
    248 	}
    249 	screen->fb.blueMask  = 0x00;
    250 	screen->fb.greenMask = 0x00;
    251 	screen->fb.redMask   = 0x00;
    252 	break;
    253     case FB_VISUAL_TRUECOLOR:
    254     case FB_VISUAL_DIRECTCOLOR:
    255 	screen->fb.visuals = (1 << TrueColor);
    256 #define Mask(o,l)   (((1 << l) - 1) << o)
    257 	screen->fb.redMask = Mask (priv->var.red.offset, priv->var.red.length);
    258 	screen->fb.greenMask = Mask (priv->var.green.offset, priv->var.green.length);
    259 	screen->fb.blueMask = Mask (priv->var.blue.offset, priv->var.blue.length);
    260 
    261 	/*
    262 	 * This is a kludge so that Render will work -- fill in the gaps
    263 	 * in the pixel
    264 	 */
    265 	screen->fb.redMask = fbdevMakeContig (screen->fb.redMask,
    266 						 screen->fb.greenMask|
    267 						 screen->fb.blueMask);
    268 
    269 	screen->fb.greenMask = fbdevMakeContig (screen->fb.greenMask,
    270 						   screen->fb.redMask|
    271 						   screen->fb.blueMask);
    272 
    273 	screen->fb.blueMask = fbdevMakeContig (screen->fb.blueMask,
    274 						  screen->fb.redMask|
    275 						  screen->fb.greenMask);
    276 
    277 	allbits = screen->fb.redMask | screen->fb.greenMask | screen->fb.blueMask;
    278 	depth = 32;
    279 	while (depth && !(allbits & (1 << (depth - 1))))
    280 	    depth--;
    281 	break;
    282     default:
    283 	return FALSE;
    284 	break;
    285     }
    286     screen->fb.depth = depth;
    287     screen->fb.bitsPerPixel = priv->var.bits_per_pixel;
    288 
    289     scrpriv->randr = screen->randr;
    290 
    291     return fbdevMapFramebuffer (screen);
    292 }
    293 
    294 Bool
    295 fbdevScreenInit (KdScreenInfo *screen)
    296 {
    297     FbdevScrPriv *scrpriv;
    298 
    299     scrpriv = calloc(1, sizeof (FbdevScrPriv));
    300     if (!scrpriv)
    301 	return FALSE;
    302     screen->driver = scrpriv;
    303     if (!fbdevScreenInitialize (screen, scrpriv))
    304     {
    305 	screen->driver = 0;
    306 	free(scrpriv);
    307 	return FALSE;
    308     }
    309     return TRUE;
    310 }
    311 
    312 static void *
    313 fbdevWindowLinear (ScreenPtr	pScreen,
    314 		   CARD32	row,
    315 		   CARD32	offset,
    316 		   int		mode,
    317 		   CARD32	*size,
    318 		   void		*closure)
    319 {
    320     KdScreenPriv(pScreen);
    321     FbdevPriv	    *priv = pScreenPriv->card->driver;
    322 
    323     if (!pScreenPriv->enabled)
    324 	return 0;
    325     *size = priv->fix.line_length;
    326     return (CARD8 *) priv->fb + row * priv->fix.line_length + offset;
    327 }
    328 
    329 Bool
    330 fbdevMapFramebuffer (KdScreenInfo *screen)
    331 {
    332     FbdevScrPriv	*scrpriv = screen->driver;
    333     KdPointerMatrix	m;
    334     FbdevPriv		*priv = screen->card->driver;
    335 
    336     if (scrpriv->randr != RR_Rotate_0)
    337 	scrpriv->shadow = TRUE;
    338     else
    339 	scrpriv->shadow = FALSE;
    340 
    341     KdComputePointerMatrix (&m, scrpriv->randr, screen->width, screen->height);
    342 
    343     KdSetPointerMatrix (&m);
    344 
    345     screen->width = priv->var.xres;
    346     screen->height = priv->var.yres;
    347 
    348     if (scrpriv->shadow)
    349     {
    350 	if (!KdShadowFbAlloc (screen,
    351 			      scrpriv->randr & (RR_Rotate_90|RR_Rotate_270)))
    352 	    return FALSE;
    353     }
    354     else
    355     {
    356         screen->fb.byteStride = priv->fix.line_length;
    357         screen->fb.pixelStride = (priv->fix.line_length * 8 /
    358     				 priv->var.bits_per_pixel);
    359         screen->fb.frameBuffer = (CARD8 *) (priv->fb);
    360     }
    361 
    362     return TRUE;
    363 }
    364 
    365 static void
    366 fbdevSetScreenSizes (ScreenPtr pScreen)
    367 {
    368     KdScreenPriv(pScreen);
    369     KdScreenInfo	*screen = pScreenPriv->screen;
    370     FbdevScrPriv	*scrpriv = screen->driver;
    371     FbdevPriv		*priv = screen->card->driver;
    372 
    373     if (scrpriv->randr & (RR_Rotate_0|RR_Rotate_180))
    374     {
    375 	pScreen->width = priv->var.xres;
    376 	pScreen->height = priv->var.yres;
    377 	pScreen->mmWidth = screen->width_mm;
    378 	pScreen->mmHeight = screen->height_mm;
    379     }
    380     else
    381     {
    382 	pScreen->width = priv->var.yres;
    383 	pScreen->height = priv->var.xres;
    384 	pScreen->mmWidth = screen->height_mm;
    385 	pScreen->mmHeight = screen->width_mm;
    386     }
    387 }
    388 
    389 static Bool
    390 fbdevUnmapFramebuffer (KdScreenInfo *screen)
    391 {
    392     KdShadowFbFree (screen);
    393     return TRUE;
    394 }
    395 
    396 static Bool
    397 fbdevSetShadow (ScreenPtr pScreen)
    398 {
    399     KdScreenPriv(pScreen);
    400     KdScreenInfo	*screen = pScreenPriv->screen;
    401     FbdevScrPriv	*scrpriv = screen->driver;
    402     FbdevPriv		*priv = screen->card->driver;
    403     ShadowUpdateProc	update;
    404     ShadowWindowProc	window;
    405     int			useYX = 0;
    406 
    407 #ifdef __arm__
    408     /* Use variant copy routines that always read left to right in the
    409        shadow framebuffer.  Reading vertical strips is exceptionally
    410        slow on XScale due to cache effects.  */
    411     useYX = 1;
    412 #endif
    413 
    414     window = fbdevWindowLinear;
    415     update = 0;
    416     if (scrpriv->randr)
    417 	if (priv->var.bits_per_pixel == 16) {
    418 	    switch (scrpriv->randr) {
    419 	    case RR_Rotate_90:
    420 		if (useYX)
    421 		    update = shadowUpdateRotate16_90YX;
    422 		else
    423 		    update =  shadowUpdateRotate16_90;
    424 		break;
    425 	    case RR_Rotate_180:
    426 		update = shadowUpdateRotate16_180;
    427 		break;
    428 	    case RR_Rotate_270:
    429 		if (useYX)
    430 		    update = shadowUpdateRotate16_270YX;
    431 		else
    432 		    update =  shadowUpdateRotate16_270;
    433 		break;
    434 	    default:
    435 		update = shadowUpdateRotate16;
    436 		break;
    437 	    }
    438 	} else
    439 	    update = shadowUpdateRotatePacked;
    440     else
    441 	update = shadowUpdatePacked;
    442     return KdShadowSet (pScreen, scrpriv->randr, update, window);
    443 }
    444 
    445 
    446 #ifdef RANDR
    447 static Bool
    448 fbdevRandRGetInfo (ScreenPtr pScreen, Rotation *rotations)
    449 {
    450     KdScreenPriv(pScreen);
    451     KdScreenInfo	    *screen = pScreenPriv->screen;
    452     FbdevScrPriv	    *scrpriv = screen->driver;
    453     RRScreenSizePtr	    pSize;
    454     Rotation		    randr;
    455     int			    n;
    456 
    457     *rotations = RR_Rotate_All|RR_Reflect_All;
    458 
    459     for (n = 0; n < pScreen->numDepths; n++)
    460 	if (pScreen->allowedDepths[n].numVids)
    461 	    break;
    462     if (n == pScreen->numDepths)
    463 	return FALSE;
    464 
    465     pSize = RRRegisterSize (pScreen,
    466 			    screen->width,
    467 			    screen->height,
    468 			    screen->width_mm,
    469 			    screen->height_mm);
    470 
    471     randr = KdSubRotation (scrpriv->randr, screen->randr);
    472 
    473     RRSetCurrentConfig (pScreen, randr, 0, pSize);
    474 
    475     return TRUE;
    476 }
    477 
    478 static Bool
    479 fbdevRandRSetConfig (ScreenPtr		pScreen,
    480 		     Rotation		randr,
    481 		     int		rate,
    482 		     RRScreenSizePtr	pSize)
    483 {
    484     KdScreenPriv(pScreen);
    485     KdScreenInfo	*screen = pScreenPriv->screen;
    486     FbdevScrPriv	*scrpriv = screen->driver;
    487     Bool		wasEnabled = pScreenPriv->enabled;
    488     FbdevScrPriv	oldscr;
    489     int			oldwidth;
    490     int			oldheight;
    491     int			oldmmwidth;
    492     int			oldmmheight;
    493     int			newwidth, newheight;
    494 
    495     if (screen->randr & (RR_Rotate_0|RR_Rotate_180))
    496     {
    497 	newwidth = pSize->width;
    498 	newheight = pSize->height;
    499     }
    500     else
    501     {
    502 	newwidth = pSize->height;
    503 	newheight = pSize->width;
    504     }
    505 
    506     if (wasEnabled)
    507 	KdDisableScreen (pScreen);
    508 
    509     oldscr = *scrpriv;
    510 
    511     oldwidth = screen->width;
    512     oldheight = screen->height;
    513     oldmmwidth = pScreen->mmWidth;
    514     oldmmheight = pScreen->mmHeight;
    515 
    516     /*
    517      * Set new configuration
    518      */
    519 
    520     scrpriv->randr = KdAddRotation (screen->randr, randr);
    521 
    522     fbdevUnmapFramebuffer (screen);
    523 
    524     if (!fbdevMapFramebuffer (screen))
    525 	goto bail4;
    526 
    527     KdShadowUnset (screen->pScreen);
    528 
    529     if (!fbdevSetShadow (screen->pScreen))
    530 	goto bail4;
    531 
    532     fbdevSetScreenSizes (screen->pScreen);
    533 
    534     /*
    535      * Set frame buffer mapping
    536      */
    537     (*pScreen->ModifyPixmapHeader) (fbGetScreenPixmap (pScreen),
    538 				    pScreen->width,
    539 				    pScreen->height,
    540 				    screen->fb.depth,
    541 				    screen->fb.bitsPerPixel,
    542 				    screen->fb.byteStride,
    543 				    screen->fb.frameBuffer);
    544 
    545     /* set the subpixel order */
    546 
    547     KdSetSubpixelOrder (pScreen, scrpriv->randr);
    548     if (wasEnabled)
    549 	KdEnableScreen (pScreen);
    550 
    551     return TRUE;
    552 
    553 bail4:
    554     fbdevUnmapFramebuffer (screen);
    555     *scrpriv = oldscr;
    556     (void) fbdevMapFramebuffer (screen);
    557     pScreen->width = oldwidth;
    558     pScreen->height = oldheight;
    559     pScreen->mmWidth = oldmmwidth;
    560     pScreen->mmHeight = oldmmheight;
    561 
    562     if (wasEnabled)
    563 	KdEnableScreen (pScreen);
    564     return FALSE;
    565 }
    566 
    567 static Bool
    568 fbdevRandRInit (ScreenPtr pScreen)
    569 {
    570     rrScrPrivPtr    pScrPriv;
    571 
    572     if (!RRScreenInit (pScreen))
    573 	return FALSE;
    574 
    575     pScrPriv = rrGetScrPriv(pScreen);
    576     pScrPriv->rrGetInfo = fbdevRandRGetInfo;
    577     pScrPriv->rrSetConfig = fbdevRandRSetConfig;
    578     return TRUE;
    579 }
    580 #endif
    581 
    582 static Bool
    583 fbdevCreateColormap (ColormapPtr pmap)
    584 {
    585     ScreenPtr		pScreen = pmap->pScreen;
    586     KdScreenPriv(pScreen);
    587     FbdevPriv		*priv = pScreenPriv->card->driver;
    588     VisualPtr		pVisual;
    589     int			i;
    590     int			nent;
    591     xColorItem		*pdefs;
    592 
    593     switch (priv->fix.visual) {
    594     case FB_VISUAL_STATIC_PSEUDOCOLOR:
    595 	pVisual = pmap->pVisual;
    596 	nent = pVisual->ColormapEntries;
    597 	pdefs = malloc(nent * sizeof (xColorItem));
    598 	if (!pdefs)
    599 	    return FALSE;
    600 	for (i = 0; i < nent; i++)
    601 	    pdefs[i].pixel = i;
    602 	fbdevGetColors (pScreen, nent, pdefs);
    603 	for (i = 0; i < nent; i++)
    604 	{
    605 	    pmap->red[i].co.local.red = pdefs[i].red;
    606 	    pmap->red[i].co.local.green = pdefs[i].green;
    607 	    pmap->red[i].co.local.blue = pdefs[i].blue;
    608 	}
    609 	free(pdefs);
    610 	return TRUE;
    611     default:
    612 	return fbInitializeColormap (pmap);
    613     }
    614 }
    615 
    616 Bool
    617 fbdevInitScreen (ScreenPtr pScreen)
    618 {
    619 #ifdef TOUCHSCREEN
    620     KdTsPhyScreen = pScreen->myNum;
    621 #endif
    622 
    623     pScreen->CreateColormap = fbdevCreateColormap;
    624     return TRUE;
    625 }
    626 
    627 Bool
    628 fbdevFinishInitScreen (ScreenPtr pScreen)
    629 {
    630     if (!shadowSetup (pScreen))
    631 	return FALSE;
    632 
    633 #ifdef RANDR
    634     if (!fbdevRandRInit (pScreen))
    635 	return FALSE;
    636 #endif
    637 
    638     return TRUE;
    639 }
    640 
    641 
    642 Bool
    643 fbdevCreateResources (ScreenPtr pScreen)
    644 {
    645     return fbdevSetShadow (pScreen);
    646 }
    647 
    648 void
    649 fbdevPreserve (KdCardInfo *card)
    650 {
    651 }
    652 
    653 static int
    654 fbdevUpdateFbColormap(FbdevPriv *priv, int minidx, int maxidx)
    655 {
    656     struct fb_cmap cmap;
    657 
    658     cmap.start = minidx;
    659     cmap.len = maxidx - minidx + 1;
    660     cmap.red = &priv->red[minidx];
    661     cmap.green = &priv->green[minidx];
    662     cmap.blue = &priv->blue[minidx];
    663     cmap.transp = 0;
    664 
    665     return ioctl(priv->fd, FBIOPUTCMAP, &cmap);
    666 }
    667 
    668 Bool
    669 fbdevEnable (ScreenPtr pScreen)
    670 {
    671     KdScreenPriv(pScreen);
    672     FbdevPriv		*priv = pScreenPriv->card->driver;
    673     int			k;
    674 
    675     priv->var.activate = FB_ACTIVATE_NOW|FB_CHANGE_CMAP_VBL;
    676 
    677     /* display it on the LCD */
    678     k = ioctl (priv->fd, FBIOPUT_VSCREENINFO, &priv->var);
    679     if (k < 0)
    680     {
    681 	perror ("FBIOPUT_VSCREENINFO");
    682 	return FALSE;
    683     }
    684 
    685     if (priv->fix.visual == FB_VISUAL_DIRECTCOLOR)
    686     {
    687 	int		i;
    688 
    689 	for (i = 0;
    690 	     i < (1 << priv->var.red.length) ||
    691 	     i < (1 << priv->var.green.length) ||
    692 	     i < (1 << priv->var.blue.length); i++)
    693 	{
    694 	    priv->red[i] = i * 65535 / ((1 << priv->var.red.length) - 1);
    695 	    priv->green[i] = i * 65535 / ((1 << priv->var.green.length) - 1);
    696 	    priv->blue[i] = i * 65535 / ((1 << priv->var.blue.length) - 1);
    697 	}
    698 
    699 	fbdevUpdateFbColormap(priv, 0, i);
    700     }
    701     return TRUE;
    702 }
    703 
    704 Bool
    705 fbdevDPMS (ScreenPtr pScreen, int mode)
    706 {
    707     KdScreenPriv(pScreen);
    708     FbdevPriv	*priv = pScreenPriv->card->driver;
    709     static int oldmode = -1;
    710 
    711     if (mode == oldmode)
    712 	return TRUE;
    713 #ifdef FBIOPUT_POWERMODE
    714     if (ioctl (priv->fd, FBIOPUT_POWERMODE, &mode) >= 0)
    715     {
    716 	oldmode = mode;
    717 	return TRUE;
    718     }
    719 #endif
    720 #ifdef FBIOBLANK
    721     if (ioctl (priv->fd, FBIOBLANK, mode ? mode + 1 : 0) >= 0)
    722     {
    723 	oldmode = mode;
    724 	return TRUE;
    725     }
    726 #endif
    727     return FALSE;
    728 }
    729 
    730 void
    731 fbdevDisable (ScreenPtr pScreen)
    732 {
    733 }
    734 
    735 void
    736 fbdevRestore (KdCardInfo *card)
    737 {
    738 }
    739 
    740 void
    741 fbdevScreenFini (KdScreenInfo *screen)
    742 {
    743 }
    744 
    745 void
    746 fbdevCardFini (KdCardInfo *card)
    747 {
    748     FbdevPriv	*priv = card->driver;
    749 
    750     munmap (priv->fb_base, priv->fix.smem_len);
    751     close (priv->fd);
    752     free(priv);
    753 }
    754 
    755 /*
    756  * Retrieve actual colormap and return selected n entries in pdefs.
    757  */
    758 void
    759 fbdevGetColors (ScreenPtr pScreen, int n, xColorItem *pdefs)
    760 {
    761     KdScreenPriv(pScreen);
    762     FbdevPriv	    *priv = pScreenPriv->card->driver;
    763     struct fb_cmap  cmap;
    764     int		    p;
    765     int		    k;
    766     int		    min, max;
    767 
    768     min = 256;
    769     max = 0;
    770     for (k = 0; k < n; k++)
    771     {
    772 	if (pdefs[k].pixel < min)
    773 	    min = pdefs[k].pixel;
    774 	if (pdefs[k].pixel > max)
    775 	    max = pdefs[k].pixel;
    776     }
    777     cmap.start = min;
    778     cmap.len = max - min + 1;
    779     cmap.red = &priv->red[min];
    780     cmap.green = &priv->green[min];
    781     cmap.blue = &priv->blue[min];
    782     cmap.transp = 0;
    783     k = ioctl (priv->fd, FBIOGETCMAP, &cmap);
    784     if (k < 0)
    785     {
    786 	perror ("can't get colormap");
    787 	return;
    788     }
    789     while (n--)
    790     {
    791 	p = pdefs->pixel;
    792 	pdefs->red = priv->red[p];
    793 	pdefs->green = priv->green[p];
    794 	pdefs->blue = priv->blue[p];
    795 	pdefs++;
    796     }
    797 }
    798 
    799 /*
    800  * Change colormap by updating n entries described in pdefs.
    801  */
    802 void
    803 fbdevPutColors (ScreenPtr pScreen, int n, xColorItem *pdefs)
    804 {
    805     KdScreenPriv(pScreen);
    806     FbdevPriv	*priv = pScreenPriv->card->driver;
    807     int		    p;
    808     int		    min, max;
    809 
    810     min = 256;
    811     max = 0;
    812     while (n--)
    813     {
    814 	p = pdefs->pixel;
    815 	priv->red[p] = pdefs->red;
    816 	priv->green[p] = pdefs->green;
    817 	priv->blue[p] = pdefs->blue;
    818 	if (p < min)
    819 	    min = p;
    820 	if (p > max)
    821 	    max = p;
    822 	pdefs++;
    823     }
    824 
    825     fbdevUpdateFbColormap(priv, min, max);
    826 }
    827