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