1
1

441 строка
9.9 KiB
C

/*
* (c) 2010, SWD Embedded Systems Limited, http://www.kpda.ru
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "vesabios.h"
static void
vga_enter(disp_adapter_t *adapter)
{
disp_acquire_vga_resources(adapter);
disp_device_active(adapter, 1, 1);
}
static void
vga_leave(disp_adapter_t *adapter)
{
vb_context_t *vb = adapter->ms_ctx;
disp_device_active(adapter, 0, vb->mode_set);
disp_release_vga_resources(adapter);
}
static int
setstride(vb_context_t *ctx)
{
vbios_regs_t regs;
memset(&regs, 0, sizeof regs);
regs.eax = 0x4f06;
regs.ebx = 2;
regs.ecx = ctx->vidstride; /* set stride to specific width */
if (vbios_int(ctx->adapter->vbios, 0x10, &regs, 0) != -1)
return 0;
else
return -1;
}
static int
setmode(vb_context_t *ctx, unsigned mode, CRTCInfoBlock_t *crtc_params)
{
vbios_regs_t regs;
int xfer_size = 0;
struct vbios_context *vbios = ctx->adapter->vbios;
memset(&regs, 0, sizeof regs);
if (mode < 0x100) {
/* VGA bios set mode */
regs.eax = mode;
} else {
/* VESA bios set mode */
regs.eax = 0x4f02;
regs.ebx = mode;
if (crtc_params != NULL) {
/* VBE 3.0 refresh rate support */
regs.ebx |= 1<<11;
regs.es = vbios->xfer_area_seg;
regs.edi = vbios->xfer_area_off;
xfer_size = sizeof (*crtc_params);
}
}
if (vbios_int(ctx->adapter->vbios, 0x10, &regs, xfer_size) != -1 &&
!(mode >= 0x100 && (regs.eax & 0xffff) != 0x004f))
return 0;
else
return -1;
}
/* Put the chip back into standard VGA mode */
void
vesa_restore_vga(disp_adapter_t *ctx)
{
vb_context_t *vb = ctx->ms_ctx;
vga_enter(ctx);
if (setmode(ctx->ms_ctx, 3, NULL) == -1)
disp_perror(ctx, "vesa_restore_vga");
vga_leave(ctx);
vb->mode_set = 0;
}
static void
vesa_get_crtc_params(disp_adapter_t *adapter,
int refresh, int xres, int yres, CRTCInfoBlock_t *crtc_params)
{
disp_crtc_settings_t crtc;
int h_gran;
if (disp_mode_get_entry(adapter, &crtc,
"/etc/system/config/crtc-settings", xres, yres, refresh) != 0) {
crtc.xres = xres;
crtc.yres = yres;
crtc.refresh = refresh;
crtc.h_granularity = h_gran = 8;
crtc.v_granularity = 1;
disp_crtc_calc(&crtc);
} else
h_gran = 1;
memset(crtc_params, 0, sizeof (*crtc_params));
crtc_params->HorizontalTotal = crtc.h_total * h_gran;
crtc_params->HorizontalSyncStart = crtc.h_sync_start * h_gran;
crtc_params->HorizontalSyncEnd =
(crtc.h_sync_start+crtc.h_sync_len) * h_gran;
crtc_params->VerticalTotal = crtc.v_total;
crtc_params->VerticalSyncStart = crtc.v_sync_start;
crtc_params->VerticalSyncEnd =
(crtc.v_sync_start+crtc.v_sync_len);
crtc_params->Flags = 0;
crtc_params->PixelClock = crtc.pixel_clock * 1000;
crtc_params->RefreshRate = crtc.refresh * 100;
}
/* Place details on `mode' into `info' struct */
int
vesa_get_modeinfo(disp_adapter_t *ctx,
int dispno, disp_mode_t mode, disp_mode_info_t *info)
{
VESAModeInfoStruct vmode;
VESAInfoBlockStruct VIB;
int rc = -1;
DISP_ASSERT(dispno == 0);
memset(info, 0, sizeof (*info));
vga_enter(ctx);
if (vesa_ModeInfo(ctx->vbios, mode & ~0x4000, &vmode) == NULL)
goto done;
if (vesa_InfoBlock(ctx->vbios, &VIB) == NULL)
goto done;
info->size = sizeof (*info);
info->mode = mode;
info->xres = vmode.XResolution;
info->yres = vmode.YResolution;
/* Linear frame buffer properties */
if (vmode.PhysBasePtr == 0)
goto done;
else
info->fb_addr = vmode.PhysBasePtr;
if (info->fb_addr == 0) {
errno = EINVAL;
goto done;
}
info->fb_stride = vmode.BytesPerScanLine;
info->fb_size = VIB.TotalMemory * 0x10000;
switch (vmode.BitsPerPixel) {
case 8:
info->pixel_format = DISP_SURFACE_FORMAT_PAL8;
break;
case 15:
case 16:
if (vmode.GreenMaskSize == 5)
info->pixel_format = DISP_SURFACE_FORMAT_ARGB1555;
else
info->pixel_format = DISP_SURFACE_FORMAT_RGB565;
break;
case 24:
info->pixel_format = DISP_SURFACE_FORMAT_RGB888;
break;
case 32:
info->pixel_format = DISP_SURFACE_FORMAT_ARGB8888;
break;
}
#if 0
if (vesa_HaveSetDisplayOffset(ctx->vbios))
info->caps |= DISP_MCAP_SET_DISPLAY_OFFSET;
#endif
if (vesa_HaveDPMS(ctx->vbios))
info->caps |= DISP_MCAP_DPMS_SUPPORTED;
info->crtc_start_gran = DISP_BITS_PER_PIXEL(info->pixel_format);
// Panning supported if not 24bpp (24bpp screwed up strides on a lot of cards)
if(info->pixel_format != DISP_SURFACE_FORMAT_RGB888) {
info->caps |= DISP_MCAP_VIRTUAL_PANNING;
info->crtc_pitch_gran = 16;
info->max_virtual_width = 3200;
info->max_virtual_height = 2400;
}
if (VIB.VESAVersion >= 0x300) {
info->u.fixed.refresh[0] = 60;
info->u.fixed.refresh[1] = 70;
info->u.fixed.refresh[2] = 72;
info->u.fixed.refresh[3] = 75;
info->u.fixed.refresh[4] = 85;
info->u.fixed.refresh[5] = 0;
} else {
info->u.fixed.refresh[0] = 60; /* More than likely if not VESA 3 */
info->u.fixed.refresh[1] = 0;
}
rc = 0;
done:
vga_leave(ctx);
return rc;
}
int
vesa_set_mode(disp_adapter_t *ctx, int dispno, disp_mode_t mode,
disp_crtc_settings_t *settings, disp_surface_t *surf, unsigned flags)
{
vb_context_t *vb = ctx->ms_ctx;
disp_mode_info_t mi;
int rc;
CRTCInfoBlock_t *crtc_params;
DISP_ASSERT(dispno == 0);
if (vesa_get_modeinfo(ctx, 0, mode, &mi) == -1)
return -1;
if (vb->vidptr) {
disp_munmap_device_memory(vb->vidptr, mi.fb_size);
vb->vidptr = NULL;
}
if (mi.fb_addr == 0) {
errno = EINVAL;
return -1;
}
vb->vidptr = disp_mmap_device_memory(mi.fb_addr, mi.fb_size,
DISP_PROT_READ | DISP_PROT_WRITE, DISP_MAP_LAZY);
if (vb->vidptr == NULL)
return -1;
vb->vidbase = mi.fb_addr;
ctx->adapter_ram = vb->vidsize = mi.fb_size;
if(surf->stride > mi.fb_stride && mi.caps & DISP_MCAP_VIRTUAL_PANNING)
vb->vidstride = surf->stride;
else
vb->vidstride = mi.fb_stride;
vb->format = mi.pixel_format;
/* Fill in info about where to draw */
surf->vidptr = vb->vidptr;
surf->paddr = mi.fb_addr;
surf->offset = 0;
surf->stride = vb->vidstride;
surf->pixel_format = mi.pixel_format;
surf->flags = DISP_SURFACE_DISPLAYABLE | DISP_SURFACE_PAGE_ALIGNED |
DISP_SURFACE_CPU_LINEAR_READABLE |
DISP_SURFACE_CPU_LINEAR_WRITEABLE | DISP_SURFACE_2D_TARGETABLE;
if (!(mi.caps & DISP_MCAP_SET_DISPLAY_OFFSET)) {
/*
* There can only be a single displayable surface, and
* it must begin at offset 0
*/
memcpy(&vb->visible, surf, sizeof (*surf));
vb->visible.height = surf->height;
} else
vb->visible.height = 0;
vb->visible.offset = 0;
vb->current_mode_caps = mi.caps;
if (settings->refresh > 60) {
/* VBE 3.0 refresh rate support */
crtc_params = (void *)ctx->vbios->xfer_area_ptr;
vesa_get_crtc_params(ctx, settings->refresh, mi.xres, mi.yres,
crtc_params);
} else
crtc_params = NULL;
vga_enter(ctx);
rc = setmode(ctx->ms_ctx, mode, crtc_params);
if(surf->stride > mi.fb_stride && mi.caps & DISP_MCAP_VIRTUAL_PANNING)
if (setstride(ctx->ms_ctx) == -1)
disp_printf(vb->adapter,"Set Stride failed");
if (rc == 0)
vb->mode_set = 1;
else
errno = ENOSYS;
vga_leave(ctx);
return rc;
}
/* Place a list of mode ID's in `list' */
int
vesa_get_modelist(disp_adapter_t *ctx, int dispno, unsigned short *list,
int index, int size)
{
uint16_t VModes[DISP_MAX_MODES + 1];
int i, j = 0, rc = -1;
VESAInfoBlockStruct VIB;
VESAModeInfoStruct VMI;
if (dispno != 0)
return -1;
list[0] = DISP_MODE_LISTEND;
vga_enter(ctx);
if (vesa_InfoBlock(ctx->vbios, &VIB) != NULL) {
/* Get the list of VESA modes */
if (vesa_ModeList(ctx->vbios, &VIB, VModes) == NULL)
goto done;
for (i = 0; i < DISP_MAX_MODES; i++) {
if (i < index)
continue;
if (j >= size-1)
break;
if (VModes[i] == 0xffff)
break;
(void)vesa_ModeInfo(ctx->vbios, VModes[i], &VMI);
if (VMI.MemoryModel != VESA_MM_DirectColor &&
!(VMI.MemoryModel == VESA_MM_VGA8Packed &&
(VModes[i] & 0xf00)))
continue;
/* Don't support any of this tripe yet */
if (VMI.NumberOfPlanes > 1 || VMI.NumberOfBanks > 1
|| VMI.BitsPerPixel < 8)
continue;
if (!(VMI.ModeAttributes & 1))
continue;
/* Check that mode fits into memory */
if ((VMI.BytesPerScanLine * VMI.YResolution) > (VIB.TotalMemory * 0x10000))
continue;
if (VModes[i] >= 0x100 && (VMI.ModeAttributes & 0x80) &&
VIB.VESAVersion >= 0x200) {
/* A linear VESA mode */
list[j++] = VModes[i] | 0x4000;
}
rc = 0;
}
}
list[j] = DISP_MODE_LISTEND;
done:
vga_leave(ctx);
return rc;
}
int
vesa_set_display_offset(disp_adapter_t *ctx,
int dispno, unsigned offset, int wait_vsync)
{
vb_context_t *vb = ctx->ms_ctx;
int rc;
DISP_ASSERT(dispno == 0);
vga_enter(ctx);
rc = vesa_SetDisplayOffset(ctx->vbios,
offset%vb->vidstride, offset/vb->vidstride, wait_vsync);
vga_leave(ctx);
return rc;
}
void
vesa_set_scroll_pos(disp_adapter_t *adapter, int dispno,
unsigned xoff, unsigned yoff)
{
vb_context_t *vb = adapter->ms_ctx;
int rc;
unsigned offset;
offset = (yoff*vb->vidstride) +
((xoff*DISP_BITS_PER_PIXEL(vb->format)+ 7)>>3);
DISP_ASSERT(dispno == 0);
vga_enter(adapter);
rc = vesa_SetDisplayOffset(adapter->vbios,
(offset/DISP_BYTES_PER_PIXEL(vb->format))%vb->vidstride,
offset/vb->vidstride, 0);
vga_leave(adapter);
}
int
vesa_set_palette(disp_adapter_t *ctx, int dispno,
int index, int count, disp_color_t *pal)
{
int rc;
DISP_ASSERT(dispno == 0);
vga_enter(ctx);
rc = vesa_BIOSSetPalette(ctx->vbios, pal, index, count);
vga_leave(ctx);
return rc;
}
int
vesa_set_dpms_mode(disp_adapter_t *ctx, int dispno, int dpms_mode)
{
int rc;
DISP_ASSERT(dispno == 0);
vga_enter(ctx);
rc = vesa_SetDPMSMode(ctx->vbios, dpms_mode);
vga_leave(ctx);
return rc;
}