xref: /original-bsd/sys/i386/isa/pccons.c (revision e2bb50a5)
1 /*-
2  * Copyright (c) 1990 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * William Jolitz.
7  *
8  * Added support for ibmpc term type and improved keyboard support. -Don Ahn
9  *
10  * %sccs.include.386.c%
11  *
12  *	@(#)pccons.c	5.2 (Berkeley) 06/23/90
13  */
14 
15 /*
16  * code to work keyboard & display for console
17  */
18 #include "param.h"
19 #include "conf.h"
20 #include "dir.h"
21 #include "ioctl.h"
22 #include "user.h"
23 #include "proc.h"
24 #include "tty.h"
25 #include "uio.h"
26 #include "machine/device.h"
27 #include "callout.h"
28 #include "systm.h"
29 #include "kernel.h"
30 #include "syslog.h"
31 #include "icu.h"
32 
33 struct	tty cons;
34 
35 struct	consoftc {
36 	char	cs_flags;
37 #define	CSF_ACTIVE	0x1	/* timeout active */
38 #define	CSF_POLLING	0x2	/* polling for input */
39 	char	cs_lastc;	/* last char sent */
40 	int	cs_timo;	/* timeouts since interrupt */
41 	u_long	cs_wedgecnt;	/* times restarted */
42 } consoftc;
43 
44 int cnprobe(), cnattach();
45 
46 struct	driver cndriver = {
47 	cnprobe, cnattach, "cn",
48 };
49 
50 /*
51  * We check the console periodically to make sure
52  * that it hasn't wedged.  Unfortunately, if an XOFF
53  * is typed on the console, that can't be distinguished
54  * from more catastrophic failure.
55  */
56 #define	CN_TIMERVAL	(hz)		/* frequency at which to check cons */
57 #define	CN_TIMO		(2*60)		/* intervals to allow for output char */
58 
59 int	cnstart();
60 int	ttrstrt();
61 char	partab[];
62 
63 /*
64  * Wait for CP to accept last CP command sent
65  * before setting up next command.
66  */
67 #define	waitforlast(timo) { \
68 	if (cnlast) { \
69 		(timo) = 10000; \
70 		do \
71 			uncache((char *)&cnlast->cp_unit); \
72 		while ((cnlast->cp_unit&CPTAKE) == 0 && --(timo)); \
73 	} \
74 }
75 
76 u_char inb();
77 
78 cnprobe(dev)
79 struct device *dev;
80 {
81 	u_char c;
82 	int again = 0;
83 
84 	/* Enable interrupts and keyboard controller */
85 	while (inb(0x64)&2); outb(0x64,0x60);
86 	while (inb(0x64)&2); outb(0x60,0x4D);
87 
88 	/* Start keyboard stuff RESET */
89 	while (inb(0x64)&2);	/* wait input ready */
90 	outb(0x60,0xFF);	/* RESET */
91 	while((c=inb(0x60))!=0xFA) {
92 		if ((c == 0xFE) ||  (c == 0xFF)) {
93 			if(!again)printf("KEYBOARD disconnected: RECONNECT \n");
94 			while (inb(0x64)&2);	/* wait input ready */
95 			outb(0x60,0xFF);	/* RESET */
96 			again = 1;
97 		}
98 	}
99 	if (again) printf("KEYBOARD Reconnected\n");
100 	/* pick up keyboard reset return code */
101 	sgetc(1);
102 	return 1;
103 }
104 
105 cnattach(dev)
106 struct device *dev;
107 {
108 	INTREN(IRQ1);
109 }
110 
111 /*ARGSUSED*/
112 cnopen(dev, flag)
113 	dev_t dev;
114 {
115 	register struct tty *tp;
116 	int unit = minor(dev);
117 
118 	tp = &cons;
119 	if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
120 		return (EBUSY);
121 	tp->t_oproc = cnstart;
122 	if ((tp->t_state&TS_ISOPEN) == 0) {
123 		ttychars(tp);
124 		tp->t_state = TS_ISOPEN|TS_CARR_ON;
125 		tp->t_flags = EVENP|ECHO|XTABS|CRMOD;
126 		splnone();
127 	}
128 	return ((*linesw[tp->t_line].l_open)(dev, tp));
129 }
130 
131 
132 cnclose(dev)
133 	dev_t dev;
134 {
135 	(*linesw[cons.t_line].l_close)(&cons);
136 	ttyclose(&cons);
137 	INTRDIS(IRQ1);
138 }
139 
140 /*ARGSUSED*/
141 cnread(dev, uio)
142 	dev_t dev;
143 	struct uio *uio;
144 {
145 	return ((*linesw[cons.t_line].l_read)(&cons, uio));
146 }
147 
148 /*ARGSUSED*/
149 cnwrite(dev, uio)
150 	dev_t dev;
151 	struct uio *uio;
152 {
153 	return ((*linesw[cons.t_line].l_write)(&cons, uio));
154 }
155 
156 /*
157  * Got a console receive interrupt -
158  * the console processor wants to give us a character.
159  * Catch the character, and see who it goes to.
160  */
161 cnrint(dev)
162 	dev_t dev;
163 {
164 	int c;
165 
166 	c = sgetc(1);
167 	if (c&0x100)return;
168 	if (consoftc.cs_flags&CSF_POLLING)
169 		return;
170 #ifdef KDB
171 	if (kdbrintr(c, &cons))
172 		return;
173 #endif
174 	(*linesw[cons.t_line].l_rint)(c&0xff, &cons);
175 }
176 
177 cnioctl(dev, cmd, addr, flag)
178 	dev_t dev;
179 	caddr_t addr;
180 {
181 	register struct tty *tp = &cons;
182 	register error;
183 
184 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr);
185 	if (error >= 0)
186 		return error;
187 	if ((error = ttioctl(tp, cmd, addr, flag)) < 0)
188 		error = ENOTTY;
189 	else if (cmd == TIOCSETP || cmd == TIOCSETN)
190 		cnparams(tp);
191 	return (error);
192 }
193 
194 int	consintr = 1;
195 /*
196  * Got a console transmission interrupt -
197  * the console processor wants another character.
198  */
199 cnxint(dev)
200 	dev_t dev;
201 {
202 	register struct tty *tp;
203 	register int unit;
204 
205 	if (!consintr)
206 		return;
207 	cons.t_state &= ~TS_BUSY;
208 	consoftc.cs_timo = 0;
209 	if (cons.t_line)
210 		(*linesw[cons.t_line].l_start)(&cons);
211 	else
212 		cnstart(&cons);
213 }
214 
215 cnstart(tp)
216 	register struct tty *tp;
217 {
218 	register c, s;
219 
220 	s = spltty();
221 	if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
222 		goto out;
223 	if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
224 		if (tp->t_state&TS_ASLEEP) {
225 			tp->t_state &= ~TS_ASLEEP;
226 			wakeup((caddr_t)&tp->t_outq);
227 		}
228 		if (tp->t_wsel) {
229 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
230 			tp->t_wsel = 0;
231 			tp->t_state &= ~TS_WCOLL;
232 		}
233 	}
234 	while (tp->t_outq.c_cc != 0) {
235 		c = getc(&tp->t_outq) & 0xff;
236 		if ((tp->t_flags & (RAW|LITOUT)) == 0) {
237 			if (c > 0177)
238 			{
239 				timeout(ttrstrt, (caddr_t)tp, (c&0177));
240 				tp->t_state |= TS_TIMEOUT;
241 				break;
242 			}
243 			c &= 0177;
244 		}
245 		splx(s);
246 		sput(c,0x7);
247 		s = spltty();
248 	}
249 out:
250 	splx(s);
251 }
252 
253 cnputc(c)
254 	char c;
255 {
256 	if (c == '\n')
257 		sput('\r',0x3);
258 	sput(c, 0x3);
259 }
260 
261 /*
262  * Print a character on console.
263  */
264 cnputchar(c, tp)
265 	char c;
266 	register struct tty *tp;
267 {
268 	sput(c,0x2);
269 	if (c=='\n') getchar();
270 }
271 
272 
273 cngetc()
274 {
275 	register int c, s;
276 
277 	s = spltty();		/* block cnrint while we poll */
278 	c = sgetc(0);
279 	if (c == '\r') c = '\n';
280 	splx(s);
281 	return (c);
282 }
283 
284 cngetchar(tp)
285 	register struct tty *tp;
286 {
287 	int c;
288 
289 	c = sgetc(0);
290 	return (c&0xff);
291 }
292 
293 /*
294  * Set line parameters
295  */
296 cnparams(tp)
297 	register struct tty *tp;
298 {
299 }
300 
301 #ifdef KDB
302 /*
303  * Turn input polling on/off (used by debugger).
304  */
305 cnpoll(onoff)
306 	int onoff;
307 {
308 }
309 #endif
310 
311 extern int hz;
312 
313 sysbeepstop()
314 {
315 	/* disable counter 2 */
316 	outb(0x61,inb(0x61)&0xFC);
317 }
318 
319 sysbeep()
320 {
321 	/* enable counter 2 */
322 	outb(0x61,inb(0x61)|3);
323 	/* set command for counter 2, 2 byte write */
324 	outb(0x43,0xB6);
325 	/* send 0x637 for 750 HZ */
326 	outb(0x42,0x37);
327 	outb(0x42,0x06);
328 	timeout(sysbeepstop,0,hz/4);
329 }
330 
331 #define	COL		80
332 #define	ROW		25
333 #define	CHR		2
334 #define MONO_BASE	0x3B4
335 #define MONO_BUF	0xB0000
336 #define CGA_BASE	0x3D4
337 #define CGA_BUF		0xB8000
338 #define IOPHYSMEM	0xA0000
339 
340 u_char	color = 0xe ;
341 static unsigned int addr_6845;
342 u_short *Crtat = (u_short *)MONO_BUF;
343 
344 /* cursor() sets an offset (0-1999) into the 80x25 text area    */
345 /* Theoretically there should be a slight delay between outb's  */
346 /* and if your display has cursor problems that may be it.      */
347 /* This may have to be left as is since it is done after every  */
348 /* char and can seriously affect performance .                  */
349 
350 cursor(pos)
351 int pos;
352 {
353 	outb(addr_6845,14);
354 	outb(addr_6845+1,pos >> 8);
355 	outb(addr_6845,15);
356 	outb(addr_6845+1,pos&0xff);
357 }
358 
359 /* sput has support for emulation of the 'ibmpc' termcap entry. */
360 /* This is a bare-bones implementation of a bare-bones entry    */
361 /* One modification: Change li#24 to li#25 to reflect 25 lines  */
362 /* sput tries to do 16-bit writes.  This may not work on all.   */
363 
364 sput(c, ca)
365 u_char c, ca;
366 {
367 
368 	static int esc,ebrac,eparm,cx,cy,row,so;
369 	static u_short *crtat = 0;
370 	int s;
371 
372 	s = splnone();
373 
374 /*
375 	if(inb(0x64)&1)sgetc(1);
376 */
377 	if (crtat == 0) {
378 
379 		/* Crtat initialized to point to MONO buffer   */
380 		/* if not present change to CGA_BUF offset     */
381 		/* ONLY ADD the difference since locore.s adds */
382 		/* in the remapped offset at the right time    */
383 
384 		*Crtat = (u_short) 0xA55A;
385 		if (*Crtat != 0xA55A) {
386 			Crtat = Crtat + (CGA_BUF-MONO_BUF)/CHR;
387 			addr_6845 = CGA_BASE;
388 		} else addr_6845 = MONO_BASE;
389 		crtat = Crtat; bzero (crtat,COL*ROW*CHR);
390 	}
391 	switch(c) {
392 	case 0x1B:
393 		esc = 1; ebrac = 0; eparm = 0;
394 		break;
395 
396 	case '\t':
397 		do {
398 			*crtat++ = (ca<<8)| ' '; row++ ;
399 		} while (row %8);
400 		break;
401 
402 	case '\010':
403 		crtat--; row--;
404 		if (row < 0) row += COL;  /* non-destructive backspace */
405 		break;
406 
407 	case '\r':
408 		crtat -= row ; row = 0;
409 		break;
410 
411 	case '\n':
412 		crtat += COL ;
413 		break;
414 
415 	default:
416 		if (esc) {
417 			if (ebrac) {
418 				switch(c) {
419 				case 'm': /* no support for standout */
420 					if (!cx) so = 0;
421 					else so = 1;
422 					esc = 0; ebrac = 0; eparm = 0;
423 					break;
424 				case 'A': /* back one row */
425 					crtat -= COL;
426 					esc = 0; ebrac = 0; eparm = 0;
427 					break;
428 				case 'B': /* down one row */
429 					crtat += COL;
430 					esc = 0; ebrac = 0; eparm = 0;
431 					break;
432 				case 'C': /* right cursor */
433 					crtat++; row++;
434 					esc = 0; ebrac = 0; eparm = 0;
435 					break;
436 				case 'J': /* Clear to end of display */
437 					bzero(crtat,(Crtat+COL*ROW-crtat)*CHR);
438 					esc = 0; ebrac = 0; eparm = 0;
439 					break;
440 				case 'K': /* Clear to EOL */
441 					bzero(crtat,(COL-row)*CHR);
442 					esc = 0; ebrac = 0; eparm = 0;
443 					break;
444 				case 'H': /* Cursor move */
445 					if ((!cx)||(!cy)) {
446 						crtat = Crtat;
447 						row = 0;
448 					} else {
449 						crtat = Crtat+(cx-1)*COL+cy-1;
450 						row = cy-1;
451 					}
452 					esc = 0; ebrac = 0; eparm = 0;
453 					break;
454 				case ';': /* Switch params in cursor def */
455 					eparm = 1;
456 					splx(s);
457 					return;
458 				default: /* Only numbers valid here */
459 					if ((c >= '0')&&(c <= '9')) {
460 						if (eparm) {
461 							cy *= 10;
462 							cy += c - '0';
463 						} else {
464 							cx *= 10;
465 							cx += c - '0';
466 						}
467 					} else {
468 						esc = 0; ebrac = 0; eparm = 0;
469 					}
470 					splx(s);
471 					return;
472 				}
473 				break;
474 			} else if (c == 'c') { /* Clear screen & home */
475 				bzero(Crtat,COL*ROW*CHR);
476 				crtat = Crtat; row = 0;
477 				esc = 0; ebrac = 0; eparm = 0;
478 			}else if (c == '[') { /* Start ESC [ sequence */
479 				ebrac = 1; cx = 0; cy = 0; eparm = 0;
480 			}else{ /* Invalid, clear state */
481 				 esc = 0; ebrac = 0; eparm = 0;
482 			}
483 		} else {
484 			if (c == 7) {
485 				sysbeep();
486 			}
487 			/* Print only printables */
488 			else if (c >= ' ') {
489 				if (so) {
490 					*crtat++ = 0x7000| c; row++ ;
491 				} else {
492 					*crtat++ = (ca<<8)| c; row++ ;
493 				}
494 				if (row >= COL) row = 0;
495 				break ;
496 			}
497 		}
498 	}
499 	if (crtat >= Crtat+COL*(ROW)) { /* scroll check */
500 		bcopy(Crtat+COL,Crtat,COL*(ROW-1)*CHR);
501 		bzero (Crtat+COL*(ROW-1),COL*CHR) ;
502 		crtat -= COL ;
503 	}
504 	cursor(crtat-Crtat);
505 	splx(s);
506 }
507 
508 
509 
510 #define	L		0x0001	/* locking function */
511 #define	SHF		0x0002	/* keyboard shift */
512 #define	ALT		0x0004	/* alternate shift -- alternate chars */
513 #define	NUM		0x0008	/* numeric shift  cursors vs. numeric */
514 #define	CTL		0x0010	/* control shift  -- allows ctl function */
515 #define	CPS		0x0020	/* caps shift -- swaps case of letter */
516 #define	ASCII		0x0040	/* ascii code for this key */
517 #define	STP		0x0080	/* stop output */
518 #define	FUNC		0x0100	/* function key */
519 #define	SCROLL		0x0200	/* scroll lock key */
520 
521 unsigned	__debug = 0 ;
522 u_short action[] = {
523 0,     ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII,		/* scan  0- 7 */
524 ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII,		/* scan  8-15 */
525 ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII,		/* scan 16-23 */
526 ASCII, ASCII, ASCII, ASCII, ASCII,   CTL, ASCII, ASCII,		/* scan 24-31 */
527 ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII,		/* scan 32-39 */
528 ASCII, ASCII, SHF  , ASCII, ASCII, ASCII, ASCII, ASCII,		/* scan 40-47 */
529 ASCII, ASCII, ASCII, ASCII, ASCII, ASCII,  SHF,  ASCII,		/* scan 48-55 */
530   ALT, ASCII, CPS  , FUNC , FUNC , FUNC , FUNC , FUNC ,		/* scan 56-63 */
531 FUNC , FUNC , FUNC , FUNC , FUNC , NUM, STP, ASCII,		/* scan 64-71 */
532 ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII,		/* scan 72-79 */
533 ASCII, ASCII, ASCII, ASCII,     0,     0,     0,     0,		/* scan 80-87 */
534 0,0,0,0,0,0,0,0,
535 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
536 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,	} ;
537 
538 u_char unshift[] = {	/* no shift */
539 0,     033  , '1'  , '2'  , '3'  , '4'  , '5'  , '6'  ,		/* scan  0- 7 */
540 '7'  , '8'  , '9'  , '0'  , '-'  , '='  , 0177 ,'\t'  ,		/* scan  8-15 */
541 
542 'q'  , 'w'  , 'e'  , 'r'  , 't'  , 'y'  , 'u'  , 'i'  ,		/* scan 16-23 */
543 'o'  , 'p'  , '['  , ']'  , '\r' , CTL  , 'a'  , 's'  ,		/* scan 24-31 */
544 
545 'd'  , 'f'  , 'g'  , 'h'  , 'j'  , 'k'  , 'l'  , ';'  ,		/* scan 32-39 */
546 '\'' , '`'  , SHF  , '\\' , 'z'  , 'x'  , 'c'  , 'v'  ,		/* scan 40-47 */
547 
548 'b'  , 'n'  , 'm'  , ','  , '.'  , '/'  , SHF  ,   '*',		/* scan 48-55 */
549 ALT  , ' '  , CPS,     1,     2,    3 ,     4,     5,		/* scan 56-63 */
550 
551     6,     7,     8,     9,    10, NUM, STP,   '7',		/* scan 64-71 */
552   '8',   '9',   '-',   '4',   '5',   '6',   '+',   '1',		/* scan 72-79 */
553 
554   '2',   '3',   '0',   '.',     0,     0,     0,     0,		/* scan 80-87 */
555 0,0,0,0,0,0,0,0,
556 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
557 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,	} ;
558 
559 u_char shift[] = {	/* shift shift */
560 0,     033  , '!'  , '@'  , '#'  , '$'  , '%'  , '^'  ,		/* scan  0- 7 */
561 '&'  , '*'  , '('  , ')'  , '_'  , '+'  , 0177 ,'\t'  ,		/* scan  8-15 */
562 'Q'  , 'W'  , 'E'  , 'R'  , 'T'  , 'Y'  , 'U'  , 'I'  ,		/* scan 16-23 */
563 'O'  , 'P'  , '{'  , '}'  , '\r' , CTL  , 'A'  , 'S'  ,		/* scan 24-31 */
564 'D'  , 'F'  , 'G'  , 'H'  , 'J'  , 'K'  , 'L'  , ':'  ,		/* scan 32-39 */
565 '"'  , '~'  , SHF  , '|'  , 'Z'  , 'X'  , 'C'  , 'V'  ,		/* scan 40-47 */
566 'B'  , 'N'  , 'M'  , '<'  , '>'  , '?'  , SHF  ,   '*',		/* scan 48-55 */
567 ALT  , ' '  , CPS,     0,     0, ' '  ,     0,     0,		/* scan 56-63 */
568     0,     0,     0,     0,     0, NUM, STP,   '7',		/* scan 64-71 */
569   '8',   '9',   '-',   '4',   '5',   '6',   '+',   '1',		/* scan 72-79 */
570   '2',   '3',   '0',   '.',     0,     0,     0,     0,		/* scan 80-87 */
571 0,0,0,0,0,0,0,0,
572 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
573 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,	} ;
574 
575 u_char ctl[] = {	/* CTL shift */
576 0,     033  , '!'  , 000  , '#'  , '$'  , '%'  , 036  ,		/* scan  0- 7 */
577 '&'  , '*'  , '('  , ')'  , 037  , '+'  , 034  ,'\177',		/* scan  8-15 */
578 021  , 027  , 005  , 022  , 024  , 031  , 025  , 011  ,		/* scan 16-23 */
579 017  , 020  , 033  , 035  , '\r' , CTL  , 001  , 023  ,		/* scan 24-31 */
580 004  , 006  , 007  , 010  , 012  , 013  , 014  , ';'  ,		/* scan 32-39 */
581 '\'' , '`'  , SHF  , 034  , 032  , 030  , 003  , 026  ,		/* scan 40-47 */
582 002  , 016  , 015  , '<'  , '>'  , '?'  , SHF  ,   '*',		/* scan 48-55 */
583 ALT  , ' '  , CPS,     0,     0, ' '  ,     0,     0,		/* scan 56-63 */
584 CPS,     0,     0,     0,     0,     0,     0,     0,		/* scan 64-71 */
585     0,     0,     0,     0,     0,     0,     0,     0,		/* scan 72-79 */
586     0,     0,     0,     0,     0,     0,     0,     0,		/* scan 80-87 */
587     0,     0,   033, '7'  , '4'  , '1'  ,     0, NUM,		/* scan 88-95 */
588 '8'  , '5'  , '2'  ,     0, STP, '9'  , '6'  , '3'  ,		/*scan  96-103*/
589 '.'  ,     0, '*'  , '-'  , '+'  ,     0,     0,     0,		/*scan 104-111*/
590 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,	} ;
591 
592 #ifdef notdef
593 struct key {
594 	u_short action;		/* how this key functions */
595 	char	ascii[8];	/* ascii result character indexed by shifts */
596 };
597 #endif
598 
599 u_char shfts, ctls, alts, caps, num, stp, scroll;
600 
601 #define	KBSTAT		0x64	/* kbd status port */
602 #define	KBS_INP_BUF_FUL	0x02	/* kbd char ready */
603 #define	KBDATA		0x60	/* kbd data port */
604 #define	KBSTATUSPORT	0x61	/* kbd status */
605 
606 update_led()
607 {
608 	while (inb(0x64)&2);	/* wait input ready */
609 	outb(0x60,0xED);	/* LED Command */
610 	while (inb(0x64)&2);	/* wait input ready */
611 	outb(0x60,scroll | 2*num | 4*caps);
612 }
613 
614 /*
615 sgetc(noblock) : get a character from the keyboard. If noblock = 0 wait until
616 a key is gotten.  Otherwise return a 0x100 (256).
617 */
618 int sgetc(noblock)
619 {
620 	u_char dt; unsigned key;
621 loop:
622 	/* First see if there is something in the keyboard port */
623 	if (inb(KBSTAT)&1) dt = inb(KBDATA);
624 	else { if (noblock) return (0x100); else goto loop; }
625 
626 	/* Check for cntl-alt-del */
627 	if ((dt == 83)&&ctls&&alts) _exit();
628 
629 	/* Check for make/break */
630 	if (dt & 0x80) {
631 		/* break */
632 		dt = dt & 0x7f ;
633 		switch (action[dt]) {
634 		case SHF: shfts = 0; break;
635 		case ALT: alts = 0; break;
636 		case CTL: ctls = 0; break;
637 		case FUNC:
638 			/* Toggle debug flags */
639 			key = unshift[dt];
640 			if(__debug & (1<<key)) __debug &= ~(1<<key) ;
641 			else __debug |= (1<<key) ;
642 			break;
643 		}
644 	} else {
645 		/* make */
646 		dt = dt & 0x7f ;
647 		switch (action[dt]) {
648 		/* LOCKING KEYS */
649 		case NUM: num ^= 1; update_led(); break;
650 		case CPS: caps ^= 1; update_led(); break;
651 		case SCROLL: scroll ^= 1; update_led(); break;
652 		case STP: stp ^= 1; if(stp) goto loop; break;
653 
654 		/* NON-LOCKING KEYS */
655 		case SHF: shfts = 1; break;
656 		case ALT: alts = 1; break;
657 		case CTL: ctls = 1; break;
658 		case ASCII:
659 			if (shfts) dt = shift[dt];
660 			else if (ctls) dt = ctl[dt];
661 			else dt = unshift[dt];
662 			if (caps && (dt >= 'a' && dt <= 'z')) dt -= 'a' - 'A';
663 			return(dt);
664 		}
665 	}
666 	if (noblock) return (0x100); else goto loop;
667 }
668 
669 pg(p,q,r,s,t,u,v,w,x,y,z) char *p; {
670 	printf(p,q,r,s,t,u,v,w,x,y,z);
671 	printf("\n");
672 	return(getchar());
673 }
674 
675 /* special characters */
676 #define bs	8
677 #define lf	10
678 #define cr	13
679 #define cntlc	3
680 #define del	0177
681 #define cntld	4
682 
683 getchar()
684 {
685 	register char thechar;
686 	register delay;
687 	int x;
688 
689 	consoftc.cs_flags |= CSF_POLLING;
690 	x=splhigh();
691 	sput('>',0x6);
692 	while (1) {
693 		thechar = (char) sgetc(0);
694 		consoftc.cs_flags &= ~CSF_POLLING;
695 		splx(x);
696 		switch (thechar) {
697 		    default: if (thechar >= ' ')
698 			     	sput(thechar,0x6);
699 			     return(thechar);
700 		    case cr:
701 		    case lf: sput(cr,0x6);
702 			     sput(lf,0x6);
703 			     return(lf);
704 		    case bs:
705 		    case del:
706 			     sput(bs,0x6);
707 			     sput(' ',0x6);
708 			     sput(bs,0x6);
709 			     return(thechar);
710 		    /*case cntlc:
711 			     sput('^',0xe) ; sput('C',0xe) ; sput('\r',0xe) ; sput('\n',0xe) ;
712 			     _exit(-2) ; */
713 		    case cntld:
714 			     sput('^',0x6) ; sput('D',0x6) ; sput('\r',0x6) ; sput('\n',0x6) ;
715 			     return(0);
716 		}
717 	}
718 }
719