/* $XConsortium: sunInit.c,v 5.32 92/12/03 10:05:15 rws Exp $ */
/*
 * sunInit.c --
 *	Initialization functions for screen/keyboard/mouse, etc.
 *
 * Copyright (c) 1987 by the Regents of the University of California
 *
 * Permission to use, copy, modify, and distribute this
 * software and its documentation for any purpose and without
 * fee is hereby granted, provided that the above copyright
 * notice appear in all copies.  The University of California
 * makes no representations about the suitability of this
 * software for any purpose.  It is provided "as is" without
 * express or implied warranty.
 *
 *
 */

/************************************************************
Copyright 1987 by Sun Microsystems, Inc. Mountain View, CA.

                    All Rights Reserved

Permission  to  use,  copy,  modify,  and  distribute   this
software  and  its documentation for any purpose and without
fee is hereby granted, provided that the above copyright no-
tice  appear  in all copies and that both that copyright no-
tice and this permission notice appear in  supporting  docu-
mentation,  and  that the names of Sun or MIT not be used in
advertising or publicity pertaining to distribution  of  the
software  without specific prior written permission. Sun and
M.I.T. make no representations about the suitability of this
software for any purpose. It is provided "as is" without any
express or implied warranty.

SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO  THIS  SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE  LI-
ABLE  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 SVR4
#include    <unistd.h>
#include    <stdlib.h>
#endif
#include    "sun.h"
#include    <servermd.h>
#include    "dixstruct.h"
#include    "dix.h"
#include    "opaque.h"
#include    "mipointer.h"

extern int sunMouseProc();
extern int sunKbdProc();
extern Bool sunBW2Probe(), sunBW2Create();
#ifndef MONO_ONLY
extern Bool sunCG2CProbe(), sunCG2CCreate();
extern Bool sunCG3CProbe(), sunCG3CCreate();
extern Bool sunCG4CProbe(), sunCG4CCreate();
#ifdef FBTYPE_SUNFAST_COLOR /* doesn't exist in sunos3.x */
extern Bool sunCG6CProbe(), sunCG6CCreate();
#endif
extern Bool sunCG8CProbe(), sunCG8CCreate ();
#endif
extern void ProcessInputEvents();

extern void SetInputCheck();
extern char *strncpy();
extern GCPtr CreateScratchGC();

#define	XDEVICE	"XDEVICE"
#define	PARENT	"WINDOW_GFX"

static int autoRepeatHandlersInstalled;	/* FALSE each time InitOutput called */

static Bool sunDevsProbed = FALSE;
Bool sunSupportsDepth8 = FALSE;
Bool sunSupportsDepth24 = FALSE;
unsigned long sunGeneration = 0;
int sunScreenIndex;
Bool FlipPixels = FALSE;

#ifdef SVR4
Signal(sig, handler)
    int sig;
    void (*handler)();
{
    struct sigaction act;

    sigemptyset(&act.sa_mask);
    if (handler != SIG_IGN)
	sigaddset(&act.sa_mask, sig);
    act.sa_flags = 0;
    act.sa_handler = handler;
    sigaction(sig, &act, NULL);
}
#endif

/*-
 *-----------------------------------------------------------------------
 * SigIOHandler --
 *	Signal handler for SIGIO - input is available.
 *
 * Results:
 *	sunSigIO is set - ProcessInputEvents() will be called soon.
 *
 * Side Effects:
 *	None
 *
 *-----------------------------------------------------------------------
 */
/*ARGSUSED*/
static void
SigIOHandler(sig, code, scp)
    int		code;
    int		sig;
    struct sigcontext *scp;
{
    sunEnqueueEvents ();
}

sunFbDataRec sunFbData[] = {
#ifndef MONO_ONLY
    sunBW2Probe,  	"/dev/bwtwo0",	    sunBW2Create,
    sunCG3CProbe,  	"/dev/cgthree0",    sunCG3CCreate,
#ifdef FBTYPE_SUNFAST_COLOR
    sunCG6CProbe,	"/dev/cgsix0",	    sunCG6CCreate,
#endif
    sunCG2CProbe,  	"/dev/cgtwo0",	    sunCG2CCreate,
    sunCG4CProbe,  	"/dev/cgfour0",	    sunCG4CCreate,
#ifdef DEPTH24
    sunCG8CProbe,	"/dev/cgeight0",    sunCG8CCreate,
#endif
#endif
    sunBW2Probe,  	"/dev/bwtwo0",	    sunBW2Create,
};

