1706f2543Smrg/*
2706f2543Smrg * Copyright � 1999 Keith Packard
3706f2543Smrg *
4706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its
5706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that
6706f2543Smrg * the above copyright notice appear in all copies and that both that
7706f2543Smrg * copyright notice and this permission notice appear in supporting
8706f2543Smrg * documentation, and that the name of Keith Packard not be used in
9706f2543Smrg * advertising or publicity pertaining to distribution of the software without
10706f2543Smrg * specific, written prior permission.  Keith Packard makes no
11706f2543Smrg * representations about the suitability of this software for any purpose.  It
12706f2543Smrg * is provided "as is" without express or implied warranty.
13706f2543Smrg *
14706f2543Smrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15706f2543Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16706f2543Smrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20706f2543Smrg * PERFORMANCE OF THIS SOFTWARE.
21706f2543Smrg */
22706f2543Smrg
23706f2543Smrg#ifdef HAVE_CONFIG_H
24706f2543Smrg#include <kdrive-config.h>
25706f2543Smrg#endif
26706f2543Smrg#include "fbdev.h"
27706f2543Smrg#include <sys/ioctl.h>
28706f2543Smrg
29706f2543Smrg#include <errno.h>
30706f2543Smrg
31706f2543Smrgextern int KdTsPhyScreen;
32706f2543Smrg
33706f2543Smrgchar *fbdevDevicePath = NULL;
34706f2543Smrg
35706f2543Smrgstatic Bool
36706f2543SmrgfbdevInitialize (KdCardInfo *card, FbdevPriv *priv)
37706f2543Smrg{
38706f2543Smrg    unsigned long   off;
39706f2543Smrg
40706f2543Smrg    if (fbdevDevicePath == NULL)
41706f2543Smrg      fbdevDevicePath = "/dev/fb0";
42706f2543Smrg
43706f2543Smrg    if ((priv->fd = open(fbdevDevicePath, O_RDWR)) < 0)
44706f2543Smrg      {
45706f2543Smrg	ErrorF("Error opening framebuffer %s: %s\n",
46706f2543Smrg	       fbdevDevicePath, strerror(errno));
47706f2543Smrg        return FALSE;
48706f2543Smrg      }
49706f2543Smrg
50706f2543Smrg    /* quiet valgrind */
51706f2543Smrg    memset (&priv->fix, '\0', sizeof (priv->fix));
52706f2543Smrg    if (ioctl(priv->fd, FBIOGET_FSCREENINFO, &priv->fix) < 0) {
53706f2543Smrg	perror("Error with /dev/fb ioctl FIOGET_FSCREENINFO");
54706f2543Smrg	close (priv->fd);
55706f2543Smrg	return FALSE;
56706f2543Smrg    }
57706f2543Smrg    /* quiet valgrind */
58706f2543Smrg    memset (&priv->var, '\0', sizeof (priv->var));
59706f2543Smrg    if (ioctl(priv->fd, FBIOGET_VSCREENINFO, &priv->var) < 0) {
60706f2543Smrg	perror("Error with /dev/fb ioctl FIOGET_VSCREENINFO");
61706f2543Smrg	close (priv->fd);
62706f2543Smrg	return FALSE;
63706f2543Smrg    }
64706f2543Smrg
65706f2543Smrg    priv->fb_base = (char *) mmap ((caddr_t) NULL,
66706f2543Smrg				   priv->fix.smem_len,
67706f2543Smrg				   PROT_READ|PROT_WRITE,
68706f2543Smrg				   MAP_SHARED,
69706f2543Smrg				   priv->fd, 0);
70706f2543Smrg
71706f2543Smrg    if (priv->fb_base == (char *)-1)
72706f2543Smrg    {
73706f2543Smrg        perror("ERROR: mmap framebuffer fails!");
74706f2543Smrg	close (priv->fd);
75706f2543Smrg	return FALSE;
76706f2543Smrg    }
77706f2543Smrg    off = (unsigned long) priv->fix.smem_start % (unsigned long) getpagesize();
78706f2543Smrg    priv->fb = priv->fb_base + off;
79706f2543Smrg    return TRUE;
80706f2543Smrg}
81706f2543Smrg
82706f2543SmrgBool
83706f2543SmrgfbdevCardInit (KdCardInfo *card)
84706f2543Smrg{
85706f2543Smrg    FbdevPriv	*priv;
86706f2543Smrg
87706f2543Smrg    priv = (FbdevPriv *) malloc(sizeof (FbdevPriv));
88706f2543Smrg    if (!priv)
89706f2543Smrg	return FALSE;
90706f2543Smrg
91706f2543Smrg    if (!fbdevInitialize (card, priv))
92706f2543Smrg    {
93706f2543Smrg	free(priv);
94706f2543Smrg	return FALSE;
95706f2543Smrg    }
96706f2543Smrg    card->driver = priv;
97706f2543Smrg
98706f2543Smrg    return TRUE;
99706f2543Smrg}
100706f2543Smrg
101706f2543Smrgstatic Pixel
102706f2543SmrgfbdevMakeContig (Pixel orig, Pixel others)
103706f2543Smrg{
104706f2543Smrg    Pixel   low;
105706f2543Smrg
106706f2543Smrg    low = lowbit (orig) >> 1;
107706f2543Smrg    while (low && (others & low) == 0)
108706f2543Smrg    {
109706f2543Smrg	orig |= low;
110706f2543Smrg	low >>= 1;
111706f2543Smrg    }
112706f2543Smrg    return orig;
113706f2543Smrg}
114706f2543Smrg
115706f2543Smrgstatic Bool
116706f2543SmrgfbdevModeSupported (KdScreenInfo		*screen,
117706f2543Smrg		    const KdMonitorTiming	*t)
118706f2543Smrg{
119706f2543Smrg    return TRUE;
120706f2543Smrg}
121706f2543Smrg
122706f2543Smrgstatic void
123706f2543SmrgfbdevConvertMonitorTiming (const KdMonitorTiming *t, struct fb_var_screeninfo *var)
124706f2543Smrg{
125706f2543Smrg    memset (var, 0, sizeof (struct fb_var_screeninfo));
126706f2543Smrg
127706f2543Smrg    var->xres = t->horizontal;
128706f2543Smrg    var->yres = t->vertical;
129706f2543Smrg    var->xres_virtual = t->horizontal;
130706f2543Smrg    var->yres_virtual = t->vertical;
131706f2543Smrg    var->xoffset = 0;
132706f2543Smrg    var->yoffset = 0;
133706f2543Smrg    var->pixclock = t->clock ? 1000000000 / t->clock : 0;
134706f2543Smrg    var->left_margin = t->hbp;
135706f2543Smrg    var->right_margin = t->hfp;
136706f2543Smrg    var->upper_margin = t->vbp;
137706f2543Smrg    var->lower_margin = t->vfp;
138706f2543Smrg    var->hsync_len = t->hblank - t->hfp - t->hbp;
139706f2543Smrg    var->vsync_len = t->vblank - t->vfp - t->vbp;
140706f2543Smrg
141706f2543Smrg    var->sync = 0;
142706f2543Smrg    var->vmode = 0;
143706f2543Smrg
144706f2543Smrg    if (t->hpol == KdSyncPositive)
145706f2543Smrg      var->sync |= FB_SYNC_HOR_HIGH_ACT;
146706f2543Smrg    if (t->vpol == KdSyncPositive)
147706f2543Smrg      var->sync |= FB_SYNC_VERT_HIGH_ACT;
148706f2543Smrg}
149706f2543Smrg
150706f2543Smrgstatic Bool
151706f2543SmrgfbdevScreenInitialize (KdScreenInfo *screen, FbdevScrPriv *scrpriv)
152706f2543Smrg{
153706f2543Smrg    FbdevPriv	*priv = screen->card->driver;
154706f2543Smrg    Pixel	allbits;
155706f2543Smrg    int		depth;
156706f2543Smrg    Bool	gray;
157706f2543Smrg    struct fb_var_screeninfo var;
158706f2543Smrg    const KdMonitorTiming *t;
159706f2543Smrg    int k;
160706f2543Smrg
161706f2543Smrg    k = ioctl (priv->fd, FBIOGET_VSCREENINFO, &var);
162706f2543Smrg
163706f2543Smrg    if (!screen->width || !screen->height)
164706f2543Smrg    {
165706f2543Smrg	if (k >= 0)
166706f2543Smrg	{
167706f2543Smrg	    screen->width = var.xres;
168706f2543Smrg	    screen->height = var.yres;
169706f2543Smrg	}
170706f2543Smrg	else
171706f2543Smrg	{
172706f2543Smrg	    screen->width = 1024;
173706f2543Smrg	    screen->height = 768;
174706f2543Smrg	}
175706f2543Smrg	screen->rate = 103; /* FIXME: should get proper value from fb driver */
176706f2543Smrg    }
177706f2543Smrg    if (!screen->fb.depth)
178706f2543Smrg    {
179706f2543Smrg	if (k >= 0)
180706f2543Smrg	    screen->fb.depth = var.bits_per_pixel;
181706f2543Smrg	else
182706f2543Smrg	    screen->fb.depth = 16;
183706f2543Smrg    }
184706f2543Smrg
185706f2543Smrg    if ((screen->width != var.xres) || (screen->height != var.yres))
186706f2543Smrg    {
187706f2543Smrg      t = KdFindMode (screen, fbdevModeSupported);
188706f2543Smrg      screen->rate = t->rate;
189706f2543Smrg      screen->width = t->horizontal;
190706f2543Smrg      screen->height = t->vertical;
191706f2543Smrg
192706f2543Smrg      /* Now try setting the mode */
193706f2543Smrg      if (k < 0 || (t->horizontal != var.xres || t->vertical != var.yres))
194706f2543Smrg          fbdevConvertMonitorTiming (t, &var);
195706f2543Smrg    }
196706f2543Smrg
197706f2543Smrg    var.activate = FB_ACTIVATE_NOW;
198706f2543Smrg    var.bits_per_pixel = screen->fb.depth;
199706f2543Smrg    var.nonstd = 0;
200706f2543Smrg    var.grayscale = 0;
201706f2543Smrg
202706f2543Smrg    k = ioctl (priv->fd, FBIOPUT_VSCREENINFO, &var);
203706f2543Smrg
204706f2543Smrg    if (k < 0)
205706f2543Smrg    {
206706f2543Smrg	fprintf (stderr, "error: %s\n", strerror (errno));
207706f2543Smrg	return FALSE;
208706f2543Smrg    }
209706f2543Smrg
210706f2543Smrg    /* Re-get the "fixed" parameters since they might have changed */
211706f2543Smrg    k = ioctl (priv->fd, FBIOGET_FSCREENINFO, &priv->fix);
212706f2543Smrg    if (k < 0)
213706f2543Smrg        perror ("FBIOGET_FSCREENINFO");
214706f2543Smrg
215706f2543Smrg    /* Now get the new screeninfo */
216706f2543Smrg    ioctl (priv->fd, FBIOGET_VSCREENINFO, &priv->var);
217706f2543Smrg    depth = priv->var.bits_per_pixel;
218706f2543Smrg    gray = priv->var.grayscale;
219706f2543Smrg
220706f2543Smrg    switch (priv->fix.visual) {
221706f2543Smrg    case FB_VISUAL_PSEUDOCOLOR:
222706f2543Smrg	if (gray)
223706f2543Smrg	{
224706f2543Smrg	    screen->fb.visuals = (1 << StaticGray);
225706f2543Smrg	    /* could also support GrayScale, but what's the point? */
226706f2543Smrg	}
227706f2543Smrg	else
228706f2543Smrg	{
229706f2543Smrg	    screen->fb.visuals = ((1 << StaticGray) |
230706f2543Smrg			       (1 << GrayScale) |
231706f2543Smrg			       (1 << StaticColor) |
232706f2543Smrg			       (1 << PseudoColor) |
233706f2543Smrg			       (1 << TrueColor) |
234706f2543Smrg			       (1 << DirectColor));
235706f2543Smrg	}
236706f2543Smrg	screen->fb.blueMask  = 0x00;
237706f2543Smrg	screen->fb.greenMask = 0x00;
238706f2543Smrg	screen->fb.redMask   = 0x00;
239706f2543Smrg	break;
240706f2543Smrg    case FB_VISUAL_STATIC_PSEUDOCOLOR:
241706f2543Smrg	if (gray)
242706f2543Smrg	{
243706f2543Smrg	    screen->fb.visuals = (1 << StaticGray);
244706f2543Smrg	}
245706f2543Smrg	else
246706f2543Smrg	{
247706f2543Smrg	    screen->fb.visuals = (1 << StaticColor);
248706f2543Smrg	}
249706f2543Smrg	screen->fb.blueMask  = 0x00;
250706f2543Smrg	screen->fb.greenMask = 0x00;
251706f2543Smrg	screen->fb.redMask   = 0x00;
252706f2543Smrg	break;
253706f2543Smrg    case FB_VISUAL_TRUECOLOR:
254706f2543Smrg    case FB_VISUAL_DIRECTCOLOR:
255706f2543Smrg	screen->fb.visuals = (1 << TrueColor);
256706f2543Smrg#define Mask(o,l)   (((1 << l) - 1) << o)
257706f2543Smrg	screen->fb.redMask = Mask (priv->var.red.offset, priv->var.red.length);
258706f2543Smrg	screen->fb.greenMask = Mask (priv->var.green.offset, priv->var.green.length);
259706f2543Smrg	screen->fb.blueMask = Mask (priv->var.blue.offset, priv->var.blue.length);
260706f2543Smrg
261706f2543Smrg	/*
262706f2543Smrg	 * This is a kludge so that Render will work -- fill in the gaps
263706f2543Smrg	 * in the pixel
264706f2543Smrg	 */
265706f2543Smrg	screen->fb.redMask = fbdevMakeContig (screen->fb.redMask,
266706f2543Smrg						 screen->fb.greenMask|
267706f2543Smrg						 screen->fb.blueMask);
268706f2543Smrg
269706f2543Smrg	screen->fb.greenMask = fbdevMakeContig (screen->fb.greenMask,
270706f2543Smrg						   screen->fb.redMask|
271706f2543Smrg						   screen->fb.blueMask);
272706f2543Smrg
273706f2543Smrg	screen->fb.blueMask = fbdevMakeContig (screen->fb.blueMask,
274706f2543Smrg						  screen->fb.redMask|
275706f2543Smrg						  screen->fb.greenMask);
276706f2543Smrg
277706f2543Smrg	allbits = screen->fb.redMask | screen->fb.greenMask | screen->fb.blueMask;
278706f2543Smrg	depth = 32;
279706f2543Smrg	while (depth && !(allbits & (1 << (depth - 1))))
280706f2543Smrg	    depth--;
281706f2543Smrg	break;
282706f2543Smrg    default:
283706f2543Smrg	return FALSE;
284706f2543Smrg	break;
285706f2543Smrg    }
286706f2543Smrg    screen->fb.depth = depth;
287706f2543Smrg    screen->fb.bitsPerPixel = priv->var.bits_per_pixel;
288706f2543Smrg
289706f2543Smrg    scrpriv->randr = screen->randr;
290706f2543Smrg
291706f2543Smrg    return fbdevMapFramebuffer (screen);
292706f2543Smrg}
293706f2543Smrg
294706f2543SmrgBool
295706f2543SmrgfbdevScreenInit (KdScreenInfo *screen)
296706f2543Smrg{
297706f2543Smrg    FbdevScrPriv *scrpriv;
298706f2543Smrg
299706f2543Smrg    scrpriv = calloc(1, sizeof (FbdevScrPriv));
300706f2543Smrg    if (!scrpriv)
301706f2543Smrg	return FALSE;
302706f2543Smrg    screen->driver = scrpriv;
303706f2543Smrg    if (!fbdevScreenInitialize (screen, scrpriv))
304706f2543Smrg    {
305706f2543Smrg	screen->driver = 0;
306706f2543Smrg	free(scrpriv);
307706f2543Smrg	return FALSE;
308706f2543Smrg    }
309706f2543Smrg    return TRUE;
310706f2543Smrg}
311706f2543Smrg
312706f2543Smrgstatic void *
313706f2543SmrgfbdevWindowLinear (ScreenPtr	pScreen,
314706f2543Smrg		   CARD32	row,
315706f2543Smrg		   CARD32	offset,
316706f2543Smrg		   int		mode,
317706f2543Smrg		   CARD32	*size,
318706f2543Smrg		   void		*closure)
319706f2543Smrg{
320706f2543Smrg    KdScreenPriv(pScreen);
321706f2543Smrg    FbdevPriv	    *priv = pScreenPriv->card->driver;
322706f2543Smrg
323706f2543Smrg    if (!pScreenPriv->enabled)
324706f2543Smrg	return 0;
325706f2543Smrg    *size = priv->fix.line_length;
326706f2543Smrg    return (CARD8 *) priv->fb + row * priv->fix.line_length + offset;
327706f2543Smrg}
328706f2543Smrg
329706f2543SmrgBool
330706f2543SmrgfbdevMapFramebuffer (KdScreenInfo *screen)
331706f2543Smrg{
332706f2543Smrg    FbdevScrPriv	*scrpriv = screen->driver;
333706f2543Smrg    KdPointerMatrix	m;
334706f2543Smrg    FbdevPriv		*priv = screen->card->driver;
335706f2543Smrg
336706f2543Smrg    if (scrpriv->randr != RR_Rotate_0)
337706f2543Smrg	scrpriv->shadow = TRUE;
338706f2543Smrg    else
339706f2543Smrg	scrpriv->shadow = FALSE;
340706f2543Smrg
341706f2543Smrg    KdComputePointerMatrix (&m, scrpriv->randr, screen->width, screen->height);
342706f2543Smrg
343706f2543Smrg    KdSetPointerMatrix (&m);
344706f2543Smrg
345706f2543Smrg    screen->width = priv->var.xres;
346706f2543Smrg    screen->height = priv->var.yres;
347706f2543Smrg
348706f2543Smrg    if (scrpriv->shadow)
349706f2543Smrg    {
350706f2543Smrg	if (!KdShadowFbAlloc (screen,
351706f2543Smrg			      scrpriv->randr & (RR_Rotate_90|RR_Rotate_270)))
352706f2543Smrg	    return FALSE;
353706f2543Smrg    }
354706f2543Smrg    else
355706f2543Smrg    {
356706f2543Smrg        screen->fb.byteStride = priv->fix.line_length;
357706f2543Smrg        screen->fb.pixelStride = (priv->fix.line_length * 8 /
358706f2543Smrg    				 priv->var.bits_per_pixel);
359706f2543Smrg        screen->fb.frameBuffer = (CARD8 *) (priv->fb);
360706f2543Smrg    }
361706f2543Smrg
362706f2543Smrg    return TRUE;
363706f2543Smrg}
364706f2543Smrg
365706f2543Smrgstatic void
366706f2543SmrgfbdevSetScreenSizes (ScreenPtr pScreen)
367706f2543Smrg{
368706f2543Smrg    KdScreenPriv(pScreen);
369706f2543Smrg    KdScreenInfo	*screen = pScreenPriv->screen;
370706f2543Smrg    FbdevScrPriv	*scrpriv = screen->driver;
371706f2543Smrg    FbdevPriv		*priv = screen->card->driver;
372706f2543Smrg
373706f2543Smrg    if (scrpriv->randr & (RR_Rotate_0|RR_Rotate_180))
374706f2543Smrg    {
375706f2543Smrg	pScreen->width = priv->var.xres;
376706f2543Smrg	pScreen->height = priv->var.yres;
377706f2543Smrg	pScreen->mmWidth = screen->width_mm;
378706f2543Smrg	pScreen->mmHeight = screen->height_mm;
379706f2543Smrg    }
380706f2543Smrg    else
381706f2543Smrg    {
382706f2543Smrg	pScreen->width = priv->var.yres;
383706f2543Smrg	pScreen->height = priv->var.xres;
384706f2543Smrg	pScreen->mmWidth = screen->height_mm;
385706f2543Smrg	pScreen->mmHeight = screen->width_mm;
386706f2543Smrg    }
387706f2543Smrg}
388706f2543Smrg
389706f2543Smrgstatic Bool
390706f2543SmrgfbdevUnmapFramebuffer (KdScreenInfo *screen)
391706f2543Smrg{
392706f2543Smrg    KdShadowFbFree (screen);
393706f2543Smrg    return TRUE;
394706f2543Smrg}
395706f2543Smrg
396706f2543Smrgstatic Bool
397706f2543SmrgfbdevSetShadow (ScreenPtr pScreen)
398706f2543Smrg{
399706f2543Smrg    KdScreenPriv(pScreen);
400706f2543Smrg    KdScreenInfo	*screen = pScreenPriv->screen;
401706f2543Smrg    FbdevScrPriv	*scrpriv = screen->driver;
402706f2543Smrg    FbdevPriv		*priv = screen->card->driver;
403706f2543Smrg    ShadowUpdateProc	update;
404706f2543Smrg    ShadowWindowProc	window;
405706f2543Smrg    int			useYX = 0;
406706f2543Smrg
407706f2543Smrg#ifdef __arm__
408706f2543Smrg    /* Use variant copy routines that always read left to right in the
409706f2543Smrg       shadow framebuffer.  Reading vertical strips is exceptionally
410706f2543Smrg       slow on XScale due to cache effects.  */
411706f2543Smrg    useYX = 1;
412706f2543Smrg#endif
413706f2543Smrg
414706f2543Smrg    window = fbdevWindowLinear;
415706f2543Smrg    update = 0;
416706f2543Smrg    if (scrpriv->randr)
417706f2543Smrg	if (priv->var.bits_per_pixel == 16) {
418706f2543Smrg	    switch (scrpriv->randr) {
419706f2543Smrg	    case RR_Rotate_90:
420706f2543Smrg		if (useYX)
421706f2543Smrg		    update = shadowUpdateRotate16_90YX;
422706f2543Smrg		else
423706f2543Smrg		    update =  shadowUpdateRotate16_90;
424706f2543Smrg		break;
425706f2543Smrg	    case RR_Rotate_180:
426706f2543Smrg		update = shadowUpdateRotate16_180;
427706f2543Smrg		break;
428706f2543Smrg	    case RR_Rotate_270:
429706f2543Smrg		if (useYX)
430706f2543Smrg		    update = shadowUpdateRotate16_270YX;
431706f2543Smrg		else
432706f2543Smrg		    update =  shadowUpdateRotate16_270;
433706f2543Smrg		break;
434706f2543Smrg	    default:
435706f2543Smrg		update = shadowUpdateRotate16;
436706f2543Smrg		break;
437706f2543Smrg	    }
438706f2543Smrg	} else
439706f2543Smrg	    update = shadowUpdateRotatePacked;
440706f2543Smrg    else
441706f2543Smrg	update = shadowUpdatePacked;
442706f2543Smrg    return KdShadowSet (pScreen, scrpriv->randr, update, window);
443706f2543Smrg}
444706f2543Smrg
445706f2543Smrg
446706f2543Smrg#ifdef RANDR
447706f2543Smrgstatic Bool
448706f2543SmrgfbdevRandRGetInfo (ScreenPtr pScreen, Rotation *rotations)
449706f2543Smrg{
450706f2543Smrg    KdScreenPriv(pScreen);
451706f2543Smrg    KdScreenInfo	    *screen = pScreenPriv->screen;
452706f2543Smrg    FbdevScrPriv	    *scrpriv = screen->driver;
453706f2543Smrg    RRScreenSizePtr	    pSize;
454706f2543Smrg    Rotation		    randr;
455706f2543Smrg    int			    n;
456706f2543Smrg
457706f2543Smrg    *rotations = RR_Rotate_All|RR_Reflect_All;
458706f2543Smrg
459706f2543Smrg    for (n = 0; n < pScreen->numDepths; n++)
460706f2543Smrg	if (pScreen->allowedDepths[n].numVids)
461706f2543Smrg	    break;
462706f2543Smrg    if (n == pScreen->numDepths)
463706f2543Smrg	return FALSE;
464706f2543Smrg
465706f2543Smrg    pSize = RRRegisterSize (pScreen,
466706f2543Smrg			    screen->width,
467706f2543Smrg			    screen->height,
468706f2543Smrg			    screen->width_mm,
469706f2543Smrg			    screen->height_mm);
470706f2543Smrg
471706f2543Smrg    randr = KdSubRotation (scrpriv->randr, screen->randr);
472706f2543Smrg
473706f2543Smrg    RRSetCurrentConfig (pScreen, randr, 0, pSize);
474706f2543Smrg
475706f2543Smrg    return TRUE;
476706f2543Smrg}
477706f2543Smrg
478706f2543Smrgstatic Bool
479706f2543SmrgfbdevRandRSetConfig (ScreenPtr		pScreen,
480706f2543Smrg		     Rotation		randr,
481706f2543Smrg		     int		rate,
482706f2543Smrg		     RRScreenSizePtr	pSize)
483706f2543Smrg{
484706f2543Smrg    KdScreenPriv(pScreen);
485706f2543Smrg    KdScreenInfo	*screen = pScreenPriv->screen;
486706f2543Smrg    FbdevScrPriv	*scrpriv = screen->driver;
487706f2543Smrg    Bool		wasEnabled = pScreenPriv->enabled;
488706f2543Smrg    FbdevScrPriv	oldscr;
489706f2543Smrg    int			oldwidth;
490706f2543Smrg    int			oldheight;
491706f2543Smrg    int			oldmmwidth;
492706f2543Smrg    int			oldmmheight;
493706f2543Smrg    int			newwidth, newheight;
494706f2543Smrg
495706f2543Smrg    if (screen->randr & (RR_Rotate_0|RR_Rotate_180))
496706f2543Smrg    {
497706f2543Smrg	newwidth = pSize->width;
498706f2543Smrg	newheight = pSize->height;
499706f2543Smrg    }
500706f2543Smrg    else
501706f2543Smrg    {
502706f2543Smrg	newwidth = pSize->height;
503706f2543Smrg	newheight = pSize->width;
504706f2543Smrg    }
505706f2543Smrg
506706f2543Smrg    if (wasEnabled)
507706f2543Smrg	KdDisableScreen (pScreen);
508706f2543Smrg
509706f2543Smrg    oldscr = *scrpriv;
510706f2543Smrg
511706f2543Smrg    oldwidth = screen->width;
512706f2543Smrg    oldheight = screen->height;
513706f2543Smrg    oldmmwidth = pScreen->mmWidth;
514706f2543Smrg    oldmmheight = pScreen->mmHeight;
515706f2543Smrg
516706f2543Smrg    /*
517706f2543Smrg     * Set new configuration
518706f2543Smrg     */
519706f2543Smrg
520706f2543Smrg    scrpriv->randr = KdAddRotation (screen->randr, randr);
521706f2543Smrg
522706f2543Smrg    fbdevUnmapFramebuffer (screen);
523706f2543Smrg
524706f2543Smrg    if (!fbdevMapFramebuffer (screen))
525706f2543Smrg	goto bail4;
526706f2543Smrg
527706f2543Smrg    KdShadowUnset (screen->pScreen);
528706f2543Smrg
529706f2543Smrg    if (!fbdevSetShadow (screen->pScreen))
530706f2543Smrg	goto bail4;
531706f2543Smrg
532706f2543Smrg    fbdevSetScreenSizes (screen->pScreen);
533706f2543Smrg
534706f2543Smrg    /*
535706f2543Smrg     * Set frame buffer mapping
536706f2543Smrg     */
537706f2543Smrg    (*pScreen->ModifyPixmapHeader) (fbGetScreenPixmap (pScreen),
538706f2543Smrg				    pScreen->width,
539706f2543Smrg				    pScreen->height,
540706f2543Smrg				    screen->fb.depth,
541706f2543Smrg				    screen->fb.bitsPerPixel,
542706f2543Smrg				    screen->fb.byteStride,
543706f2543Smrg				    screen->fb.frameBuffer);
544706f2543Smrg
545706f2543Smrg    /* set the subpixel order */
546706f2543Smrg
547706f2543Smrg    KdSetSubpixelOrder (pScreen, scrpriv->randr);
548706f2543Smrg    if (wasEnabled)
549706f2543Smrg	KdEnableScreen (pScreen);
550706f2543Smrg
551706f2543Smrg    return TRUE;
552706f2543Smrg
553706f2543Smrgbail4:
554706f2543Smrg    fbdevUnmapFramebuffer (screen);
555706f2543Smrg    *scrpriv = oldscr;
556706f2543Smrg    (void) fbdevMapFramebuffer (screen);
557706f2543Smrg    pScreen->width = oldwidth;
558706f2543Smrg    pScreen->height = oldheight;
559706f2543Smrg    pScreen->mmWidth = oldmmwidth;
560706f2543Smrg    pScreen->mmHeight = oldmmheight;
561706f2543Smrg
562706f2543Smrg    if (wasEnabled)
563706f2543Smrg	KdEnableScreen (pScreen);
564706f2543Smrg    return FALSE;
565706f2543Smrg}
566706f2543Smrg
567706f2543Smrgstatic Bool
568706f2543SmrgfbdevRandRInit (ScreenPtr pScreen)
569706f2543Smrg{
570706f2543Smrg    rrScrPrivPtr    pScrPriv;
571706f2543Smrg
572706f2543Smrg    if (!RRScreenInit (pScreen))
573706f2543Smrg	return FALSE;
574706f2543Smrg
575706f2543Smrg    pScrPriv = rrGetScrPriv(pScreen);
576706f2543Smrg    pScrPriv->rrGetInfo = fbdevRandRGetInfo;
577706f2543Smrg    pScrPriv->rrSetConfig = fbdevRandRSetConfig;
578706f2543Smrg    return TRUE;
579706f2543Smrg}
580706f2543Smrg#endif
581706f2543Smrg
582706f2543Smrgstatic Bool
583706f2543SmrgfbdevCreateColormap (ColormapPtr pmap)
584706f2543Smrg{
585706f2543Smrg    ScreenPtr		pScreen = pmap->pScreen;
586706f2543Smrg    KdScreenPriv(pScreen);
587706f2543Smrg    FbdevPriv		*priv = pScreenPriv->card->driver;
588706f2543Smrg    VisualPtr		pVisual;
589706f2543Smrg    int			i;
590706f2543Smrg    int			nent;
591706f2543Smrg    xColorItem		*pdefs;
592706f2543Smrg
593706f2543Smrg    switch (priv->fix.visual) {
594706f2543Smrg    case FB_VISUAL_STATIC_PSEUDOCOLOR:
595706f2543Smrg	pVisual = pmap->pVisual;
596706f2543Smrg	nent = pVisual->ColormapEntries;
597706f2543Smrg	pdefs = malloc(nent * sizeof (xColorItem));
598706f2543Smrg	if (!pdefs)
599706f2543Smrg	    return FALSE;
600706f2543Smrg	for (i = 0; i < nent; i++)
601706f2543Smrg	    pdefs[i].pixel = i;
602706f2543Smrg	fbdevGetColors (pScreen, nent, pdefs);
603706f2543Smrg	for (i = 0; i < nent; i++)
604706f2543Smrg	{
605706f2543Smrg	    pmap->red[i].co.local.red = pdefs[i].red;
606706f2543Smrg	    pmap->red[i].co.local.green = pdefs[i].green;
607706f2543Smrg	    pmap->red[i].co.local.blue = pdefs[i].blue;
608706f2543Smrg	}
609706f2543Smrg	free(pdefs);
610706f2543Smrg	return TRUE;
611706f2543Smrg    default:
612706f2543Smrg	return fbInitializeColormap (pmap);
613706f2543Smrg    }
614706f2543Smrg}
615706f2543Smrg
616706f2543SmrgBool
617706f2543SmrgfbdevInitScreen (ScreenPtr pScreen)
618706f2543Smrg{
619706f2543Smrg#ifdef TOUCHSCREEN
620706f2543Smrg    KdTsPhyScreen = pScreen->myNum;
621706f2543Smrg#endif
622706f2543Smrg
623706f2543Smrg    pScreen->CreateColormap = fbdevCreateColormap;
624706f2543Smrg    return TRUE;
625706f2543Smrg}
626706f2543Smrg
627706f2543SmrgBool
628706f2543SmrgfbdevFinishInitScreen (ScreenPtr pScreen)
629706f2543Smrg{
630706f2543Smrg    if (!shadowSetup (pScreen))
631706f2543Smrg	return FALSE;
632706f2543Smrg
633706f2543Smrg#ifdef RANDR
634706f2543Smrg    if (!fbdevRandRInit (pScreen))
635706f2543Smrg	return FALSE;
636706f2543Smrg#endif
637706f2543Smrg
638706f2543Smrg    return TRUE;
639706f2543Smrg}
640706f2543Smrg
641706f2543Smrg
642706f2543SmrgBool
643706f2543SmrgfbdevCreateResources (ScreenPtr pScreen)
644706f2543Smrg{
645706f2543Smrg    return fbdevSetShadow (pScreen);
646706f2543Smrg}
647706f2543Smrg
648706f2543Smrgvoid
649706f2543SmrgfbdevPreserve (KdCardInfo *card)
650706f2543Smrg{
651706f2543Smrg}
652706f2543Smrg
653706f2543Smrgstatic int
654706f2543SmrgfbdevUpdateFbColormap(FbdevPriv *priv, int minidx, int maxidx)
655706f2543Smrg{
656706f2543Smrg    struct fb_cmap cmap;
657706f2543Smrg
658706f2543Smrg    cmap.start = minidx;
659706f2543Smrg    cmap.len = maxidx - minidx + 1;
660706f2543Smrg    cmap.red = &priv->red[minidx];
661706f2543Smrg    cmap.green = &priv->green[minidx];
662706f2543Smrg    cmap.blue = &priv->blue[minidx];
663706f2543Smrg    cmap.transp = 0;
664706f2543Smrg
665706f2543Smrg    return ioctl(priv->fd, FBIOPUTCMAP, &cmap);
666706f2543Smrg}
667706f2543Smrg
668706f2543SmrgBool
669706f2543SmrgfbdevEnable (ScreenPtr pScreen)
670706f2543Smrg{
671706f2543Smrg    KdScreenPriv(pScreen);
672706f2543Smrg    FbdevPriv		*priv = pScreenPriv->card->driver;
673706f2543Smrg    int			k;
674706f2543Smrg
675706f2543Smrg    priv->var.activate = FB_ACTIVATE_NOW|FB_CHANGE_CMAP_VBL;
676706f2543Smrg
677706f2543Smrg    /* display it on the LCD */
678706f2543Smrg    k = ioctl (priv->fd, FBIOPUT_VSCREENINFO, &priv->var);
679706f2543Smrg    if (k < 0)
680706f2543Smrg    {
681706f2543Smrg	perror ("FBIOPUT_VSCREENINFO");
682706f2543Smrg	return FALSE;
683706f2543Smrg    }
684706f2543Smrg
685706f2543Smrg    if (priv->fix.visual == FB_VISUAL_DIRECTCOLOR)
686706f2543Smrg    {
687706f2543Smrg	int		i;
688706f2543Smrg
689706f2543Smrg	for (i = 0;
690706f2543Smrg	     i < (1 << priv->var.red.length) ||
691706f2543Smrg	     i < (1 << priv->var.green.length) ||
692706f2543Smrg	     i < (1 << priv->var.blue.length); i++)
693706f2543Smrg	{
694706f2543Smrg	    priv->red[i] = i * 65535 / ((1 << priv->var.red.length) - 1);
695706f2543Smrg	    priv->green[i] = i * 65535 / ((1 << priv->var.green.length) - 1);
696706f2543Smrg	    priv->blue[i] = i * 65535 / ((1 << priv->var.blue.length) - 1);
697706f2543Smrg	}
698706f2543Smrg
699706f2543Smrg	fbdevUpdateFbColormap(priv, 0, i);
700706f2543Smrg    }
701706f2543Smrg    return TRUE;
702706f2543Smrg}
703706f2543Smrg
704706f2543SmrgBool
705706f2543SmrgfbdevDPMS (ScreenPtr pScreen, int mode)
706706f2543Smrg{
707706f2543Smrg    KdScreenPriv(pScreen);
708706f2543Smrg    FbdevPriv	*priv = pScreenPriv->card->driver;
709706f2543Smrg    static int oldmode = -1;
710706f2543Smrg
711706f2543Smrg    if (mode == oldmode)
712706f2543Smrg	return TRUE;
713706f2543Smrg#ifdef FBIOPUT_POWERMODE
714706f2543Smrg    if (ioctl (priv->fd, FBIOPUT_POWERMODE, &mode) >= 0)
715706f2543Smrg    {
716706f2543Smrg	oldmode = mode;
717706f2543Smrg	return TRUE;
718706f2543Smrg    }
719706f2543Smrg#endif
720706f2543Smrg#ifdef FBIOBLANK
721706f2543Smrg    if (ioctl (priv->fd, FBIOBLANK, mode ? mode + 1 : 0) >= 0)
722706f2543Smrg    {
723706f2543Smrg	oldmode = mode;
724706f2543Smrg	return TRUE;
725706f2543Smrg    }
726706f2543Smrg#endif
727706f2543Smrg    return FALSE;
728706f2543Smrg}
729706f2543Smrg
730706f2543Smrgvoid
731706f2543SmrgfbdevDisable (ScreenPtr pScreen)
732706f2543Smrg{
733706f2543Smrg}
734706f2543Smrg
735706f2543Smrgvoid
736706f2543SmrgfbdevRestore (KdCardInfo *card)
737706f2543Smrg{
738706f2543Smrg}
739706f2543Smrg
740706f2543Smrgvoid
741706f2543SmrgfbdevScreenFini (KdScreenInfo *screen)
742706f2543Smrg{
743706f2543Smrg}
744706f2543Smrg
745706f2543Smrgvoid
746706f2543SmrgfbdevCardFini (KdCardInfo *card)
747706f2543Smrg{
748706f2543Smrg    FbdevPriv	*priv = card->driver;
749706f2543Smrg
750706f2543Smrg    munmap (priv->fb_base, priv->fix.smem_len);
751706f2543Smrg    close (priv->fd);
752706f2543Smrg    free(priv);
753706f2543Smrg}
754706f2543Smrg
755706f2543Smrg/*
756706f2543Smrg * Retrieve actual colormap and return selected n entries in pdefs.
757706f2543Smrg */
758706f2543Smrgvoid
759706f2543SmrgfbdevGetColors (ScreenPtr pScreen, int n, xColorItem *pdefs)
760706f2543Smrg{
761706f2543Smrg    KdScreenPriv(pScreen);
762706f2543Smrg    FbdevPriv	    *priv = pScreenPriv->card->driver;
763706f2543Smrg    struct fb_cmap  cmap;
764706f2543Smrg    int		    p;
765706f2543Smrg    int		    k;
766706f2543Smrg    int		    min, max;
767706f2543Smrg
768706f2543Smrg    min = 256;
769706f2543Smrg    max = 0;
770706f2543Smrg    for (k = 0; k < n; k++)
771706f2543Smrg    {
772706f2543Smrg	if (pdefs[k].pixel < min)
773706f2543Smrg	    min = pdefs[k].pixel;
774706f2543Smrg	if (pdefs[k].pixel > max)
775706f2543Smrg	    max = pdefs[k].pixel;
776706f2543Smrg    }
777706f2543Smrg    cmap.start = min;
778706f2543Smrg    cmap.len = max - min + 1;
779706f2543Smrg    cmap.red = &priv->red[min];
780706f2543Smrg    cmap.green = &priv->green[min];
781706f2543Smrg    cmap.blue = &priv->blue[min];
782706f2543Smrg    cmap.transp = 0;
783706f2543Smrg    k = ioctl (priv->fd, FBIOGETCMAP, &cmap);
784706f2543Smrg    if (k < 0)
785706f2543Smrg    {
786706f2543Smrg	perror ("can't get colormap");
787706f2543Smrg	return;
788706f2543Smrg    }
789706f2543Smrg    while (n--)
790706f2543Smrg    {
791706f2543Smrg	p = pdefs->pixel;
792706f2543Smrg	pdefs->red = priv->red[p];
793706f2543Smrg	pdefs->green = priv->green[p];
794706f2543Smrg	pdefs->blue = priv->blue[p];
795706f2543Smrg	pdefs++;
796706f2543Smrg    }
797706f2543Smrg}
798706f2543Smrg
799706f2543Smrg/*
800706f2543Smrg * Change colormap by updating n entries described in pdefs.
801706f2543Smrg */
802706f2543Smrgvoid
803706f2543SmrgfbdevPutColors (ScreenPtr pScreen, int n, xColorItem *pdefs)
804706f2543Smrg{
805706f2543Smrg    KdScreenPriv(pScreen);
806706f2543Smrg    FbdevPriv	*priv = pScreenPriv->card->driver;
807706f2543Smrg    int		    p;
808706f2543Smrg    int		    min, max;
809706f2543Smrg
810706f2543Smrg    min = 256;
811706f2543Smrg    max = 0;
812706f2543Smrg    while (n--)
813706f2543Smrg    {
814706f2543Smrg	p = pdefs->pixel;
815706f2543Smrg	priv->red[p] = pdefs->red;
816706f2543Smrg	priv->green[p] = pdefs->green;
817706f2543Smrg	priv->blue[p] = pdefs->blue;
818706f2543Smrg	if (p < min)
819706f2543Smrg	    min = p;
820706f2543Smrg	if (p > max)
821706f2543Smrg	    max = p;
822706f2543Smrg	pdefs++;
823706f2543Smrg    }
824706f2543Smrg
825706f2543Smrg    fbdevUpdateFbColormap(priv, min, max);
826706f2543Smrg}
827