コード例 #1
0
ファイル: virtual.c プロジェクト: chunhualiu/OpenNT
/* To support a mis-matched disk spcmswd.drv and insignia.386 we
 * do the setting of virtualisation selectors here, if the
 * insignia.386 driver is less than version 1. Later drivers
 * use VxD_Device_Init to set the selectors.
 */
GLOBAL void set_virtual_selectors_from_mswdvr IFN0()
{
	if (insignia_386_version < 1)
	{
		sas_init_pm_selectors (getCX(), getDX());
	}
}
コード例 #2
0
ファイル: maskitem.cpp プロジェクト: gyw90131/AreaView
void MaskItem::closing()
{
    qDebug() << "closing...";
    QSettings settings("SIS", "AreaView");
    settings.beginGroup("circle");
    settings.setValue("radius", (m_size / 2));
    settings.setValue("x", getCX());
    settings.setValue("y", getCY());
    settings.endGroup();
}
コード例 #3
0
ファイル: demdisp.c プロジェクト: chunhualiu/OpenNT
BOOL DemDispatch (ULONG iSvc)
{
#if DBG
    if(iSvc < SVC_DEMLASTSVC && (fShowSVCMsg & DEMSVCTRACE) &&
	 apfnSVC[iSvc] != demNotYetImplemented){
	sprintf(demDebugBuffer,"DemDispatch: Entering %s\n\tAX=%.4x BX=%.4x CX=%.4x DX=%.4x DI=%.4x SI=%.4x\n",
	       aSVCNames[iSvc],getAX(),getBX(),getCX(),getDX(),getDI(),getSI());
        OutputDebugStringOem(demDebugBuffer);
	sprintf(demDebugBuffer,"\tCS=%.4x IP=%.4x DS=%.4x ES=%.4x SS=%.4x SP=%.4x BP=%.4x\n",
                getCS(),getIP(), getDS(),getES(),getSS(),getSP(),getBP());
        OutputDebugStringOem(demDebugBuffer);
    }
#endif

    if (iSvc >= SVC_DEMLASTSVC){
#if DBG
	sprintf(demDebugBuffer,"Unimplemented SVC index %x\n",iSvc);
        OutputDebugStringOem(demDebugBuffer);
#endif
	setCF(1);
	return FALSE;
    }

    if (pHardErrPacket) {
	pHardErrPacket->vhe_fbInt24 = 0;
    }
    CurrentISVC = iSvc;
    (apfnSVC [iSvc])();


#if DBG
    if((fShowSVCMsg & DEMSVCTRACE)){
	sprintf(demDebugBuffer,"DemDispatch:On Leaving %s\n\tAX=%.4x BX=%.4x CX=%.4x DX=%.4x DI=%.4x SI=%.4x\n",
               aSVCNames[iSvc],getAX(),getBX(),getCX(),getDX(),getDI(),getSI());
        OutputDebugStringOem(demDebugBuffer);
	sprintf(demDebugBuffer,"\tCS=%.4x IP=%.4x DS=%.4x ES=%.4x SS=%.4x SP=%.4x BP=%.4x CF=%x\n",
                getCS(),getIP(), getDS(),getES(),getSS(),getSP(),getBP(),getCF());
        OutputDebugStringOem(demDebugBuffer);
    }
#endif
    return TRUE;
}
コード例 #4
0
ファイル: cmdexec.c プロジェクト: chunhualiu/OpenNT
VOID cmdReturnExitCode (VOID)
{
VDMINFO VDMInfo;
PREDIRCOMPLETE_INFO pRdrInfo;

    VDMInfo.VDMState = RETURN_ON_NO_COMMAND;
    VDMInfo.EnviornmentSize = 0;
    VDMInfo.ErrorCode = (ULONG)getDX();
    VDMInfo.CmdSize = 0;
    VDMInfo.TitleLen = 0;
    VDMInfo.ReservedLen = 0;
    VDMInfo.DesktopLen = 0;
    VDMInfo.CurDirectoryLen = 0;


    CntrlHandlerState = (CntrlHandlerState & ~CNTRL_SHELLCOUNT) |
                         (((WORD)(CntrlHandlerState & CNTRL_SHELLCOUNT))+1);

    nt_block_event_thread(0);
    fBlock = TRUE;

    // a dos program just terminate, inherit its current directories
    // and tell base too.
    cmdUpdateCurrentDirectories((BYTE)getAL());

    // Check for any copying needed for redirection
    pRdrInfo = (PREDIRCOMPLETE_INFO) (((ULONG)getBX() << 16) + (ULONG)getCX());

    if (cmdCheckCopyForRedirection (pRdrInfo) == FALSE)
            VDMInfo.ErrorCode = ERROR_NOT_ENOUGH_MEMORY;

    GetNextVDMCommand (&VDMInfo);
    if (VDMInfo.CmdSize > 0){
        setCF(1);
        IsRepeatCall = TRUE;
    }
    else {
        setCF(0);
        setAL((UCHAR)dwExitCode32);
        nt_resume_event_thread();
        nt_std_handle_notification(fSoftpcRedirectionOnShellOut);
        fBlock = FALSE;
    }

    CntrlHandlerState = (CntrlHandlerState & ~CNTRL_SHELLCOUNT) |
                         (((WORD)(CntrlHandlerState & CNTRL_SHELLCOUNT))-1);

    return;
}
コード例 #5
0
ファイル: nt_bop.c プロジェクト: chunhualiu/OpenNT
void MS_bop_F(void)
{
    extern void kb_setup_vectors(void);


    kb_setup_vectors();


#ifdef MONITOR

    AddrIretBopTable = ( ((ULONG)getDS() << 16) | (ULONG)getDI() );

#ifndef PROD
    if (getCX() != VDM_RM_IRETBOPSIZE) {
        OutputDebugString("NTVDM:spacing != VDM_RM_IRETBOPSIZE\n");
        DebugBreak();
        }
#endif
#endif

    /*
     * Now that spckbd is loaded, and the ivt rom vectors are hooked
     * we can allow hw interrupts.
     */
    // nt_init_event_thread will resume the event thread after it
    // sync up BIOS led states with the system
    // ResumeThread(ThreadInfo.EventMgr.Handle);
    host_ica_lock();
    DelayIrqLine = 0;
    if (!ica_restart_interrupts(ICA_SLAVE))
        ica_restart_interrupts(ICA_MASTER);
    host_ica_unlock();

#ifdef MONITOR
    setCF(1);
#else
    setCF(0);
#endif
}
コード例 #6
0
ファイル: demlock.c プロジェクト: chunhualiu/OpenNT
VOID demLockOper (VOID)
{
HANDLE	hFile;
DWORD	dwFileOffset,cbLock;

    // Collect all the parameters
    hFile = GETHANDLE(getBX(),getBP());
    dwFileOffset = GETULONG (getCX(),getDX());
    cbLock = GETULONG (getSI(),getDI());

    if(getAL() == 0){  // Locking case
	if (LockFile (hFile,
		      dwFileOffset,
		      0,
		      cbLock,
		      0
		     ) == TRUE) {
	    setCF (0);
	    return;
	}
    }
    else {
	if (UnlockFile (hFile,
			dwFileOffset,
			0,
			cbLock,
			0
		       ) == TRUE) {
	    setCF (0);
	    return;
	}
    }

    // Operation failed
    demClientError(hFile, (CHAR)-1);
    return;
}
コード例 #7
0
ファイル: sbbsexec.c プロジェクト: kindy/synchronet-bbs-1
__declspec(dllexport) void __cdecl VDDDispatch(void) 
{
	char			str[512];
	DWORD			count;
	DWORD			msgs;
	int				retval;
	int				node_num;
	BYTE*			p;
	vdd_status_t*	status;
	static  DWORD	writes;
	static  DWORD	bytes_written;
	static	DWORD	reads;
	static  DWORD	bytes_read;
	static  DWORD	inbuf_poll;
	static	DWORD	online_poll;
	static	DWORD	status_poll;
	static	DWORD	vdd_yields;
	static	DWORD	vdd_calls;
	VDD_IO_HANDLERS  IOHandlers = { NULL };
	static VDD_IO_PORTRANGE PortRange;

	retval=0;
	node_num=getBH();

	lprintf(LOG_DEBUG,"VDD_OP: (handle=%d) %d (arg=%X)", getAX(),getBL(),getCX());
	vdd_calls++;

	switch(getBL()) {

		case VDD_OPEN:

			sscanf("$Revision: 1.40 $", "%*s %s", revision);

			lprintf(LOG_INFO,"Synchronet Virtual Device Driver, rev %s %s %s"
				,revision, __DATE__, __TIME__);
#if 0
			sprintf(str,"sbbsexec%d.log",node_num);
			fp=fopen(str,"wb");
#endif

			sprintf(str,"\\\\.\\mailslot\\sbbsexec\\wr%d",node_num);
			rdslot=CreateMailslot(str
				,0 //LINEAR_RX_BUFLEN		/* Max message size (0=any) */
				,MAILSLOT_WAIT_FOREVER 	/* Read timeout */
				,NULL);
			if(rdslot==INVALID_HANDLE_VALUE) {
				lprintf(LOG_ERR,"!VDD_OPEN: Error %d opening %s"
					,GetLastError(),str);
				retval=1;
				break;
			}

			sprintf(str,"\\\\.\\mailslot\\sbbsexec\\rd%d",node_num);
			wrslot=CreateFile(str
				,GENERIC_WRITE
				,FILE_SHARE_READ
				,NULL
				,OPEN_EXISTING
				,FILE_ATTRIBUTE_NORMAL
				,(HANDLE) NULL);
			if(wrslot==INVALID_HANDLE_VALUE) {
				lprintf(LOG_ERR,"!VDD_OPEN: Error %d opening %s"
					,GetLastError(),str);
				retval=2;
				break;
			}

			if(RingBufInit(&rdbuf, RINGBUF_SIZE_IN)!=0) {
				retval=3;
				break;
			}

			sprintf(str,"sbbsexec_hungup%d",node_num);
			hungup_event=OpenEvent(
				EVENT_ALL_ACCESS,	/* access flag  */
				FALSE,				/* inherit flag  */
				str);				/* pointer to event-object name  */
			if(hungup_event==NULL) {
				lprintf(LOG_ERR,"!VDD_OPEN: Error %d opening %s"
					,GetLastError(),str);
				retval=4;
				break;
			}

			sprintf(str,"sbbsexec_hangup%d",node_num);
			hangup_event=OpenEvent(
				EVENT_ALL_ACCESS,	/* access flag  */
				FALSE,				/* inherit flag  */
				str);				/* pointer to event-object name  */
			if(hangup_event==NULL) {
				lprintf(LOG_WARNING,"!VDD_OPEN: Error %d opening %s"
					,GetLastError(),str);
			}

			status_poll=0;
			inbuf_poll=0;
			online_poll=0;
			yields=0;

			lprintf(LOG_INFO,"Yield interval: %f milliseconds", yield_interval);

			if(virtualize_uart) {
				lprintf(LOG_INFO,"Virtualizing UART (0x%x, IRQ %u)"
					,uart_io_base, uart_irq);

				IOHandlers.inb_handler = uart_rdport;
				IOHandlers.outb_handler = uart_wrport;
				PortRange.First=uart_io_base;
				PortRange.Last=uart_io_base + UART_IO_RANGE;

				VDDInstallIOHook((HANDLE)getAX(), 1, &PortRange, &IOHandlers);

				interrupt_event=CreateEvent(NULL,FALSE,FALSE,NULL);
				InitializeCriticalSection(&interrupt_mutex);

				_beginthread(interrupt_thread, 0, NULL);
			}

			lprintf(LOG_DEBUG,"VDD_OPEN: Opened successfully (wrslot=%p)", wrslot);

			_beginthread(input_thread, 0, NULL);

			retval=0;
			break;

		case VDD_CLOSE:
			lprintf(LOG_INFO,"VDD_CLOSE: rdbuf=%u "
				"status_poll=%u inbuf_poll=%u online_poll=%u yields=%u vdd_yields=%u vdd_calls=%u"
				,RingBufFull(&rdbuf),status_poll,inbuf_poll,online_poll
				,yields,vdd_yields,vdd_calls);
			lprintf(LOG_INFO,"           read=%u bytes (in %u calls)",bytes_read,reads);
			lprintf(LOG_INFO,"           wrote=%u bytes (in %u calls)",bytes_written,writes);

			if(virtualize_uart) {
				lprintf(LOG_INFO,"Uninstalling Virtualizaed UART IO Hook");
				VDDDeInstallIOHook((HANDLE)getAX(), 1, &PortRange);
			}

			CloseHandle(rdslot);
			CloseHandle(wrslot);
			if(hungup_event!=NULL)
				CloseHandle(hungup_event);
			if(hangup_event!=NULL)
				CloseHandle(hangup_event);

#if 0	/* This isn't strictly necessary... 
		   and possibly the cause of a NULL dereference in the input_thread */
			RingBufDispose(&rdbuf);
#endif
			status_poll=0;
			retval=0;

			break;

		case VDD_READ:
			count = getCX();
			if(count != 1)
				lprintf(LOG_DEBUG,"VDD_READ of %d",count);
			p = (BYTE*) GetVDMPointer((ULONG)((getES() << 16)|getDI())
				,count,FALSE); 
			retval=vdd_read(p, count);
			reads++;
			bytes_read+=retval;
			reset_yield();
			break;

		case VDD_PEEK:
			count = getCX();
			if(count != 1)
				lprintf(LOG_DEBUG,"VDD_PEEK of %d",count);

			p = (BYTE*) GetVDMPointer((ULONG)((getES() << 16)|getDI())
				,count,FALSE); 
			retval=RingBufPeek(&rdbuf,p,count);
			reset_yield();
			break;

		case VDD_WRITE:
			count = getCX();
			if(count != 1)
				lprintf(LOG_DEBUG,"VDD_WRITE of %d",count);
			p = (BYTE*) GetVDMPointer((ULONG)((getES() << 16)|getDI())
				,count,FALSE); 
			if(!WriteFile(wrslot,p,count,&retval,NULL)) {
				lprintf(LOG_ERR,"!VDD_WRITE: WriteFile Error %d (size=%d)"
					,GetLastError(),retval);
				retval=0;
			} else {
				writes++;
				bytes_written+=retval;
				reset_yield();
			}
			break;

		case VDD_STATUS:

			status_poll++;
			count = getCX();
			if(count != sizeof(vdd_status_t)) {
				lprintf(LOG_DEBUG,"!VDD_STATUS: wrong size (%d!=%d)",count,sizeof(vdd_status_t));
				retval=sizeof(vdd_status_t);
				break;
			}
			status = (vdd_status_t*) GetVDMPointer((ULONG)((getES() << 16)|getDI())
				,count,FALSE); 

			status->inbuf_size=RINGBUF_SIZE_IN;
			status->inbuf_full=RingBufFull(&rdbuf);
			msgs=0;

			/* OUTBUF FULL/SIZE */
			if(!GetMailslotInfo(
				wrslot,					/* mailslot handle  */
 				&status->outbuf_size,	/* address of maximum message size  */
				&status->outbuf_full,	/* address of size of next message  */
				&msgs,					/* address of number of messages  */
 				NULL					/* address of read time-out  */
				)) {
				lprintf(LOG_ERR,"!VDD_STATUS: GetMailSlotInfo(%p) failed, error %u (msgs=%u, inbuf_full=%u, inbuf_size=%u)"
					,wrslot
					,GetLastError(), msgs, status->inbuf_full, status->inbuf_size);
				status->outbuf_full=0;
				status->outbuf_size=DEFAULT_MAX_MSG_SIZE;
			} else
				lprintf(LOG_DEBUG,"VDD_STATUS: MailSlot maxmsgsize=%u, nextmsgsize=%u, msgs=%u"
					,status->outbuf_size
					,status->outbuf_full
					,msgs);
			if(status->outbuf_full==MAILSLOT_NO_MESSAGE)
				status->outbuf_full=0;
			status->outbuf_full*=msgs;
			
			/* ONLINE */
			if(WaitForSingleObject(hungup_event,0)==WAIT_OBJECT_0)
				status->online=0;
			else
				status->online=1;

			retval=0;	/* success */
			break;

		case VDD_INBUF_PURGE:
			RingBufReInit(&rdbuf);
			retval=0;
			break;

		case VDD_OUTBUF_PURGE:
			lprintf(LOG_WARNING,"!VDD_OUTBUF_PURGE: NOT IMPLEMENTED");
			retval=0;
			break;

		case VDD_INBUF_FULL:
			retval=RingBufFull(&rdbuf);
			inbuf_poll++;
			break;

		case VDD_INBUF_SIZE:
			retval=RINGBUF_SIZE_IN;
			break;

		case VDD_OUTBUF_FULL:
			if(!GetMailslotInfo(
				wrslot,		/* mailslot handle  */
 				NULL,		/* address of maximum message size  */
				&retval,	/* address of size of next message  */
				&msgs,		/* address of number of messages  */
 				NULL		/* address of read time-out  */
				))
				retval=0;
			if(retval==MAILSLOT_NO_MESSAGE)
				retval=0;
			retval*=msgs;
			break;

		case VDD_OUTBUF_SIZE:
			if(!GetMailslotInfo(
				wrslot,		/* mailslot handle  */
 				&retval,	/* address of maximum message size  */
				NULL,		/* address of size of next message  */
				NULL,		/* address of number of messages  */
 				NULL		/* address of read time-out  */
				)) 
				retval=DEFAULT_MAX_MSG_SIZE;
			break;

		case VDD_ONLINE:
			if(WaitForSingleObject(hungup_event,0)==WAIT_OBJECT_0)
				retval=0;
			else
				retval=1;
			online_poll++;
			break;

		case VDD_YIELD:			/* forced yield */
			vdd_yields++;
			yield();
			break;

		case VDD_MAYBE_YIELD:	/* yield if YieldInterval is enabled and expired */
			maybe_yield();
			break;

		case VDD_LOAD_INI_FILE:	/* Load and parse settings file */
			{
				FILE*	fp;
				char	cwd[MAX_PATH+1];

				/* Load exec/sbbsexec.ini first (setting default values) */
				count = getCX();
				p = (BYTE*)GetVDMPointer((ULONG)((getES() << 16)|getDI())
					,count,FALSE); 
				iniFileName(ini_fname, sizeof(ini_fname), p, INI_FILENAME);
				if((fp=fopen(ini_fname,"r"))!=NULL) {
					ini=iniReadFile(fp);
					fclose(fp);
					parse_ini(ROOT_SECTION);
				}

				/* Load cwd/sbbsexec.ini second (over-riding default values) */
				GetCurrentDirectory(sizeof(cwd),cwd);
				iniFileName(ini_fname, sizeof(ini_fname), cwd, INI_FILENAME);
				if((fp=fopen(ini_fname,"r"))!=NULL) {
					ini=iniReadFile(fp);
					fclose(fp);
					parse_ini(ROOT_SECTION);
				}
			}
			break;

		case VDD_LOAD_INI_SECTION:	/* Parse (program-specific) sub-section of settings file */
			count = getCX();
			p = (BYTE*)GetVDMPointer((ULONG)((getES() << 16)|getDI())
				,count,FALSE); 
			parse_ini(p);
			break;

		case VDD_DEBUG_OUTPUT:	/* Send string to debug output */
			count = getCX();
			p = (BYTE*)GetVDMPointer((ULONG)((getES() << 16)|getDI())
				,count,FALSE); 
			lputs(LOG_INFO, p);
			break;

		case VDD_HANGUP:
			hangup();
			break;

		default:
			lprintf(LOG_ERR,"!UNKNOWN VDD_OP: %d",getBL());
			break;
	}
	setAX((WORD)retval);
}
コード例 #8
0
ファイル: virtual.c プロジェクト: chunhualiu/OpenNT
/*
   Entry point from Windows 386 Virtual Device Driver (INSIGNIA.386) - Provide
   virtualising services as required.
 */
