summaryrefslogtreecommitdiffstats
path: root/usr.sbin/pcvt/kbdio/kbdio.y
blob: 9207d26b2943f2a17647b122ba0a4d2039499603 (plain)
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
/* Hello emacs, this should be edited in -*- Fundamental -*- mode */
%{
/*
 * Copyright (c) 1994 Joerg Wunsch
 *
 * All rights reserved.
 *
 * This program is free software.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by Joerg Wunsch
 * 4. The name of the developer may not be used to endorse or promote
 *    products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ident "$FreeBSD$"

/*
 * $Log: kbdio.y,v $
 * Revision 1.2  1994/09/18  19:49:22  j
 * Refined expr handling; can now set/clear bits.
 *
 * Revision 1.1  1994/09/18  12:57:13  j
 * Initial revision
 *
 *
 */

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/fcntl.h>
#include <machine/cpufunc.h>
#include <machine/pcvt_ioctl.h>

#ifdef __NetBSD__
#include <machine/pio.h>
#endif

#define	KBD_DELAY \
	{ u_char x = inb(0x84); } \
	{ u_char x = inb(0x84); } \
	{ u_char x = inb(0x84); } \
	{ u_char x = inb(0x84); } \
	{ u_char x = inb(0x84); } \
	{ u_char x = inb(0x84); }

#define YYDEBUG 1

void yyerror(const char *msg);

static	void help(int), status(void), data(int), kbd(int), cmdbyte(int),
	kbc(int), whatMCA(void);
static	int kbget(void);
%}

%union {
	int num;
}

%token		NEWLINE
%token		ALL CMD DATA DEFAULTS ECHOC ENABLE EXPR HELP ID LED
%token		MAKE ONLY RELEASE RESEND RESET SCAN STATUS TYPEMATIC
%token		WHAT
%token	<num>	NUM

%type	<num>	expr opr

%%

interpret:	lines ;

lines:		line
		| lines line
		;

line:		statements NEWLINE
		| NEWLINE
		| error	NEWLINE		{ fprintf(stderr, "bing!\n"); }
		;

statements:	statement
		| statements ';' statement
		;

statement:	'?'			{ help(0); }
		| HELP			{ help(0); }
		| HELP EXPR		{ help(1); }
		| STATUS '?'		{ status(); }
		| WHAT '?'		{ whatMCA(); }
		| DATA '?'		{ data(kbget()); }
		| LED '=' NUM		{ kbd(0xed); kbd($3); }
		| ECHOC			{ kbd(0xee); kbget(); }
		| SCAN '=' NUM		{ kbd(0xf0); kbd($3);
					  if($3 == 0) data(kbget()); }
		| SCAN '?'		{ kbd(0xf0); kbd(0); data(kbget()); }
		| ID '?'		{ kbd(0xf2); data(kbget());
					  data(kbget()); }
		| TYPEMATIC '=' NUM ',' NUM
					{ kbd(0xf3);
					  if($3 > 1000) $3 = 1000;
					  if($5 > 30) $5 = 30;
					  if($5 < 2) $5 = 2;
					  kbd(
					      (int)
						(8.0 * log(30.0 / (double)$5)
						 / log(2))
					      | ((($3 / 250) - 1) * 32)
					     );
					}
		| ENABLE		{ kbd(0xf4); }
		| DEFAULTS		{ kbd(0xf6); }
		| ALL TYPEMATIC		{ kbd(0xf7); }
		| ALL MAKE RELEASE	{ kbd(0xf8); }
		| ALL MAKE ONLY		{ kbd(0xf9); }
		| ALL TYPEMATIC MAKE RELEASE
					{ kbd(0xfa); }
		| NUM TYPEMATIC		{ kbd(0xfb); kbd($1); }
		| NUM MAKE RELEASE	{ kbd(0xfc); kbd($1); }
		| NUM MAKE ONLY		{ kbd(0xfd); kbd($1); }
		| RESEND		{ kbd(0xfe); }
		| RESET			{ kbd(0xff); }
		| CMD '?'		{ kbc(0x20); cmdbyte(kbget()); }
		| CMD '=' expr		{ kbc(0x60); kbd($3); }
		| /* lambda */
		;

expr:		opr			{ $$ = $1; }
		| expr '+' opr		{ $$ = $1 | $3; }
		| expr '-' opr		{ $$ = $1 & ~($3); }
		;

opr:		NUM			{ $$ = $1; }
		| CMD			{ kbc(0x20); $$ = kbget(); }
		;

%%