#ifdef MONO_ONLY
#define DEV_START   0
#define DEV_END	    0
#else
#define DEV_START   1
#define DEV_END	    1
#endif

/*
 * NUMSCREENS is the number of supported frame buffers (i.e. the number of
 * structures in sunFbData which have an actual probeProc).
 */
#define NUMSCREENS (sizeof(sunFbData)/sizeof(sunFbData[0]))
#define NUMDEVICES  2

fbFd sunFbs[NUMDEVICES];

static PixmapFormatRec	format1 = {
    1, 1, BITMAP_SCANLINE_PAD,	/* 1-bit deep */
};
static PixmapFormatRec	format8 = {
    8, 8, BITMAP_SCANLINE_PAD,	/* 8-bit deep */
};
static PixmapFormatRec	format24 = {
    24, 32, BITMAP_SCANLINE_PAD,	/* 24-bit deep */
};

/*-
 *-----------------------------------------------------------------------
 * sunNonBlockConsoleOff --
 *	Turn non-blocking mode on the console off, so you don't get logged
 *	out when the server exits.
 *
 * Results:
 *	None.
 *
 * Side Effects:
 *	None.
 *
 *-----------------------------------------------------------------------
 */
/*ARGSUSED*/
#ifdef SVR4
void
sunNonBlockConsoleOff()
#else
sunNonBlockConsoleOff(arg)
    char	*arg;
#endif
{
    register int i;

    i = fcntl(2, F_GETFL, 0);
    if (i >= 0)
	(void) fcntl(2, F_SETFL, i & ~FNDELAY);
}

/*-
 *-----------------------------------------------------------------------
 * InitOutput --
 *	Initialize screenInfo for all actually accessible framebuffers.
 *	The
 *
 * Results:
 *	screenInfo init proc field set
 *
 * Side Effects:
 *	None
 *
 *-----------------------------------------------------------------------
 */

InitOutput(pScreenInfo, argc, argv)
    ScreenInfo 	  *pScreenInfo;
    int     	  argc;
    char    	  **argv;
{
    int     	  i, n, dev;
    int		  nonBlockConsole = 0;
    static int	  setup_on_exit = 0;
    int		  devStart = DEV_START;
    extern Bool	  RunFromSmartParent;

    if (!monitorResolution)
	monitorResolution = 90;
    if (RunFromSmartParent)
	nonBlockConsole = 1;
    for (i = 1; i < argc; i++) {
	if (!strcmp(argv[i],"-debug"))
	    nonBlockConsole = 0;
	else if (!strcmp(argv[i],"-mono"))
	    devStart = 0;
    }
    /*
     *	Writes to /dev/console can block - causing an
     *	excess of error messages to hang the server in
     *	deadlock.  So.......
     */
    if (nonBlockConsole) {
	if (!setup_on_exit) {
#ifdef SVR4
	    if (atexit(sunNonBlockConsoleOff))
#else
	    if (on_exit(sunNonBlockConsoleOff, (char *)0))
#endif
		ErrorF("InitOutput: can't register NBIO exit handler\n");
	    setup_on_exit = 1;
	}
	i = fcntl(2, F_GETFL, 0);
	if (i >= 0)
	    i = fcntl(2, F_SETFL, i | FNDELAY);
	if (i < 0) {
	    perror("fcntl");
	    ErrorF("InitOutput: can't put stderr in non-block mode\n");
	}
    }
    pScreenInfo->imageByteOrder = IMAGE_BYTE_ORDER;
    pScreenInfo->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT;
    pScreenInfo->bitmapScanlinePad = BITMAP_SCANLINE_PAD;
    pScreenInfo->bitmapBitOrder = BITMAP_BIT_ORDER;

    pScreenInfo->numPixmapFormats = 1;
    pScreenInfo->formats[0] = format1;

    autoRepeatHandlersInstalled = FALSE;

    if (!sunDevsProbed)
    {
	n = 0;
	for (i = NUMSCREENS, dev = devStart; --i >= DEV_END; dev++) {
	    if ((*sunFbData[dev].probeProc)(pScreenInfo, n, dev, argc, argv))
		n++;
	    else
		sunFbData[dev].createProc = NULL;
	}
	sunDevsProbed = TRUE;
	if (n == 0)
	    return;
    }
    if (sunSupportsDepth8)
	pScreenInfo->formats[pScreenInfo->numPixmapFormats++] = format8;
    if (sunSupportsDepth24)
	pScreenInfo->formats[pScreenInfo->numPixmapFormats++] = format24;
    for (i = NUMSCREENS, dev = devStart; --i >= DEV_END; dev++) {
	if (sunFbData[dev].createProc)
	    (*sunFbData[dev].createProc)(pScreenInfo, argc, argv);
    }
    sunInitCursor();
    signal(SIGWINCH, SIG_IGN);
}