GLOBAL void
virtual_device_trap IFN0()
   {
   int new_vb;

   switch ( getEAX() )
      {
   case VxD_Device_Init:
      /* We can check that the Intel version is valid */

      insignia_386_version = getDX();

      always_trace2("386 VxD: Device_Init version %d.%02d",
		    insignia_386_version / 100,
		    insignia_386_version % 100);

      /* pm selectors for virtualisation are in ebx and ecx */

      if ((getBX() !=0) && (getCX() !=0))
	sas_init_pm_selectors (getBX(), getCX());
      else
	always_trace0("386 VxD: Device_Init. Failed to get pm selectors!!");

      /* Compatibility test:
       * Return in top half of EDX the the "current" Intel version of the driver.
       * This allows an incompatible future driver to reject an old SoftWindows.
       */
#define INTEL_VERSION	102
      setEDX(INTEL_VERSION << 16);
      break;

   case VxD_Sys_VM_Init:
      always_trace0("386 VxD: Sys_VM_Init.");

      /* As safety measure undo anything which may be currently active */
      deallocate_all_NIDDB();
      restore_snapshot();

      /* Lock out Insignia Device Driver requests */
      allocation_allowed = FALSE;

      /* Form new instance */
      if ( allocate_NIDDB(getEBX(), &new_vb) )
	 {
	 /* Make new instance active (for create callback) */
	 swap_NIDDB(new_vb);

	 /* Copy instance data and action create callback */
	 copy_instance_data(vrecs[new_vb].vr_pinst_tbl, snapshot_ptrs);

	 /* Return virtualising byte to INSIGNIA.386 */
	 setEAX(new_vb);
	 }
      else
	 {
	 /* We can't do it */
	 setCF(1);   /* Inform Windows that Virtual Machine can't be created */
	 host_error(EG_MALLOC_FAILURE, ERR_CONT , "");
	 }
      break;

   case VxD_VM_Init:
      always_trace0("386 VxD: VM_Init.");
      /* Form new instance */
      if ( allocate_NIDDB(getEBX(), &new_vb) )
	 {
	 /* Make new instance active (for create callback) */
	 swap_NIDDB(new_vb);

	 /* Copy instance data and action create callback */
	 copy_instance_data(vrecs[new_vb].vr_pinst_tbl, snapshot_ptrs);

	 /* Return virtualising byte to INSIGNIA.386 */
	 setEAX(new_vb);
	 }
      else
	 {
	 /* We can't do it */
	 setCF(1);   /* Inform Windows that Virtual Machine can't be created */
	 host_error(EG_MALLOC_FAILURE, ERR_CONT , "");
	 }
      break;

   case VxD_VM_Not_Executeable:
      always_trace0("386 VxD: VM_Not_Executeable.");
      deallocate_specific_NIDDB(getEBX());
      break;

   case VxD_Device_Reboot_Notify:
      always_trace0("386 VxD: Device_Reboot_Notify.");
      deallocate_all_NIDDB();
      restore_snapshot();

      /* Clear our version number in case we are changing disks */
      insignia_386_version = 0;
      break;

   case VxD_System_Exit:
      always_trace0("386 VxD: System_Exit.");
      deallocate_all_NIDDB();
      restore_snapshot();
      ClearInstanceDataMarking();

#ifndef NTVDM
      host_mswin_disable();
#endif /* ! NTVDM */

      /* Clear our version number in case we are changing disks */
      insignia_386_version = 0;
      break;

   default:
      always_trace1("386 VxD: Unrecognised Control Message. 0x%02x", getEAX());
      }
   }