static void
help(int topic) {
	switch(topic) {
	case 0:
	printf(
	"Input consists of lines, containing one or more semicolon-separated\n"
	"statements. Numbers are implicitly hexadecimal, append a dot for\n"
	"decimal numbers. Valid statements include:\n"
	"help [expr];		give help [to expression syntax]\n"
	"status ?		interpret kbd ctrl status byte\n"
	"what ?			check for MCA type 1 or 2 motherboard controller\n"
	"data ?			get one byte of data\n"
	"led = NUM		set kbd LEDs\n"
	"echo = NUM		echo byte to kbd\n"
	"scan = NUM; scan ?	set scan code set; return current set\n"
	"id ?			get two id bytes\n"
	"typematic=delay,rate	set typematic delay(ms)&rate(1/s)\n"
	"enable; defaults	enable kbd; back to defaults\n"
	"all typematic		make all keys typematic\n"
	"all make release	make all keys sending make/release\n"
	"all make only		make all keys sending make only\n"
	"all typematic make release	make all keys typematic & make/release\n"
	"NUM typematic		make specific key typematic\n"
	"NUM make release	make specific key sending make/release\n"
	"NUM make only		make specific key sending make only\n"
	"resend; reset		resend last byte from kbd; reset kbd\n"
	"cmd ?			fetch kbd ctrl command byte\n"
	"cmd = expr		set kbd ctrl command byte\n"
	"\n");
	break;

	case 1:
	printf(
	"Expressions can either consist of a number, possibly followed\n"
	"by a + or - sign and bit values in numeric or symbolic form.\n"
	"Symbolic bit values are:\n"
	"SCCONV IGNPAR CLKLOW OVRINH TEST IRQ\n"
	"\n");
	break;
	}
}

static void
status(void) {
	int c = inb(0x64);
	if(c&0x80) printf("parity error | ");
	if(c&0x40) printf("rx timeout | ");
	if(c&0x20) printf("tx timeout | ");
	if(c&0x10) printf("kbd released ");
	else       printf("kbd locked   ");
	if(c&0x08) printf("| cmd last sent  ");
	else       printf("| data last sent ");
	if(c&0x04) printf("| power-on ");
	else       printf("| test ok  ");
	if(c&0x02) printf("| ctrl write busy ");
	else       printf("| ctrl write ok   ");
	if(c&0x01) printf("| ctrl read ok\n");
	else       printf("| ctrl read empty\n");
}

/* see: Frank van Gilluwe, "The Undocumented PC", Addison Wesley 1994, pp 273 */

static void
whatMCA(void) {
	int new, sav;
	kbc(0x20);		/* get command byte */
	sav = kbget();		/* sav = command byte */
	kbc(0x60);		/* set command byte */
	kbd(sav | 0x40);	/* set keyboard xlate bit */
	kbc(0x20);		/* get keyboard command */
	new = kbget();		/* new = command byte */
	kbc(0x60);		/* set command byte */
	kbd(sav);		/* restore command byte */
	if(new & 0xbf)
		printf("Hmm - looks like MCA type 1 motherboard controller\n");
	else
		printf("Hmm - looks like MCA type 2 motherboard controller\n");
}

static void
kbd(int d) {
	int i = 100000;
	while(i && (inb(0x64) & 2)) i--;
	if(i == 0) { printf("kbd write: timed out\n"); return; }
	outb(0x60, d);
}

static void
kbc(int d) {
	int i = 100000;
	while(i && (inb(0x64) & 2)) i--;
	if(i == 0) { printf("ctrl write: timed out\n"); return; }
	outb(0x64, d);
}

static int
kbget(void) {
	int i, c;
	for(;;) {
		i = 10000;
		while(i && (inb(0x64) & 1) == 0) i--;
		if(i == 0) { printf("data read: timed out\n"); return -1; }
		KBD_DELAY
		c = (unsigned char)inb(0x60);
		switch(c) {
			case 0: case 0xff:
				printf("got kbd overrun\n"); break;
			case 0xaa:
				printf("got self-test OK\n"); break;
			case 0xee:
				printf("got ECHO byte\n"); break;
			case 0xfa:
				printf("got ACK\n"); break;
			case 0xfc:
				printf("got self-test FAIL\n"); break;
			case 0xfd:
				printf("got internal failure\n"); break;
			case 0xfe:
				printf("got RESEND request\n"); break;
			default:
				goto done;
		}
	}
done:
	return c;
}

static void
cmdbyte(int d) {
	if(d&0x40) printf("scan conv ");
	else       printf("pass thru ");
	if(d&0x20) printf("| ign parity   ");
	else       printf("| check parity ");
	if(d&0x10) printf("| kbd clk low ");
	else       printf("| enable kbd  ");
	if(d&0x08) printf("| override kbd inh ");
	if(d&0x04) printf("| test ok  ");
	else       printf("| power-on ");
	if(d&0x01) printf("| irq 1 enable\n");
	else       printf("| no irq\n");
}

static void
data(int d) {
	if(d < 0) return;
	printf("data: 0x%02x\n", d);
}

void yyerror(const char *msg) {
	fprintf(stderr, "yyerror: %s\n", msg);
}

int main(int argc, char **argv) {
	int fd;

	if(argc > 1) yydebug = 1;

	if((fd = open("/dev/console", O_RDONLY)) < 0)
		fd = 0;

	if(ioctl(fd, KDENABIO, 0) < 0) {
		perror("ioctl(KDENABIO)");
		return 1;
	}
	yyparse();

	(void)ioctl(fd, KDDISABIO, 0);
	return 0;
}

OpenPOWER on IntegriCloud