1081 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			1081 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
 * Xephyr - A kdrive X server thats runs in a host X window.
 | 
						|
 *          Authored by Matthew Allum <mallum@openedhand.com>
 | 
						|
 * 
 | 
						|
 * Copyright © 2004 Nokia 
 | 
						|
 *
 | 
						|
 * Permission to use, copy, modify, distribute, and sell this software and its
 | 
						|
 * documentation for any purpose is hereby granted without fee, provided that
 | 
						|
 * the above copyright notice appear in all copies and that both that
 | 
						|
 * copyright notice and this permission notice appear in supporting
 | 
						|
 * documentation, and that the name of Nokia not be used in
 | 
						|
 * advertising or publicity pertaining to distribution of the software without
 | 
						|
 * specific, written prior permission. Nokia makes no
 | 
						|
 * representations about the suitability of this software for any purpose.  It
 | 
						|
 * is provided "as is" without express or implied warranty.
 | 
						|
 *
 | 
						|
 * NOKIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 | 
						|
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 | 
						|
 * EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 | 
						|
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 | 
						|
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 | 
						|
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 | 
						|
 * PERFORMANCE OF THIS SOFTWARE.
 | 
						|
 */
 | 
						|
 | 
						|
#ifdef HAVE_CONFIG_H
 | 
						|
#include <kdrive-config.h>
 | 
						|
#endif
 | 
						|
#include "ephyr.h"
 | 
						|
 | 
						|
#include "inputstr.h"
 | 
						|
#include "scrnintstr.h"
 | 
						|
#include "ephyrlog.h"
 | 
						|
 | 
						|
#ifdef XEPHYR_DRI
 | 
						|
#include "ephyrdri.h"
 | 
						|
#include "ephyrdriext.h"
 | 
						|
#include "ephyrglxext.h"
 | 
						|
#endif /*XEPHYR_DRI*/
 | 
						|
 | 
						|
extern int KdTsPhyScreen;
 | 
						|
#ifdef GLXEXT
 | 
						|
extern Bool noGlxVisualInit;
 | 
						|
#endif
 | 
						|
 | 
						|
KdKeyboardInfo *ephyrKbd;
 | 
						|
KdPointerInfo *ephyrMouse;
 | 
						|
EphyrKeySyms ephyrKeySyms;
 | 
						|
Bool ephyrNoDRI=FALSE ;
 | 
						|
Bool ephyrNoXV=FALSE ;
 | 
						|
 | 
						|
static int mouseState = 0;
 | 
						|
 | 
						|
typedef struct _EphyrInputPrivate {
 | 
						|
    Bool    enabled;
 | 
						|
} EphyrKbdPrivate, EphyrPointerPrivate;
 | 
						|
 | 
						|
Bool   EphyrWantGrayScale = 0;
 | 
						|
 | 
						|
 | 
						|
Bool
 | 
						|
