/* (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; }