From 7fe60435bce6595a9c58a9bfd8244d74b5320e96 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Tue, 15 Jan 2013 08:46:13 +0100 Subject: Import DirectFB141_2k11R3_beta5 --- Source/DirectFB/systems/fbdev/fbdev.c | 2782 +++++++++++++++++++++++++++++++++ 1 file changed, 2782 insertions(+) create mode 100755 Source/DirectFB/systems/fbdev/fbdev.c (limited to 'Source/DirectFB/systems/fbdev/fbdev.c') diff --git a/Source/DirectFB/systems/fbdev/fbdev.c b/Source/DirectFB/systems/fbdev/fbdev.c new file mode 100755 index 0000000..3691cff --- /dev/null +++ b/Source/DirectFB/systems/fbdev/fbdev.c @@ -0,0 +1,2782 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include /* Needs to be included before dfb_types.h */ + +#include +#include +#include +#include +#include +#include +#if defined(HAVE_SYSIO) +# include +#endif +#include +#include +#include +#include + +#include + +#ifdef USE_SYSFS +# include +#endif + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "fbdev.h" +#include "fb.h" +#include "vt.h" +#include "agp.h" + +#include + +DFB_CORE_SYSTEM( fbdev ) + + +D_DEBUG_DOMAIN( FBDev_Mode, "FBDev/Mode", "FBDev System Module Mode Switching" ); + +/******************************************************************************/ + +extern const SurfacePoolFuncs fbdevSurfacePoolFuncs; + +static FusionCallHandlerResult +fbdev_ioctl_call_handler( int caller, + int call_arg, + void *call_ptr, + void *ctx, + unsigned int serial, + int *ret_val ); + +static int fbdev_ioctl( int request, void *arg, int arg_size ); + +#define FBDEV_IOCTL(request,arg) fbdev_ioctl( request, arg, sizeof(*(arg)) ) + +FBDev *dfb_fbdev = NULL; + +/******************************************************************************/ + +static int primaryLayerDataSize ( void ); + +static int primaryRegionDataSize( void ); + +static DFBResult primaryInitLayer ( CoreLayer *layer, + void *driver_data, + void *layer_data, + DFBDisplayLayerDescription *description, + DFBDisplayLayerConfig *config, + DFBColorAdjustment *adjustment ); + +static DFBResult primarySetColorAdjustment( CoreLayer *layer, + void *driver_data, + void *layer_data, + DFBColorAdjustment *adjustment ); + +static DFBResult primaryTestRegion ( CoreLayer *layer, + void *driver_data, + void *layer_data, + CoreLayerRegionConfig *config, + CoreLayerRegionConfigFlags *failed ); + +static DFBResult primaryAddRegion ( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data, + CoreLayerRegionConfig *config ); + +static DFBResult primarySetRegion ( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data, + CoreLayerRegionConfig *config, + CoreLayerRegionConfigFlags updated, + CoreSurface *surface, + CorePalette *palette, + CoreSurfaceBufferLock *lock ); + +static DFBResult primaryRemoveRegion ( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data ); + +static DFBResult primaryFlipRegion ( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data, + CoreSurface *surface, + DFBSurfaceFlipFlags flags, + CoreSurfaceBufferLock *lock ); + + +static DisplayLayerFuncs primaryLayerFuncs = { + .LayerDataSize = primaryLayerDataSize, + .RegionDataSize = primaryRegionDataSize, + .InitLayer = primaryInitLayer, + + .SetColorAdjustment = primarySetColorAdjustment, + + .TestRegion = primaryTestRegion, + .AddRegion = primaryAddRegion, + .SetRegion = primarySetRegion, + .RemoveRegion = primaryRemoveRegion, + .FlipRegion = primaryFlipRegion, +}; + +/******************************************************************************/ + +static DFBResult primaryInitScreen ( CoreScreen *screen, + CoreGraphicsDevice *device, + void *driver_data, + void *screen_data, + DFBScreenDescription *description ); + +static DFBResult primarySetPowerMode( CoreScreen *screen, + void *driver_data, + void *screen_data, + DFBScreenPowerMode mode ); + +static DFBResult primaryWaitVSync ( CoreScreen *screen, + void *driver_data, + void *layer_data ); + +static DFBResult primaryGetScreenSize( CoreScreen *screen, + void *driver_data, + void *screen_data, + int *ret_width, + int *ret_height ); + +static ScreenFuncs primaryScreenFuncs = { + .InitScreen = primaryInitScreen, + .SetPowerMode = primarySetPowerMode, + .WaitVSync = primaryWaitVSync, + .GetScreenSize = primaryGetScreenSize, +}; + +/******************************************************************************/ + +static DFBResult dfb_fbdev_read_modes( void ); +static DFBResult dfb_fbdev_set_gamma_ramp( DFBSurfacePixelFormat format ); +static DFBResult dfb_fbdev_set_palette( CorePalette *palette ); +static DFBResult dfb_fbdev_set_rgb332_palette( void ); +static DFBResult dfb_fbdev_pan( int xoffset, int yoffset, bool onsync ); +static DFBResult dfb_fbdev_blank( int level ); +static void dfb_fbdev_var_to_mode( const struct fb_var_screeninfo *var, + VideoMode *mode ); + +/******************************************************************************/ + +static inline +void waitretrace (void) +{ +#if defined(HAVE_INB_OUTB_IOPL) + if (iopl(3)) + return; + + if (!(inb (0x3cc) & 1)) { + while ((inb (0x3ba) & 0x8)) + ; + + while (!(inb (0x3ba) & 0x8)) + ; + } + else { + while ((inb (0x3da) & 0x8)) + ; + + while (!(inb (0x3da) & 0x8)) + ; + } +#endif +} + +/******************************************************************************/ + +static DFBResult dfb_fbdev_open( void ) +{ + DFBResult error_result = DFB_FAILURE; + + if (dfb_config->fb_device) { + dfb_fbdev->fd = open( dfb_config->fb_device, O_RDWR ); + if (dfb_fbdev->fd < 0) { + D_PERROR( "DirectFB/FBDev: Error opening '%s'!\n", + dfb_config->fb_device); + + error_result = errno2result( errno ); + goto error; + } + } + else if (getenv( "FRAMEBUFFER" ) && *getenv( "FRAMEBUFFER" ) != '\0') { + dfb_fbdev->fd = open( getenv ("FRAMEBUFFER"), O_RDWR ); + if (dfb_fbdev->fd < 0) { + D_PERROR( "DirectFB/FBDev: Error opening '%s'!\n", + getenv ("FRAMEBUFFER")); + + error_result = errno2result( errno ); + goto error; + } + } + else { + dfb_fbdev->fd = direct_try_open( "/dev/fb0", "/dev/fb/0", O_RDWR, true ); + if (dfb_fbdev->fd < 0) { + D_ERROR( "DirectFB/FBDev: Error opening framebuffer device!\n" ); + D_ERROR( "DirectFB/FBDev: Use 'fbdev' option or set FRAMEBUFFER environment variable.\n" ); + error_result = DFB_INIT; + goto error; + } + } + + /* should be closed automatically in children upon exec(...) */ + if (fcntl( dfb_fbdev->fd, F_SETFD, FD_CLOEXEC ) < 0) + { + D_PERROR( "Fusion/Init: Setting FD_CLOEXEC flag failed!\n" ); + goto error; + } + + return DFB_OK; +error: + return error_result; +} + +/******************************************************************************/ + +static void +dfb_fbdev_get_pci_info( FBDevShared *shared ) +{ + char buf[512]; + int vendor = -1; + int model = -1; + +#ifdef USE_SYSFS + if (!sysfs_get_mnt_path( buf, 512 )) { + struct sysfs_class_device *classdev; + struct sysfs_device *device; + struct sysfs_attribute *attr; + char *fbdev; + char dev[5] = { 'f', 'b', '0', 0, 0 }; + + fbdev = dfb_config->fb_device; + if (!fbdev) + fbdev = getenv( "FRAMEBUFFER" ); + + if (fbdev) { + if (!strncmp( fbdev, "/dev/fb/", 8 )) + snprintf( dev, 5, "fb%s", fbdev+8 ); + else if (!strncmp( fbdev, "/dev/fb", 7 )) + snprintf( dev, 5, "fb%s", fbdev+7 ); + } + + classdev = sysfs_open_class_device( "graphics", dev ); + if (classdev) { + device = sysfs_get_classdev_device( classdev ); + + if (device) { + attr = sysfs_get_device_attr( device, "vendor" ); + if (attr) + sscanf( attr->value, "0x%04x", &vendor ); + + attr = sysfs_get_device_attr( device, "device" ); + if (attr) + sscanf( attr->value, "0x%04x", &model ); + + if (vendor != -1 && model != -1) { + sscanf( device->name, "0000:%02x:%02x.%1x", + &shared->pci.bus, + &shared->pci.dev, + &shared->pci.func ); + + shared->device.vendor = vendor; + shared->device.model = model; + } + } + + sysfs_close_class_device( classdev ); + } + } +#endif /* USE_SYSFS */ + + /* try /proc interface */ + if (vendor == -1 || model == -1) { + FILE *fp; + int id; + int bus; + int dev; + int func; + + fp = fopen( "/proc/bus/pci/devices", "r" ); + if (!fp) { + D_DEBUG( "DirectFB/FBDev: " + "couldn't access /proc/bus/pci/devices!\n" ); + return; + } + + while (fgets( buf, 512, fp )) { + if (sscanf( buf, "%04x\t%04x%04x", &id, &vendor, &model ) == 3) { + bus = (id & 0xff00) >> 8; + dev = (id & 0x00ff) >> 3; + func = (id & 0x0007); + + if (bus == dfb_config->pci.bus && + dev == dfb_config->pci.dev && + func == dfb_config->pci.func) + { + shared->pci.bus = bus; + shared->pci.dev = dev; + shared->pci.func = func; + + shared->device.vendor = vendor; + shared->device.model = model; + + break; + } + } + } + + fclose( fp ); + } +} + + +/** public **/ + +static void +system_get_info( CoreSystemInfo *info ) +{ + info->type = CORE_FBDEV; + info->caps = CSCAPS_ACCELERATION; + + snprintf( info->name, DFB_CORE_SYSTEM_INFO_NAME_LENGTH, "FBDev" ); +} + +static DFBResult +system_initialize( CoreDFB *core, void **data ) +{ + DFBResult ret; + CoreScreen *screen; + long page_size; + FBDevShared *shared = NULL; + FusionSHMPoolShared *pool; + FusionSHMPoolShared *pool_data; + + D_ASSERT( dfb_fbdev == NULL ); + + pool = dfb_core_shmpool( core ); + pool_data = dfb_core_shmpool_data( core ); + + dfb_fbdev = D_CALLOC( 1, sizeof(FBDev) ); + if (!dfb_fbdev) + return D_OOM(); + + dfb_fbdev->fd = -1; + + shared = (FBDevShared*) SHCALLOC( pool, 1, sizeof(FBDevShared) ); + if (!shared) { + ret = D_OOSHM(); + goto error; + } + + shared->shmpool = pool; + shared->shmpool_data = pool_data; + + fusion_arena_add_shared_field( dfb_core_arena( core ), "fbdev", shared ); + + dfb_fbdev->core = core; + dfb_fbdev->shared = shared; + + page_size = direct_pagesize(); + + shared->page_mask = page_size < 0 ? 0 : (page_size - 1); + + ret = dfb_fbdev_open(); + if (ret) + goto error; + + if (dfb_config->vt) { + ret = dfb_vt_initialize(); + if (ret) + goto error; + } + + ret = DFB_INIT; + + /* Retrieve fixed informations like video ram size */ + if (ioctl( dfb_fbdev->fd, FBIOGET_FSCREENINFO, &shared->fix ) < 0) { + D_PERROR( "DirectFB/FBDev: " + "Could not get fixed screen information!\n" ); + goto error; + } + + D_INFO( "DirectFB/FBDev: Found '%s' (ID %d) with frame buffer at 0x%08lx, %dk (MMIO 0x%08lx, %dk)\n", + shared->fix.id, shared->fix.accel, + shared->fix.smem_start, shared->fix.smem_len >> 10, + shared->fix.mmio_start, shared->fix.mmio_len >> 10 ); + + /* Map the framebuffer */ + dfb_fbdev->framebuffer_base = mmap( NULL, shared->fix.smem_len, + PROT_READ | PROT_WRITE, MAP_SHARED, + dfb_fbdev->fd, 0 ); + if (dfb_fbdev->framebuffer_base == MAP_FAILED) { + D_PERROR( "DirectFB/FBDev: " + "Could not mmap the framebuffer!\n"); + dfb_fbdev->framebuffer_base = NULL; + goto error; + } + + if (ioctl( dfb_fbdev->fd, FBIOGET_VSCREENINFO, &shared->orig_var ) < 0) { + D_PERROR( "DirectFB/FBDev: " + "Could not get variable screen information!\n" ); + goto error; + } + + shared->current_var = shared->orig_var; + shared->current_var.accel_flags = 0; + + if (ioctl( dfb_fbdev->fd, FBIOPUT_VSCREENINFO, &shared->current_var ) < 0) { + D_PERROR( "DirectFB/FBDev: " + "Could not disable console acceleration!\n" ); + goto error; + } + + dfb_fbdev_var_to_mode( &shared->current_var, + &shared->current_mode ); + + shared->orig_cmap_memory = SHMALLOC( pool_data, 256 * 2 * 4 ); + if (!shared->orig_cmap_memory) { + ret = D_OOSHM(); + goto error; + } + + shared->orig_cmap.start = 0; + shared->orig_cmap.len = 256; + shared->orig_cmap.red = shared->orig_cmap_memory + 256 * 2 * 0; + shared->orig_cmap.green = shared->orig_cmap_memory + 256 * 2 * 1; + shared->orig_cmap.blue = shared->orig_cmap_memory + 256 * 2 * 2; + shared->orig_cmap.transp = shared->orig_cmap_memory + 256 * 2 * 3; + + if (ioctl( dfb_fbdev->fd, FBIOGETCMAP, &shared->orig_cmap ) < 0) { + D_DEBUG( "DirectFB/FBDev: " + "Could not retrieve palette for backup!\n" ); + + memset( &shared->orig_cmap, 0, sizeof(shared->orig_cmap) ); + + SHFREE( pool_data, shared->orig_cmap_memory ); + shared->orig_cmap_memory = NULL; + } + + shared->temp_cmap_memory = SHMALLOC( pool_data, 256 * 2 * 4 ); + if (!shared->temp_cmap_memory) { + ret = D_OOSHM(); + goto error; + } + + shared->temp_cmap.start = 0; + shared->temp_cmap.len = 256; + shared->temp_cmap.red = shared->temp_cmap_memory + 256 * 2 * 0; + shared->temp_cmap.green = shared->temp_cmap_memory + 256 * 2 * 1; + shared->temp_cmap.blue = shared->temp_cmap_memory + 256 * 2 * 2; + shared->temp_cmap.transp = shared->temp_cmap_memory + 256 * 2 * 3; + + shared->current_cmap_memory = SHMALLOC( pool_data, 256 * 2 * 4 ); + if (!shared->current_cmap_memory) { + ret = D_OOSHM(); + goto error; + } + + shared->current_cmap.start = 0; + shared->current_cmap.len = 256; + shared->current_cmap.red = shared->current_cmap_memory + 256 * 2 * 0; + shared->current_cmap.green = shared->current_cmap_memory + 256 * 2 * 1; + shared->current_cmap.blue = shared->current_cmap_memory + 256 * 2 * 2; + shared->current_cmap.transp = shared->current_cmap_memory + 256 * 2 * 3; + + dfb_fbdev_get_pci_info( shared ); + + if (dfb_config->agp) { + /* Do not fail here, AGP slot could be unavailable */ + ret = dfb_agp_initialize(); + if (ret) { + D_DEBUG( "DirectFB/FBDev: dfb_agp_initialize()\n\t->%s\n", + DirectFBErrorString( ret ) ); + ret = DFB_OK; + } + } + + fusion_call_init( &shared->fbdev_ioctl, + fbdev_ioctl_call_handler, NULL, dfb_core_world(core) ); + + dfb_surface_pool_initialize( core, &fbdevSurfacePoolFuncs, &dfb_fbdev->shared->pool ); + + /* Register primary screen functions */ + screen = dfb_screens_register( NULL, NULL, &primaryScreenFuncs ); + + /* Register primary layer functions */ + dfb_layers_register( screen, NULL, &primaryLayerFuncs ); + + *data = dfb_fbdev; + + return DFB_OK; + + +error: + if (shared) { + if (shared->orig_cmap_memory) + SHFREE( pool_data, shared->orig_cmap_memory ); + + if (shared->temp_cmap_memory) + SHFREE( pool_data, shared->temp_cmap_memory ); + + if (shared->current_cmap_memory) + SHFREE( pool_data, shared->current_cmap_memory ); + + SHFREE( pool, shared ); + } + + if (dfb_fbdev->framebuffer_base) + munmap( dfb_fbdev->framebuffer_base, shared->fix.smem_len ); + + if (dfb_fbdev->fd != -1) + close( dfb_fbdev->fd ); + + D_FREE( dfb_fbdev ); + dfb_fbdev = NULL; + + return ret; +} + +static DFBResult +system_join( CoreDFB *core, void **data ) +{ + DFBResult ret; + CoreScreen *screen; + void *shared; + + D_ASSERT( dfb_fbdev == NULL ); + + if (dfb_config->vt) { + ret = dfb_vt_join(); + if (ret) + return ret; + } + + dfb_fbdev = D_CALLOC( 1, sizeof(FBDev) ); + if (!dfb_fbdev) + return D_OOM(); + + fusion_arena_get_shared_field( dfb_core_arena( core ), + "fbdev", &shared ); + + dfb_fbdev->core = core; + dfb_fbdev->shared = shared; + + /* Open framebuffer device */ + ret = dfb_fbdev_open(); + if (ret) { + D_FREE( dfb_fbdev ); + dfb_fbdev = NULL; + return ret; + } + + /* Map the framebuffer */ + dfb_fbdev->framebuffer_base = mmap( NULL, dfb_fbdev->shared->fix.smem_len, + PROT_READ | PROT_WRITE, MAP_SHARED, + dfb_fbdev->fd, 0 ); + if (dfb_fbdev->framebuffer_base == MAP_FAILED) { + D_PERROR( "DirectFB/FBDev: " + "Could not mmap the framebuffer!\n"); + close( dfb_fbdev->fd ); + D_FREE( dfb_fbdev ); + dfb_fbdev = NULL; + + return DFB_INIT; + } + + /* Open AGP device */ + ret = dfb_agp_join(); + if (ret) { + D_ERROR( "DirectFB/FBDev: Could not join AGP!\n" ); + munmap( dfb_fbdev->framebuffer_base, + dfb_fbdev->shared->fix.smem_len ); + close( dfb_fbdev->fd ); + D_FREE( dfb_fbdev ); + dfb_fbdev = NULL; + + return ret; + } + + dfb_surface_pool_join( core, dfb_fbdev->shared->pool, &fbdevSurfacePoolFuncs ); + + /* Register primary screen functions */ + screen = dfb_screens_register( NULL, NULL, &primaryScreenFuncs ); + + /* Register primary layer functions */ + dfb_layers_register( screen, NULL, &primaryLayerFuncs ); + + *data = dfb_fbdev; + + return DFB_OK; +} + +static DFBResult +system_shutdown( bool emergency ) +{ + DFBResult ret; + VideoMode *m; + FBDevShared *shared; + FusionSHMPoolShared *pool; + + D_ASSERT( dfb_fbdev != NULL ); + + shared = dfb_fbdev->shared; + + D_ASSERT( shared != NULL ); + + pool = shared->shmpool; + + D_ASSERT( pool != NULL ); + + m = shared->modes; + while (m) { + VideoMode *next = m->next; + SHFREE( pool, m ); + m = next; + } + + if (ioctl( dfb_fbdev->fd, FBIOPUT_VSCREENINFO, &shared->orig_var ) < 0) { + D_PERROR( "DirectFB/FBDev: " + "Could not restore variable screen information!\n" ); + } + + if (shared->orig_cmap.len) { + if (ioctl( dfb_fbdev->fd, FBIOPUTCMAP, &shared->orig_cmap ) < 0) + D_DEBUG( "DirectFB/FBDev: " + "Could not restore palette!\n" ); + } + + if (shared->orig_cmap_memory) + SHFREE( shared->shmpool_data, shared->orig_cmap_memory ); + + if (shared->temp_cmap_memory) + SHFREE( shared->shmpool_data, shared->temp_cmap_memory ); + + if (shared->current_cmap_memory) + SHFREE( shared->shmpool_data, shared->current_cmap_memory ); + + fusion_call_destroy( &shared->fbdev_ioctl ); + + dfb_agp_shutdown(); + + dfb_surface_pool_destroy( dfb_fbdev->shared->pool ); + + munmap( dfb_fbdev->framebuffer_base, shared->fix.smem_len ); + + if (dfb_config->vt) { + ret = dfb_vt_shutdown( emergency ); + if (ret) + return ret; + } + + close( dfb_fbdev->fd ); + + SHFREE( pool, shared ); + D_FREE( dfb_fbdev ); + dfb_fbdev = NULL; + + return DFB_OK; +} + +static DFBResult +system_leave( bool emergency ) +{ + DFBResult ret; + + D_ASSERT( dfb_fbdev != NULL ); + + dfb_agp_leave(); + + dfb_surface_pool_leave( dfb_fbdev->shared->pool ); + + munmap( dfb_fbdev->framebuffer_base, + dfb_fbdev->shared->fix.smem_len ); + + if (dfb_config->vt) { + ret = dfb_vt_leave( emergency ); + if (ret) + return ret; + } + + close( dfb_fbdev->fd ); + + D_FREE( dfb_fbdev ); + dfb_fbdev = NULL; + + return DFB_OK; +} + +static DFBResult +system_suspend( void ) +{ + return DFB_OK; +} + +static DFBResult +system_resume( void ) +{ + return DFB_OK; +} + +/******************************************************************************/ + +static volatile void * +system_map_mmio( unsigned int offset, + int length ) +{ + void *addr; + + if (length <= 0) + length = dfb_fbdev->shared->fix.mmio_len; + + addr = mmap( NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, + dfb_fbdev->fd, dfb_fbdev->shared->fix.smem_len + offset ); + if (addr == MAP_FAILED) { + D_PERROR( "DirectFB/FBDev: Could not mmap MMIO region " + "(offset %d, length %d)!\n", offset, length ); + return NULL; + } + + return(volatile void*) ((u8*) addr + (dfb_fbdev->shared->fix.mmio_start & + dfb_fbdev->shared->page_mask)); +} + +static void +system_unmap_mmio( volatile void *addr, + int length ) +{ + if (length <= 0) + length = dfb_fbdev->shared->fix.mmio_len; + + if (munmap( (void*) ((u8*) addr - (dfb_fbdev->shared->fix.mmio_start & + dfb_fbdev->shared->page_mask)), length ) < 0) + D_PERROR( "DirectFB/FBDev: Could not unmap MMIO region " + "at %p (length %d)!\n", addr, length ); +} + +static int +system_get_accelerator( void ) +{ +#ifdef FB_ACCEL_MATROX_MGAG400 + if (!strcmp( dfb_fbdev->shared->fix.id, "MATROX DH" )) + return FB_ACCEL_MATROX_MGAG400; +#endif +#ifdef FB_ACCEL_EP9X + if (!strcmp( dfb_fbdev->shared->fix.id, "ep9xfb" )) + return FB_ACCEL_EP9X; +#endif + + if (dfb_config->accelerator) + return dfb_config->accelerator; + + if (dfb_fbdev->shared->fix.mmio_len > 0) + return dfb_fbdev->shared->fix.accel; + return -1; +} + +static VideoMode * +system_get_modes( void ) +{ + return dfb_fbdev->shared->modes; +} + +static VideoMode * +system_get_current_mode( void ) +{ + return &dfb_fbdev->shared->current_mode; +} + +static DFBResult +system_thread_init( void ) +{ + if (dfb_config->block_all_signals) + direct_signals_block_all(); + + return DFB_OK; +} + +static bool +system_input_filter( CoreInputDevice *device, + DFBInputEvent *event ) +{ + if (dfb_config->vt && dfb_config->vt_switching) { + switch (event->type) { + case DIET_KEYPRESS: + if (DFB_KEY_TYPE(event->key_symbol) == DIKT_FUNCTION && + event->modifiers == (DIMM_CONTROL | DIMM_ALT)) + return dfb_vt_switch( event->key_symbol - DIKS_F1 + 1 ); + + break; + + case DIET_KEYRELEASE: + if (DFB_KEY_TYPE(event->key_symbol) == DIKT_FUNCTION && + event->modifiers == (DIMM_CONTROL | DIMM_ALT)) + return true; + + break; + + default: + break; + } + } + + return false; +} + +static unsigned long +system_video_memory_physical( unsigned int offset ) +{ + return dfb_fbdev->shared->fix.smem_start + offset; +} + +static void * +system_video_memory_virtual( unsigned int offset ) +{ + return(void*)((u8*)(dfb_fbdev->framebuffer_base) + offset); +} + +static unsigned int +system_videoram_length( void ) +{ + return dfb_fbdev->shared->fix.smem_len; +} + +static unsigned long +system_aux_memory_physical( unsigned int offset ) +{ + if (dfb_fbdev->shared->agp) + return dfb_fbdev->shared->agp->info.aper_base + offset; + return 0; +} + +static void * +system_aux_memory_virtual( unsigned int offset ) +{ + if (dfb_fbdev->agp) + return (void*)(u8*)dfb_fbdev->agp->base + offset; + return NULL; +} + +static unsigned int +system_auxram_length( void ) +{ + if (dfb_fbdev->shared->agp) + return dfb_fbdev->shared->agp->agp_mem; + return 0; +} + +static void +system_get_busid( int *ret_bus, int *ret_dev, int *ret_func ) +{ + *ret_bus = dfb_fbdev->shared->pci.bus; + *ret_dev = dfb_fbdev->shared->pci.dev; + *ret_func = dfb_fbdev->shared->pci.func; +} + +static void +system_get_deviceid( unsigned int *ret_vendor_id, + unsigned int *ret_device_id ) +{ + *ret_vendor_id = dfb_fbdev->shared->device.vendor; + *ret_device_id = dfb_fbdev->shared->device.model; +} + +/******************************************************************************/ + +static DFBResult +init_modes( void ) +{ + dfb_fbdev_read_modes(); + + if (!dfb_fbdev->shared->modes) { + /* try to use current mode*/ + dfb_fbdev->shared->modes = (VideoMode*) SHCALLOC( dfb_fbdev->shared->shmpool, + 1, sizeof(VideoMode) ); + if (!dfb_fbdev->shared->modes) + return D_OOSHM(); + + *dfb_fbdev->shared->modes = dfb_fbdev->shared->current_mode; + + if (dfb_fbdev_test_mode_simple(dfb_fbdev->shared->modes)) { + D_ERROR("DirectFB/FBDev: " + "No supported modes found in /etc/fb.modes and " + "current mode not supported!\n"); + + D_ERROR( "DirectFB/FBDev: Current mode's pixelformat: " + "rgba %d/%d, %d/%d, %d/%d, %d/%d (%dbit)\n", + dfb_fbdev->shared->orig_var.red.length, + dfb_fbdev->shared->orig_var.red.offset, + dfb_fbdev->shared->orig_var.green.length, + dfb_fbdev->shared->orig_var.green.offset, + dfb_fbdev->shared->orig_var.blue.length, + dfb_fbdev->shared->orig_var.blue.offset, + dfb_fbdev->shared->orig_var.transp.length, + dfb_fbdev->shared->orig_var.transp.offset, + dfb_fbdev->shared->orig_var.bits_per_pixel ); + + return DFB_INIT; + } + } + + return DFB_OK; +} + +/******************************************************************************/ + +static DFBResult +primaryInitScreen( CoreScreen *screen, + CoreGraphicsDevice *device, + void *driver_data, + void *screen_data, + DFBScreenDescription *description ) +{ + /* Set the screen capabilities. */ + description->caps = DSCCAPS_VSYNC | DSCCAPS_POWER_MANAGEMENT; + + /* Set the screen name. */ + snprintf( description->name, + DFB_SCREEN_DESC_NAME_LENGTH, "FBDev Primary Screen" ); + + return DFB_OK; +} + +static DFBResult +primarySetPowerMode( CoreScreen *screen, + void *driver_data, + void *screen_data, + DFBScreenPowerMode mode ) +{ + int level; + + switch (mode) { + case DSPM_OFF: + level = 4; + break; + case DSPM_SUSPEND: + level = 3; + break; + case DSPM_STANDBY: + level = 2; + break; + case DSPM_ON: + level = 0; + break; + default: + return DFB_INVARG; + } + + return dfb_fbdev_blank( level ); +} + +static DFBResult +primaryWaitVSync( CoreScreen *screen, + void *driver_data, + void *screen_data ) +{ + static const int zero = 0; + + if (dfb_config->pollvsync_none) + return DFB_OK; + + if (ioctl( dfb_fbdev->fd, FBIO_WAITFORVSYNC, &zero )) + waitretrace(); + + return DFB_OK; +} + +static DFBResult +primaryGetScreenSize( CoreScreen *screen, + void *driver_data, + void *screen_data, + int *ret_width, + int *ret_height ) +{ + D_ASSERT( dfb_fbdev != NULL ); + D_ASSERT( dfb_fbdev->shared != NULL ); + + *ret_width = dfb_fbdev->shared->current_mode.xres; + *ret_height = dfb_fbdev->shared->current_mode.yres; + + return DFB_OK; +} + +/******************************************************************************/ + +static int +primaryLayerDataSize( void ) +{ + return 0; +} + +static int +primaryRegionDataSize( void ) +{ + return 0; +} + +static DFBResult +primaryInitLayer( CoreLayer *layer, + void *driver_data, + void *layer_data, + DFBDisplayLayerDescription *description, + DFBDisplayLayerConfig *config, + DFBColorAdjustment *adjustment ) +{ + DFBResult ret; + VideoMode *default_mode; + + /* initialize mode table */ + ret = init_modes(); + if (ret) + return ret; + + default_mode = dfb_fbdev->shared->modes; + + /* set capabilities and type */ + description->caps = DLCAPS_SURFACE | DLCAPS_CONTRAST | + DLCAPS_SATURATION | DLCAPS_BRIGHTNESS; + description->type = DLTF_GRAPHICS; + + /* set name */ + snprintf( description->name, + DFB_DISPLAY_LAYER_DESC_NAME_LENGTH, "FBDev Primary Layer" ); + + /* fill out default color adjustment */ + adjustment->flags = DCAF_BRIGHTNESS | DCAF_CONTRAST | DCAF_SATURATION; + adjustment->brightness = 0x8000; + adjustment->contrast = 0x8000; + adjustment->saturation = 0x8000; + + /* fill out the default configuration */ + config->flags = DLCONF_WIDTH | DLCONF_HEIGHT | + DLCONF_PIXELFORMAT | DLCONF_BUFFERMODE; + config->buffermode = DLBM_FRONTONLY; + config->width = dfb_config->mode.width ? dfb_config->mode.width : default_mode->xres; + config->height = dfb_config->mode.height ? dfb_config->mode.height : default_mode->yres; + + if (dfb_config->mode.format) + config->pixelformat = dfb_config->mode.format; + else + config->pixelformat = dfb_pixelformat_for_depth( default_mode->bpp ); + + return DFB_OK; +} + +static DFBResult +primarySetColorAdjustment( CoreLayer *layer, + void *driver_data, + void *layer_data, + DFBColorAdjustment *adjustment ) +{ + struct fb_cmap *cmap = &dfb_fbdev->shared->current_cmap; + struct fb_cmap *temp = &dfb_fbdev->shared->temp_cmap; + int contrast = adjustment->contrast >> 8; + int brightness = (adjustment->brightness >> 8) - 128; + int saturation = adjustment->saturation >> 8; + int r, g, b, i; + + if (dfb_fbdev->shared->fix.visual != FB_VISUAL_DIRECTCOLOR) + return DFB_UNIMPLEMENTED; + + /* Use gamma ramp to set color attributes */ + for (i = 0; i < (int)cmap->len; i++) { + r = cmap->red[i]; + g = cmap->green[i]; + b = cmap->blue[i]; + r >>= 8; + g >>= 8; + b >>= 8; + + /* + * Brightness Adjustment: Increase/Decrease each color channels + * by a constant amount as specified by value of brightness. + */ + if (adjustment->flags & DCAF_BRIGHTNESS) { + r += brightness; + g += brightness; + b += brightness; + + r = CLAMP( r, 0, 255 ); + g = CLAMP( g, 0, 255 ); + b = CLAMP( b, 0, 255 ); + } + + /* + * Contrast Adjustment: We increase/decrease the "separation" + * between colors in proportion to the value specified by the + * contrast control. Decreasing the contrast has a side effect + * of decreasing the brightness. + */ + + if (adjustment->flags & DCAF_CONTRAST) { + /* Increase contrast */ + if (contrast > 128) { + int c = contrast - 128; + + r = ((r + c/2)/c) * c; + g = ((g + c/2)/c) * c; + b = ((b + c/2)/c) * c; + } + /* Decrease contrast */ + else if (contrast < 127) { + r = (r * contrast) >> 7; + g = (g * contrast) >> 7; + b = (b * contrast) >> 7; + } + + r = CLAMP( r, 0, 255 ); + g = CLAMP( g, 0, 255 ); + b = CLAMP( b, 0, 255 ); + } + + /* + * Saturation Adjustment: This is is a better implementation. + * Saturation is implemented by "mixing" a proportion of medium + * gray to the color value. On the other side, "removing" + * a proportion of medium gray oversaturates the color. + */ + if (adjustment->flags & DCAF_SATURATION) { + if (saturation > 128) { + int gray = saturation - 128; + int color = 128 - gray; + + r = ((r - gray) << 7) / color; + g = ((g - gray) << 7) / color; + b = ((b - gray) << 7) / color; + } + else if (saturation < 128) { + int color = saturation; + int gray = 128 - color; + + r = ((r * color) >> 7) + gray; + g = ((g * color) >> 7) + gray; + b = ((b * color) >> 7) + gray; + } + + r = CLAMP( r, 0, 255 ); + g = CLAMP( g, 0, 255 ); + b = CLAMP( b, 0, 255 ); + } + r |= r << 8; + g |= g << 8; + b |= b << 8; + + temp->red[i] = (unsigned short)r; + temp->green[i] = (unsigned short)g; + temp->blue[i] = (unsigned short)b; + } + + temp->len = cmap->len; + temp->start = cmap->start; + if (FBDEV_IOCTL( FBIOPUTCMAP, temp ) < 0) { + D_PERROR( "DirectFB/FBDev: Could not set the palette!\n" ); + + return errno2result(errno); + } + + return DFB_OK; +} + +const VideoMode * +dfb_fbdev_find_mode( int width, int height ) +{ + FBDevShared *shared = dfb_fbdev->shared; + const VideoMode *videomode = shared->modes; + const VideoMode *highest = NULL; + + while (videomode) { + if (videomode->xres == width && videomode->yres == height) { + if (!highest || highest->priority < videomode->priority) + highest = videomode; + } + + videomode = videomode->next; + } + + if (!highest) + D_ERROR( "FBDev/Mode: No mode found for %dx%d!\n", width, height ); + + return highest; +} + +static DFBResult +primaryTestRegion( CoreLayer *layer, + void *driver_data, + void *layer_data, + CoreLayerRegionConfig *config, + CoreLayerRegionConfigFlags *failed ) +{ + FBDevShared *shared = dfb_fbdev->shared; + CoreLayerRegionConfigFlags fail = CLRCF_NONE; + const VideoMode *mode; + + D_DEBUG_AT( FBDev_Mode, "%s( %dx%d, %s )\n", __FUNCTION__, + config->source.w, config->source.h, dfb_pixelformat_name(config->format) ); + + mode = dfb_fbdev_find_mode( config->source.w, config->source.h ); + + if (!mode || dfb_fbdev_test_mode( mode, config )) + fail |= CLRCF_WIDTH | CLRCF_HEIGHT | CLRCF_FORMAT | CLRCF_BUFFERMODE; + + if (config->options) + fail |= CLRCF_OPTIONS; + + if ((config->source.x && !shared->fix.xpanstep) || + (config->source.y && !shared->fix.ypanstep && !shared->fix.ywrapstep)) + fail |= CLRCF_SOURCE; + + if (failed) + *failed = fail; + + if (fail) + return DFB_UNSUPPORTED; + + return DFB_OK; +} + +static DFBResult +primaryAddRegion( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data, + CoreLayerRegionConfig *config ) +{ + return DFB_OK; +} + +static DFBResult +primarySetRegion( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data, + CoreLayerRegionConfig *config, + CoreLayerRegionConfigFlags updated, + CoreSurface *surface, + CorePalette *palette, + CoreSurfaceBufferLock *lock ) +{ + DFBResult ret; + FBDevShared *shared = dfb_fbdev->shared; + + if (updated & CLRCF_SOURCE) { + if (config->source.w == shared->current_var.xres && config->source.h == shared->current_var.yres) { + ret = dfb_fbdev_pan( config->source.x, lock->offset / lock->pitch + config->source.y, true ); + if (ret) + return ret; + } + else { + const VideoMode *mode; + + D_INFO( "FBDev/Mode: Setting %dx%d %s\n", config->source.w, config->source.h, + dfb_pixelformat_name( surface->config.format ) ); + + mode = dfb_fbdev_find_mode( config->source.w, config->source.h ); + if (!mode) + return DFB_UNSUPPORTED; + + ret = dfb_fbdev_set_mode( mode, surface, config->source.x, + lock->offset / lock->pitch + config->source.y ); + if (ret) + return ret; + } + } + + if ((updated & CLRCF_PALETTE) && palette) + dfb_fbdev_set_palette( palette ); + + /* remember configuration */ + shared->config = *config; + + return DFB_OK; +} + +static DFBResult +primaryRemoveRegion( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data ) +{ + return DFB_OK; +} + +static DFBResult +primaryFlipRegion( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data, + CoreSurface *surface, + DFBSurfaceFlipFlags flags, + CoreSurfaceBufferLock *lock ) +{ + DFBResult ret; + CoreLayerRegionConfig *config = &dfb_fbdev->shared->config; + + if (((flags & DSFLIP_WAITFORSYNC) == DSFLIP_WAITFORSYNC) && + !dfb_config->pollvsync_after) + dfb_screen_wait_vsync( dfb_screens_at(DSCID_PRIMARY) ); + + ret = dfb_fbdev_pan( config->source.x, + lock->offset / lock->pitch + config->source.y, + (flags & DSFLIP_WAITFORSYNC) == DSFLIP_ONSYNC ); + if (ret) + return ret; + + if ((flags & DSFLIP_WAIT) && + (dfb_config->pollvsync_after || !(flags & DSFLIP_ONSYNC))) + dfb_screen_wait_vsync( dfb_screens_at(DSCID_PRIMARY) ); + + dfb_surface_flip( surface, false ); + + return DFB_OK; +} + +/** fbdev internal **/ + +static void +dfb_fbdev_var_to_mode( const struct fb_var_screeninfo *var, + VideoMode *mode ) +{ + mode->xres = var->xres; + mode->yres = var->yres; + mode->bpp = var->bits_per_pixel; + mode->hsync_len = var->hsync_len; + mode->vsync_len = var->vsync_len; + mode->left_margin = var->left_margin; + mode->right_margin = var->right_margin; + mode->upper_margin = var->upper_margin; + mode->lower_margin = var->lower_margin; + mode->pixclock = var->pixclock; + mode->hsync_high = (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 1 : 0; + mode->vsync_high = (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 1 : 0; + mode->csync_high = (var->sync & FB_SYNC_COMP_HIGH_ACT) ? 1 : 0; + mode->sync_on_green = (var->sync & FB_SYNC_ON_GREEN) ? 1 : 0; + mode->external_sync = (var->sync & FB_SYNC_EXT) ? 1 : 0; + mode->broadcast = (var->sync & FB_SYNC_BROADCAST) ? 1 : 0; + mode->laced = (var->vmode & FB_VMODE_INTERLACED) ? 1 : 0; + mode->doubled = (var->vmode & FB_VMODE_DOUBLE) ? 1 : 0; +} + +#if 0 +static int dfb_fbdev_compatible_format( struct fb_var_screeninfo *var, + int al, int rl, int gl, int bl, + int ao, int ro, int go, int bo ) +{ + int ah, rh, gh, bh; + int vah, vrh, vgh, vbh; + + ah = al + ao - 1; + rh = rl + ro - 1; + gh = gl + go - 1; + bh = bl + bo - 1; + + vah = var->transp.length + var->transp.offset - 1; + vrh = var->red.length + var->red.offset - 1; + vgh = var->green.length + var->green.offset - 1; + vbh = var->blue.length + var->blue.offset - 1; + + if ((!al || (ah == vah && al >= (int)var->transp.length)) && + (!rl || (rh == vrh && rl >= (int)var->red.length)) && + (!gl || (gh == vgh && gl >= (int)var->green.length)) && + (!bl || (bh == vbh && bl >= (int)var->blue.length))) + return 1; + + return 0; +} + +static DFBSurfacePixelFormat dfb_fbdev_get_pixelformat( struct fb_var_screeninfo *var ) +{ + switch (var->bits_per_pixel) { + + case 8: +/* + This check is omitted, since we want to use RGB332 even if the + hardware uses a palette (in that case we initialize a calculated + one to have correct colors) + + if (fbdev_compatible_format( var, 0, 3, 3, 2, 0, 5, 2, 0 ))*/ + + return DSPF_RGB332; + + case 15: + if (dfb_fbdev_compatible_format( var, 0, 5, 5, 5, 0, 10, 5, 0 )) + return DSPF_RGB555; + + if(dfb_fbdev_compatible_format( var, 1, 5, 5, 5, 15, 10, 5, 0 )) + return DSPF_ARGB1555; + + if (dfb_fbdev_compatible_format( var, 0, 5, 5, 5, 0, 0, 5, 10 )) + return DSPF_BGR555; + + break; + + case 16: + if (dfb_fbdev_compatible_format( var, 0, 5, 5, 5, 0, 10, 5, 0 )) + return DSPF_RGB555; + + if(dfb_fbdev_compatible_format( var, 1, 5, 5, 5, 15, 10, 5, 0 )) + return DSPF_ARGB1555; + + if (dfb_fbdev_compatible_format( var, 4, 4, 4, 4, 12, 8, 4, 0 )) + return DSPF_ARGB4444; + + if (dfb_fbdev_compatible_format( var, 4, 4, 4, 4, 0, 12, 8, 4 )) + return DSPF_RGBA4444; + + if (dfb_fbdev_compatible_format( var, 0, 4, 4, 4, 0, 8, 4, 0 )) + return DSPF_RGB444; + + if (dfb_fbdev_compatible_format( var, 0, 5, 6, 5, 0, 11, 5, 0 )) + return DSPF_RGB16; + + if (dfb_fbdev_compatible_format( var, 0, 5, 5, 5, 0, 0, 5, 10 )) + return DSPF_BGR555; + + break; + + case 18: + if (dfb_fbdev_compatible_format( var, 1, 6, 6, 6, 18, 12, 6, 0 )) + return DSPF_ARGB1666; + + if (dfb_fbdev_compatible_format( var, 6, 6, 6, 6, 18, 12, 6, 0 )) + return DSPF_ARGB6666; + + if (dfb_fbdev_compatible_format( var, 0, 6, 6, 6, 0, 12, 6, 0 )) + return DSPF_RGB18; + break; + + case 24: + if (dfb_fbdev_compatible_format( var, 0, 8, 8, 8, 0, 16, 8, 0 )) + return DSPF_RGB24; + + if (dfb_fbdev_compatible_format( var, 6, 6, 6, 6, 18, 12, 6, 0 )) + return DSPF_ARGB6666; + break; + + case 32: + if (dfb_fbdev_compatible_format( var, 0, 8, 8, 8, 0, 16, 8, 0 )) + return DSPF_RGB32; + + if (dfb_fbdev_compatible_format( var, 8, 8, 8, 8, 24, 16, 8, 0 )) + return DSPF_ARGB; + + break; + } + + D_ERROR( "DirectFB/FBDev: Unsupported pixelformat: " + "rgba %d/%d, %d/%d, %d/%d, %d/%d (%dbit)\n", + var->red.length, var->red.offset, + var->green.length, var->green.offset, + var->blue.length, var->blue.offset, + var->transp.length, var->transp.offset, + var->bits_per_pixel ); + + return DSPF_UNKNOWN; +} +#endif + +/* + * pans display (flips buffer) using fbdev ioctl + */ +static DFBResult +dfb_fbdev_pan( int xoffset, int yoffset, bool onsync ) +{ +// DFBResult ret; + int result; + struct fb_var_screeninfo *var; + FBDevShared *shared = dfb_fbdev->shared; + + if (!shared->fix.xpanstep && !shared->fix.ypanstep && !shared->fix.ywrapstep) + return DFB_OK; + + var = &shared->current_var; + + if (var->xres_virtual < xoffset + var->xres) { + D_ERROR( "DirectFB/FBDev: xres %d, vxres %d, xoffset %d\n", + var->xres, var->xres_virtual, xoffset ); + D_BUG( "panning buffer out of range" ); + return DFB_BUG; + } + + if (var->yres_virtual < yoffset + var->yres) { + D_ERROR( "DirectFB/FBDev: yres %d, vyres %d, offset %d\n", + var->yres, var->yres_virtual, yoffset ); + D_BUG( "panning buffer out of range" ); + return DFB_BUG; + } + + if (shared->fix.xpanstep) + var->xoffset = xoffset - (xoffset % shared->fix.xpanstep); + else + var->xoffset = 0; + + if (shared->fix.ywrapstep) { + var->yoffset = yoffset - (yoffset % shared->fix.ywrapstep); + var->vmode |= FB_VMODE_YWRAP; + } + else if (shared->fix.ypanstep) { + var->yoffset = yoffset - (yoffset % shared->fix.ypanstep); + var->vmode &= ~FB_VMODE_YWRAP; + } + else { + var->yoffset = 0; + } + + var->activate = onsync ? FB_ACTIVATE_VBL : FB_ACTIVATE_NOW; + +#if 0 + ret = fusion_call_execute( &shared->fbdev_ioctl, FCEF_NONE, FBIOPAN_DISPLAY, var, &result ); + if (ret) + return DFB_FUSION; + + if (result) { + errno = result; +#else + if (ioctl( dfb_fbdev->fd, FBIOPAN_DISPLAY, var ) < 0) { + result = errno; +#endif + D_PERROR( "DirectFB/FBDev: Panning display failed (x=%u y=%u ywrap=%d vbl=%d)!\n", + var->xoffset, var->yoffset, + (var->vmode & FB_VMODE_YWRAP) ? 1 : 0, + (var->activate & FB_ACTIVATE_VBL) ? 1 : 0); + + return errno2result(result); + } + + return DFB_OK; +} + +/* + * blanks display using fbdev ioctl + */ +static DFBResult +dfb_fbdev_blank( int level ) +{ + if (ioctl( dfb_fbdev->fd, FBIOBLANK, level ) < 0) { + D_PERROR( "DirectFB/FBDev: Display blanking failed!\n" ); + + return errno2result( errno ); + } + + return DFB_OK; +} + +static DFBResult +dfb_fbdev_mode_to_var( const VideoMode *mode, + DFBSurfacePixelFormat pixelformat, + unsigned int vxres, + unsigned int vyres, + unsigned int xoffset, + unsigned int yoffset, + DFBDisplayLayerBufferMode buffermode, + struct fb_var_screeninfo *ret_var ) +{ + struct fb_var_screeninfo var; + FBDevShared *shared = dfb_fbdev->shared; + + D_DEBUG_AT( FBDev_Mode, "%s( mode: %p )\n", __FUNCTION__, mode ); + + D_ASSERT( mode != NULL ); + D_ASSERT( ret_var != NULL ); + + D_DEBUG_AT( FBDev_Mode, " -> resolution %dx%d\n", mode->xres, mode->yres ); + D_DEBUG_AT( FBDev_Mode, " -> virtual %dx%d\n", vxres, vyres ); + D_DEBUG_AT( FBDev_Mode, " -> pixelformat %s\n", dfb_pixelformat_name(pixelformat) ); + D_DEBUG_AT( FBDev_Mode, " -> buffermode %s\n", + buffermode == DLBM_FRONTONLY ? "FRONTONLY" : + buffermode == DLBM_BACKVIDEO ? "BACKVIDEO" : + buffermode == DLBM_BACKSYSTEM ? "BACKSYSTEM" : + buffermode == DLBM_TRIPLE ? "TRIPLE" : "invalid!" ); + + /* Start from current information */ + var = shared->current_var; + var.activate = FB_ACTIVATE_NOW; + + /* Set timings */ + var.pixclock = mode->pixclock; + var.left_margin = mode->left_margin; + var.right_margin = mode->right_margin; + var.upper_margin = mode->upper_margin; + var.lower_margin = mode->lower_margin; + var.hsync_len = mode->hsync_len; + var.vsync_len = mode->vsync_len; + + /* Set resolution */ + var.xres = mode->xres; + var.yres = mode->yres; + var.xres_virtual = vxres; + var.yres_virtual = vyres; + + if (shared->fix.xpanstep) + var.xoffset = xoffset - (xoffset % shared->fix.xpanstep); + else + var.xoffset = 0; + + if (shared->fix.ywrapstep) + var.yoffset = yoffset - (yoffset % shared->fix.ywrapstep); + else if (shared->fix.ypanstep) + var.yoffset = yoffset - (yoffset % shared->fix.ypanstep); + else + var.yoffset = 0; + + /* Set buffer mode */ + switch (buffermode) { + case DLBM_TRIPLE: + if (shared->fix.ypanstep == 0 && shared->fix.ywrapstep == 0) + return DFB_UNSUPPORTED; + + var.yres_virtual *= 3; + break; + + case DLBM_BACKVIDEO: + if (shared->fix.ypanstep == 0 && shared->fix.ywrapstep == 0) + return DFB_UNSUPPORTED; + + var.yres_virtual *= 2; + break; + + case DLBM_BACKSYSTEM: + case DLBM_FRONTONLY: + break; + + default: + return DFB_UNSUPPORTED; + } + + /* Set pixel format */ + var.bits_per_pixel = DFB_BITS_PER_PIXEL(pixelformat); + var.transp.length = var.transp.offset = 0; + + switch (pixelformat) { + case DSPF_ARGB1555: + var.transp.length = 1; + var.red.length = 5; + var.green.length = 5; + var.blue.length = 5; + var.transp.offset = 15; + var.red.offset = 10; + var.green.offset = 5; + var.blue.offset = 0; + break; + + case DSPF_RGB555: + var.red.length = 5; + var.green.length = 5; + var.blue.length = 5; + var.red.offset = 10; + var.green.offset = 5; + var.blue.offset = 0; + break; + + case DSPF_ARGB4444: + var.transp.length = 4; + var.red.length = 4; + var.green.length = 4; + var.blue.length = 4; + var.transp.offset = 12; + var.red.offset = 8; + var.green.offset = 4; + var.blue.offset = 0; + break; + + case DSPF_RGBA4444: + var.transp.length = 4; + var.red.length = 4; + var.green.length = 4; + var.blue.length = 4; + var.transp.offset = 0; + var.red.offset = 12; + var.green.offset = 8; + var.blue.offset = 4; + break; + + case DSPF_RGB444: + var.red.length = 4; + var.green.length = 4; + var.blue.length = 4; + var.red.offset = 8; + var.green.offset = 4; + var.blue.offset = 0; + break; + + case DSPF_RGB32: + var.red.length = 8; + var.green.length = 8; + var.blue.length = 8; + var.red.offset = 16; + var.green.offset = 8; + var.blue.offset = 0; + break; + + case DSPF_RGB16: + var.red.length = 5; + var.green.length = 6; + var.blue.length = 5; + var.red.offset = 11; + var.green.offset = 5; + var.blue.offset = 0; + break; + + case DSPF_ARGB: + case DSPF_AiRGB: + var.transp.length = 8; + var.red.length = 8; + var.green.length = 8; + var.blue.length = 8; + var.transp.offset = 24; + var.red.offset = 16; + var.green.offset = 8; + var.blue.offset = 0; + break; + + case DSPF_LUT8: + case DSPF_RGB24: + case DSPF_RGB332: + break; + + case DSPF_ARGB1666: + var.transp.length = 1; + var.red.length = 6; + var.green.length = 6; + var.blue.length = 6; + var.transp.offset = 18; + var.red.offset = 12; + var.green.offset = 6; + var.blue.offset = 0; + break; + + case DSPF_ARGB6666: + var.transp.length = 6; + var.red.length = 6; + var.green.length = 6; + var.blue.length = 6; + var.transp.offset = 18; + var.red.offset = 12; + var.green.offset = 6; + var.blue.offset = 0; + break; + + case DSPF_RGB18: + var.red.length = 6; + var.green.length = 6; + var.blue.length = 6; + var.red.offset = 12; + var.green.offset = 6; + var.blue.offset = 0; + break; + + default: + return DFB_UNSUPPORTED; + } + + /* Set sync options */ + var.sync = 0; + if (mode->hsync_high) + var.sync |= FB_SYNC_HOR_HIGH_ACT; + if (mode->vsync_high) + var.sync |= FB_SYNC_VERT_HIGH_ACT; + if (mode->csync_high) + var.sync |= FB_SYNC_COMP_HIGH_ACT; + if (mode->sync_on_green) + var.sync |= FB_SYNC_ON_GREEN; + if (mode->external_sync) + var.sync |= FB_SYNC_EXT; + if (mode->broadcast) + var.sync |= FB_SYNC_BROADCAST; + + /* Set interlace/linedouble */ + var.vmode = 0; + if (mode->laced) + var.vmode |= FB_VMODE_INTERLACED; + if (mode->doubled) + var.vmode |= FB_VMODE_DOUBLE; + + *ret_var = var; + + return DFB_OK; +} + +DFBResult +dfb_fbdev_test_mode( const VideoMode *mode, + const CoreLayerRegionConfig *config ) +{ + DFBResult ret; + struct fb_var_screeninfo var; + FBDevShared *shared = dfb_fbdev->shared; + const DFBRectangle *source = &config->source; + + D_DEBUG_AT( FBDev_Mode, "%s( mode: %p, config: %p )\n", __FUNCTION__, mode, config ); + + D_ASSERT( mode != NULL ); + D_ASSERT( config != NULL ); + + /* Is panning supported? */ + if (source->w != mode->xres && shared->fix.xpanstep == 0) + return DFB_UNSUPPORTED; + if (source->h != mode->yres && shared->fix.ypanstep == 0 && shared->fix.ywrapstep == 0) + return DFB_UNSUPPORTED; + + ret = dfb_fbdev_mode_to_var( mode, config->format, config->width, config->height, + 0, 0, config->buffermode, &var ); + if (ret) + return ret; + + /* Enable test mode */ + var.activate = FB_ACTIVATE_TEST; + + + dfb_gfxcard_lock( GDLF_WAIT | GDLF_SYNC | GDLF_RESET | GDLF_INVALIDATE ); + + if (FBDEV_IOCTL( FBIOPUT_VSCREENINFO, &var ) < 0) { + int erno = errno; + dfb_gfxcard_unlock(); + D_DEBUG_AT( FBDev_Mode, " => FAILED!\n" ); + return errno2result( erno ); + } + + dfb_gfxcard_unlock(); + + D_DEBUG_AT( FBDev_Mode, " => SUCCESS\n" ); + + return DFB_OK; +} + +DFBResult +dfb_fbdev_test_mode_simple( const VideoMode *mode ) +{ + DFBResult ret; + struct fb_var_screeninfo var; + + D_DEBUG_AT( FBDev_Mode, "%s( mode: %p )\n", __FUNCTION__, mode ); + + D_ASSERT( mode != NULL ); + + ret = dfb_fbdev_mode_to_var( mode, dfb_pixelformat_for_depth(mode->bpp), mode->xres, mode->yres, + 0, 0, DLBM_FRONTONLY, &var ); + if (ret) + return ret; + + /* Enable test mode */ + var.activate = FB_ACTIVATE_TEST; + + if (FBDEV_IOCTL( FBIOPUT_VSCREENINFO, &var ) < 0) { + D_DEBUG_AT( FBDev_Mode, " => FAILED!\n" ); + return errno2result( errno ); + } + + D_DEBUG_AT( FBDev_Mode, " => SUCCESS\n" ); + + return DFB_OK; +} + +static int num_video_buffers( CoreSurface *surface ) +{ + int i; + + for (i = 0; i < surface->num_buffers; i++) { + if (surface->buffers[i]->policy == CSP_SYSTEMONLY) + break; + } + + return i; +} + +DFBResult +dfb_fbdev_set_mode( const VideoMode *mode, + CoreSurface *surface, + unsigned int xoffset, + unsigned int yoffset ) +{ + DFBResult ret; + struct fb_var_screeninfo var; + FBDevShared *shared = dfb_fbdev->shared; + DFBDisplayLayerBufferMode buffermode = DLBM_FRONTONLY; + const CoreSurfaceConfig *config = &surface->config ; + + D_DEBUG_AT( FBDev_Mode, "%s( mode: %p, config: %p )\n", __FUNCTION__, mode, config ); + + D_ASSERT( mode != NULL ); + D_ASSERT( config != NULL ); + + switch (num_video_buffers( surface )) { + case 3: + buffermode = DLBM_TRIPLE; + break; + case 2: + buffermode = DLBM_BACKVIDEO; + break; + case 1: + buffermode = DLBM_FRONTONLY; + break; + default: + D_BUG( "dfb_fbdev_set_mode() called with %d video buffers!", num_video_buffers( surface ) ); + return DFB_BUG; + } + + ret = dfb_fbdev_mode_to_var( mode, config->format, config->size.w, config->size.h, + xoffset, yoffset, buffermode, &var ); + if (ret) { + D_ERROR( "FBDev/Mode: Failed to switch to %dx%d %s (buffermode %d)\n", + config->size.w, config->size.h, dfb_pixelformat_name(config->format), buffermode ); + return ret; + } + + + dfb_gfxcard_lock( GDLF_WAIT | GDLF_SYNC | GDLF_RESET | GDLF_INVALIDATE ); + + if (FBDEV_IOCTL( FBIOPUT_VSCREENINFO, &var ) < 0) { + int erno = errno; + + dfb_gfxcard_unlock(); + + D_DEBUG_AT( FBDev_Mode, " => FAILED!\n" ); + + D_ERROR( "FBDev/Mode: Failed to switched to %dx%d (virtual %dx%d) at %d bit (%s)!\n", + var.xres, var.yres, var.xres_virtual, var.yres_virtual, var.bits_per_pixel, + dfb_pixelformat_name(config->format) ); + + return errno2result( erno ); + } + + D_DEBUG_AT( FBDev_Mode, " => SUCCESS\n" ); + + shared->current_var = var; + dfb_fbdev_var_to_mode( &var, &shared->current_mode ); + + /* To get the new pitch */ + FBDEV_IOCTL( FBIOGET_FSCREENINFO, &shared->fix ); + + D_INFO( "FBDev/Mode: Switched to %dx%d (virtual %dx%d) at %d bit (%s), pitch %d\n", + var.xres, var.yres, var.xres_virtual, var.yres_virtual, var.bits_per_pixel, + dfb_pixelformat_name(config->format), shared->fix.line_length ); + + if (config->format == DSPF_RGB332) + dfb_fbdev_set_rgb332_palette(); + else + dfb_fbdev_set_gamma_ramp( config->format ); + + /* invalidate original pan offset */ + shared->orig_var.xoffset = 0; + shared->orig_var.yoffset = 0; + + dfb_surfacemanager_adjust_heap_offset( dfb_fbdev->shared->manager, + var.yres_virtual * shared->fix.line_length ); + + dfb_gfxcard_after_set_var(); + + dfb_gfxcard_unlock(); + + return DFB_OK; +} + + +#if 0 +DFBResult +dfb_fbdev_set_mode( CoreSurface *surface, + VideoMode *mode, + CoreLayerRegionConfig *config ) +{ + unsigned int vxres, vyres; + struct fb_var_screeninfo var; + FBDevShared *shared = dfb_fbdev->shared; + DFBSurfacePixelFormat format; + + D_DEBUG("DirectFB/FBDev: dfb_fbdev_set_mode (surface: %p, " + "mode: %p, buffermode: %d)\n", surface, mode, + config ? config->buffermode : DLBM_FRONTONLY); + + if (!mode) + mode = &shared->current_mode; + + var = shared->current_var; + + if (config) { + DFBRectangle *source = &config->source; + + /* Is panning supported? */ + if (source->w != mode->xres && shared->fix.xpanstep == 0) + return DFB_UNSUPPORTED; + if (source->h != mode->yres && shared->fix.ypanstep == 0 && shared->fix.ywrapstep == 0) + return DFB_UNSUPPORTED; + + vxres = config->width; + vyres = config->height; + + var.xoffset = source->x; + var.yoffset = source->y; + + switch (config->buffermode) { + case DLBM_TRIPLE: + if (shared->fix.ypanstep == 0 && shared->fix.ywrapstep == 0) + return DFB_UNSUPPORTED; + vyres *= 3; + break; + + case DLBM_BACKVIDEO: + if (shared->fix.ypanstep == 0 && shared->fix.ywrapstep == 0) + return DFB_UNSUPPORTED; + vyres *= 2; + break; + + case DLBM_BACKSYSTEM: + case DLBM_FRONTONLY: + break; + + default: + return DFB_UNSUPPORTED; + } + + var.bits_per_pixel = DFB_BYTES_PER_PIXEL(config->format) * 8; + + var.transp.length = var.transp.offset = 0; + + switch (config->format) { + case DSPF_ARGB1555: + var.transp.length = 1; + var.red.length = 5; + var.green.length = 5; + var.blue.length = 5; + var.transp.offset = 15; + var.red.offset = 10; + var.green.offset = 5; + var.blue.offset = 0; + break; + + case DSPF_RGB555: + var.red.length = 5; + var.green.length = 5; + var.blue.length = 5; + var.red.offset = 10; + var.green.offset = 5; + var.blue.offset = 0; + break; + + case DSPF_BGR555: + var.red.length = 5; + var.green.length = 5; + var.blue.length = 5; + var.red.offset = 0; + var.green.offset = 5; + var.blue.offset = 10; + break; + + case DSPF_ARGB4444: + var.transp.length = 4; + var.red.length = 4; + var.green.length = 4; + var.blue.length = 4; + var.transp.offset = 12; + var.red.offset = 8; + var.green.offset = 4; + var.blue.offset = 0; + break; + + case DSPF_RGBA4444: + var.transp.length = 4; + var.red.length = 4; + var.green.length = 4; + var.blue.length = 4; + var.transp.offset = 0; + var.red.offset = 12; + var.green.offset = 8; + var.blue.offset = 4; + break; + + case DSPF_RGB444: + var.red.length = 4; + var.green.length = 4; + var.blue.length = 4; + var.red.offset = 8; + var.green.offset = 4; + var.blue.offset = 0; + break; + + case DSPF_RGB32: + var.red.length = 8; + var.green.length = 8; + var.blue.length = 8; + var.red.offset = 16; + var.green.offset = 8; + var.blue.offset = 0; + break; + + case DSPF_RGB16: + var.red.length = 5; + var.green.length = 6; + var.blue.length = 5; + var.red.offset = 11; + var.green.offset = 5; + var.blue.offset = 0; + break; + + case DSPF_ARGB: + case DSPF_AiRGB: + var.transp.length = 8; + var.red.length = 8; + var.green.length = 8; + var.blue.length = 8; + var.transp.offset = 24; + var.red.offset = 16; + var.green.offset = 8; + var.blue.offset = 0; + break; + + case DSPF_LUT8: + case DSPF_RGB24: + case DSPF_RGB332: + break; + + case DSPF_ARGB1666: + var.transp.length = 1; + var.red.length = 6; + var.green.length = 6; + var.blue.length = 6; + var.transp.offset = 18; + var.red.offset = 12; + var.green.offset = 6; + var.blue.offset = 0; + break; + + case DSPF_ARGB6666: + var.transp.length = 6; + var.red.length = 6; + var.green.length = 6; + var.blue.length = 6; + var.transp.offset = 18; + var.red.offset = 12; + var.green.offset = 6; + var.blue.offset = 0; + break; + + case DSPF_RGB18: + var.red.length = 6; + var.green.length = 6; + var.blue.length = 6; + var.red.offset = 12; + var.green.offset = 6; + var.blue.offset = 0; + break; + + default: + return DFB_UNSUPPORTED; + } + } + else { + vxres = mode->xres; + vyres = mode->yres; + + var.xoffset = 0; + var.yoffset = 0; + + var.bits_per_pixel = mode->bpp; + } + + var.activate = surface ? FB_ACTIVATE_NOW : FB_ACTIVATE_TEST; + + var.xres = mode->xres; + var.yres = mode->yres; + var.xres_virtual = vxres; + var.yres_virtual = vyres; + + var.pixclock = mode->pixclock; + var.left_margin = mode->left_margin; + var.right_margin = mode->right_margin; + var.upper_margin = mode->upper_margin; + var.lower_margin = mode->lower_margin; + var.hsync_len = mode->hsync_len; + var.vsync_len = mode->vsync_len; + + var.sync = 0; + if (mode->hsync_high) + var.sync |= FB_SYNC_HOR_HIGH_ACT; + if (mode->vsync_high) + var.sync |= FB_SYNC_VERT_HIGH_ACT; + if (mode->csync_high) + var.sync |= FB_SYNC_COMP_HIGH_ACT; + if (mode->sync_on_green) + var.sync |= FB_SYNC_ON_GREEN; + if (mode->external_sync) + var.sync |= FB_SYNC_EXT; + if (mode->broadcast) + var.sync |= FB_SYNC_BROADCAST; + + var.vmode = 0; + if (mode->laced) + var.vmode |= FB_VMODE_INTERLACED; + if (mode->doubled) + var.vmode |= FB_VMODE_DOUBLE; + + dfb_gfxcard_lock( GDLF_WAIT | GDLF_SYNC | GDLF_RESET | GDLF_INVALIDATE ); + + if (FBDEV_IOCTL( FBIOPUT_VSCREENINFO, &var ) < 0) { + int erno = errno; + + if (surface) + D_PERROR( "DirectFB/FBDev: " + "Could not set video mode (FBIOPUT_VSCREENINFO)!\n" ); + + dfb_gfxcard_unlock(); + + return errno2result( erno ); + } + + /* + * the video mode was set successfully, check if there is enough + * video ram (for buggy framebuffer drivers) + */ + + if (shared->fix.smem_len < (var.yres_virtual * + var.xres_virtual * + var.bits_per_pixel >> 3) + || (var.xres_virtual < vxres) + || (var.yres_virtual < vyres)) + { + if (surface) { + D_PERROR( "DirectFB/FBDev: " + "Could not set video mode (not enough video ram)!\n" ); + + /* restore mode */ + FBDEV_IOCTL( FBIOPUT_VSCREENINFO, &shared->current_var ); + } + + dfb_gfxcard_unlock(); + + return DFB_INVARG; + } + + /* If surface is NULL the mode was only tested, otherwise apply changes. */ + if (surface) { + struct fb_fix_screeninfo fix; + + FBDEV_IOCTL( FBIOGET_VSCREENINFO, &var ); + + vxres = var.xres_virtual; + switch (config->buffermode) { + case DLBM_TRIPLE: + vyres = var.yres_virtual / 3; + break; + case DLBM_BACKVIDEO: + vyres = var.yres_virtual / 2; + break; + default: + vyres = var.yres_virtual; + break; + } + + format = dfb_fbdev_get_pixelformat( &var ); + if (format == DSPF_UNKNOWN) { + D_WARN( "unknown format" ); + + /* restore mode */ + FBDEV_IOCTL( FBIOPUT_VSCREENINFO, &shared->current_var ); + + dfb_gfxcard_unlock(); + + return DFB_UNSUPPORTED; + } + + if (!config) { + dfb_gfxcard_unlock(); + + return DFB_OK; + } + + if (format != config->format) { + if (DFB_BYTES_PER_PIXEL(format) == 1 || + (format == DSPF_RGB32 && config->format == DSPF_ARGB) || + (format == DSPF_RGB32 && config->format == DSPF_AiRGB) || + (format == DSPF_ARGB && config->format == DSPF_AiRGB)) + format = config->format; + } + + if (config->format == DSPF_RGB332) + dfb_fbdev_set_rgb332_palette(); + else + dfb_fbdev_set_gamma_ramp( config->format ); + + shared->current_var = var; + dfb_fbdev_var_to_mode( &var, &shared->current_mode ); + + /* invalidate original pan offset */ + shared->orig_var.xoffset = 0; + shared->orig_var.yoffset = 0; + + surface->config.size.w = vxres; + surface->config.size.h = vyres; + surface->config.format = format; + + /* To get the new pitch */ + FBDEV_IOCTL( FBIOGET_FSCREENINFO, &fix ); + + D_INFO( "FBDev/Mode: Switched to %dx%d (%dx%d) at %d bit %s (wanted %s).\n", + var.xres, var.yres, var.xres_virtual, var.yres_virtual, var.bits_per_pixel, + dfb_pixelformat_name(format), dfb_pixelformat_name(config->format) ); + + /* ++Tony: Other information (such as visual formats) will also change */ + shared->fix = fix; + + dfb_surfacemanager_adjust_heap_offset( dfb_fbdev->shared->manager, + var.yres_virtual * fix.line_length ); + + if (shared->fix.xpanstep || shared->fix.ypanstep || shared->fix.ywrapstep) + dfb_fbdev_pan( var.xoffset, var.yoffset, false ); + + dfb_gfxcard_after_set_var(); + + dfb_surface_notify( surface, + CSNF_SIZEFORMAT | CSNF_FLIP | + CSNF_VIDEO | CSNF_SYSTEM ); + } + + dfb_gfxcard_unlock(); + + return DFB_OK; +} +#endif + +/* + * parses video modes in /etc/fb.modes and stores them in dfb_fbdev->shared->modes + * (to be replaced by DirectFB's own config system + */ +static DFBResult +dfb_fbdev_read_modes( void ) +{ + FILE *fp; + char line[80],label[32],value[16]; + int geometry=0, timings=0; + int dummy; + VideoMode temp_mode; + FBDevShared *shared = dfb_fbdev->shared; + VideoMode *prev = shared->modes; + + D_DEBUG_AT( FBDev_Mode, "%s()\n", __FUNCTION__ ); + + if (!(fp = fopen("/etc/fb.modes","r"))) + return errno2result( errno ); + + while (fgets(line,79,fp)) { + if (sscanf(line, "mode \"%31[^\"]\"",label) == 1) { + memset( &temp_mode, 0, sizeof(VideoMode) ); + + geometry = 0; + timings = 0; + + while (fgets(line,79,fp) && !(strstr(line,"endmode"))) { + if (5 == sscanf(line," geometry %d %d %d %d %d", &temp_mode.xres, &temp_mode.yres, &dummy, &dummy, &temp_mode.bpp)) { + geometry = 1; + } + else if (7 == sscanf(line," timings %d %d %d %d %d %d %d", &temp_mode.pixclock, &temp_mode.left_margin, &temp_mode.right_margin, + &temp_mode.upper_margin, &temp_mode.lower_margin, &temp_mode.hsync_len, &temp_mode.vsync_len)) { + timings = 1; + } + else if (1 == sscanf(line, " hsync %15s",value) && 0 == strcasecmp(value,"high")) { + temp_mode.hsync_high = 1; + } + else if (1 == sscanf(line, " vsync %15s",value) && 0 == strcasecmp(value,"high")) { + temp_mode.vsync_high = 1; + } + else if (1 == sscanf(line, " csync %15s",value) && 0 == strcasecmp(value,"high")) { + temp_mode.csync_high = 1; + } + else if (1 == sscanf(line, " laced %15s",value) && 0 == strcasecmp(value,"true")) { + temp_mode.laced = 1; + } + else if (1 == sscanf(line, " double %15s",value) && 0 == strcasecmp(value,"true")) { + temp_mode.doubled = 1; + } + else if (1 == sscanf(line, " gsync %15s",value) && 0 == strcasecmp(value,"true")) { + temp_mode.sync_on_green = 1; + } + else if (1 == sscanf(line, " extsync %15s",value) && 0 == strcasecmp(value,"true")) { + temp_mode.external_sync = 1; + } + else if (1 == sscanf(line, " bcast %15s",value) && 0 == strcasecmp(value,"true")) { + temp_mode.broadcast = 1; + } + } + + if (geometry && timings && !dfb_fbdev_test_mode_simple(&temp_mode)) { + VideoMode *mode = SHCALLOC( shared->shmpool, 1, sizeof(VideoMode) ); + if (!mode) { + D_OOSHM(); + continue; + } + + if (!prev) + shared->modes = mode; + else + prev->next = mode; + + direct_memcpy (mode, &temp_mode, sizeof(VideoMode)); + + prev = mode; + + D_DEBUG_AT( FBDev_Mode, " +-> %16s %4dx%4d %s%s\n", label, temp_mode.xres, temp_mode.yres, + temp_mode.laced ? "interlaced " : "", temp_mode.doubled ? "doublescan" : "" ); + } + } + } + + fclose (fp); + + return DFB_OK; +} + +/* + * some fbdev drivers use the palette as gamma ramp in >8bpp modes, to have + * correct colors, the gamme ramp has to be initialized. + */ + +static u16 +dfb_fbdev_calc_gamma(int n, int max) +{ + int ret = 65535 * n / max; + return CLAMP( ret, 0, 65535 ); +} + +static DFBResult +dfb_fbdev_set_gamma_ramp( DFBSurfacePixelFormat format ) +{ + int i; + + int red_size = 0; + int green_size = 0; + int blue_size = 0; + int red_max = 0; + int green_max = 0; + int blue_max = 0; + + struct fb_cmap *cmap; + + if (!dfb_fbdev) { + D_BUG( "dfb_fbdev_set_gamma_ramp() called while dfb_fbdev == NULL!" ); + + return DFB_BUG; + } + + switch (format) { + case DSPF_ARGB1555: + case DSPF_RGB555: + case DSPF_BGR555: + red_size = 32; + green_size = 32; + blue_size = 32; + break; + case DSPF_ARGB4444: + case DSPF_RGBA4444: + case DSPF_RGB444: + case DSPF_RGB16: + red_size = 32; + green_size = 64; + blue_size = 32; + break; + case DSPF_RGB24: + case DSPF_RGB32: + case DSPF_ARGB: + red_size = 256; + green_size = 256; + blue_size = 256; + break; + default: + return DFB_OK; + } + + /* + * ++Tony: The gamma ramp must be set differently if in DirectColor, + * ie, to mimic TrueColor, index == color[index]. + */ + if (dfb_fbdev->shared->fix.visual == FB_VISUAL_DIRECTCOLOR) { + red_max = 65536 / (256/red_size); + green_max = 65536 / (256/green_size); + blue_max = 65536 / (256/blue_size); + } + else { + red_max = red_size; + green_max = green_size; + blue_max = blue_size; + } + + cmap = &dfb_fbdev->shared->current_cmap; + + /* assume green to have most weight */ + cmap->len = green_size; + + for (i = 0; i < red_size; i++) + cmap->red[i] = dfb_fbdev_calc_gamma( i, red_max ); + + for (i = 0; i < green_size; i++) + cmap->green[i] = dfb_fbdev_calc_gamma( i, green_max ); + + for (i = 0; i < blue_size; i++) + cmap->blue[i] = dfb_fbdev_calc_gamma( i, blue_max ); + + /* ++Tony: Some drivers use the upper byte, some use the lower */ + if (dfb_fbdev->shared->fix.visual == FB_VISUAL_DIRECTCOLOR) { + for (i = 0; i < red_size; i++) + cmap->red[i] |= cmap->red[i] << 8; + + for (i = 0; i < green_size; i++) + cmap->green[i] |= cmap->green[i] << 8; + + for (i = 0; i < blue_size; i++) + cmap->blue[i] |= cmap->blue[i] << 8; + } + + if (FBDEV_IOCTL( FBIOPUTCMAP, cmap ) < 0) { + D_PERROR( "DirectFB/FBDev: " + "Could not set gamma ramp" ); + + return errno2result(errno); + } + + return DFB_OK; +} + +static DFBResult +dfb_fbdev_set_palette( CorePalette *palette ) +{ + int i; + struct fb_cmap *cmap = &dfb_fbdev->shared->current_cmap; + + D_ASSERT( palette != NULL ); + + cmap->len = palette->num_entries <= 256 ? palette->num_entries : 256; + + for (i = 0; i < (int)cmap->len; i++) { + cmap->red[i] = palette->entries[i].r; + cmap->green[i] = palette->entries[i].g; + cmap->blue[i] = palette->entries[i].b; + cmap->transp[i] = 0xff - palette->entries[i].a; + + cmap->red[i] |= cmap->red[i] << 8; + cmap->green[i] |= cmap->green[i] << 8; + cmap->blue[i] |= cmap->blue[i] << 8; + cmap->transp[i] |= cmap->transp[i] << 8; + } + + if (FBDEV_IOCTL( FBIOPUTCMAP, cmap ) < 0) { + D_PERROR( "DirectFB/FBDev: Could not set the palette!\n" ); + + return errno2result(errno); + } + + return DFB_OK; +} + +static DFBResult +dfb_fbdev_set_rgb332_palette( void ) +{ + DFBResult ret = DFB_OK; + int red_val; + int green_val; + int blue_val; + int i = 0; + FusionSHMPoolShared *pool = dfb_fbdev->shared->shmpool_data; + + struct fb_cmap cmap; + + if (!dfb_fbdev) { + D_BUG( "dfb_fbdev_set_rgb332_palette() called while dfb_fbdev == NULL!" ); + + return DFB_BUG; + } + + cmap.start = 0; + cmap.len = 256; + cmap.red = (u16*)SHMALLOC( pool, 2 * 256 ); + if (!cmap.red) { + return D_OOSHM(); + } + cmap.green = (u16*)SHMALLOC( pool, 2 * 256 ); + if (!cmap.green) { + ret = D_OOSHM(); + goto free_red; + } + cmap.blue = (u16*)SHMALLOC( pool, 2 * 256 ); + if (!cmap.blue) { + ret = D_OOSHM(); + goto free_green; + } + cmap.transp = (u16*)SHMALLOC( pool, 2 * 256 ); + if (!cmap.transp) { + ret = D_OOSHM(); + goto free_blue; + } + + for (red_val = 0; red_val < 8 ; red_val++) { + for (green_val = 0; green_val < 8 ; green_val++) { + for (blue_val = 0; blue_val < 4 ; blue_val++) { + cmap.red[i] = dfb_fbdev_calc_gamma( red_val, 7 ); + cmap.green[i] = dfb_fbdev_calc_gamma( green_val, 7 ); + cmap.blue[i] = dfb_fbdev_calc_gamma( blue_val, 3 ); + cmap.transp[i] = (i ? 0x2000 : 0xffff); + i++; + } + } + } + + if (FBDEV_IOCTL( FBIOPUTCMAP, &cmap ) < 0) { + D_PERROR( "DirectFB/FBDev: " + "Could not set rgb332 palette" ); + ret = errno2result(errno); + goto free_transp; + } + + free_transp: + SHFREE( pool, cmap.transp ); + free_blue: + SHFREE( pool, cmap.blue ); + free_green: + SHFREE( pool, cmap.green ); + free_red: + SHFREE( pool, cmap.red ); + + return ret; +} + +static FusionCallHandlerResult +fbdev_ioctl_call_handler( int caller, + int call_arg, + void *call_ptr, + void *ctx, + unsigned int serial, + int *ret_val ) +{ + int ret; + const char cursoroff_str[] = "\033[?1;0;0c"; + const char blankoff_str[] = "\033[9;0]"; + + if (dfb_config->vt) { + if (!dfb_config->kd_graphics && call_arg == FBIOPUT_VSCREENINFO) + ioctl( dfb_fbdev->vt->fd, KDSETMODE, KD_GRAPHICS ); + } + + ret = ioctl( dfb_fbdev->fd, call_arg, call_ptr ); + if (ret) + ret = errno; + + if (dfb_config->vt) { + if (call_arg == FBIOPUT_VSCREENINFO) { + if (!dfb_config->kd_graphics) { + ioctl( dfb_fbdev->vt->fd, KDSETMODE, KD_TEXT ); + write( dfb_fbdev->vt->fd, cursoroff_str, strlen(cursoroff_str) ); + write( dfb_fbdev->vt->fd, blankoff_str, strlen(blankoff_str) ); + } + } + } + + *ret_val = ret; + + return FCHR_RETURN; +} + +static int +fbdev_ioctl( int request, void *arg, int arg_size ) +{ + int ret; + int erno; + void *tmp_shm = NULL; + FBDevShared *shared; + + D_ASSERT( dfb_fbdev != NULL ); + + shared = dfb_fbdev->shared; + + D_ASSERT( shared != NULL ); + + if (dfb_core_is_master( dfb_fbdev->core )) { + fbdev_ioctl_call_handler( 1, request, arg, NULL, 0, &ret ); + errno = ret; + return errno ? -1 : 0; + } + + if (arg) { + if (!fusion_is_shared( dfb_core_world(dfb_fbdev->core), arg )) { + tmp_shm = SHMALLOC( shared->shmpool, arg_size ); + if (!tmp_shm) { + errno = ENOMEM; + return -1; + } + + direct_memcpy( tmp_shm, arg, arg_size ); + } + } + + ret = fusion_call_execute( &shared->fbdev_ioctl, FCEF_NONE, + request, tmp_shm ? tmp_shm : arg, &erno ); + + if (tmp_shm) { + direct_memcpy( arg, tmp_shm, arg_size ); + SHFREE( shared->shmpool, tmp_shm ); + } + + errno = erno; + + return errno ? -1 : 0; +} + -- cgit