/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/os2/os2_VTsw.c,v 3.13 2003/06/10 17:03:54 dawes Exp $ */
/*
 * Copyright 1993 by David Wexelblat <dwex@goblin.org>
 * Modified 1996 by Sebastien Marineau <marineau@genie.uottawa.ca>
 *
 * 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 David Wexelblat not be used in
 * advertising or publicity pertaining to distribution of the software without
 * specific, written prior permission.  David Wexelblat makes no representations
 * about the suitability of this software for any purpose.  It is provided
 * "as is" without express or implied warranty.
 *
 * DAVID WEXELBLAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL DAVID WEXELBLAT 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.
 *
 */
/* $XConsortium: os2_VTsw.c /main/7 1996/05/13 16:37:55 kaleb $ */

#define I_NEED_OS2_H
#define NEED_EVENTS
#include "X.h"
#include "input.h"
#include "scrnintstr.h"

#define INCL_WINSWITCHLIST
#define INCL_VIO
#define INCL_KBD
#define INCL_DOSPROCESS
#define INCL_DOSSEMAPHORES
#define INCL_DOSERRORS
#undef RT_FONT
#include "xf86.h"
#include "xf86Priv.h"
#include "xf86_OSlib.h"
#include "atKeynames.h"

BOOL SwitchedToWPS=FALSE;
BOOL WaitingForAccess=FALSE;
void os2PostKbdEvent();
HEV hevServerHasFocus;
HEV hevSwitchRequested;
HEV hevErrorPopupDetected;
extern HEV hevPopupPending;
extern HEV hSwitchToSem;
BOOL os2PopupErrorPending=FALSE;

/*
 * Added OS/2 code to handle switching back to WPS
 */


Bool xf86VTSwitchPending()
{
	return(xf86Info.vtRequestsPending ? TRUE : FALSE);
}

Bool xf86VTSwitchAway()
{
        APIRET rc;
	ULONG  drive;

        xf86Info.vtRequestsPending=FALSE;
        SwitchedToWPS=TRUE;

	rc = DosQuerySysInfo(5,5,&drive,sizeof(drive));
	rc = DosSuppressPopUps(0x0000L,drive+96);	/* Disable popups */
	DosPostEventSem(hevSwitchRequested);
	usleep(30000);
	return(TRUE);
}

Bool xf86VTSwitchTo()
{
	APIRET rc;
	ULONG drive,postCount;

	xf86Info.vtRequestsPending=FALSE;
	SwitchedToWPS=FALSE;
	rc = DosResetEventSem(hSwitchToSem,&postCount);
	DosPostEventSem(hevSwitchRequested);
	rc = DosQuerySysInfo(5,5,&drive,sizeof(drive));
	rc = DosSuppressPopUps(0x0001L,drive+96);     /* Disable popups */

	/* We reset the state of the control key */
	os2PostKbdEvent(KEY_LCtrl,1);
	os2PostKbdEvent(KEY_LCtrl,0);
	os2PostKbdEvent(KEY_RCtrl,1);
	os2PostKbdEvent(KEY_RCtrl,0);
	os2PostKbdEvent(KEY_Alt,1);
	os2PostKbdEvent(KEY_Alt,0);
	return(TRUE);
}