/*-
 *-----------------------------------------------------------------------
 * InitInput --
 *	Initialize all supported input devices...what else is there
 *	besides pointer and keyboard?
 *
 * Results:
 *	None.
 *
 * Side Effects:
 *	Two DeviceRec's are allocated and registered as the system pointer
 *	and keyboard devices.
 *
 *-----------------------------------------------------------------------
 */
/*ARGSUSED*/
InitInput(argc, argv)
    int     	  argc;
    char    	  **argv;
{
    DevicePtr p, k;
    static int  zero = 0;
    
    p = AddInputDevice(sunMouseProc, TRUE);
    k = AddInputDevice(sunKbdProc, TRUE);
    if (!p || !k)
	FatalError("failed to create input devices in InitInput");

    RegisterPointerDevice(p);
    RegisterKeyboardDevice(k);
    miRegisterPointerDevice(screenInfo.screens[0], p);
    if (!mieqInit (k, p))
	return FALSE;
#ifdef SVR4
    Signal(SIGPOLL, SigIOHandler);
#else
    signal(SIGIO, SigIOHandler);
#endif
}


static Bool
sunCloseScreen (i, pScreen)
    int		i;
    ScreenPtr	pScreen;
{
    SetupScreen(pScreen);
    Bool    ret;

#ifdef SVR4
    Signal (SIGPOLL, SIG_IGN);
#else
    signal (SIGIO, SIG_IGN);
#endif
    sunDisableCursor (pScreen);
    pScreen->CloseScreen = pPrivate->CloseScreen;
    ret = (*pScreen->CloseScreen) (i, pScreen);
    (void) (*pScreen->SaveScreen) (pScreen, SCREEN_SAVER_OFF);
    xfree ((pointer) pPrivate);
    return ret;
}

Bool
sunSaveScreen (pScreen, on)
    ScreenPtr	pScreen;
    int		on;
{
    int		state;

    if (on != SCREEN_SAVER_FORCER)
    {
	if (on == SCREEN_SAVER_ON)
	    state = 0;
	else
	    state = 1;
	(void) ioctl(sunFbs[pScreen->myNum].fd, FBIOSVIDEO, &state);
    }
    return( TRUE );
}

/*-
 *-----------------------------------------------------------------------
 * sunScreenInit --
 *	Things which must be done for all types of frame buffers...
 *	Should be called last of all.
 *
 * Results:
 *	TRUE if successful, else FALSE
 *
 * Side Effects:
 *	Both a BlockHandler and a WakeupHandler are installed for the
 *	first screen.  Together, these handlers implement autorepeat
 *	keystrokes on the Sun.
 *
 *-----------------------------------------------------------------------
 */

Bool
sunScreenAllocate (pScreen)
    ScreenPtr	pScreen;
{
    sunScreenPtr    pPrivate;

    if (sunGeneration != serverGeneration)
    {
	sunScreenIndex = AllocateScreenPrivateIndex();
	if (sunScreenIndex < 0)
	    return FALSE;
	sunGeneration = serverGeneration;
    }
    pPrivate = (sunScreenPtr) xalloc (sizeof (sunScreenRec));
    if (!pPrivate)
	return FALSE;

    pScreen->devPrivates[sunScreenIndex].ptr = (pointer) pPrivate;
    return TRUE;
}

