mirror of
https://github.com/X11Libre/xserver.git
synced 2026-11-15 05:23:40 +00:00
kdrive/fbdev: Split framebuffer modesetting into a separate function
Properly get the screen refresh rate from the fb driver. Allow unknown user-specified modes Signed-off-by: stefan11111 <stefan11111github@gmail.com>
This commit is contained in:
parent
4216d22ebc
commit
d784dfb842
1 changed files with 125 additions and 41 deletions
|
|
@ -147,6 +147,31 @@ fbdevModeSupported(KdScreenInfo * screen, const KdMonitorTiming * t)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
fbdevGetRefreshRate(const struct fb_var_screeninfo *var)
|
||||
{
|
||||
#define PICOS2HZ(a) (1.0e12/(a))
|
||||
long scanline = var->left_margin + var->xres + var->right_margin + var->hsync_len;
|
||||
long v_total = var->upper_margin + var->yres + var->lower_margin + var->vsync_len;
|
||||
long vblank = v_total * scanline * var->pixclock;
|
||||
|
||||
long rate = vblank ? PICOS2HZ(vblank) : -1;
|
||||
|
||||
/* Make sure the rate is reasonable */
|
||||
if (rate > 0 && rate <= 1000) {
|
||||
return rate;
|
||||
}
|
||||
|
||||
/**
|
||||
* We could probe the refresh rate by doing FBIO_WAITFORVSYNC,
|
||||
* measuring the time between them, and matching that to a list of common rates.
|
||||
* However, if the rate reported by the driver is wrong, the driver probably doesn't care about
|
||||
* refresh rates.
|
||||
*/
|
||||
return 103;
|
||||
#undef PICOS2HZ
|
||||
}
|
||||
|
||||
static void
|
||||
fbdevConvertMonitorTiming(const KdMonitorTiming * t,
|
||||
struct fb_var_screeninfo *var)
|
||||
|
|
@ -176,15 +201,91 @@ fbdevConvertMonitorTiming(const KdMonitorTiming * t,
|
|||
var->sync |= FB_SYNC_VERT_HIGH_ACT;
|
||||
}
|
||||
|
||||
static Bool
|
||||
fbdevSetMode(KdScreenInfo *screen, const KdMonitorTiming *t)
|
||||
{
|
||||
FbdevPriv *priv = screen->card->driver;
|
||||
struct fb_var_screeninfo var = {0};
|
||||
int depth;
|
||||
int k;
|
||||
|
||||
k = ioctl(priv->fd, FBIOGET_VSCREENINFO, &var);
|
||||
|
||||
screen->rate = t->rate;
|
||||
screen->width = t->horizontal;
|
||||
screen->height = t->vertical;
|
||||
|
||||
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) {
|
||||
LogMessage(X_ERROR, "Xfbdev(%d): FBIOPUT_VSCREENINFO: %s\n",
|
||||
screen->card->mynum, strerror(errno));
|
||||
}
|
||||
|
||||
/* Re-get the "fixed" parameters since they might have changed */
|
||||
k = ioctl(priv->fd, FBIOGET_FSCREENINFO, &priv->fix);
|
||||
if (k < 0) {
|
||||
LogMessage(X_ERROR, "Xfbdev(%d): FBIOGET_FSCREENINFO: %s\n",
|
||||
screen->card->mynum, strerror(errno));
|
||||
}
|
||||
|
||||
/* Now get the new screeninfo */
|
||||
k = ioctl(priv->fd, FBIOGET_VSCREENINFO, &priv->var);
|
||||
if (k >= 0) {
|
||||
/* Just because the ioctl didn't fail, it doesn't mean we could set the mode */
|
||||
LogMessage(X_INFO, "Xfbdev(%d): Current screen mode: width = %d, height = %d\n",
|
||||
screen->card->mynum, priv->var.xres, priv->var.yres);
|
||||
}
|
||||
|
||||
depth = priv->var.bits_per_pixel;
|
||||
|
||||
/* Calculate fix.line_length if it's zero */
|
||||
if (!priv->fix.line_length)
|
||||
priv->fix.line_length = (priv->var.xres_virtual * depth + 7) / 8;
|
||||
|
||||
return (k >= 0) && (t->horizontal == priv->var.xres) && (t->vertical == var.yres);
|
||||
}
|
||||
|
||||
static void
|
||||
fbdevConvertVarToTiming(const struct fb_var_screeninfo *var,
|
||||
KdMonitorTiming * t)
|
||||
{
|
||||
|
||||
t->horizontal = var->xres;
|
||||
t->vertical = var->yres;
|
||||
t->clock = var->pixclock ? 1000000000 / var->pixclock : 0;
|
||||
t->hbp = var->left_margin;
|
||||
t->hfp = var->right_margin;
|
||||
t->vbp = var->upper_margin;
|
||||
t->vfp = var->lower_margin;
|
||||
t->hblank = var->hsync_len + t->hfp + t->hbp;
|
||||
t->vblank = var->vsync_len + t->vfp + t->vbp;
|
||||
|
||||
t->rate = fbdevGetRefreshRate(var);
|
||||
|
||||
t->hpol = (var->sync & FB_SYNC_HOR_HIGH_ACT) ? KdSyncPositive : KdSyncNegative;
|
||||
t->vpol = (var->sync & FB_SYNC_VERT_HIGH_ACT) ? KdSyncPositive : KdSyncNegative;
|
||||
}
|
||||
|
||||
static Bool
|
||||
fbdevScreenInitialize(KdScreenInfo * screen, FbdevScrPriv * scrpriv)
|
||||
{
|
||||
FbdevPriv *priv = screen->card->driver;
|
||||
Pixel allbits;
|
||||
int depth;
|
||||
int rate;
|
||||
Bool gray;
|
||||
struct fb_var_screeninfo var;
|
||||
const KdMonitorTiming *t;
|
||||
KdMonitorTiming curr_mode = {0};
|
||||
int k;
|
||||
|
||||
k = ioctl(priv->fd, FBIOGET_VSCREENINFO, &var);
|
||||
|
|
@ -193,12 +294,15 @@ fbdevScreenInitialize(KdScreenInfo * screen, FbdevScrPriv * scrpriv)
|
|||
if (k >= 0) {
|
||||
screen->width = var.xres;
|
||||
screen->height = var.yres;
|
||||
}
|
||||
else {
|
||||
screen->rate = fbdevGetRefreshRate(&var);
|
||||
} else {
|
||||
screen->width = 1024;
|
||||
screen->height = 768;
|
||||
screen->rate = 103;
|
||||
}
|
||||
screen->rate = 103; /* FIXME: should get proper value from fb driver */
|
||||
}
|
||||
if (!screen->rate) {
|
||||
screen->rate = (k >= 0) ? fbdevGetRefreshRate(&var) : 103;
|
||||
}
|
||||
if (!screen->fb.depth) {
|
||||
if (k >= 0)
|
||||
|
|
@ -207,52 +311,32 @@ fbdevScreenInitialize(KdScreenInfo * screen, FbdevScrPriv * scrpriv)
|
|||
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);
|
||||
rate = KdFindRate(screen, fbdevModeSupported);
|
||||
if (k >= 0) {
|
||||
/* Add the current framebuffer mode */
|
||||
fbdevConvertVarToTiming(&var, &curr_mode);
|
||||
KdAddMode(&curr_mode);
|
||||
if (!rate) {
|
||||
/* Add the desired framebuffer mode */
|
||||
curr_mode.horizontal = screen->width;
|
||||
curr_mode.vertical = screen->height;
|
||||
KdAddMode(&curr_mode);
|
||||
}
|
||||
}
|
||||
|
||||
var.activate = FB_ACTIVATE_NOW;
|
||||
var.bits_per_pixel = screen->fb.depth;
|
||||
var.nonstd = 0;
|
||||
var.grayscale = 0;
|
||||
|
||||
LogMessage(X_INFO, "Xfbdev(%d): Desired screen mode: width = %d, height = %d\n",
|
||||
screen->card->mynum, var.xres, var.yres);
|
||||
|
||||
k = ioctl(priv->fd, FBIOPUT_VSCREENINFO, &var);
|
||||
|
||||
if (k < 0) {
|
||||
LogMessage(X_ERROR, "Xfbdev(%d): FBIOPUT_VSCREENINFO: %s\n",
|
||||
screen->card->mynum, strerror(errno));
|
||||
return FALSE;
|
||||
/* Fbdev rate isn't reliable, don't forbid modes based on it */
|
||||
if (screen->rate < rate) {
|
||||
screen->rate = rate;
|
||||
}
|
||||
|
||||
/* Re-get the "fixed" parameters since they might have changed */
|
||||
k = ioctl(priv->fd, FBIOGET_FSCREENINFO, &priv->fix);
|
||||
if (k < 0)
|
||||
LogMessage(X_ERROR, "Xfbdev(%d): FBIOGET_FSCREENINFO: %s\n",
|
||||
screen->card->mynum, strerror(errno));
|
||||
t = KdFindMode(screen, fbdevModeSupported);
|
||||
|
||||
/* Sets priv->fix, priv->var */
|
||||
fbdevSetMode(screen, t);
|
||||
|
||||
/* Now get the new screeninfo */
|
||||
ioctl(priv->fd, FBIOGET_VSCREENINFO, &priv->var);
|
||||
depth = priv->var.bits_per_pixel;
|
||||
gray = priv->var.grayscale;
|
||||
|
||||
/* Just because the ioctl didn't fail, it doesn't mean we could set the mode */
|
||||
LogMessage(X_INFO, "Xfbdev(%d): Actual screen mode: width = %d, height = %d\n",
|
||||
screen->card->mynum, priv->var.xres, priv->var.yres);
|
||||
|
||||
/* 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:
|
||||
|
|
|
|||
Loading…
Reference in a new issue