summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/i386/go32/console/inch.c
blob: 992723a4a01ed0e312b80b57c39721d1700c5bf0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/*
 *  $Id$
 */

#include <pc.h>
#include <go32.h>
#include <bsp.h>
#include <cpu.h>

/*
 * Ports for PC keyboard
 */
#define KBD_CTL 0x61
#define KBD_DATA 0x60
#define KBD_STATUS 0x64

static char key_map[] = {
0,033,'1','2','3','4','5','6','7','8','9','0','-','=','\b','\t',
'q','w','e','r','t','y','u','i','o','p','[',']',015,0x80,
'a','s','d','f','g','h','j','k','l',';',047,0140,0x80,
0134,'z','x','c','v','b','n','m',',','.','/',0x80,
'*',0x80,' ',0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,'0',0177
};

static char shift_map[] = {
0,033,'!','@','#','$','%','^','&','*','(',')','_','+','\b','\t',
'Q','W','E','R','T','Y','U','I','O','P','{','}',015,0x80,
'A','S','D','F','G','H','J','K','L',':',042,'~',0x80,
'|','Z','X','C','V','B','N','M','<','>','?',0x80,
'*',0x80,' ',0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,'7','8','9',0x80,'4','5','6',0x80,
'1','2','3','0',177
};

extern int _IBMPC_Use_Go32_IO;

#define KBD_BUF_SIZE	256
static char		kbd_buffer[ KBD_BUF_SIZE ];
static unsigned int	kbd_first = 0;
static unsigned int	kbd_last  = 0;

/* This function can be called during a poll for input, or by an ISR.	*/
/* Basically any time you want to process a keypress.			*/
int _IBMPC_scankey( char * ch )
{
	unsigned char c;
	unsigned char outch;
	static int shift_pressed = 0;
	static int ctrl_pressed = 0;
	static int caps_pressed = 0;

	/* Read keyboard controller, toggle enable */
	inport_byte( KBD_CTL, c );
	outport_byte( KBD_CTL, c & ~0x80 );
	outport_byte( KBD_CTL, c | 0x80 );
	outport_byte( KBD_CTL, c & ~0x80 );

	/* See if it has data */
	inport_byte( KBD_STATUS, c );
	if ( ( c & 0x01 ) == 0 )
	    return 0;

	/* Read the data.  Handle nonsense with shift, control, etc. */
	inport_byte( KBD_DATA, c );
	switch ( c ) {
	case 0x36:
	case 0x2a:
		shift_pressed = 1;
		return 0;
	case 0x3a:
		caps_pressed = 1;
		return 0;
	case 0x1d:
		ctrl_pressed = 1;
		return 0;
	case 0xb6:
	case 0xaa:
		shift_pressed = 0;
		return 0;
	case 0xba:
		caps_pressed = 0;
		return 0;
	case 0x9d:
		ctrl_pressed = 0;
		return 0;
	/*
	 * Ignore unrecognized keys--usually arrow and such
	 */
	default:
		if ( c & 0x80 )
		    /* High-bit on means key is being released, not pressed */
		    return 0;
		if ( c == 88 )
		    /* F12 - abort */
		    exit( 1 );
		if ( c > 0x39 )  {
		    return 0;
		}
	}

	/* Strip high bit, look up in our map */
	c &= 127;
	if ( ctrl_pressed )  {
	    outch = key_map[c];
	    outch &= 037;
	} else {
	    outch = shift_pressed ? shift_map[c] : key_map[c];
	    if ( caps_pressed )  {
		if      ( outch >= 'A' && outch <= 'Z' )  outch += 'a' - 'A';
		else if ( outch >= 'a' && outch <= 'z' )  outch -= 'a' - 'A';
	    }
	}

	*ch = outch;
	return 1;
}


void _IBMPC_keyboard_isr( rtems_unsigned32 interrupt )
{
    if ( _IBMPC_scankey( & kbd_buffer[ kbd_last ] ) )  {
	/* Got one; save it if there is enough room in buffer. */
	unsigned int next = (kbd_last + 1) % KBD_BUF_SIZE;
	if ( next != kbd_first )
	    kbd_last = next;
    }

    /* Mark interrupt as handled */
    outport_byte( 0x20, 0x20 );
}


int _IBMPC_chrdy( char * ch )
{
    if ( _IBMPC_Use_Go32_IO )  {
	/* Read keyboard via BIOS: raw mode. */
	if ( kbhit() )  {
	    *ch = getkey();
	    return 1;
	} else {
	    return 0;
	}
    } else {
	/* Check buffer our ISR builds */
	if ( kbd_first != kbd_last )  {
	    *ch = kbd_buffer[ kbd_first ];
	    kbd_first = (kbd_first + 1) % KBD_BUF_SIZE;
	    return 1;
	} else {
	    return 0;
	}
    }
}

int _IBMPC_inch( void )
{
    char Ch;
    while ( ! _IBMPC_chrdy( & Ch ) )
	continue;
    return Ch;
}