618 lines
13 KiB
C
618 lines
13 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
fwsignal.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module implements the ARC firmware Signal Handling Functions.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Lluis Abello (lluis) 24-Sep-1991
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "fwp.h"
|
|||
|
#include "iodevice.h"
|
|||
|
#ifdef DUO
|
|||
|
#include "duoint.h"
|
|||
|
#else
|
|||
|
#include "jazzint.h"
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Define Signal types
|
|||
|
//
|
|||
|
|
|||
|
typedef
|
|||
|
VOID
|
|||
|
(*SIGNALHANDLER)(
|
|||
|
IN LONG
|
|||
|
);
|
|||
|
|
|||
|
#define SIGINT (0)
|
|||
|
#define SIGDefault (SIGNALHANDLER)(0)
|
|||
|
#define SIGIgnore (SIGNALHANDLER)(1)
|
|||
|
|
|||
|
typedef
|
|||
|
SIGNALHANDLER
|
|||
|
(*PARC_SIGNAL_ROUTINE) (
|
|||
|
IN LONG Sig,
|
|||
|
IN SIGNALHANDLER Handler
|
|||
|
);
|
|||
|
|
|||
|
typedef struct _R4000_CAUSE_REGISTER {
|
|||
|
ULONG Zero1:2;
|
|||
|
ULONG ExcCode:5;
|
|||
|
ULONG Zero2:1;
|
|||
|
ULONG IP:8;
|
|||
|
ULONG Zero3:12;
|
|||
|
ULONG CE:2;
|
|||
|
ULONG Zero4:1;
|
|||
|
ULONG BD:1;
|
|||
|
} R4000_CAUSE_REGISTER, *PR4000_CAUSE_REGISTER;
|
|||
|
|
|||
|
VOID
|
|||
|
SIGINTIgnore(
|
|||
|
IN LONG Sig
|
|||
|
);
|
|||
|
|
|||
|
extern KEYBOARD_BUFFER KbdBuffer;
|
|||
|
extern PVOID MonitorExceptionHandler;
|
|||
|
volatile BOOLEAN DeviceInterruptFlag;
|
|||
|
SIGNALHANDLER SIGINTHandler = (SIGNALHANDLER)SIGINTIgnore;
|
|||
|
|
|||
|
//
|
|||
|
// Keyboard static variables.
|
|||
|
//
|
|||
|
|
|||
|
BOOLEAN KbdCtrl = FALSE;
|
|||
|
BOOLEAN Scan0xE0 = FALSE;
|
|||
|
|
|||
|
// 1111 1 1111122222222 2 2333333333344 4 44444445555 5 5 55
|
|||
|
// Character # 234567890123 4 5678901234567 8 9012345678901 2 34567890123 4 5 67
|
|||
|
PCHAR NormalLookup = "1234567890-=\b\0qwertyuiop[]\n\0asdfghjkl;'`\0\\zxcvbnm,./\0\0\0 ";
|
|||
|
PCHAR ShiftedLookup = "!@#$%^&*()_+\b\0QWERTYUIOP{}\n\0ASDFGHJKL:\"~\0\|ZXCVBNM<>?\0\0\0 ";
|
|||
|
|
|||
|
extern BOOLEAN FwLeftShift;
|
|||
|
extern BOOLEAN FwRightShift;
|
|||
|
extern BOOLEAN FwControl;
|
|||
|
extern BOOLEAN FwAlt;
|
|||
|
extern BOOLEAN FwCapsLock;
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
SIGINTIgnore(
|
|||
|
IN LONG Sig
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine implements the Signal Ignore. It gets called when
|
|||
|
a SIGINT signal raises and SIGIgnore was associated.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
??
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
SIGNALHANDLER
|
|||
|
FwSignal(
|
|||
|
IN LONG Sig,
|
|||
|
IN SIGNALHANDLER Handler
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine implements the ARC firmware signal routine.
|
|||
|
It associates the supplied Handler with the Signal.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Sig - Signal number (Only SIGINT is defined).
|
|||
|
|
|||
|
Handler - Handler to call when the signal rises.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns the address of any previous handler routine associated
|
|||
|
with this signal.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
SIGNALHANDLER Tmp;
|
|||
|
Tmp=SIGINTHandler;
|
|||
|
if (Handler == SIGDefault) {
|
|||
|
SIGINTHandler = (SIGNALHANDLER)MonitorExceptionHandler;
|
|||
|
return Tmp;
|
|||
|
}
|
|||
|
if (Handler == SIGIgnore) {
|
|||
|
SIGINTHandler = (SIGNALHANDLER)SIGINTIgnore;
|
|||
|
return Tmp;
|
|||
|
}
|
|||
|
SIGINTHandler = Handler;
|
|||
|
return Tmp;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
ARC_STATUS
|
|||
|
FwWaitForDeviceInterrupt(
|
|||
|
USHORT InterruptMask,
|
|||
|
ULONG Timeout
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called to wait for an specific I/O device interrupt.
|
|||
|
It sets a boolean to FALSE
|
|||
|
enables the device interrupt in the interrupt enable register
|
|||
|
Polls the boolean until becomes true.
|
|||
|
Returns to the caller.
|
|||
|
|
|||
|
When the Inerrupt handler detects an interrupt which is not
|
|||
|
the keyboard interrupt sets the boolean to true and disables all
|
|||
|
the I/O device interrupts except the keyboard in the interrupt
|
|||
|
enable register.
|
|||
|
|
|||
|
To guarantee that the interrupt received is the expected one
|
|||
|
the argument InterruptMask must have only one bit set.
|
|||
|
It's not possible to wait for a keyboard interrupt.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
InterruptMask - Mask to enable the device interrupt in the
|
|||
|
interrupt enable register.
|
|||
|
|
|||
|
Timeout - a timeout value in seconds. Note that a timeout of 0 gives an
|
|||
|
actual timeout of between 0 and 1, a timeout of 1 gives an actual
|
|||
|
timeout of between 1 and 2, and so on.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ESUCCESS if the interrupt occurs, EIO if a timeout occurs. It doesn't
|
|||
|
return until the requested interrupt occurs.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG Time1, Time2;
|
|||
|
|
|||
|
//
|
|||
|
// set flag to FALSE
|
|||
|
//
|
|||
|
|
|||
|
DeviceInterruptFlag = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// Enable requested interrupt plus keyboard interrupt.
|
|||
|
//
|
|||
|
|
|||
|
InterruptMask |= (1 << (KEYBOARD_VECTOR - DEVICE_VECTORS - 1));
|
|||
|
WRITE_REGISTER_USHORT(&((PINTERRUPT_REGISTERS)INTERRUPT_VIRTUAL_BASE)->Enable,
|
|||
|
InterruptMask);
|
|||
|
//
|
|||
|
// wait until flag becomes TRUE.
|
|||
|
//
|
|||
|
|
|||
|
Time1 = FwGetRelativeTime();
|
|||
|
while (DeviceInterruptFlag == FALSE) {
|
|||
|
Time2 = FwGetRelativeTime();
|
|||
|
if ((Time2 - Time1) > (Timeout + 1)) {
|
|||
|
return(EIO);
|
|||
|
}
|
|||
|
}
|
|||
|
return ESUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
StoreKeyboardChar(
|
|||
|
IN UCHAR Character
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine stores the given character into the circular
|
|||
|
buffer if there is enough room. Otherwise the character is lost.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Character - Supplies the translated scan code to store into the buffer
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
//
|
|||
|
// Store scan code in buffer if there is room.
|
|||
|
//
|
|||
|
if (((KbdBuffer.WriteIndex+1) % KBD_BUFFER_SIZE) != KbdBuffer.ReadIndex) {
|
|||
|
KbdBuffer.WriteIndex = (KbdBuffer.WriteIndex+1) % KBD_BUFFER_SIZE;
|
|||
|
KbdBuffer.Buffer[KbdBuffer.WriteIndex] = Character;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
TranslateScanCode(
|
|||
|
IN UCHAR Scan
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine translates the given keyboard scan code into an
|
|||
|
ASCII character and puts it in the circular buffer.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Scan - Supplies the scan code read from the keyboard.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
UCHAR FwControlCharacter=0;
|
|||
|
UCHAR FwFunctionCharacter;
|
|||
|
BOOLEAN MakeCode;
|
|||
|
UCHAR Char;
|
|||
|
|
|||
|
//
|
|||
|
// Check 0xE0, which introduces a two key sequence.
|
|||
|
//
|
|||
|
|
|||
|
if (Scan == 0xE0) {
|
|||
|
Scan0xE0 = TRUE;
|
|||
|
return;
|
|||
|
}
|
|||
|
if (Scan0xE0 == TRUE) {
|
|||
|
//
|
|||
|
// Check for PrintScrn (used as SysRq, also found in its true Alt
|
|||
|
// form below).
|
|||
|
//
|
|||
|
if (Scan == KEY_PRINT_SCREEN) {
|
|||
|
StoreKeyboardChar(ASCII_SYSRQ);
|
|||
|
Scan0xE0 = FALSE;
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Look for scan codes that indicate shift, control, or alt keys. Bit 7
|
|||
|
// of scan code indicates upward or downward keypress.
|
|||
|
//
|
|||
|
MakeCode = !(Scan & 0x80);
|
|||
|
switch (Scan & 0x7F) {
|
|||
|
|
|||
|
case KEY_LEFT_SHIFT:
|
|||
|
FwLeftShift = MakeCode;
|
|||
|
return;
|
|||
|
|
|||
|
case KEY_RIGHT_SHIFT:
|
|||
|
FwRightShift = MakeCode;
|
|||
|
return;
|
|||
|
|
|||
|
case KEY_CONTROL:
|
|||
|
FwControl = MakeCode;
|
|||
|
return;
|
|||
|
|
|||
|
case KEY_ALT:
|
|||
|
FwAlt = MakeCode;
|
|||
|
return;
|
|||
|
|
|||
|
default:
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// The rest of the keys only do something on make.
|
|||
|
//
|
|||
|
|
|||
|
if (MakeCode) {
|
|||
|
|
|||
|
//
|
|||
|
// Check for control keys.
|
|||
|
//
|
|||
|
|
|||
|
switch (Scan) {
|
|||
|
|
|||
|
case KEY_UP_ARROW:
|
|||
|
FwControlCharacter = 'A';
|
|||
|
break;
|
|||
|
|
|||
|
case KEY_DOWN_ARROW:
|
|||
|
FwControlCharacter = 'B';
|
|||
|
break;
|
|||
|
|
|||
|
case KEY_RIGHT_ARROW:
|
|||
|
FwControlCharacter = 'C';
|
|||
|
break;
|
|||
|
|
|||
|
case KEY_LEFT_ARROW:
|
|||
|
FwControlCharacter = 'D';
|
|||
|
break;
|
|||
|
|
|||
|
case KEY_HOME:
|
|||
|
FwControlCharacter = 'H';
|
|||
|
break;
|
|||
|
|
|||
|
case KEY_END:
|
|||
|
FwControlCharacter = 'K';
|
|||
|
break;
|
|||
|
|
|||
|
case KEY_PAGE_UP:
|
|||
|
FwControlCharacter = '?';
|
|||
|
break;
|
|||
|
|
|||
|
case KEY_PAGE_DOWN:
|
|||
|
FwControlCharacter = '/';
|
|||
|
break;
|
|||
|
|
|||
|
case KEY_INSERT:
|
|||
|
FwControlCharacter = '@';
|
|||
|
break;
|
|||
|
|
|||
|
case KEY_DELETE:
|
|||
|
FwControlCharacter = 'P';
|
|||
|
break;
|
|||
|
|
|||
|
case KEY_SYS_REQUEST:
|
|||
|
StoreKeyboardChar(ASCII_SYSRQ);
|
|||
|
return;
|
|||
|
|
|||
|
case KEY_ESC:
|
|||
|
StoreKeyboardChar(ASCII_ESC);
|
|||
|
return;
|
|||
|
|
|||
|
case KEY_CAPS_LOCK:
|
|||
|
FwCapsLock = !FwCapsLock;
|
|||
|
return;
|
|||
|
|
|||
|
case KEY_F1:
|
|||
|
FwControlCharacter = 'O';
|
|||
|
FwFunctionCharacter = 'P';
|
|||
|
break;
|
|||
|
|
|||
|
case KEY_F2:
|
|||
|
FwControlCharacter = 'O';
|
|||
|
FwFunctionCharacter = 'Q';
|
|||
|
break;
|
|||
|
|
|||
|
case KEY_F3:
|
|||
|
FwControlCharacter = 'O';
|
|||
|
FwFunctionCharacter = 'w';
|
|||
|
break;
|
|||
|
|
|||
|
case KEY_F4:
|
|||
|
FwControlCharacter = 'O';
|
|||
|
FwFunctionCharacter = 'x';
|
|||
|
break;
|
|||
|
|
|||
|
case KEY_F5:
|
|||
|
FwControlCharacter = 'O';
|
|||
|
FwFunctionCharacter = 't';
|
|||
|
break;
|
|||
|
|
|||
|
case KEY_F6:
|
|||
|
FwControlCharacter = 'O';
|
|||
|
FwFunctionCharacter = 'u';
|
|||
|
break;
|
|||
|
|
|||
|
case KEY_F7:
|
|||
|
FwControlCharacter = 'O';
|
|||
|
FwFunctionCharacter = 'q';
|
|||
|
break;
|
|||
|
|
|||
|
case KEY_F8:
|
|||
|
FwControlCharacter = 'O';
|
|||
|
FwFunctionCharacter = 'r';
|
|||
|
break;
|
|||
|
|
|||
|
case KEY_F9:
|
|||
|
FwControlCharacter = 'O';
|
|||
|
FwFunctionCharacter = 'p';
|
|||
|
break;
|
|||
|
|
|||
|
case KEY_F10:
|
|||
|
FwControlCharacter = 'O';
|
|||
|
FwFunctionCharacter = 'M';
|
|||
|
break;
|
|||
|
|
|||
|
// case KEY_F11:
|
|||
|
// FwControlCharacter = 'O';
|
|||
|
// FwFunctionCharacter = 'A';
|
|||
|
// break;
|
|||
|
//
|
|||
|
// case KEY_F12:
|
|||
|
// FwControlCharacter = 'O';
|
|||
|
// FwFunctionCharacter = 'B';
|
|||
|
// break;
|
|||
|
|
|||
|
default:
|
|||
|
Char = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Check to see if the scan code corresponds to an ASCII
|
|||
|
// character.
|
|||
|
//
|
|||
|
|
|||
|
if (((Scan >= 16) && (Scan <= 25)) ||
|
|||
|
((Scan >= 30) && (Scan <= 38)) ||
|
|||
|
((Scan >= 44) && (Scan <= 50))) {
|
|||
|
if (((FwLeftShift || FwRightShift) && !FwCapsLock) ||
|
|||
|
(!(FwLeftShift || FwRightShift) && FwCapsLock)) {
|
|||
|
Char = ShiftedLookup[Scan - 2];
|
|||
|
} else {
|
|||
|
Char = NormalLookup[Scan - 2];
|
|||
|
}
|
|||
|
} else {
|
|||
|
if ((Scan > 1) && (Scan < 58)) {
|
|||
|
|
|||
|
//
|
|||
|
// Its ASCII but not alpha, so don't shift on CapsLock.
|
|||
|
//
|
|||
|
|
|||
|
if (FwLeftShift || FwRightShift) {
|
|||
|
Char = ShiftedLookup[Scan - 2];
|
|||
|
} else {
|
|||
|
Char = NormalLookup[Scan - 2];
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If a character, store it in buffer.
|
|||
|
//
|
|||
|
|
|||
|
if (Char) {
|
|||
|
StoreKeyboardChar(Char);
|
|||
|
return;
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
if (FwControlCharacter) {
|
|||
|
StoreKeyboardChar(ASCII_CSI);
|
|||
|
StoreKeyboardChar(FwControlCharacter);
|
|||
|
if (FwControlCharacter == 'O') {
|
|||
|
StoreKeyboardChar(FwFunctionCharacter);
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
FwInterruptHandler(
|
|||
|
IN R4000_CAUSE_REGISTER Cause
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called when an interrupt occurs.
|
|||
|
Only device interrupts are handled.
|
|||
|
In a Keyboard interrupt, it reads the scan code and puts it
|
|||
|
in a buffer. If a Ctrl C sequence is detected it raises SIGINT.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Cause - R4000 cause register.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
FALSE If the exception could not be handled.
|
|||
|
TRUE Otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
UCHAR IntP;
|
|||
|
UCHAR ScanCode;
|
|||
|
volatile USHORT TmpShort;
|
|||
|
|
|||
|
//
|
|||
|
// Ignore EISA and TIMER interrupts. TEMPTEMP
|
|||
|
//
|
|||
|
|
|||
|
if (!(Cause.IP & ~((1 << 4) | (1 << 6)))) {
|
|||
|
return(TRUE);
|
|||
|
}
|
|||
|
|
|||
|
if (Cause.IP != (1 << 3)) { // if not device interrupt
|
|||
|
return FALSE; // exit
|
|||
|
}
|
|||
|
IntP = READ_REGISTER_UCHAR(INTERRUPT_SOURCE);
|
|||
|
|
|||
|
//
|
|||
|
// if the interrupt is not from the keyboard,
|
|||
|
// set the Boolean to tell that a device interrupt ocurred and
|
|||
|
// disable all I/O device interrupts except keyboard.
|
|||
|
//
|
|||
|
if (IntP != KEYBOARD_DEVICE) {
|
|||
|
DeviceInterruptFlag = TRUE;
|
|||
|
WRITE_REGISTER_USHORT(&((PINTERRUPT_REGISTERS)INTERRUPT_VIRTUAL_BASE)->Enable,
|
|||
|
(1 << (KEYBOARD_VECTOR - DEVICE_VECTORS - 1)));
|
|||
|
|
|||
|
//
|
|||
|
// Read register to synchronize write.
|
|||
|
//
|
|||
|
TmpShort = READ_REGISTER_USHORT(&((PINTERRUPT_REGISTERS)INTERRUPT_VIRTUAL_BASE)->Enable);
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Wait 10 microseconds in case we have a slow keyboard controller that posts the interrupt
|
|||
|
// before the character is ready.
|
|||
|
//
|
|||
|
|
|||
|
FwStallExecution(10);
|
|||
|
|
|||
|
//
|
|||
|
// Handle the keyboard interrupt.
|
|||
|
//
|
|||
|
while (READ_REGISTER_UCHAR(&KEYBOARD_READ->Status) & KBD_OBF_MASK == 0) {
|
|||
|
}
|
|||
|
ScanCode = READ_REGISTER_UCHAR(&KEYBOARD_READ->Data);
|
|||
|
|
|||
|
switch (ScanCode) {
|
|||
|
|
|||
|
//
|
|||
|
// Ctrl Make
|
|||
|
//
|
|||
|
case 0x1D: KbdCtrl = TRUE;
|
|||
|
break;
|
|||
|
//
|
|||
|
// Ctrl Break
|
|||
|
//
|
|||
|
case 0x9D: KbdCtrl = FALSE;
|
|||
|
break;
|
|||
|
//
|
|||
|
// C
|
|||
|
//
|
|||
|
case 0x2E: if (KbdCtrl) {
|
|||
|
(SIGINTHandler)(SIGINT);
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Translate the scan code.
|
|||
|
//
|
|||
|
TranslateScanCode(ScanCode);
|
|||
|
return TRUE;
|
|||
|
}
|