ephyrInitialize (KdCardInfo *card, EphyrPriv *priv)
 | 
						|
{
 | 
						|
  OsSignal(SIGUSR1, hostx_handle_signal);
 | 
						|
  
 | 
						|
  priv->base = 0;
 | 
						|
  priv->bytes_per_line = 0;
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
ephyrCardInit (KdCardInfo *card)
 | 
						|
{
 | 
						|
  EphyrPriv	*priv;
 | 
						|
  
 | 
						|
  priv = (EphyrPriv *) xalloc (sizeof (EphyrPriv));
 | 
						|
  if (!priv)
 | 
						|
    return FALSE;
 | 
						|
  
 | 
						|
  if (!ephyrInitialize (card, priv))
 | 
						|
    {
 | 
						|
      xfree (priv);
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  card->driver = priv;
 | 
						|
  
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
ephyrScreenInitialize (KdScreenInfo *screen, EphyrScrPriv *scrpriv)
 | 
						|
{
 | 
						|
  int width = 640, height = 480; 
 | 
						|
  unsigned long redMask, greenMask, blueMask;
 | 
						|
  
 | 
						|
  if (hostx_want_screen_size(screen, &width, &height)
 | 
						|
      || !screen->width || !screen->height)
 | 
						|
    {
 | 
						|
      screen->width = width;
 | 
						|
      screen->height = height;
 | 
						|
    }
 | 
						|
 | 
						|
  if (EphyrWantGrayScale)
 | 
						|
    screen->fb[0].depth = 8;
 | 
						|
 | 
						|
  if (screen->fb[0].depth && screen->fb[0].depth != hostx_get_depth())
 | 
						|
    {
 | 
						|
      if (screen->fb[0].depth < hostx_get_depth()
 | 
						|
	  && (screen->fb[0].depth == 24 || screen->fb[0].depth == 16
 | 
						|
	      || screen->fb[0].depth == 8))
 | 
						|
	{
 | 
						|
	  hostx_set_server_depth(screen, screen->fb[0].depth);
 | 
						|
	}
 | 
						|
      else
 | 
						|
	ErrorF("\nXephyr: requested screen depth not supported, setting to match hosts.\n");
 | 
						|
    }
 | 
						|
  
 | 
						|
  screen->fb[0].depth = hostx_get_server_depth(screen);
 | 
						|
  screen->rate = 72;
 | 
						|
  
 | 
						|
  if (screen->fb[0].depth <= 8)
 | 
						|
    {
 | 
						|
      if (EphyrWantGrayScale)
 | 
						|
	screen->fb[0].visuals = ((1 << StaticGray) | (1 << GrayScale));
 | 
						|
      else
 | 
						|
	screen->fb[0].visuals = ((1 << StaticGray) |
 | 
						|
				 (1 << GrayScale) |
 | 
						|
				 (1 << StaticColor) |
 | 
						|
				 (1 << PseudoColor) |
 | 
						|
				 (1 << TrueColor) |
 | 
						|
				 (1 << DirectColor));
 | 
						|
      
 | 
						|
      screen->fb[0].redMask   = 0x00;
 | 
						|
      screen->fb[0].greenMask = 0x00;
 | 
						|
      screen->fb[0].blueMask  = 0x00;
 | 
						|
      screen->fb[0].depth        = 8;
 | 
						|
      screen->fb[0].bitsPerPixel = 8;
 | 
						|
    }
 | 
						|
  else 
 | 
						|
    {
 | 
						|
      screen->fb[0].visuals = (1 << TrueColor);
 | 
						|
      
 | 
						|
      if (screen->fb[0].depth <= 15)
 | 
						|
	{
 | 
						|
	  screen->fb[0].depth = 15;
 | 
						|
	  screen->fb[0].bitsPerPixel = 16;
 | 
						|
	}
 | 
						|
      else if (screen->fb[0].depth <= 16)
 | 
						|
	{
 | 
						|
	  screen->fb[0].depth = 16;
 | 
						|
	  screen->fb[0].bitsPerPixel = 16;
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  screen->fb[0].depth = 24;
 | 
						|
	  screen->fb[0].bitsPerPixel = 32;
 | 
						|
	}
 | 
						|
 | 
						|
      hostx_get_visual_masks (screen, &redMask, &greenMask, &blueMask);
 | 
						|
 | 
						|
      screen->fb[0].redMask = (Pixel) redMask;
 | 
						|
      screen->fb[0].greenMask = (Pixel) greenMask;
 | 
						|
      screen->fb[0].blueMask = (Pixel) blueMask;
 | 
						|
 | 
						|
    }
 | 
						|
  
 | 
						|
  scrpriv->randr = screen->randr;
 | 
						|
 | 
						|
  return ephyrMapFramebuffer (screen);
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
ephyrScreenInit (KdScreenInfo *screen)
 | 
						|
{
 | 
						|
  EphyrScrPriv *scrpriv;
 | 
						|
  
 | 
						|
  scrpriv = xalloc (sizeof (EphyrScrPriv));
 | 
						|
 | 
						|
  if (!scrpriv)
 | 
						|
    return FALSE;
 | 
						|
 | 
						|
  memset (scrpriv, 0, sizeof (EphyrScrPriv));
 | 
						|
  screen->driver = scrpriv;
 | 
						|
 | 
						|
  if (!ephyrScreenInitialize (screen, scrpriv))
 | 
						|
    {
 | 
						|
      screen->driver = 0;
 | 
						|
      xfree (scrpriv);
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
    
 | 
						|
void*
 | 
						|
ephyrWindowLinear (ScreenPtr	pScreen,
 | 
						|
		   CARD32	row,
 | 
						|
		   CARD32	offset,
 | 
						|
		   int		mode,
 | 
						|
		   CARD32	*size,
 | 
						|
		   void		*closure)
 | 
						|
{
 | 
						|
  KdScreenPriv(pScreen);
 | 
						|
  EphyrPriv	    *priv = pScreenPriv->card->driver;
 | 
						|
  
 | 
						|
  if (!pScreenPriv->enabled)
 | 
						|
    return 0;
 | 
						|
 | 
						|
  *size = priv->bytes_per_line;
 | 
						|
  return priv->base + row * priv->bytes_per_line + offset;
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
ephyrMapFramebuffer (KdScreenInfo *screen)
 | 
						|
{
 | 
						|
  EphyrScrPriv  *scrpriv = screen->driver;
 | 
						|
  EphyrPriv	  *priv    = screen->card->driver;
 | 
						|
  KdPointerMatrix m;
 | 
						|
  int buffer_height;
 | 
						|
  
 | 
						|
  EPHYR_LOG("screen->width: %d, screen->height: %d index=%d",
 | 
						|
	     screen->width, screen->height, screen->mynum);
 | 
						|
  
 | 
						|
  KdComputePointerMatrix (&m, scrpriv->randr, screen->width, screen->height);
 | 
						|
  KdSetPointerMatrix (&m);
 | 
						|
  
 | 
						|
  priv->bytes_per_line = ((screen->width * screen->fb[0].bitsPerPixel + 31) >> 5) << 2;
 | 
						|
  
 | 
						|
  /* point the framebuffer to the data in an XImage */
 | 
						|
  /* If fakexa is enabled, allocate a larger buffer so that fakexa has space to
 | 
						|
   * put offscreen pixmaps.
 | 
						|
   */
 | 
						|
  if (ephyrFuncs.initAccel == NULL)
 | 
						|
    buffer_height = screen->height;
 | 
						|
  else
 | 
						|
    buffer_height = 3 * screen->height;
 | 
						|
 | 
						|
  priv->base = hostx_screen_init (screen, screen->width, screen->height, buffer_height);
 | 
						|
 | 
						|
  screen->memory_base  = (CARD8 *) (priv->base);
 | 
						|
  screen->memory_size  = priv->bytes_per_line * buffer_height;
 | 
						|
  screen->off_screen_base = priv->bytes_per_line * screen->height;
 | 
						|
  
 | 
						|
  if ((scrpriv->randr & RR_Rotate_0) && !(scrpriv->randr & RR_Reflect_All))
 | 
						|
    {
 | 
						|
      scrpriv->shadow = FALSE;
 | 
						|
      
 | 
						|
      screen->fb[0].byteStride = priv->bytes_per_line;
 | 
						|
      screen->fb[0].pixelStride = screen->width;
 | 
						|
      screen->fb[0].frameBuffer = (CARD8 *) (priv->base);
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      /* Rotated/Reflected so we need to use shadow fb */
 | 
						|
      scrpriv->shadow = TRUE;
 | 
						|
      
 | 
						|
      EPHYR_LOG("allocing shadow");
 | 
						|
      
 | 
						|
      KdShadowFbAlloc (screen, 0, 
 | 
						|
		       scrpriv->randr & (RR_Rotate_90|RR_Rotate_270));
 | 
						|
    }
 | 
						|
  
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ephyrSetScreenSizes (ScreenPtr pScreen)
 | 
						|
{
 | 
						|
  KdScreenPriv(pScreen);
 | 
						|
  KdScreenInfo	*screen = pScreenPriv->screen;
 | 
						|
  EphyrScrPriv	*scrpriv = screen->driver;
 | 
						|
  
 | 
						|
  if (scrpriv->randr & (RR_Rotate_0|RR_Rotate_180))
 | 
						|
    {
 | 
						|
      pScreen->width = screen->width;
 | 
						|
      pScreen->height = screen->height;
 | 
						|
      pScreen->mmWidth = screen->width_mm;
 | 
						|
      pScreen->mmHeight = screen->height_mm;
 | 
						|
    }
 | 
						|
  else 
 | 
						|
    {
 | 
						|
      pScreen->width = screen->height;
 | 
						|
      pScreen->height = screen->width;
 | 
						|
      pScreen->mmWidth = screen->height_mm;
 | 
						|
      pScreen->mmHeight = screen->width_mm;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
ephyrUnmapFramebuffer (KdScreenInfo *screen)
 | 
						|
{
 | 
						|
  EphyrScrPriv  *scrpriv = screen->driver;
 | 
						|
  
 | 
						|
  if (scrpriv->shadow)
 | 
						|
    KdShadowFbFree (screen, 0);
 | 
						|
  
 | 
						|
  /* Note, priv->base will get freed when XImage recreated */
 | 
						|
  
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
void 
 | 
						|
ephyrShadowUpdate (ScreenPtr pScreen, shadowBufPtr pBuf)
 | 
						|
{
 | 
						|
  KdScreenPriv(pScreen);
 | 
						|
  KdScreenInfo *screen = pScreenPriv->screen;
 | 
						|
  
 | 
						|
  EPHYR_LOG("slow paint");
 | 
						|
  
 | 
						|
  /* FIXME: Slow Rotated/Reflected updates could be much
 | 
						|
   * much faster efficiently updating via tranforming 
 | 
						|
   * pBuf->pDamage  regions     
 | 
						|
  */
 | 
						|
  shadowUpdateRotatePacked(pScreen, pBuf);
 | 
						|
  hostx_paint_rect(screen, 0,0,0,0, screen->width, screen->height);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
ephyrInternalDamageRedisplay (ScreenPtr pScreen)
 | 
						|
{
 | 
						|
  KdScreenPriv(pScreen);
 | 
						|
  KdScreenInfo	*screen = pScreenPriv->screen;
 | 
						|
  EphyrScrPriv	*scrpriv = screen->driver;
 | 
						|
  RegionPtr	 pRegion;
 | 
						|
 | 
						|
  if (!scrpriv || !scrpriv->pDamage)
 | 
						|
    return;
 | 
						|
 | 
						|
  pRegion = DamageRegion (scrpriv->pDamage);
 | 
						|
 | 
						|
  if (REGION_NOTEMPTY (pScreen, pRegion))
 | 
						|
    {
 | 
						|
      int           nbox;
 | 
						|
      BoxPtr        pbox;
 | 
						|
 | 
						|
      nbox = REGION_NUM_RECTS (pRegion);
 | 
						|
      pbox = REGION_RECTS (pRegion);
 | 
						|
 | 
						|
      while (nbox--)
 | 
						|
        {
 | 
						|
          hostx_paint_rect(screen,
 | 
						|
                           pbox->x1, pbox->y1,
 | 
						|
                           pbox->x1, pbox->y1,
 | 
						|
                           pbox->x2 - pbox->x1,
 | 
						|
                           pbox->y2 - pbox->y1);
 | 
						|
          pbox++;
 | 
						|
        }
 | 
						|
      DamageEmpty (scrpriv->pDamage);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
ephyrInternalDamageBlockHandler (pointer   data,
 | 
						|
				 OSTimePtr pTimeout,
 | 
						|
				 pointer   pRead)
 | 
						|
{
 | 
						|
  ScreenPtr pScreen = (ScreenPtr) data;
 | 
						|
  
 | 
						|
  ephyrInternalDamageRedisplay (pScreen);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
ephyrInternalDamageWakeupHandler (pointer data, int i, pointer LastSelectMask)
 | 
						|
{
 | 
						|
  /* FIXME: Not needed ? */
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
ephyrSetInternalDamage (ScreenPtr pScreen)
 | 
						|
{
 | 
						|
  KdScreenPriv(pScreen);
 | 
						|
  KdScreenInfo	*screen = pScreenPriv->screen;
 | 
						|
  EphyrScrPriv	*scrpriv = screen->driver;
 | 
						|
  PixmapPtr      pPixmap = NULL;
 | 
						|
  
 | 
						|
  scrpriv->pDamage = DamageCreate ((DamageReportFunc) 0,
 | 
						|
				   (DamageDestroyFunc) 0,
 | 
						|
				   DamageReportNone,
 | 
						|
				   TRUE,
 | 
						|
				   pScreen,
 | 
						|
				   pScreen);
 | 
						|
  
 | 
						|
  if (!RegisterBlockAndWakeupHandlers (ephyrInternalDamageBlockHandler,
 | 
						|
				       ephyrInternalDamageWakeupHandler,
 | 
						|
				       (pointer) pScreen))
 | 
						|
    return FALSE;
 | 
						|
  
 | 
						|
  pPixmap = (*pScreen->GetScreenPixmap) (pScreen);
 | 
						|
  
 | 
						|
  DamageRegister (&pPixmap->drawable, scrpriv->pDamage);
 | 
						|
      
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ephyrUnsetInternalDamage (ScreenPtr pScreen)
 | 
						|
{
 | 
						|
  KdScreenPriv(pScreen);
 | 
						|
  KdScreenInfo	*screen = pScreenPriv->screen;
 | 
						|
  EphyrScrPriv	*scrpriv = screen->driver;
 | 
						|
  PixmapPtr      pPixmap = NULL;
 | 
						|
  
 | 
						|
  pPixmap = (*pScreen->GetScreenPixmap) (pScreen);
 | 
						|
  DamageUnregister (&pPixmap->drawable, scrpriv->pDamage);
 | 
						|
  
 | 
						|
  RemoveBlockAndWakeupHandlers (ephyrInternalDamageBlockHandler,
 | 
						|
				ephyrInternalDamageWakeupHandler,
 | 
						|
				(pointer) pScreen);
 | 
						|
}
 | 
						|
 | 
						|
#ifdef RANDR
 | 
						|
Bool
 | 
						|
ephyrRandRGetInfo (ScreenPtr pScreen, Rotation *rotations)
 | 
						|
{
 | 
						|
  KdScreenPriv(pScreen);
 | 
						|
  KdScreenInfo	    *screen = pScreenPriv->screen;
 | 
						|
  EphyrScrPriv	    *scrpriv = screen->driver;
 | 
						|
  RRScreenSizePtr	    pSize;
 | 
						|
  Rotation		    randr;
 | 
						|
  int			    n = 0;
 | 
						|
  
 | 
						|
  EPHYR_LOG("mark");
 | 
						|
  
 | 
						|
  struct { int width, height; } sizes[] = 
 | 
						|
    {
 | 
						|
      { 1600, 1200 },
 | 
						|
      { 1400, 1050 },
 | 
						|
      { 1280, 960  },
 | 
						|
      { 1280, 1024 },
 | 
						|
      { 1152, 864 },
 | 
						|
      { 1024, 768 },
 | 
						|
      { 832, 624 },
 | 
						|
      { 800, 600 },
 | 
						|
      { 720, 400 },
 | 
						|
      { 480, 640 },
 | 
						|
      { 640, 480 },
 | 
						|
      { 640, 400 },
 | 
						|
      { 320, 240 },
 | 
						|
      { 240, 320 },
 | 
						|
      { 160, 160 }, 
 | 
						|
      { 0, 0 }
 | 
						|
    };
 | 
						|
 | 
						|
  *rotations = RR_Rotate_All|RR_Reflect_All;
 | 
						|
 | 
						|
  if (!hostx_want_preexisting_window (screen)
 | 
						|
      && !hostx_want_fullscreen ()) /* only if no -parent switch */
 | 
						|
    {
 | 
						|
      while (sizes[n].width != 0 && sizes[n].height != 0)
 | 
						|
	{
 | 
						|
	  RRRegisterSize (pScreen,
 | 
						|
			  sizes[n].width,
 | 
						|
			  sizes[n].height, 
 | 
						|
			  (sizes[n].width * screen->width_mm)/screen->width,
 | 
						|
			  (sizes[n].height *screen->height_mm)/screen->height
 | 
						|
			  );
 | 
						|
	  n++;
 | 
						|
	}
 | 
						|
    }
 | 
						|
  
 | 
						|
  pSize = RRRegisterSize (pScreen,
 | 
						|
			  screen->width,
 | 
						|
			  screen->height, 
 | 
						|
			  screen->width_mm,
 | 
						|
			  screen->height_mm);
 | 
						|
    
 | 
						|
  randr = KdSubRotation (scrpriv->randr, screen->randr);
 | 
						|
  
 | 
						|
  RRSetCurrentConfig (pScreen, randr, 0, pSize);
 | 
						|
    
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
ephyrRandRSetConfig (ScreenPtr		pScreen,
 | 
						|
		     Rotation		randr,
 | 
						|
		     int		rate,
 | 
						|
		     RRScreenSizePtr	pSize)
 | 
						|
{
 | 
						|
  KdScreenPriv(pScreen);
 | 
						|
  KdScreenInfo	*screen    = pScreenPriv->screen;
 | 
						|
  EphyrScrPriv	*scrpriv   = screen->driver;
 | 
						|
  Bool		wasEnabled = pScreenPriv->enabled;
 | 
						|
  EphyrScrPriv	oldscr;
 | 
						|
  int		oldwidth, oldheight, oldmmwidth, oldmmheight;
 | 
						|
  Bool          oldshadow;
 | 
						|
  int		newwidth, newheight;
 | 
						|
  
 | 
						|
  if (screen->randr & (RR_Rotate_0|RR_Rotate_180))
 | 
						|
    {
 | 
						|
      newwidth = pSize->width;
 | 
						|
      newheight = pSize->height;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      newwidth = pSize->height;
 | 
						|
      newheight = pSize->width;
 | 
						|
    }
 | 
						|
  
 | 
						|
  if (wasEnabled)
 | 
						|
    KdDisableScreen (pScreen);
 | 
						|
 | 
						|
  oldscr = *scrpriv;
 | 
						|
    
 | 
						|
  oldwidth    = screen->width;
 | 
						|
  oldheight   = screen->height;
 | 
						|
  oldmmwidth  = pScreen->mmWidth;
 | 
						|
  oldmmheight = pScreen->mmHeight;
 | 
						|
  oldshadow   = scrpriv->shadow;
 | 
						|
  
 | 
						|
  /*
 | 
						|
   * Set new configuration
 | 
						|
   */
 | 
						|
  
 | 
						|
  scrpriv->randr = KdAddRotation (screen->randr, randr);
 | 
						|
  
 | 
						|
  KdOffscreenSwapOut (screen->pScreen);
 | 
						|
  
 | 
						|
  ephyrUnmapFramebuffer (screen); 
 | 
						|
  
 | 
						|
  screen->width  = newwidth;
 | 
						|
  screen->height = newheight;
 | 
						|
  
 | 
						|
  if (!ephyrMapFramebuffer (screen))
 | 
						|
    goto bail4;
 | 
						|
  
 | 
						|
  /* FIXME below should go in own call */
 | 
						|
  
 | 
						|
  if (oldshadow)
 | 
						|
    KdShadowUnset (screen->pScreen);
 | 
						|
  else
 | 
						|
    ephyrUnsetInternalDamage(screen->pScreen);
 | 
						|
  
 | 
						|
  if (scrpriv->shadow)
 | 
						|
    {
 | 
						|
      if (!KdShadowSet (screen->pScreen, 
 | 
						|
			scrpriv->randr, 
 | 
						|
			ephyrShadowUpdate, 
 | 
						|
			ephyrWindowLinear))
 | 
						|
	goto bail4;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      /* Without shadow fb ( non rotated ) we need 
 | 
						|
       * to use damage to efficiently update display
 | 
						|
       * via signal regions what to copy from 'fb'.
 | 
						|
       */
 | 
						|
      if (!ephyrSetInternalDamage(screen->pScreen))
 | 
						|
	goto bail4;
 | 
						|
    }
 | 
						|
  
 | 
						|
  ephyrSetScreenSizes (screen->pScreen);
 | 
						|
  
 | 
						|
  /*
 | 
						|
   * Set frame buffer mapping
 | 
						|
   */
 | 
						|
  (*pScreen->ModifyPixmapHeader) (fbGetScreenPixmap (pScreen),
 | 
						|
				  pScreen->width,
 | 
						|
				  pScreen->height,
 | 
						|
				  screen->fb[0].depth,
 | 
						|
				  screen->fb[0].bitsPerPixel,
 | 
						|
				  screen->fb[0].byteStride,
 | 
						|
				  screen->fb[0].frameBuffer);
 | 
						|
  
 | 
						|
  /* set the subpixel order */
 | 
						|
  
 | 
						|
  KdSetSubpixelOrder (pScreen, scrpriv->randr);
 | 
						|
  
 | 
						|
  if (wasEnabled)
 | 
						|
    KdEnableScreen (pScreen);
 | 
						|
  
 | 
						|
  return TRUE;
 | 
						|
  
 | 
						|
 bail4:
 | 
						|
  EPHYR_LOG("bailed");
 | 
						|
  
 | 
						|
  ephyrUnmapFramebuffer (screen);
 | 
						|
  *scrpriv = oldscr;
 | 
						|
  (void) ephyrMapFramebuffer (screen);
 | 
						|
  
 | 
						|
  pScreen->width = oldwidth;
 | 
						|
  pScreen->height = oldheight;
 | 
						|
  pScreen->mmWidth = oldmmwidth;
 | 
						|
  pScreen->mmHeight = oldmmheight;
 | 
						|
  
 | 
						|
  if (wasEnabled)
 | 
						|
    KdEnableScreen (pScreen);
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
ephyrRandRInit (ScreenPtr pScreen)
 | 
						|
{
 | 
						|
  rrScrPrivPtr    pScrPriv;
 | 
						|
  
 | 
						|
  if (!RRScreenInit (pScreen))
 | 
						|
    return FALSE;
 | 
						|
  
 | 
						|
  pScrPriv = rrGetScrPriv(pScreen);
 | 
						|
  pScrPriv->rrGetInfo = ephyrRandRGetInfo;
 | 
						|
  pScrPriv->rrSetConfig = ephyrRandRSetConfig;
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
Bool
 | 
						|
ephyrCreateColormap (ColormapPtr pmap)
 | 
						|
{
 | 
						|
  return fbInitializeColormap (pmap);
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
ephyrInitScreen (ScreenPtr pScreen)
 | 
						|
{
 | 
						|
  KdScreenPriv(pScreen);
 | 
						|
  KdScreenInfo	*screen    = pScreenPriv->screen;
 | 
						|
 | 
						|
  EPHYR_LOG ("pScreen->myNum:%d\n", pScreen->myNum) ;
 | 
						|
  hostx_set_screen_number (screen, pScreen->myNum);
 | 
						|
  hostx_set_win_title (screen, "(ctrl+shift grabs mouse and keyboard)") ;
 | 
						|
  pScreen->CreateColormap = ephyrCreateColormap;
 | 
						|
 | 
						|
#ifdef XV
 | 
						|
  if (!ephyrNoXV) {
 | 
						|
      if (!ephyrInitVideo (pScreen)) {
 | 
						|
          EPHYR_LOG_ERROR ("failed to initialize xvideo\n") ;
 | 
						|
      } else {
 | 
						|
          EPHYR_LOG ("initialized xvideo okay\n") ;
 | 
						|
      }
 | 
						|
  }
 | 
						|
#endif /*XV*/
 | 
						|
 | 
						|
#ifdef XEPHYR_DRI
 | 
						|
  if (!ephyrNoDRI && !hostx_has_dri ()) {
 | 
						|
      EPHYR_LOG ("host x does not support DRI. Disabling DRI forwarding\n") ;
 | 
						|
      ephyrNoDRI = TRUE ;
 | 
						|
      noGlxVisualInit = FALSE ;
 | 
						|
  }
 | 
						|
  if (!ephyrNoDRI) {
 | 
						|
    ephyrDRIExtensionInit (pScreen) ;
 | 
						|
    ephyrHijackGLXExtension () ;
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef GLXEXT
 | 
						|
  if (ephyrNoDRI) {
 | 
						|
      noGlxVisualInit = FALSE ;
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
ephyrFinishInitScreen (ScreenPtr pScreen)
 | 
						|
{
 | 
						|
  /* FIXME: Calling this even if not using shadow.  
 | 
						|
   * Seems harmless enough. But may be safer elsewhere.
 | 
						|
   */
 | 
						|
  if (!shadowSetup (pScreen))
 | 
						|
    return FALSE;
 | 
						|
 | 
						|
#ifdef RANDR
 | 
						|
  if (!ephyrRandRInit (pScreen))
 | 
						|
    return FALSE;
 | 
						|
#endif
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
ephyrCreateResources (ScreenPtr pScreen)
 | 
						|
{
 | 
						|
  KdScreenPriv(pScreen);
 | 
						|
  KdScreenInfo	*screen    = pScreenPriv->screen;
 | 
						|
  EphyrScrPriv	*scrpriv   = screen->driver;
 | 
						|
 | 
						|
  EPHYR_LOG("mark pScreen=%p mynum=%d shadow=%d",
 | 
						|
            pScreen, pScreen->myNum, scrpriv->shadow);
 | 
						|
 | 
						|
  if (scrpriv->shadow) 
 | 
						|
    return KdShadowSet (pScreen, 
 | 
						|
			scrpriv->randr, 
 | 
						|
			ephyrShadowUpdate, 
 | 
						|
			ephyrWindowLinear);
 | 
						|
  else
 | 
						|
    return ephyrSetInternalDamage(pScreen); 
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ephyrPreserve (KdCardInfo *card)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
ephyrEnable (ScreenPtr pScreen)
 | 
						|
{
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
ephyrDPMS (ScreenPtr pScreen, int mode)
 | 
						|
{
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ephyrDisable (ScreenPtr pScreen)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ephyrRestore (KdCardInfo *card)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ephyrScreenFini (KdScreenInfo *screen)
 | 
						|
{
 | 
						|
    EphyrScrPriv  *scrpriv = screen->driver;
 | 
						|
    if (scrpriv->shadow) {
 | 
						|
        KdShadowFbFree (screen, 0);
 | 
						|
    }
 | 
						|
    xfree(screen->driver);
 | 
						|
    screen->driver = NULL;
 | 
						|
}
 | 
						|
 | 
						|
/*  
 | 
						|
 * Port of Mark McLoughlin's Xnest fix for focus in + modifier bug.
 | 
						|
 * See https://bugs.freedesktop.org/show_bug.cgi?id=3030
 | 
						|
 */
 | 
						|
void
 | 
						|
ephyrUpdateModifierState(unsigned int state)
 | 
						|
{
 | 
						|
  DeviceIntPtr pkeydev;
 | 
						|
  KeyClassPtr  keyc;
 | 
						|
  int          i;
 | 
						|
  CARD8        mask;
 | 
						|
 | 
						|
  pkeydev = (DeviceIntPtr)LookupKeyboardDevice();
 | 
						|
 | 
						|
  if (!pkeydev)
 | 
						|
    return;
 | 
						|
  
 | 
						|
  keyc = pkeydev->key;
 | 
						|
  
 | 
						|
  state = state & 0xff;
 | 
						|
  
 | 
						|
  if (keyc->state == state)
 | 
						|
    return;
 | 
						|
  
 | 
						|
  for (i = 0, mask = 1; i < 8; i++, mask <<= 1) 
 | 
						|
    {
 | 
						|
      int key;
 | 
						|
      
 | 
						|
      /* Modifier is down, but shouldn't be   */
 | 
						|
      if ((keyc->state & mask) && !(state & mask)) 
 | 
						|
	{
 | 
						|
	  int count = keyc->modifierKeyCount[i];
 | 
						|
	  
 | 
						|
	  for (key = 0; key < MAP_LENGTH; key++)
 | 
						|
	    if (keyc->modifierMap[key] & mask) 
 | 
						|
	      {
 | 
						|
		int bit;
 | 
						|
		BYTE *kptr;
 | 
						|
		
 | 
						|
		kptr = &keyc->down[key >> 3];
 | 
						|
		bit = 1 << (key & 7);
 | 
						|
		
 | 
						|
		if (*kptr & bit && ephyrKbd &&
 | 
						|
                    ((EphyrKbdPrivate *)ephyrKbd->driverPrivate)->enabled)
 | 
						|
		  KdEnqueueKeyboardEvent(ephyrKbd, key, TRUE); /* release */
 | 
						|
		
 | 
						|
		if (--count == 0)
 | 
						|
		  break;
 | 
						|
	      }
 | 
						|
	}
 | 
						|
       
 | 
						|
      /* Modifier shoud be down, but isn't   */
 | 
						|
      if (!(keyc->state & mask) && (state & mask))
 | 
						|
	for (key = 0; key < MAP_LENGTH; key++)
 | 
						|
	  if (keyc->modifierMap[key] & mask) 
 | 
						|
	    {
 | 
						|
              if (keyc->modifierMap[key] & mask && ephyrKbd &&
 | 
						|
                  ((EphyrKbdPrivate *)ephyrKbd->driverPrivate)->enabled)
 | 
						|
	          KdEnqueueKeyboardEvent(ephyrKbd, key, FALSE); /* press */
 | 
						|
	      break;
 | 
						|
	    }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
ephyrBlockSigio (void)
 | 
						|
{
 | 
						|
    sigset_t set;
 | 
						|
 | 
						|
    sigemptyset (&set);
 | 
						|
    sigaddset (&set, SIGIO);
 | 
						|
    sigprocmask (SIG_BLOCK, &set, 0);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
ephyrUnblockSigio (void)
 | 
						|
{
 | 
						|
    sigset_t set;
 | 
						|
 | 
						|
    sigemptyset (&set);
 | 
						|
    sigaddset (&set, SIGIO);
 | 
						|
    sigprocmask (SIG_UNBLOCK, &set, 0);
 | 
						|
}
 | 
						|
 | 
						|
static Bool
 | 
						|
ephyrCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y)
 | 
						|
{
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
ephyrCrossScreen (ScreenPtr pScreen, Bool entering)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
int ephyrCurScreen; /*current event screen*/
 | 
						|
 | 
						|
static void
 | 
						|
ephyrWarpCursor (ScreenPtr pScreen, int x, int y)
 | 
						|
{
 | 
						|
    ephyrBlockSigio ();
 | 
						|
    ephyrCurScreen = pScreen->myNum;
 | 
						|
    miPointerWarpCursor (pScreen, x, y);
 | 
						|
    ephyrUnblockSigio ();
 | 
						|
}
 | 
						|
 | 
						|
miPointerScreenFuncRec ephyrPointerScreenFuncs =
 | 
						|
{
 | 
						|
  ephyrCursorOffScreen,
 | 
						|
  ephyrCrossScreen,
 | 
						|
  ephyrWarpCursor
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
void
 | 
						|
ephyrPoll(void)
 | 
						|
{
 | 
						|
  EphyrHostXEvent ev;
 | 
						|
 | 
						|
  while (hostx_get_event(&ev))
 | 
						|
    {
 | 
						|
      switch (ev.type)
 | 
						|
        {
 | 
						|
        case EPHYR_EV_MOUSE_MOTION:
 | 
						|
          if (!ephyrMouse ||
 | 
						|
              !((EphyrPointerPrivate *)ephyrMouse->driverPrivate)->enabled) {
 | 
						|
              EPHYR_LOG ("skipping mouse motion:%d\n", ephyrCurScreen) ;
 | 
						|
              continue;
 | 
						|
          }
 | 
						|
          {
 | 
						|
            if (ephyrCurScreen != ev.data.mouse_motion.screen)
 | 
						|
              {
 | 
						|
                  EPHYR_LOG ("warping mouse cursor:%d\n", ephyrCurScreen) ;
 | 
						|
                  ephyrWarpCursor(screenInfo.screens[ev.data.mouse_motion.screen],
 | 
						|
                                   ev.data.mouse_motion.x,
 | 
						|
                                   ev.data.mouse_motion.y );
 | 
						|
              }
 | 
						|
            else
 | 
						|
              {
 | 
						|
                  EPHYR_LOG ("enqueuing mouse motion:%d\n", ephyrCurScreen) ;
 | 
						|
                  KdEnqueuePointerEvent(ephyrMouse, mouseState,
 | 
						|
                                        ev.data.mouse_motion.x,
 | 
						|
                                        ev.data.mouse_motion.y,
 | 
						|
                                        0);
 | 
						|
              }
 | 
						|
          }
 | 
						|
          break;
 | 
						|
 | 
						|
        case EPHYR_EV_MOUSE_PRESS:
 | 
						|
          if (!ephyrMouse ||
 | 
						|
              !((EphyrPointerPrivate *)ephyrMouse->driverPrivate)->enabled) {
 | 
						|
              EPHYR_LOG ("skipping mouse press:%d\n", ephyrCurScreen) ;
 | 
						|
              continue;
 | 
						|
          }
 | 
						|
          EPHYR_LOG ("enqueuing mouse press:%d\n", ephyrCurScreen) ;
 | 
						|
	  ephyrUpdateModifierState(ev.key_state);
 | 
						|
	  mouseState |= ev.data.mouse_down.button_num;
 | 
						|
	  KdEnqueuePointerEvent(ephyrMouse, mouseState|KD_MOUSE_DELTA, 0, 0, 0);
 | 
						|
	  break;
 | 
						|
 | 
						|
	case EPHYR_EV_MOUSE_RELEASE:
 | 
						|
          if (!ephyrMouse ||
 | 
						|
              !((EphyrPointerPrivate *)ephyrMouse->driverPrivate)->enabled)
 | 
						|
              continue;
 | 
						|
	  ephyrUpdateModifierState(ev.key_state);
 | 
						|
	  mouseState &= ~ev.data.mouse_up.button_num;
 | 
						|
          EPHYR_LOG ("enqueuing mouse release:%d\n", ephyrCurScreen) ;
 | 
						|
	  KdEnqueuePointerEvent(ephyrMouse, mouseState|KD_MOUSE_DELTA, 0, 0, 0);
 | 
						|
	  break;
 | 
						|
 | 
						|
	case EPHYR_EV_KEY_PRESS:
 | 
						|
          if (!ephyrKbd ||
 | 
						|
              !((EphyrKbdPrivate *)ephyrKbd->driverPrivate)->enabled)
 | 
						|
              continue;
 | 
						|
	  ephyrUpdateModifierState(ev.key_state);
 | 
						|
	  KdEnqueueKeyboardEvent (ephyrKbd, ev.data.key_down.scancode, FALSE);
 | 
						|
	  break;
 | 
						|
 | 
						|
	case EPHYR_EV_KEY_RELEASE:
 | 
						|
          if (!ephyrKbd ||
 | 
						|
              !((EphyrKbdPrivate *)ephyrKbd->driverPrivate)->enabled)
 | 
						|
              continue;
 | 
						|
	  KdEnqueueKeyboardEvent (ephyrKbd, ev.data.key_up.scancode, TRUE);
 | 
						|
	  break;
 | 
						|
 | 
						|
	default:
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ephyrCardFini (KdCardInfo *card)
 | 
						|
{
 | 
						|
  EphyrPriv	*priv = card->driver;
 | 
						|
  xfree (priv);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ephyrGetColors (ScreenPtr pScreen, int fb, int n, xColorItem *pdefs)
 | 
						|
{
 | 
						|
  /* XXX Not sure if this is right */
 | 
						|
  
 | 
						|
  EPHYR_LOG("mark");
 | 
						|
  
 | 
						|
  while (n--)
 | 
						|
    {
 | 
						|
      pdefs->red = 0;
 | 
						|
      pdefs->green = 0;
 | 
						|
      pdefs->blue = 0;
 | 
						|
      pdefs++;
 | 
						|
    }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ephyrPutColors (ScreenPtr pScreen, int fb, int n, xColorItem *pdefs)
 | 
						|
{
 | 
						|
  int min, max, p;
 | 
						|
 | 
						|
  /* XXX Not sure if this is right */
 | 
						|
 | 
						|
  min = 256;
 | 
						|
  max = 0;
 | 
						|
  
 | 
						|
  while (n--)
 | 
						|
    {
 | 
						|
      p = pdefs->pixel;
 | 
						|
      if (p < min)
 | 
						|
	min = p;
 | 
						|
      if (p > max)
 | 
						|
	max = p;
 | 
						|
 | 
						|
      hostx_set_cmap_entry(p, 		
 | 
						|
			   pdefs->red >> 8,
 | 
						|
			   pdefs->green >> 8,
 | 
						|
			   pdefs->blue >> 8);
 | 
						|
      pdefs++;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* Mouse calls */
 | 
						|
 | 
						|
static Status
 | 
						|
MouseInit (KdPointerInfo *pi)
 | 
						|
{
 | 
						|
    pi->driverPrivate = (EphyrPointerPrivate *)
 | 
						|
                         xcalloc(sizeof(EphyrPointerPrivate), 1);
 | 
						|
    ((EphyrPointerPrivate *)pi->driverPrivate)->enabled = FALSE;
 | 
						|
    pi->nAxes = 3;
 | 
						|
    pi->nButtons = 32;
 | 
						|
    pi->name = KdSaveString("Xephyr virtual mouse");
 | 
						|
    ephyrMouse = pi;
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
static Status
 | 
						|
MouseEnable (KdPointerInfo *pi)
 | 
						|
{
 | 
						|
    ((EphyrPointerPrivate *)pi->driverPrivate)->enabled = TRUE;
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
MouseDisable (KdPointerInfo *pi)
 | 
						|
{
 | 
						|
    ((EphyrPointerPrivate *)pi->driverPrivate)->enabled = FALSE;
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
MouseFini (KdPointerInfo *pi)
 | 
						|
{
 | 
						|
    ephyrMouse = NULL; 
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
KdPointerDriver EphyrMouseDriver = {
 | 
						|
    "ephyr",
 | 
						|
    MouseInit,
 | 
						|
    MouseEnable,
 | 
						|
    MouseDisable,
 | 
						|
    MouseFini,
 | 
						|
    NULL,
 | 
						|
};
 | 
						|
 | 
						|
/* Keyboard */
 | 
						|
 | 
						|
static Status
 | 
						|
EphyrKeyboardInit (KdKeyboardInfo *ki)
 | 
						|
{
 | 
						|
  ki->driverPrivate = (EphyrKbdPrivate *)
 | 
						|
                       xcalloc(sizeof(EphyrKbdPrivate), 1);
 | 
						|
  hostx_load_keymap();
 | 
						|
  if (!ephyrKeySyms.map) {
 | 
						|
      ErrorF("Couldn't load keymap from host\n");
 | 
						|
      return BadAlloc;
 | 
						|
  }
 | 
						|
  ki->keySyms.minKeyCode = ephyrKeySyms.minKeyCode;
 | 
						|
  ki->keySyms.maxKeyCode = ephyrKeySyms.maxKeyCode;
 | 
						|
  ki->minScanCode = ki->keySyms.minKeyCode;
 | 
						|
  ki->maxScanCode = ki->keySyms.maxKeyCode;
 | 
						|
  ki->keySyms.mapWidth = ephyrKeySyms.mapWidth;
 | 
						|
  ki->keySyms.map = ephyrKeySyms.map;
 | 
						|
  ki->name = KdSaveString("Xephyr virtual keyboard");
 | 
						|
  ephyrKbd = ki;
 | 
						|
  return Success;
 | 
						|
}
 | 
						|
 | 
						|
static Status
 | 
						|
EphyrKeyboardEnable (KdKeyboardInfo *ki)
 | 
						|
{
 | 
						|
    ((EphyrKbdPrivate *)ki->driverPrivate)->enabled = TRUE;
 | 
						|
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
EphyrKeyboardDisable (KdKeyboardInfo *ki)
 | 
						|
{
 | 
						|
    ((EphyrKbdPrivate *)ki->driverPrivate)->enabled = FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
EphyrKeyboardFini (KdKeyboardInfo *ki)
 | 
						|
{
 | 
						|
    /* not xfree: we call malloc from hostx.c. */
 | 
						|
    free(ki->keySyms.map);
 | 
						|
    ephyrKbd = NULL;
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
EphyrKeyboardLeds (KdKeyboardInfo *ki, int leds)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
EphyrKeyboardBell (KdKeyboardInfo *ki, int volume, int frequency, int duration)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
KdKeyboardDriver EphyrKeyboardDriver = {
 | 
						|
    "ephyr",
 | 
						|
    EphyrKeyboardInit,
 | 
						|
    EphyrKeyboardEnable,
 | 
						|
    EphyrKeyboardLeds,
 | 
						|
    EphyrKeyboardBell,
 | 
						|
    EphyrKeyboardDisable,
 | 
						|
    EphyrKeyboardFini,
 | 
						|
    NULL,
 | 
						|
};
 |