Bool
sunScreenInit (pScreen)
    ScreenPtr	pScreen;
{
    SetupScreen(pScreen);
    extern void   sunBlockHandler();
    extern void   sunWakeupHandler();
    static ScreenPtr autoRepeatScreen;
    extern miPointerScreenFuncRec   sunPointerScreenFuncs;

    pPrivate->installedMap = 0;
    pPrivate->CloseScreen = pScreen->CloseScreen;
    pScreen->CloseScreen = sunCloseScreen;
    pScreen->SaveScreen = sunSaveScreen;

    /*
     *	Block/Unblock handlers
     */
    if (autoRepeatHandlersInstalled == FALSE) {
	autoRepeatScreen = pScreen;
	autoRepeatHandlersInstalled = TRUE;
    }

    if (pScreen == autoRepeatScreen) {
        pScreen->BlockHandler = sunBlockHandler;
        pScreen->WakeupHandler = sunWakeupHandler;
    }

    if (!sunCursorInitialize (pScreen))
	miDCInitialize (pScreen, &sunPointerScreenFuncs);

#ifdef SUN_WINDOWS
    /*
     * We need to wrap one of the cursor functions so that
     * we can keep the SunWindows cursor position in sync
     * with X. We still call the mi version to do the real
     * work.
     */
    pPrivate->SetCursorPosition = pScreen->SetCursorPosition;
    pScreen->SetCursorPosition = sunSetCursorPosition;
#endif
    sunInitCursor ();

    return TRUE;
}

extern char *getenv();

/*-
 *-----------------------------------------------------------------------
 * nthdev --
 *	Return the nth device in a colon-separated list of devices.
 *	n is 0-origin.
 *
 * Results:
 *	A pointer to a STATIC string which is the device name.
 *
 * Side Effects:
 *	None.
 *
 *-----------------------------------------------------------------------
 */
static char *
nthdev (dList, n)
    register char    *dList;	    /* Colon-separated device names */
    int	    n;	  	    /* Device number wanted */
{
    char *result;
    static char returnstring[100];

    while (n--) {
	while (*dList && *dList != ':') {
	    dList++;
	}
	if (*dList)
	    ++dList;
    }
    if (*dList) {
	register char *cp = dList;

	while (*cp && *cp != ':') {
	    cp++;
	}
	result = returnstring;
	strncpy (result, dList, cp - dList);
	result[cp - dList] = '\0';
    } else {
	result = (char *)0;
    }
    return (result);
}

/*-
 *-----------------------------------------------------------------------
 * sunOpenFrameBuffer --
 *	Open a frame buffer according to several rules. If running under
 *	overview and we're set up for it, use the device given in the
 *	PARENT envariable and note that the screen is under overview.
 *	Else find the device to use by looking in the sunFbData table,
 *	an XDEVICE envariable, a -dev switch or using /dev/fb if trying
 *	to open screen 0 and all else has failed.
 *
 * Results:
 *	The fd of the framebuffer.
 *
 * Side Effects:
 *
 *-----------------------------------------------------------------------
 */