/* This function is run as a thread and will notify of switch-to/switch-away events */
void os2VideoNotify(arg)
void * arg;
{
   USHORT Indic;
   USHORT NotifyType;
   APIRET rc;
   ULONG postCount;
   Bool FirstTime=TRUE;
   int timeout_count;

	rc=DosCreateEventSem(NULL,&hevServerHasFocus,0L,FALSE);
	rc=DosPostEventSem(hevServerHasFocus);
	rc=DosCreateEventSem(NULL,&hevSwitchRequested,0L,FALSE);
	rc=DosPostEventSem(hevSwitchRequested);


	while(1) {
	  Indic=0;
	  rc=VioSavRedrawWait(Indic,&NotifyType,(HVIO)0);

/* Here we handle the semaphore used to indicate wether we have screen access */
	  if(NotifyType==0) rc=DosResetEventSem(hevServerHasFocus,&postCount);
          if(FirstTime){
                   FirstTime=FALSE;
                   if(NotifyType==1) NotifyType=65535; /* In case a redraw is requested on first call */
                }

	  if(NotifyType==1){
/* Notify os2PseudoSelect() that we are back */
			rc=DosPostEventSem(hSwitchToSem);
			if (rc) xf86Msg(X_ERROR,"Post SwitchToSem returned %d\n");
/* Sanity check */
		if (!SwitchedToWPS) {
			xf86Msg(X_ERROR,
				"Abnormal switching back to server detected\n");
		}
	  }

/* Here we set the semaphore used to indicate switching request */

        if((NotifyType!=65535)&&(!WaitingForAccess)) {
                rc=DosResetEventSem(hevSwitchRequested,&postCount);
                xf86Info.vtRequestsPending=TRUE;
/* Then wait for semaphore to be posted once switch is complete. Wait 20 secs, then kill server */
               timeout_count=0;
               rc=DosSetPriority(2,3,0,1);
                     do {
                            rc=DosWaitEventSem(hevSwitchRequested,1000L);
                            if(rc==ERROR_TIMEOUT){
                               timeout_count++;
                               if(timeout_count>25){
                                  xf86Msg(X_ERROR,
					  "Server timeout on VT switch request. Server was killed\n");
                                  DosExit(1L,0);
                                  }
                               if(WaitingForAccess) {  /* The server is resetting */
                                  DosPostEventSem(hevSwitchRequested);
                                  xf86Info.vtRequestsPending=FALSE;
                                  }
                               }
                          } while (rc==ERROR_TIMEOUT);
          rc=DosSetPriority(2,2,0,1);
          }
         if(NotifyType==1) rc=DosPostEventSem(hevServerHasFocus);
         if((NotifyType==0)&&(!SwitchedToWPS))
		xf86Msg(X_ERROR,
			"Abnormal switching away from server!\n");
	} /* endwhile */

/* End of thread */
}

/* This function is run as a thread and will notify of hard-error events */
void os2HardErrorNotify(arg)
void * arg;
{
   USHORT Indic;
   USHORT NotifyType;
   APIRET rc;
   ULONG postCount;

	rc=DosCreateEventSem(NULL,&hevErrorPopupDetected,0L,FALSE);
	rc=DosPostEventSem(hevErrorPopupDetected);
        os2PopupErrorPending=FALSE;

	while(1) {
	   Indic=0;
	   rc=VioModeWait(Indic,&NotifyType,(HVIO)0);
	   if(NotifyType==0){
                os2PopupErrorPending=TRUE;
                rc=DosPostEventSem(hSwitchToSem);
                rc=DosResetEventSem(hevErrorPopupDetected,&postCount);
                rc=DosWaitEventSem(hevErrorPopupDetected,20000L);
                if(rc==ERROR_TIMEOUT) GiveUp(0);  /* Shutdown on timeout of semaphore */
	   }
	} /* endwhile */

/* End of thread */
}

static BOOL is_redirected = FALSE;

static void
redirect_output(void)
{
	/* hv300996 create redirect file on boot drive, instead
	 * anywhere you are just standing
	 */
	char buf[20],dr[3];
	ULONG drive;
	APIRET rc;

	if (is_redirected) return;

	if ((rc = DosQuerySysInfo(5,5,&drive,sizeof(drive))) != 0)
		dr[0] = 0;
	else {	
		dr[0] = drive+96;
		dr[1] = ':';
		dr[2] = 0;
	}
	sprintf(buf,"%s\\xf86log.os2",dr);

	ErrorF("\nThis is the XFree86/OS2-4.0 server\n");
	ErrorF("\nAll output from now on will be redirected to %s\n",buf);
	freopen(buf,"w",stderr);

	is_redirected = TRUE;
}

