917 lines
23 KiB
C
917 lines
23 KiB
C
|
/* all driver need this */
|
||
|
#ifdef HAVE_XORG_CONFIG_H
|
||
|
#include <xorg-config.h>
|
||
|
#endif
|
||
|
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "xf86.h"
|
||
|
#include "xf86_OSproc.h"
|
||
|
|
||
|
/* pci stuff */
|
||
|
#include "xf86PciInfo.h"
|
||
|
#include "xf86Pci.h"
|
||
|
|
||
|
#include "xf86cmap.h"
|
||
|
|
||
|
#include "fbdevhw.h"
|
||
|
#include "fbpriv.h"
|
||
|
|
||
|
#if 0
|
||
|
/* kernel header doesn't work with -ansi */
|
||
|
# include "asm/page.h" /* #define for PAGE_* */
|
||
|
#else
|
||
|
# define PAGE_MASK (~(getpagesize() - 1))
|
||
|
#endif
|
||
|
|
||
|
#include "globals.h"
|
||
|
#define DPMS_SERVER
|
||
|
#include <X11/extensions/dpms.h>
|
||
|
|
||
|
#define DEBUG 0
|
||
|
|
||
|
#define PAGE_MASK (~(getpagesize() - 1))
|
||
|
|
||
|
#if DEBUG
|
||
|
# define TRACE_ENTER(str) ErrorF("fbdevHW: " str " %d\n",pScrn->scrnIndex)
|
||
|
#else
|
||
|
# define TRACE_ENTER(str)
|
||
|
#endif
|
||
|
|
||
|
/* -------------------------------------------------------------------- */
|
||
|
|
||
|
static MODULESETUPPROTO(fbdevhwSetup);
|
||
|
|
||
|
static XF86ModuleVersionInfo fbdevHWVersRec =
|
||
|
{
|
||
|
"fbdevhw",
|
||
|
MODULEVENDORSTRING,
|
||
|
MODINFOSTRING1,
|
||
|
MODINFOSTRING2,
|
||
|
XORG_VERSION_CURRENT,
|
||
|
0, 0, 2,
|
||
|
ABI_CLASS_VIDEODRV,
|
||
|
ABI_VIDEODRV_VERSION,
|
||
|
MOD_CLASS_NONE,
|
||
|
{0,0,0,0}
|
||
|
};
|
||
|
|
||
|
_X_EXPORT XF86ModuleData fbdevhwModuleData = {
|
||
|
&fbdevHWVersRec,
|
||
|
fbdevhwSetup,
|
||
|
NULL
|
||
|
};
|
||
|
|
||
|
static pointer
|
||
|
fbdevhwSetup(pointer module, pointer opts, int *errmaj, int *errmin)
|
||
|
{
|
||
|
const char *osname;
|
||
|
|
||
|
/* Check that we're being loaded on a Linux system */
|
||
|
LoaderGetOS(&osname, NULL, NULL, NULL);
|
||
|
if (!osname || strcmp(osname, "linux") != 0) {
|
||
|
if (errmaj)
|
||
|
*errmaj = LDR_BADOS;
|
||
|
if (errmin)
|
||
|
*errmin = 0;
|
||
|
return NULL;
|
||
|
} else {
|
||
|
/* OK */
|
||
|
return (pointer)1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#include <fcntl.h>
|
||
|
#include <errno.h>
|
||
|
#include <sys/mman.h>
|
||
|
#include <sys/ioctl.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <unistd.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
/* -------------------------------------------------------------------- */
|
||
|
/* our private data, and two functions to allocate/free this */
|
||
|
|
||
|
#define FBDEVHWPTRLVAL(p) (p)->privates[fbdevHWPrivateIndex].ptr
|
||
|
#define FBDEVHWPTR(p) ((fbdevHWPtr)(FBDEVHWPTRLVAL(p)))
|
||
|
|
||
|
static int fbdevHWPrivateIndex = -1;
|
||
|
|
||
|
typedef struct {
|
||
|
/* framebuffer device: filename (/dev/fb*), handle, more */
|
||
|
char* device;
|
||
|
int fd;
|
||
|
void* fbmem;
|
||
|
unsigned int fbmem_len;
|
||
|
unsigned int fboff;
|
||
|
char* mmio;
|
||
|
unsigned int mmio_len;
|
||
|
|
||
|
/* current hardware state */
|
||
|
struct fb_fix_screeninfo fix;
|
||
|
struct fb_var_screeninfo var;
|
||
|
|
||
|
/* saved video mode */
|
||
|
struct fb_var_screeninfo saved_var;
|
||
|
|
||
|
/* FIXME: unused??? [geert] */
|
||
|
struct fb_cmap saved_cmap;
|
||
|
unsigned short *saved_red;
|
||
|
unsigned short *saved_green;
|
||
|
unsigned short *saved_blue;
|
||
|
|
||
|
/* buildin video mode */
|
||
|
DisplayModeRec buildin;
|
||
|
|
||
|
} fbdevHWRec, *fbdevHWPtr;
|
||
|
|
||
|
Bool
|
||
|
fbdevHWGetRec(ScrnInfoPtr pScrn)
|
||
|
{
|
||
|
fbdevHWPtr fPtr;
|
||
|
|
||
|
if (fbdevHWPrivateIndex < 0)
|
||
|
fbdevHWPrivateIndex = xf86AllocateScrnInfoPrivateIndex();
|
||
|
|
||
|
if (FBDEVHWPTR(pScrn) != NULL)
|
||
|
return TRUE;
|
||
|
|
||
|
fPtr = FBDEVHWPTRLVAL(pScrn) = xnfcalloc(sizeof(fbdevHWRec), 1);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
fbdevHWFreeRec(ScrnInfoPtr pScrn)
|
||
|
{
|
||
|
if (fbdevHWPrivateIndex < 0)
|
||
|
return;
|
||
|
if (FBDEVHWPTR(pScrn) == NULL)
|
||
|
return;
|
||
|
xfree(FBDEVHWPTR(pScrn));
|
||
|
FBDEVHWPTRLVAL(pScrn) = NULL;
|
||
|
}
|
||
|
|
||
|
/* -------------------------------------------------------------------- */
|
||
|
/* some helpers for printing debug informations */
|
||
|
|
||
|
#if DEBUG
|
||
|
static void
|
||
|
print_fbdev_mode(char *txt, struct fb_var_screeninfo *var)
|
||
|
{
|
||
|
ErrorF( "fbdev %s mode:\t%d %d %d %d %d %d %d %d %d %d %d:%d:%d\n",
|
||
|
txt,var->pixclock,
|
||
|
var->xres, var->right_margin, var->hsync_len, var->left_margin,
|
||
|
var->yres, var->lower_margin, var->vsync_len, var->upper_margin,
|
||
|
var->bits_per_pixel,
|
||
|
var->red.length, var->green.length, var->blue.length);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
print_xfree_mode(char *txt, DisplayModePtr mode)
|
||
|
{
|
||
|
ErrorF( "xfree %s mode:\t%d %d %d %d %d %d %d %d %d\n",
|
||
|
txt,mode->Clock,
|
||
|
mode->HDisplay, mode->HSyncStart, mode->HSyncEnd, mode->HTotal,
|
||
|
mode->VDisplay, mode->VSyncStart, mode->VSyncEnd, mode->VTotal);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/* -------------------------------------------------------------------- */
|
||
|
/* Convert timings between the XFree and the Frame Buffer Device */
|
||
|
|
||
|
static void
|
||
|
xfree2fbdev_fblayout(ScrnInfoPtr pScrn, struct fb_var_screeninfo *var)
|
||
|
{
|
||
|
var->xres_virtual = pScrn->virtualX;
|
||
|
var->yres_virtual = pScrn->virtualY;
|
||
|
var->bits_per_pixel = pScrn->bitsPerPixel;
|
||
|
var->red.length = pScrn->weight.red;
|
||
|
var->green.length = pScrn->weight.green;
|
||
|
var->blue.length = pScrn->weight.blue;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
xfree2fbdev_timing(DisplayModePtr mode, struct fb_var_screeninfo *var)
|
||
|
{
|
||
|
var->xres = mode->HDisplay;
|
||
|
var->yres = mode->VDisplay;
|
||
|
if (var->xres_virtual < var->xres)
|
||
|
var->xres_virtual = var->xres;
|
||
|
if (var->yres_virtual < var->yres)
|
||
|
var->yres_virtual = var->yres;
|
||
|
var->xoffset = var->yoffset = 0;
|
||
|
var->pixclock = mode->Clock ? 1000000000/mode->Clock : 0;
|
||
|
var->right_margin = mode->HSyncStart-mode->HDisplay;
|
||
|
var->hsync_len = mode->HSyncEnd-mode->HSyncStart;
|
||
|
var->left_margin = mode->HTotal-mode->HSyncEnd;
|
||
|
var->lower_margin = mode->VSyncStart-mode->VDisplay;
|
||
|
var->vsync_len = mode->VSyncEnd-mode->VSyncStart;
|
||
|
var->upper_margin = mode->VTotal-mode->VSyncEnd;
|
||
|
var->sync = 0;
|
||
|
if (mode->Flags & V_PHSYNC)
|
||
|
var->sync |= FB_SYNC_HOR_HIGH_ACT;
|
||
|
if (mode->Flags & V_PVSYNC)
|
||
|
var->sync |= FB_SYNC_VERT_HIGH_ACT;
|
||
|
if (mode->Flags & V_PCSYNC)
|
||
|
var->sync |= FB_SYNC_COMP_HIGH_ACT;
|
||
|
#if 1 /* Badly needed for PAL/NTSC on Amiga (amifb)!! [geert] */
|
||
|
if (mode->Flags & V_BCAST)
|
||
|
var->sync |= FB_SYNC_BROADCAST;
|
||
|
#endif
|
||
|
if (mode->Flags & V_INTERLACE)
|
||
|
var->vmode = FB_VMODE_INTERLACED;
|
||
|
else if (mode->Flags & V_DBLSCAN)
|
||
|
var->vmode = FB_VMODE_DOUBLE;
|
||
|
else
|
||
|
var->vmode = FB_VMODE_NONINTERLACED;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
fbdev2xfree_timing(struct fb_var_screeninfo *var, DisplayModePtr mode)
|
||
|
{
|
||
|
mode->Clock = var->pixclock ? 1000000000/var->pixclock : 28000000;
|
||
|
mode->HDisplay = var->xres;
|
||
|
mode->HSyncStart = mode->HDisplay+var->right_margin;
|
||
|
mode->HSyncEnd = mode->HSyncStart+var->hsync_len;
|
||
|
mode->HTotal = mode->HSyncEnd+var->left_margin;
|
||
|
mode->VDisplay = var->yres;
|
||
|
mode->VSyncStart = mode->VDisplay+var->lower_margin;
|
||
|
mode->VSyncEnd = mode->VSyncStart+var->vsync_len;
|
||
|
mode->VTotal = mode->VSyncEnd+var->upper_margin;
|
||
|
mode->Flags = 0;
|
||
|
mode->Flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? V_PHSYNC : V_NHSYNC;
|
||
|
mode->Flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? V_PVSYNC : V_NVSYNC;
|
||
|
mode->Flags |= var->sync & FB_SYNC_COMP_HIGH_ACT ? V_PCSYNC : V_NCSYNC;
|
||
|
#if 1 /* Badly needed for PAL/NTSC on Amiga (amifb)!! [geert] */
|
||
|
if (var->sync & FB_SYNC_BROADCAST)
|
||
|
mode->Flags |= V_BCAST;
|
||
|
#endif
|
||
|
if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
|
||
|
mode->Flags |= V_INTERLACE;
|
||
|
else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
|
||
|
mode->Flags |= V_DBLSCAN;
|
||
|
mode->SynthClock = mode->Clock;
|
||
|
mode->CrtcHDisplay = mode->HDisplay;
|
||
|
mode->CrtcHSyncStart = mode->HSyncStart;
|
||
|
mode->CrtcHSyncEnd = mode->HSyncEnd;
|
||
|
mode->CrtcHTotal = mode->HTotal;
|
||
|
mode->CrtcVDisplay = mode->VDisplay;
|
||
|
mode->CrtcVSyncStart = mode->VSyncStart;
|
||
|
mode->CrtcVSyncEnd = mode->VSyncEnd;
|
||
|
mode->CrtcVTotal = mode->VTotal;
|
||
|
mode->CrtcHAdjusted = FALSE;
|
||
|
mode->CrtcVAdjusted = FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* -------------------------------------------------------------------- */
|
||
|
/* open correct framebuffer device */
|
||
|
|
||
|
/* try to find the framebuffer device for a given PCI device */
|
||
|
static int
|
||
|
fbdev_open_pci(pciVideoPtr pPci, char **namep)
|
||
|
{
|
||
|
struct fb_fix_screeninfo fix;
|
||
|
char filename[16];
|
||
|
int fd,i,j;
|
||
|
memType res_start, res_end;
|
||
|
|
||
|
for (i = 0; i < 8; i++) {
|
||
|
sprintf(filename,"/dev/fb%d",i);
|
||
|
if (-1 == (fd = open(filename,O_RDWR,0))) {
|
||
|
xf86DrvMsg(-1, X_WARNING,
|
||
|
"open %s: %s\n", filename, strerror(errno));
|
||
|
continue;
|
||
|
}
|
||
|
if (-1 == ioctl(fd,FBIOGET_FSCREENINFO,(void*)&fix)) {
|
||
|
close(fd);
|
||
|
continue;
|
||
|
}
|
||
|
for (j = 0; j < 6; j++) {
|
||
|
res_start = pPci->memBase[j];
|
||
|
res_end = res_start+pPci->size[j];
|
||
|
if ((0 != fix.smem_len &&
|
||
|
(memType) fix.smem_start >= res_start &&
|
||
|
(memType) fix.smem_start < res_end) ||
|
||
|
(0 != fix.mmio_len &&
|
||
|
(memType) fix.mmio_start >= res_start &&
|
||
|
(memType) fix.mmio_start < res_end))
|
||
|
break;
|
||
|
}
|
||
|
if (j == 6) {
|
||
|
close(fd);
|
||
|
continue;
|
||
|
}
|
||
|
if (namep) {
|
||
|
*namep = xnfalloc(16);
|
||
|
strncpy(*namep,fix.id,16);
|
||
|
}
|
||
|
return fd;
|
||
|
}
|
||
|
if (namep)
|
||
|
*namep = NULL;
|
||
|
xf86DrvMsg(-1, X_ERROR,
|
||
|
"Unable to find a valid framebuffer device\n");
|
||
|
return -1;
|
||
|
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
fbdev_open(int scrnIndex, char *dev, char** namep)
|
||
|
{
|
||
|
struct fb_fix_screeninfo fix;
|
||
|
int fd;
|
||
|
|
||
|
/* try argument (from XF86Config) first */
|
||
|
if (dev) {
|
||
|
fd = open(dev,O_RDWR,0);
|
||
|
} else {
|
||
|
/* second: environment variable */
|
||
|
dev = getenv("FRAMEBUFFER");
|
||
|
if ((NULL == dev) || ((fd = open(dev,O_RDWR,0)) == -1)) {
|
||
|
/* last try: default device */
|
||
|
dev = "/dev/fb0";
|
||
|
fd = open(dev,O_RDWR,0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (fd == -1) {
|
||
|
xf86DrvMsg(scrnIndex, X_ERROR,
|
||
|
"open %s: %s\n", dev, strerror(errno));
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (namep) {
|
||
|
if (-1 == ioctl(fd,FBIOGET_FSCREENINFO,(void*)(&fix))) {
|
||
|
*namep = NULL;
|
||
|
xf86DrvMsg(scrnIndex, X_ERROR,
|
||
|
"FBIOGET_FSCREENINFO: %s\n", strerror(errno));
|
||
|
return -1;
|
||
|
} else {
|
||
|
*namep = xnfalloc(16);
|
||
|
strncpy(*namep,fix.id,16);
|
||
|
}
|
||
|
}
|
||
|
return fd;
|
||
|
}
|
||
|
|
||
|
/* -------------------------------------------------------------------- */
|
||
|
|
||
|
Bool
|
||
|
fbdevHWProbe(pciVideoPtr pPci, char *device,char **namep)
|
||
|
{
|
||
|
int fd;
|
||
|
|
||
|
if (pPci)
|
||
|
fd = fbdev_open_pci(pPci,namep);
|
||
|
else
|
||
|
fd = fbdev_open(-1,device,namep);
|
||
|
|
||
|
if (-1 == fd)
|
||
|
return FALSE;
|
||
|
close(fd);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
Bool
|
||
|
fbdevHWInit(ScrnInfoPtr pScrn, pciVideoPtr pPci, char *device)
|
||
|
{
|
||
|
fbdevHWPtr fPtr;
|
||
|
|
||
|
TRACE_ENTER("Init");
|
||
|
|
||
|
fbdevHWGetRec(pScrn);
|
||
|
fPtr = FBDEVHWPTR(pScrn);
|
||
|
|
||
|
/* open device */
|
||
|
if (pPci)
|
||
|
fPtr->fd = fbdev_open_pci(pPci,NULL);
|
||
|
else
|
||
|
fPtr->fd = fbdev_open(pScrn->scrnIndex,device,NULL);
|
||
|
if (-1 == fPtr->fd) {
|
||
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||
|
"Failed to open framebuffer device, consult warnings"
|
||
|
" and/or errors above for possible reasons\n"
|
||
|
"\t(you may have to look at the server log to see"
|
||
|
" warnings)\n");
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/* get current fb device settings */
|
||
|
if (-1 == ioctl(fPtr->fd,FBIOGET_FSCREENINFO,(void*)(&fPtr->fix))) {
|
||
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||
|
"ioctl FBIOGET_FSCREENINFO: %s\n",
|
||
|
strerror(errno));
|
||
|
return FALSE;
|
||
|
}
|
||
|
if (-1 == ioctl(fPtr->fd,FBIOGET_VSCREENINFO,(void*)(&fPtr->var))) {
|
||
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||
|
"ioctl FBIOGET_VSCREENINFO: %s\n",
|
||
|
strerror(errno));
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/* we can use the current settings as "buildin mode" */
|
||
|
fbdev2xfree_timing(&fPtr->var, &fPtr->buildin);
|
||
|
fPtr->buildin.name = "current";
|
||
|
fPtr->buildin.next = &fPtr->buildin;
|
||
|
fPtr->buildin.prev = &fPtr->buildin;
|
||
|
fPtr->buildin.type |= M_T_BUILTIN;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
char*
|
||
|
fbdevHWGetName(ScrnInfoPtr pScrn)
|
||
|
{
|
||
|
fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
|
||
|
return fPtr->fix.id;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
fbdevHWGetDepth(ScrnInfoPtr pScrn, int *fbbpp)
|
||
|
{
|
||
|
fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
|
||
|
|
||
|
if (fbbpp)
|
||
|
*fbbpp = fPtr->var.bits_per_pixel;
|
||
|
|
||
|
if (fPtr->fix.visual == FB_VISUAL_TRUECOLOR ||
|
||
|
fPtr->fix.visual == FB_VISUAL_DIRECTCOLOR)
|
||
|
return fPtr->var.red.length+fPtr->var.green.length+
|
||
|
fPtr->var.blue.length;
|
||
|
else
|
||
|
return fPtr->var.bits_per_pixel;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
fbdevHWGetLineLength(ScrnInfoPtr pScrn)
|
||
|
{
|
||
|
fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
|
||
|
|
||
|
if (fPtr->fix.line_length)
|
||
|
return fPtr->fix.line_length;
|
||
|
else
|
||
|
return fPtr->var.xres_virtual*fPtr->var.bits_per_pixel/8;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
fbdevHWGetType(ScrnInfoPtr pScrn)
|
||
|
{
|
||
|
fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
|
||
|
return fPtr->fix.type;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
fbdevHWGetVidmem(ScrnInfoPtr pScrn)
|
||
|
{
|
||
|
fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
|
||
|
return fPtr->fix.smem_len;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
fbdevHWSetVideoModes(ScrnInfoPtr pScrn)
|
||
|
{
|
||
|
fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
|
||
|
int virtX = pScrn->display->virtualX;
|
||
|
int virtY = pScrn->display->virtualY;
|
||
|
struct fb_var_screeninfo var;
|
||
|
char **modename;
|
||
|
DisplayModePtr mode,this,last = pScrn->modes;
|
||
|
|
||
|
TRACE_ENTER("VerifyModes");
|
||
|
if (NULL == pScrn->display->modes)
|
||
|
return;
|
||
|
|
||
|
for (modename = pScrn->display->modes; *modename != NULL; modename++) {
|
||
|
for (mode = pScrn->monitor->Modes; mode != NULL; mode = mode->next)
|
||
|
if (0 == strcmp(mode->name,*modename))
|
||
|
break;
|
||
|
if (NULL == mode) {
|
||
|
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
|
||
|
"\tmode \"%s\" not found\n", *modename);
|
||
|
continue;
|
||
|
}
|
||
|
memset(&var,0,sizeof(var));
|
||
|
xfree2fbdev_timing(mode,&var);
|
||
|
var.xres_virtual = virtX;
|
||
|
var.yres_virtual = virtY;
|
||
|
var.bits_per_pixel = pScrn->bitsPerPixel;
|
||
|
var.red.length = pScrn->weight.red;
|
||
|
var.green.length = pScrn->weight.green;
|
||
|
var.blue.length = pScrn->weight.blue;
|
||
|
|
||
|
var.activate = FB_ACTIVATE_TEST;
|
||
|
if (var.xres_virtual < var.xres) var.xres_virtual = var.xres;
|
||
|
if (var.yres_virtual < var.yres) var.yres_virtual = var.yres;
|
||
|
if (-1 == ioctl(fPtr->fd,FBIOPUT_VSCREENINFO,(void*)(&var))) {
|
||
|
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
|
||
|
"\tmode \"%s\" test failed\n", *modename);
|
||
|
continue;
|
||
|
}
|
||
|
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
|
||
|
"\tmode \"%s\" ok\n", *modename);
|
||
|
if (virtX < var.xres) virtX = var.xres;
|
||
|
if (virtY < var.yres) virtY = var.yres;
|
||
|
if (NULL == pScrn->modes) {
|
||
|
pScrn->modes = xnfalloc(sizeof(DisplayModeRec));
|
||
|
this = pScrn->modes;
|
||
|
memcpy(this,mode,sizeof(DisplayModeRec));
|
||
|
this->next = this;
|
||
|
this->prev = this;
|
||
|
} else {
|
||
|
this = xnfalloc(sizeof(DisplayModeRec));
|
||
|
memcpy(this,mode,sizeof(DisplayModeRec));
|
||
|
this->next = pScrn->modes;
|
||
|
this->prev = last;
|
||
|
last->next = this;
|
||
|
pScrn->modes->prev = this;
|
||
|
}
|
||
|
last = this;
|
||
|
}
|
||
|
pScrn->virtualX = virtX;
|
||
|
pScrn->virtualY = virtY;
|
||
|
}
|
||
|
|
||
|
DisplayModePtr
|
||
|
fbdevHWGetBuildinMode(ScrnInfoPtr pScrn)
|
||
|
{
|
||
|
fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
|
||
|
return &fPtr->buildin;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
fbdevHWUseBuildinMode(ScrnInfoPtr pScrn)
|
||
|
{
|
||
|
fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
|
||
|
|
||
|
TRACE_ENTER("UseBuildinMode");
|
||
|
pScrn->modes = &fPtr->buildin;
|
||
|
pScrn->virtualX = pScrn->display->virtualX;
|
||
|
pScrn->virtualY = pScrn->display->virtualY;
|
||
|
if (pScrn->virtualX < fPtr->buildin.HDisplay)
|
||
|
pScrn->virtualX = fPtr->buildin.HDisplay;
|
||
|
if (pScrn->virtualY < fPtr->buildin.VDisplay)
|
||
|
pScrn->virtualY = fPtr->buildin.VDisplay;
|
||
|
}
|
||
|
|
||
|
/* -------------------------------------------------------------------- */
|
||
|
|
||
|
static void
|
||
|
calculateFbmem_len(fbdevHWPtr fPtr)
|
||
|
{
|
||
|
fPtr->fboff = (unsigned long) fPtr->fix.smem_start & ~PAGE_MASK;
|
||
|
fPtr->fbmem_len = (fPtr->fboff+fPtr->fix.smem_len+~PAGE_MASK) &
|
||
|
PAGE_MASK;
|
||
|
}
|
||
|
|
||
|
|
||
|
void*
|
||
|
fbdevHWMapVidmem(ScrnInfoPtr pScrn)
|
||
|
{
|
||
|
fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
|
||
|
|
||
|
TRACE_ENTER("MapVidmem");
|
||
|
if (NULL == fPtr->fbmem) {
|
||
|
calculateFbmem_len(fPtr);
|
||
|
fPtr->fbmem = mmap(NULL, fPtr->fbmem_len, PROT_READ | PROT_WRITE,
|
||
|
MAP_SHARED, fPtr->fd, 0);
|
||
|
if (-1 == (long)fPtr->fbmem) {
|
||
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||
|
"mmap fbmem: %s\n", strerror(errno));
|
||
|
fPtr->fbmem = NULL;
|
||
|
} else {
|
||
|
/* Perhaps we'd better add fboff to fbmem and return 0 in
|
||
|
fbdevHWLinearOffset()? Of course we then need to mask
|
||
|
fPtr->fbmem with PAGE_MASK in fbdevHWUnmapVidmem() as
|
||
|
well. [geert] */
|
||
|
}
|
||
|
}
|
||
|
pScrn->memPhysBase = (unsigned long)fPtr->fix.smem_start & (unsigned long)(PAGE_MASK);
|
||
|
pScrn->fbOffset = (unsigned long)fPtr->fix.smem_start & (unsigned long)(~PAGE_MASK);
|
||
|
return fPtr->fbmem;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
fbdevHWLinearOffset(ScrnInfoPtr pScrn)
|
||
|
{
|
||
|
fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
|
||
|
|
||
|
TRACE_ENTER("LinearOffset");
|
||
|
return fPtr->fboff;
|
||
|
}
|
||
|
|
||
|
Bool
|
||
|
fbdevHWUnmapVidmem(ScrnInfoPtr pScrn)
|
||
|
{
|
||
|
fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
|
||
|
|
||
|
TRACE_ENTER("UnmapVidmem");
|
||
|
if (NULL != fPtr->fbmem) {
|
||
|
if (-1 == munmap(fPtr->fbmem, fPtr->fbmem_len))
|
||
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||
|
"munmap fbmem: %s\n", strerror(errno));
|
||
|
fPtr->fbmem = NULL;
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
void*
|
||
|
fbdevHWMapMMIO(ScrnInfoPtr pScrn)
|
||
|
{
|
||
|
unsigned int mmio_off;
|
||
|
|
||
|
fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
|
||
|
|
||
|
TRACE_ENTER("MapMMIO");
|
||
|
if (NULL == fPtr->mmio) {
|
||
|
/* tell the kernel not to use accels to speed up console scrolling */
|
||
|
fPtr->var.accel_flags = 0;
|
||
|
if (0 != ioctl(fPtr->fd,FBIOPUT_VSCREENINFO,(void*)(&fPtr->var))) {
|
||
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||
|
"FBIOPUT_VSCREENINFO: %s\n", strerror(errno));
|
||
|
return FALSE;
|
||
|
}
|
||
|
mmio_off = (unsigned long) fPtr->fix.mmio_start & ~PAGE_MASK;
|
||
|
fPtr->mmio_len = (mmio_off+fPtr->fix.mmio_len+~PAGE_MASK) &
|
||
|
PAGE_MASK;
|
||
|
if (NULL == fPtr->fbmem)
|
||
|
calculateFbmem_len(fPtr);
|
||
|
fPtr->mmio = mmap(NULL, fPtr->mmio_len, PROT_READ | PROT_WRITE,
|
||
|
MAP_SHARED, fPtr->fd, fPtr->fbmem_len);
|
||
|
if (-1 == (long)fPtr->mmio) {
|
||
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||
|
"mmap mmio: %s\n", strerror(errno));
|
||
|
fPtr->mmio = NULL;
|
||
|
} else
|
||
|
fPtr->mmio += mmio_off;
|
||
|
}
|
||
|
return fPtr->mmio;
|
||
|
}
|
||
|
|
||
|
Bool
|
||
|
fbdevHWUnmapMMIO(ScrnInfoPtr pScrn)
|
||
|
{
|
||
|
fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
|
||
|
|
||
|
TRACE_ENTER("UnmapMMIO");
|
||
|
if (NULL != fPtr->mmio) {
|
||
|
if (-1 == munmap((void *)((unsigned long)fPtr->mmio & PAGE_MASK), fPtr->mmio_len))
|
||
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||
|
"munmap mmio: %s\n", strerror(errno));
|
||
|
fPtr->mmio = NULL;
|
||
|
/* FIXME: restore var.accel_flags [geert] */
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/* -------------------------------------------------------------------- */
|
||
|
|
||
|
Bool
|
||
|
fbdevHWModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
|
||
|
{
|
||
|
fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
|
||
|
|
||
|
TRACE_ENTER("ModeInit");
|
||
|
xfree2fbdev_fblayout(pScrn, &fPtr->var);
|
||
|
xfree2fbdev_timing(mode, &fPtr->var);
|
||
|
#if DEBUG
|
||
|
print_xfree_mode("init",mode);
|
||
|
print_fbdev_mode("init",&fPtr->var);
|
||
|
#endif
|
||
|
pScrn->vtSema = TRUE;
|
||
|
|
||
|
/* set */
|
||
|
if (0 != ioctl(fPtr->fd,FBIOPUT_VSCREENINFO,(void*)(&fPtr->var))) {
|
||
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||
|
"FBIOPUT_VSCREENINFO: %s\n", strerror(errno));
|
||
|
return FALSE;
|
||
|
}
|
||
|
/* read back */
|
||
|
if (0 != ioctl(fPtr->fd,FBIOGET_FSCREENINFO,(void*)(&fPtr->fix))) {
|
||
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||
|
"FBIOGET_FSCREENINFO: %s\n", strerror(errno));
|
||
|
return FALSE;
|
||
|
}
|
||
|
if (0 != ioctl(fPtr->fd,FBIOGET_VSCREENINFO,(void*)(&fPtr->var))) {
|
||
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||
|
"FBIOGET_VSCREENINFO: %s\n", strerror(errno));
|
||
|
return FALSE;
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/* -------------------------------------------------------------------- */
|
||
|
/* video mode save/restore */
|
||
|
|
||
|
/* TODO: colormap */
|
||
|
void
|
||
|
fbdevHWSave(ScrnInfoPtr pScrn)
|
||
|
{
|
||
|
fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
|
||
|
|
||
|
TRACE_ENTER("Save");
|
||
|
if (0 != ioctl(fPtr->fd,FBIOGET_VSCREENINFO,(void*)(&fPtr->saved_var)))
|
||
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||
|
"FBIOGET_VSCREENINFO: %s\n", strerror(errno));
|
||
|
}
|
||
|
|
||
|
void
|
||
|
fbdevHWRestore(ScrnInfoPtr pScrn)
|
||
|
{
|
||
|
fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
|
||
|
|
||
|
TRACE_ENTER("Restore");
|
||
|
if (0 != ioctl(fPtr->fd,FBIOPUT_VSCREENINFO,(void*)(&fPtr->saved_var)))
|
||
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||
|
"FBIOPUT_VSCREENINFO: %s\n", strerror(errno));
|
||
|
}
|
||
|
|
||
|
/* -------------------------------------------------------------------- */
|
||
|
/* callback for xf86HandleColormaps */
|
||
|
|
||
|
void
|
||
|
fbdevHWLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
|
||
|
LOCO *colors, VisualPtr pVisual)
|
||
|
{
|
||
|
fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
|
||
|
struct fb_cmap cmap;
|
||
|
unsigned short red,green,blue;
|
||
|
int i;
|
||
|
|
||
|
TRACE_ENTER("LoadPalette");
|
||
|
cmap.len = 1;
|
||
|
cmap.red = &red;
|
||
|
cmap.green = &green;
|
||
|
cmap.blue = &blue;
|
||
|
cmap.transp = NULL;
|
||
|
for (i = 0; i < numColors; i++) {
|
||
|
cmap.start = indices[i];
|
||
|
red = (colors[indices[i]].red << 8) |
|
||
|
colors[indices[i]].red;
|
||
|
green = (colors[indices[i]].green << 8) |
|
||
|
colors[indices[i]].green;
|
||
|
blue = (colors[indices[i]].blue << 8) |
|
||
|
colors[indices[i]].blue;
|
||
|
if (-1 == ioctl(fPtr->fd,FBIOPUTCMAP,(void*)&cmap))
|
||
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||
|
"FBIOPUTCMAP: %s\n", strerror(errno));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* -------------------------------------------------------------------- */
|
||
|
/* these can be hooked directly into ScrnInfoRec */
|
||
|
|
||
|
ModeStatus
|
||
|
fbdevHWValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
|
||
|
{
|
||
|
ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
|
||
|
fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
|
||
|
struct fb_var_screeninfo var;
|
||
|
|
||
|
TRACE_ENTER("ValidMode");
|
||
|
memcpy(&var,&fPtr->var,sizeof(var));
|
||
|
xfree2fbdev_timing(mode, &var);
|
||
|
var.activate = FB_ACTIVATE_TEST;
|
||
|
if (0 != ioctl(fPtr->fd,FBIOPUT_VSCREENINFO,(void*)(&fPtr->var))) {
|
||
|
xf86DrvMsg(scrnIndex, X_ERROR,
|
||
|
"FBIOPUT_VSCREENINFO: %s\n", strerror(errno));
|
||
|
return MODE_BAD;
|
||
|
}
|
||
|
return MODE_OK;
|
||
|
}
|
||
|
|
||
|
Bool
|
||
|
fbdevHWSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
|
||
|
{
|
||
|
ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
|
||
|
fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
|
||
|
|
||
|
TRACE_ENTER("SwitchMode");
|
||
|
xfree2fbdev_timing(mode, &fPtr->var);
|
||
|
if (0 != ioctl(fPtr->fd,FBIOPUT_VSCREENINFO,(void*)(&fPtr->var))) {
|
||
|
xf86DrvMsg(scrnIndex, X_ERROR,
|
||
|
"FBIOPUT_VSCREENINFO: %s\n", strerror(errno));
|
||
|
return FALSE;
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
fbdevHWAdjustFrame(int scrnIndex, int x, int y, int flags)
|
||
|
{
|
||
|
ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
|
||
|
fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
|
||
|
|
||
|
TRACE_ENTER("AdjustFrame");
|
||
|
if ( x < 0 || x + fPtr->var.xres > fPtr->var.xres_virtual ||
|
||
|
y < 0 || y + fPtr->var.yres > fPtr->var.yres_virtual )
|
||
|
return;
|
||
|
|
||
|
fPtr->var.xoffset = x;
|
||
|
fPtr->var.yoffset = y;
|
||
|
if (-1 == ioctl(fPtr->fd,FBIOPAN_DISPLAY,(void*)&fPtr->var))
|
||
|
xf86DrvMsgVerb(scrnIndex, X_WARNING, 5,
|
||
|
"FBIOPAN_DISPLAY: %s\n", strerror(errno));
|
||
|
}
|
||
|
|
||
|
Bool
|
||
|
fbdevHWEnterVT(int scrnIndex, int flags)
|
||
|
{
|
||
|
ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
|
||
|
|
||
|
TRACE_ENTER("EnterVT");
|
||
|
if (!fbdevHWModeInit(pScrn, pScrn->currentMode))
|
||
|
return FALSE;
|
||
|
fbdevHWAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
fbdevHWLeaveVT(int scrnIndex, int flags)
|
||
|
{
|
||
|
ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
|
||
|
|
||
|
TRACE_ENTER("LeaveVT");
|
||
|
fbdevHWRestore(pScrn);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
fbdevHWDPMSSet(ScrnInfoPtr pScrn, int mode, int flags)
|
||
|
{
|
||
|
fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
|
||
|
unsigned long fbmode;
|
||
|
|
||
|
TRACE_ENTER("DPMSSet");
|
||
|
if (!pScrn->vtSema)
|
||
|
return;
|
||
|
|
||
|
switch (mode) {
|
||
|
case DPMSModeOn:
|
||
|
fbmode = 0;
|
||
|
break;
|
||
|
case DPMSModeStandby:
|
||
|
fbmode = 2;
|
||
|
break;
|
||
|
case DPMSModeSuspend:
|
||
|
fbmode = 3;
|
||
|
break;
|
||
|
case DPMSModeOff:
|
||
|
fbmode = 4;
|
||
|
break;
|
||
|
default:
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (-1 == ioctl(fPtr->fd, FBIOBLANK, (void *)fbmode))
|
||
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||
|
"FBIOBLANK: %s\n", strerror(errno));
|
||
|
}
|
||
|
|
||
|
Bool
|
||
|
fbdevHWSaveScreen(ScreenPtr pScreen, int mode)
|
||
|
{
|
||
|
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
|
||
|
fbdevHWPtr fPtr = FBDEVHWPTR(pScrn);
|
||
|
unsigned long unblank;
|
||
|
|
||
|
TRACE_ENTER("HWSaveScreen");
|
||
|
if (!pScrn->vtSema)
|
||
|
return TRUE;
|
||
|
|
||
|
unblank = xf86IsUnblank(mode);
|
||
|
|
||
|
if (-1 == ioctl(fPtr->fd, FBIOBLANK, (void *)(1-unblank))) {
|
||
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||
|
"FBIOBLANK: %s\n", strerror(errno));
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
xf86SwitchModeProc *
|
||
|
fbdevHWSwitchModeWeak(void) { return fbdevHWSwitchMode; }
|
||
|
|
||
|
xf86AdjustFrameProc *
|
||
|
fbdevHWAdjustFrameWeak(void) { return fbdevHWAdjustFrame; }
|
||
|
|
||
|
xf86EnterVTProc *
|
||
|
fbdevHWEnterVTWeak(void) { return fbdevHWEnterVT; }
|
||
|
|
||
|
xf86LeaveVTProc *
|
||
|
fbdevHWLeaveVTWeak(void) { return fbdevHWLeaveVT; }
|
||
|
|
||
|
xf86ValidModeProc *
|
||
|
fbdevHWValidModeWeak(void) { return fbdevHWValidMode; }
|
||
|
|
||
|
xf86DPMSSetProc *
|
||
|
fbdevHWDPMSSetWeak(void) { return fbdevHWDPMSSet; }
|
||
|
|
||
|
xf86LoadPaletteProc *
|
||
|
fbdevHWLoadPaletteWeak(void) { return fbdevHWLoadPalette; }
|
||
|
|
||
|
SaveScreenProcPtr
|
||
|
fbdevHWSaveScreenWeak(void) { return fbdevHWSaveScreen; }
|