int
sunOpenFrameBuffer(expect, pfbType, index, fbNum, argc, argv)
    int	    	  expect;   	/* The expected type of framebuffer */
    struct fbtype *pfbType; 	/* Place to store the fb info */
    int	    	  fbNum;    	/* Index into the sunFbData array */
    int	    	  index;    	/* Screen index */
    int	    	  argc;	    	/* Command-line arguments... */
    char	  **argv;   	/* ... */
{
    char       	  *name=(char *)0;
    int           i;	    	/* Index into argument list */
    int           fd = -1;	    	/* Descriptor to device */
    static int	  devFbUsed=FALSE;  /* true if /dev/fb has been used for a */
    	    	  	    	    /* screen already */
    static Bool	  inited = FALSE;
    static char	  *xdevice; 	/* string of devices to use from environ */
    static char	  *devsw;   	/* string of devices from args */
    struct fbgattr  fbattr;
    int		  type;

    sunFbs[index].parent = FALSE;

    if (!inited) {
	xdevice = devsw = (char *)NULL;

	xdevice = getenv (XDEVICE);
	/*
	 * Look for an argument of the form -dev <device-string>
	 * If such a one is found place the <device-string> in devsw.
	 */
	for (i = 1; i < argc; i++) {
	    if ((strcmp(argv[i], "-dev") == 0) && (i + 1 < argc)) {
		devsw = argv[i+1];
		break;
	    }
	}
	inited = TRUE;
    }

    /*
     * Attempt to find a file name for the frame buffer 
     */

    /*
     * First see if any device was given on the command line.
     * If one was and the device is both readable and writeable,
     * set 'name' to it, else set it to NULL.
     */
    if (devsw == (char *)NULL ||
	(name = nthdev (devsw, index)) == (char *)NULL ||
	(access (name, R_OK | W_OK) != 0) ||
	(strcmp(name, sunFbData[fbNum].devName) != 0)) {
	    name = (char *)NULL;
    }
	    
    /*
     * If we still don't have a device for this screen, check the
     * environment variable for one. If one was given, stick its
     * path in name and check its accessibility. If it's not
     * properly accessible, then reset the name to NULL to force the
     * checking of the sunFbData array.
     */
    if (devsw == (char *)NULL && name == (char *)NULL &&
	xdevice != (char *)NULL &&
	(name = nthdev(xdevice, index)) != (char *)NULL &&
	(access (name, R_OK | W_OK) != 0)) {
	    name = (char *)NULL;
    }

    /*
     * Take the device given in the frame buffer description
     * and see if it exists and is accessible. If it does/is,
     * we will use it, as long as no other device was given.
     */
    if (devsw == (char *)NULL && name == (char *)NULL &&
	access(sunFbData[fbNum].devName, (R_OK | W_OK)) == 0) {
	    name = sunFbData[fbNum].devName;
    }

    /*
     * If we still have nothing and have yet to use "/dev/fb" for
     * a screen, default the name to be "/dev/fb"
     */
    if (devsw == (char *)NULL && name == (char *)NULL && !devFbUsed) {
	name = "/dev/fb";
    }


    if (name != (char *) NULL && sunUseSunWindows()) {
#ifdef	SUN_WINDOWS

	/*
	 * Running X in coexistence with SunWindows.
	 *
	 * This section of code enables X to run with SunWindows.  This is 
	 * accomplished by opening up screens and windows in the SunWindows 
	 * style and accepting input events from them.  However, since the X 
	 * graphics libraries want a raw framebuffer, we open the 
	 * framebuffer of the current screen and return that.  So we get 
	 * input from SunWindows but send output to the raw framebuffer.
	 */

	char       *parent = getenv("WINDOW_PARENT");
	struct screen sc;
	int	    winFd;
	int	    parentFd;
	int	    framebufferFd;
	Rect	    r;
	static struct screen newScreen;
	struct inputmask inputMask;
	Bool	    keepParent = FALSE;
	static int  sunFbFound = 0;	/* True if FB found under SunWindows */

	/*
	 * If no device was specified on the command line, open the window 
	 * specified in WINDOW_PARENT.  If a device was specified, open a 
	 * new screen on that device and use it as a parent window.
	 */

	if ( devsw ) {
	    bzero( (caddr_t)&newScreen, sizeof(newScreen) );
	    strcpy( newScreen.scr_fbname, name );
	    newScreen.scr_flags |= SCR_TOGGLEENABLE;
	    if ( (parentFd = win_screennew( &newScreen )) < 0 ) {
		ErrorF( "sunOpenFrameBuffer: Can't open new screen on %s.\n",
		    name );
		return( -1 );
	    }
	    keepParent = TRUE;
	} else {
	    if ((parentFd = open(parent, 2, 0)) < 0) {
		ErrorF("sunOpenFrameBuffer: Can't open parent %s.\n", parent);
		return (-1);
	    }
	}

	if ((winFd = win_getnewwindow()) < 0) {
	    ErrorF("sunOpenFrameBuffer: Can't open a new window.\n");
	    close( parentFd );
	    return (-1);
	}

	/* link the new window into the window hierarchy */
	bzero((caddr_t) & r, sizeof r);
	win_getrect(parentFd, &r);
	win_setrect(winFd, &r);
	win_setlink(winFd, WL_PARENT, win_fdtonumber(parentFd));
	win_setlink(winFd, WL_OLDERSIB, win_getlink(parentFd, WL_TOPCHILD));
	sunFbs[index].parent = TRUE;

	/*
	 * We would like to close the parent window here, since it's no 
	 * longer needed.  However, in the case where the parent is really a 
	 * screen, we have to keep it open, because closing a screen closes 
	 * all the windows on that screen.
	 */

	if ( ! keepParent )
	    close(parentFd);
	
	/*
	 * Express interest in SunView mouse events.  Note: the win_insert 
	 * must be AFTER setting the input mask in order to receive the 
	 * initial LOC_WINENTER event.
	 */

	input_imnull(&inputMask);
	inputMask.im_flags = IM_ASCII | IM_META | IM_NEGEVENT | IM_INTRANSIT;

	win_setinputcodebit(&inputMask, LOC_MOVE);
	win_setinputcodebit(&inputMask, LOC_WINEXIT);
	win_setinputcodebit(&inputMask, LOC_WINENTER);
	win_setinputcodebit(&inputMask, MS_LEFT);
	win_setinputcodebit(&inputMask, MS_MIDDLE);
	win_setinputcodebit(&inputMask, MS_RIGHT);
	win_set_pick_mask(winFd, &inputMask);

	input_imnull(&inputMask);
	win_setinputcodebit(&inputMask, KBD_USE);
	win_setinputcodebit(&inputMask, KBD_DONE);
	win_set_kbd_mask(winFd, &inputMask);

	win_insert(winFd);

	/*
	 * Determine the framebuffer name from the window's screen, then 
	 * open it.  Then do an FBIOGTYPE ioctl to determine its type.
	 */

	win_screenget( winFd, &sc );
	if ((framebufferFd = open(sc.scr_fbname, O_RDWR, 0)) < 0) {
	    ErrorF("sunOpenFrameBuffer: can't open %s\n",sc.scr_fbname);
	    (void) close(winFd);
	    (void) close(parentFd);
	    return (-1);
	}

	if (ioctl(framebufferFd, FBIOGTYPE, pfbType) < 0) {
	    perror("sunOpenFrameBuffer: FBIOGTYPE");
badfb:
	    (void) close(framebufferFd);
	    (void) close(winFd);
	    (void) close(parentFd);
	    return (-1);
	}

	if (pfbType->fb_type != expect) {
	    struct fbgattr fbgattr;
	    int i;

	    /*
	     * On a 3/110 we only want to open one display
	     * on /dev/fb (or /dev/cgfour0) if no device is
	     * specified in the command line.  If not, we won't
	     * be able to slide back and forth between X displays
	     * since only one SunWindows framebuffer is open.
	     * The screen that is opened is /dev/bwtwo0.
	     */
	    if (sunFbFound && (devsw == (char *) NULL))
		goto badfb;

	    if (ioctl(framebufferFd, FBIOGATTR, &fbgattr) < 0)
		goto badfb;
	    
	    for (i=0; i<FB_ATTR_NEMUTYPES; i++)
		if (fbgattr.emu_types[i] == expect)
		    break;
		else if (fbgattr.emu_types[i] == -1)
		    goto badfb;
	}
        /*
	 * NDELAY only applies to "input" fds, or fds that can be
	 * read.  sunwindows fds are read, while frame buffer fds aren't.
	 * That's why this fcntl is in the conditional compilation section.
	 */

	if (fcntl(winFd, F_SETFL, FNDELAY|FASYNC) < 0) {
	    ErrorF("Can't set FNDELAY|FASYNC on %s\n",name);
	    perror("sunOpenFrameBuffer");
	    (void) close(winFd);
	    return (-1);
	}
	
	fd = framebufferFd;
	windowFd = winFd;
	sunFbFound++;
#else
	ErrorF("Not configured to run inside SunWindows\n");
	fd = -1;
#endif /* SUN_WINDOWS */
    } else if (name) {
	fd = open(name, O_RDWR, 0);
        if (fd < 0) {
	    return (-1);
	} 
	if (ioctl(fd, FBIOGATTR, &fbattr) < 0)
	{
	    if (ioctl(fd, FBIOGTYPE, pfbType) < 0) {
	    	perror("sunOpenFrameBuffer");
	    	(void) close(fd);
	    	return (-1);
	    }
	    type = pfbType->fb_type;
	}
	else
	{
	    int	i;

	    type = fbattr.real_type;
	    *pfbType = fbattr.fbtype;
	    if (expect == FBTYPE_SUN2BW && expect != type)
	    {
	    	for (i = 0; i < FB_ATTR_NEMUTYPES; i++)
	    	{
		    if (expect == fbattr.emu_types[i])
		    {
		    	type = fbattr.emu_types[i];
			break;
		    }
	    	}
	    }
	}
	/* XXX - this is temporary 'cos the CG4 pretends its a BW2 */
	if (strcmp(name, sunFbData[fbNum].devName) != 0 && type != expect)
	{
	    (void) close(fd);
	    return (-1);
	}
    }

    if (name && strcmp (name, "/dev/fb") == 0) {
	devFbUsed = TRUE;
    }

    return (fd);
}