void
os2ServerVideoAccess()
{
   APIRET rc;
   ULONG fgSession;
   ULONG length=4;
   CHAR Status;

   /* Redirect output as early as possible */
   /* redirect_output(); */
   /* too many logfiles, server will log to /usr/adm */

/* Wait for screen access. This is called at server reset or at server startup */
/* Here we do some waiting until this session comes in the foreground before *
 * going any further. This is because we may have been started in the bg      */

        if(serverGeneration==1){
                rc=VioScrLock(0, &Status, (HVIO)0);
                while(Status != 0){
                        rc=VioScrLock(0, &Status, (HVIO)0);
                        DosSleep(1000);
                        }
                VioScrUnLock((HVIO)0);
                return;
                }
        WaitingForAccess=TRUE;
        rc=DosWaitEventSem(hevServerHasFocus,SEM_INDEFINITE_WAIT);
        WaitingForAccess=FALSE;
        SwitchedToWPS=FALSE;  /* In case server has reset while we were switched to WPS */
}

/* This next function will attempt to recover from a hard error popup
 * with an EnterLeave call
 */

void os2RecoverFromPopup()
{
	int j;
	ULONG postCount;

	if (os2PopupErrorPending) {
#if 0
		for (j = 0; j < screenInfo.numScreens; j++)
			(XF86SCRNINFO(screenInfo.screens[j])->EnterLeaveVT)(LEAVE, j);
		for (j = 0; j < screenInfo.numScreens; j++)
			(XF86SCRNINFO(screenInfo.screens[j])->EnterLeaveVT)(ENTER, j);
#endif
		DosResetEventSem(hSwitchToSem,&postCount);

		for (j = 0; j < xf86NumScreens; j++) {
			if (xf86Screens[j]->EnableDisableFBAccess)
				(*xf86Screens[j]->EnableDisableFBAccess)(j, FALSE);
		}
		xf86EnterServerState(SETUP);
		for (j = 0; j < xf86NumScreens; j++)
			xf86Screens[j]->LeaveVT(j, 0);
		for (j = 0; j < xf86NumScreens; j++) {
			xf86Screens[j]->EnterVT(j, 0);
		}
		xf86EnterServerState(OPERATING);
		for (j = 0; j < xf86NumScreens; j++) {
			if (xf86Screens[j]->EnableDisableFBAccess)
				(*xf86Screens[j]->EnableDisableFBAccess)(j, TRUE);
		}

		/* We reset the state of the control key */
		os2PostKbdEvent(KEY_LCtrl,1);
		os2PostKbdEvent(KEY_LCtrl,0);
		os2PostKbdEvent(KEY_RCtrl,1);
		os2PostKbdEvent(KEY_RCtrl,0);
		os2PostKbdEvent(KEY_Alt,1);
		os2PostKbdEvent(KEY_Alt,0);

		/* Turn screen saver off when switching back */
		SaveScreens(SCREEN_SAVER_FORCER,ScreenSaverReset);
		os2PopupErrorPending=FALSE;
		DosPostEventSem(hevErrorPopupDetected);
	}
}

/* This checks wether a popup event is waiting. The semaphore would be reset
 * by the XF86VIO.DLL function
 */

void os2CheckPopupPending()
{
	int j;
	ULONG postCount;

	return;  /* For now this is a no-op */

#if 0
	DosQueryEventSem(hevPopupPending,&postCount);
	if (postCount==0) {               /* We have a popup pending */
#if 0
		for (j = 0; j < screenInfo.numScreens; j++)
			(XF86SCRNINFO(screenInfo.screens[j])->EnterLeaveVT)(LEAVE, j);
#endif
		DosPostEventSem(hevPopupPending);
	}
#endif
}