コード例 #9
0
ファイル: kbdbios32.c プロジェクト: Nevermore2015/reactos
static VOID WINAPI BiosKeyboardService(LPWORD Stack)
{
    switch (getAH())
    {
        /* Wait for keystroke and read */
        case 0x00:
        /* Wait for extended keystroke and read */
        case 0x10:  // FIXME: Temporarily do the same as INT 16h, 00h
        {
            /* Read the character (and wait if necessary) */
            WORD Character = BiosGetCharacter();

            if (Character == 0xFFFF)
            {
                /* No key available. Set the handler CF to repeat the BOP */
                setCF(1);
                break;
            }

            setAX(Character);

            break;
        }

        /* Get keystroke status */
        case 0x01:
        /* Get extended keystroke status */
        case 0x11:  // FIXME: Temporarily do the same as INT 16h, 01h
        {
            WORD Character = BiosPeekCharacter();

            if (Character != 0xFFFF)
            {
                /* There is a character, clear ZF and return it */
                Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_ZF;
                setAX(Character);
            }
            else
            {
                /* No character, set ZF */
                Stack[STACK_FLAGS] |= EMULATOR_FLAG_ZF;
            }

            break;
        }

        /* Get shift status */
        case 0x02:
        {
            /* Return the lower byte of the keyboard shift status word */
            setAL(LOBYTE(Bda->KeybdShiftFlags));
            break;
        }

        /* Reserved */
        case 0x04:
        {
            DPRINT1("BIOS Function INT 16h, AH = 0x04 is RESERVED\n");
            break;
        }

        /* Push keystroke */
        case 0x05:
        {
            /* Return 0 if success, 1 if failure */
            setAL(BiosKbdBufferPush(getCX()) == FALSE);
            break;
        }

        /* Get extended shift status */
        case 0x12:
        {
            /*
             * Be careful! The returned word is similar to Bda->KeybdShiftFlags
             * but the high byte is organized differently:
             * the bytes 2 and 3 of the high byte are not the same...
             */
            WORD KeybdShiftFlags = (Bda->KeybdShiftFlags & 0xF3FF);

            /* Return the extended keyboard shift status word */
            setAX(KeybdShiftFlags);
            break;
        }

        default:
        {
            DPRINT1("BIOS Function INT 16h, AH = 0x%02X NOT IMPLEMENTED\n",
                    getAH());
        }
    }
}