|
|
1.1 root 1: /*
2: * User configurable AT keyboard/display driver.
3: * 286/386 AT COHERENT
4: */
5: #include <sys/coherent.h>
6: #ifdef _I386
7: #include <sys/reg.h>
8: #else
9: #include <sys/i8086.h>
10: #endif
11: #include <sys/con.h>
12: #include <errno.h>
13: #include <sys/stat.h>
14: #include <sys/tty.h>
15: #include <signal.h>
16: #include <sys/seg.h>
17: #include <sys/sched.h>
18: #include <sys/kb.h>
19: #include <sys/devices.h>
20: #include <sys/silo.h>
21:
22: #include <sys/vt.h>
23:
24: #define ISVEC 1 /* Keyboard interrupt vector */
25: #define DEBUG 0
26:
27: #define KBDEBUG(x) T_CON(1,printf(x)); /* debugging output */
28: #define KBDEBUG2(x,y) T_CON(1,printf(x,y)); /* debugging output */
29: #define KBDEBUG3(x,y,z) T_CON(1,printf(x,y,z)); /* debugging output */
30:
31: /*
32: * values for kbstate
33: */
34: #define KB_IDLE 0 /* nothing going on right now */
35: #define KB_SINGLE 1 /* sent a single byte cmd to the kbd */
36: #define KB_DOUBLE_1 2 /* sent 1st byte of 2-byte cmd to kbd */
37: #define KB_DOUBLE_2 3 /* sent 2nd byte of 2-byte cmd to kbd */
38:
39: /*
40: * patchable params for non-standard keyboards
41: */
42: int KBDATA = 0x60; /* Keyboard data */
43: int KBCTRL = 0x61; /* Keyboard control */
44: int KBSTS_CMD = 0x64; /* Keyboard status/command */
45: int KBFLAG = 0x80; /* Keyboard reset flag */
46: int KBBOOT = 1; /* 0: disallow reboot from keyboard */
47: int KBTIMEOUT = 10000; /* shouldn't need this much */
48: int KBCMDBYTE = 0x05; /* no translation */
49:
50: /*
51: * KBSTATUS bits
52: */
53: #define STS_OBUF_FULL 0x01 /* kbd output buffer full */
54: #define STS_IBUF_FULL 0x02 /* kbd input buffer full */
55: #define STS_SYSTEM 0x04
56: #define STS_CMD_DATA 0x08 /* 1: command or status */
57: #define STS_INHIBIT 0x10 /* 0: keyboard inhibited */
58: #define STS_AUX_OBUF_FULL 0x20
59: #define STS_TIMEOUT 0x40 /* general timeout */
60: #define STS_PAR_ERR 0x80 /* parity error */
61:
62: /*
63: * The following are magic commands which read from or write to the
64: * controller command byte. These get output to the KBSTS_CMD port.
65: */
66: #define C_READ_CMD 0x20 /* read controller command byte */
67: #define C_WRITE_CMD 0x60 /* write controller command byte */
68: #define C_TRANSLATE 0x40 /* translate enable bit in cmd byte */
69:
70: /*
71: * Globals:
72: * The 286 keyboard mapping table is too large to fit into kernel data space,
73: * so we need to allocate a segment to it. 386 is easy.
74: * The function keys tend to be small and tend to change substantially
75: * more often than the mapping table, so we keep them in the kernel data space.
76: */
77: static unsigned shift; /* state of all shift/lock keys */
78: static unsigned char **funkeyp = 0; /* ptr to array of func. keys ptrs */
79: static FNKEY *fnkeys = 0; /* pointer to structure of values */
80: static unsigned fklength; /* length of k_fnval field in fnkeys */
81: static unsigned prev_cmd; /* previous command sent to KBD */
82: static unsigned cmd2; /* 2nd byte of command to KBD */
83: static unsigned sh_index; /* shift/lock state index */
84: #ifdef _I386
85: static KBTBL kb[MAX_KEYS]; /* keyboard table */
86: #else
87: static SEG *kbsegp; /* keyboard table segment */
88: #endif
89:
90: /*
91: * State variables.
92: */
93: int islock; /* Keyboard locked flag */
94: int isbusy; /* Raw input conversion busy */
95: static char table_loaded; /* true == keyboard table resident */
96: static char fk_loaded; /* true == function keys resident */
97: static int kbstate = KB_IDLE; /* current keyboard state */
98:
99: /*
100: * Functions.
101: */
102: int isrint();
103: int istime();
104: void isbatch();
105: int mmstart();
106: int isopen();
107: int isclose();
108: int isread();
109: int mmwrite();
110: int isioctl();
111: void mmwatch();
112: int isload();
113: int isuload();
114: int ispoll();
115: int nulldev();
116: int nonedev();
117: int updleds();
118:
119: static int isioctl0();
120:
121: /*
122: * Configuration table.
123: */
124: CON iscon ={
125: DFCHR|DFPOL, /* Flags */
126: KB_MAJOR, /* Major index */
127: isopen, /* Open */
128: isclose, /* Close */
129: nulldev, /* Block */
130: isread, /* Read */
131: mmwrite, /* Write */
132: #ifdef _I386
133: isioctl0, /* Ioctl */
134: #else
135: isioctl, /* Ioctl */
136: #endif
137: nulldev, /* Powerfail */
138: mmwatch, /* Timeout */
139: isload, /* Load */
140: isuload, /* Unload */
141: ispoll /* Poll */
142: };
143:
144: /*
145: ==============================================================================
146: ==============================================================================
147: */
148: /* constants for vtdata[] */
149: #define VT_VGAPORT 0x3D4
150: #define VT_MONOPORT 0x3B4
151:
152: #ifdef _I386
153: #define VT_MONOBASE SEG_VIDEOa
154: #define VT_VGABASE SEG_VIDEOb
155: #else
156: #define VT_MONOBASE 0xB000
157: #define VT_VGABASE 0xB800
158: #endif
159:
160: /*
161: Patchable table entrys,
162: we go indirect in order to produce a label which can be addressed
163: */
164: HWentry VTVGA = { 4, 0, VT_VGAPORT, { 0, VT_VGABASE }, { 25, 80 } };
165: HWentry VTMONO = { 4, 0, VT_MONOPORT, { 0, VT_MONOBASE }, { 25, 80 } };
166:
167: HWentry *vtHWtable[] = {
168: VTVGA, /* VGA followed by MONO is compatible to DOS */
169: VTMONO,
170: 0 /* MUST STAY AS LAST ELEMENT !!! */
171: };
172:
173: extern int mminit();
174: static VTDATA const_vtdata = {
175: mminit, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 23, 24, 0, 0, 0, 23, 0, 0, 1
176: };
177:
178: /* later this should be dynamic */
179: VTDATA *vtconsole, **vtdata;
180:
181: int vtcount, vtmax;
182: extern int vtactive;
183: int vt_verbose = { 0 };
184: int vt_opened = { 0 };
185:
186: /* Terminal structure. */
187: TTY **vttty;
188:
189: /*
190: ==============================================================================
191: ==============================================================================
192: */
193:
194: static silo_t in_silo;
195:
196: /*
197: * Given hw pointer for one of four types of adapters, see if
198: * device is present by write/readback of video memory.
199: *
200: * return 1 if present, else 0
201: */
202: int
203: hwpresent( hw )
204: HWentry *hw;
205: {
206: int save, present = 1;
207:
208: PRINTV( "hwpresent: %x:%x",
209: hw->vidmemory.seg, hw->vidmemory.off );
210: save = ffword( hw->vidmemory.off, hw->vidmemory.seg );
211:
212: sfword( hw->vidmemory.off, hw->vidmemory.seg, 0xAA55 );
213: if( ffword( hw->vidmemory.off, hw->vidmemory.seg ) != 0xAA55 )
214: present = 0;
215:
216: sfword( hw->vidmemory.off, hw->vidmemory.seg, 0x55AA );
217: if( ffword( hw->vidmemory.off, hw->vidmemory.seg ) != 0x55AA )
218: present = 0;
219:
220: sfword( hw->vidmemory.off, hw->vidmemory.seg, save );
221: PRINTV( "%s present\n", present ? "" : " NOT" );
222: return present;
223: }
224:
225: /*
226: * Load entry point.
227: */
228: isload()
229: {
230: register int i;
231: register HWentry **hw;
232: register VTDATA *vp;
233:
234: PRINTV("vtload:\n");
235: fk_loaded = 0;
236: table_loaded = 0;
237: kbstate = KB_IDLE;
238:
239: /* figure out what our current max is */
240: for( vtmax = 0, hw = vtHWtable; *hw; ++hw ) {
241: vtmax += (*hw)->count;
242: (*hw)->found = 0; /* assume non-exist */
243: }
244: PRINTV( "vtload: %d screens possible\n", vtmax );
245:
246: vtdata = (VTDATA **) kalloc( vtmax * sizeof( *vtdata ) );
247: if( vtdata == NULL ) {
248: printf( "vtload: unable to obtain vtdata[%d]\n", vtmax );
249: u.u_error = -1;
250: return;
251: }
252: PRINTV( "vtload: obtained vtdata[%d] @%x\n", vtmax, vtdata );
253:
254: vttty = (TTY **) kalloc( vtmax * sizeof( *vttty ) );
255: if( vttty == NULL ) {
256: printf( "vtload: unable to obtain vttty[%d]\n", vtmax );
257: u.u_error = -1;
258: return;
259: }
260: PRINTV( "vtload: obtained vttty[%d] @%x\n", vtmax, vttty );
261:
262: /* determine which video adaptors are present */
263: for( vtcount = 0, hw = vtHWtable; *hw; ++hw ) {
264: /* suppress board sensing since it seems to confuse some equipment */
265: #if 0
266: if( !hwpresent(*hw) )
267: continue;
268: #endif
269:
270: /* remember our logical start */
271: (*hw)->start = vtcount;
272: PRINTV( ", start %d\n", vtcount );
273:
274: /* allocate the necessary memory */
275: for ( i = 0; i < (*hw)->count; ++i ) {
276: vp = vtdata[vtcount] = kalloc( sizeof(VTDATA) );
277: PRINTV( " vtdata[%d] = @%x\n", vtcount, vp );
278: if( vp == NULL || !VTttyinit(vtcount) ) {
279: printf("not enough memory for VTDATA\n" );
280: break;
281: }
282:
283: /* fill in appropriately */
284: *vp = const_vtdata;
285: vp->vmm_port = (*hw)->port;
286: vp->vmm_vseg = (*hw)->vidmemory.seg;
287: vp->vmm_voff = (*hw)->vidmemory.off;
288:
289: vp->vt_ind = vtcount;
290: vtdatainit(vp);
291: if (i == 0 ) {
292: vp->vmm_visible = VNKB_TRUE;
293: vp->vmm_seg = vp->vmm_vseg;
294: vp->vmm_off = vp->vmm_voff;
295: updscreen(vtcount);
296: }
297: (*hw)->found++;
298: vtcount++;
299: }
300: }
301:
302: /*
303: * initialize vtconsole
304: */
305: vtconsole = vtdata[vtactive = 0];
306: vtconsole->vmm_invis = 0; /* vtconsole cursor visible */
307:
308: /*
309: * Seize keyboard interrupt.
310: */
311: #ifdef _I386
312: setivec(ISVEC, isrint);
313: #else
314: #if VT_MAJOR == KB_MAJOR
315: setivec(1, isrint);
316: #else
317: /*
318: * Map table and vector to us
319: */
320: i = sphi();
321: PRINTV( "VTload: unload old vector\n" );
322: kcall( Kclrivec, 1 );
323: setivec(1, isrint);
324: spl( i );
325: #endif
326: #endif /* _I386 */
327:
328: /*
329: * Enable mmwatch() invocation every second.
330: */
331: drvl[VT_MAJOR].d_time = 1;
332:
333: /*
334: * Initialize video display.
335: */
336: for ( i = 0; i < vtcount; ++i )
337: mmstart( vttty[i] );
338:
339:
340: #ifndef _I386
341: /*
342: * Allocate a segment to store the in-core keyboard table.
343: * This would be a lot more convenient in kernel data space,
344: * but small model COHERENT doesn't have that luxury.
345: */
346: kbsegp = salloc((fsize_t)MAX_TABLE_SIZE, SFSYST|SFNSWP|SFHIGH);
347: if (kbsegp == (SEG *)0)
348: printf("kb: unable to allocate keyboard table segment\n");
349: KBDEBUG("Exiting kbload()\n");
350: #endif
351: fklength = 0;
352: }
353:
354: /*
355: * Unload entry point.
356: */
357: isuload()
358: {
359: register int i;
360: register level = sphi();
361:
362: clrivec(ISVEC);
363: #ifndef _I386
364: #if VT_MAJOR != KB_MAJOR
365: kcall( Ksetivec, ISVEC, &Kisrint );
366: #endif
367: #endif
368: spl( level );
369:
370: /* Restore pointers to original state. */
371: vtconsole = vtdata[0];
372: vtconsole->vmm_invis = 0;
373: vtconsole->vmm_visible = VNKB_TRUE;
374:
375: if( vt_opened )
376: printf( "VTclose with %d open screens\n", vt_opened );
377: if( kbstate != KB_IDLE )
378: printf("kb: keyboard busy during unload\n");
379: #ifndef _I386
380: if (kbsegp != (SEG *)0) {
381: table_loaded = 0;
382: sfree(kbsegp);
383: }
384: #endif
385:
386: #ifndef _I386
387: for( i = 0; i < vtcount; ++i ) {
388: PRINTV( "VTuload: free far %x:%x, tty %x\n",
389: vttty[i]->t_buffer->s_faddr, vttty[i] );
390: sfree( vttty[i]->t_buffer );
391: kfree( vttty[i] );
392: sfree( vtdata[i].vt_buffer );
393: }
394: #endif
395: }
396:
397: /*
398: * Open routine.
399: */
400: isopen(dev, mode)
401: dev_t dev;
402: unsigned int mode;
403: {
404: register int s;
405: register TTY *tp;
406: int index = vtindex(dev);
407:
408: PRINTV("isopen: %x\n", dev);
409: if (index < 0 || index >= vtcount) {
410: u.u_error = ENXIO;
411: return;
412: }
413:
414: tp = vttty[index];
415: if ((tp->t_flags&T_EXCL) != 0 && !super()) {
416: u.u_error = ENODEV;
417: return;
418: }
419: ttsetgrp(tp, dev, mode);
420:
421: s = sphi();
422: if (tp->t_open++ == 0) {
423: tp->t_flags = T_CARR; /* indicate "carrier" */
424: ttopen(tp);
425: }
426: spl(s);
427: #if 0
428: updleds(); /* update keyboard status LEDS */
429: #endif
430: }
431:
432:
433: void isvtswitch();
434:
435: /*
436: * Close a tty.
437: */
438: isclose(dev)
439: {
440: register int s;
441: int index = vtindex(dev);
442: register TTY *tp = vttty[index];
443:
444: #if 0
445: s = sphi();
446: if (--tp->t_open == 0) {
447: ttclose(tp);
448: spl(s);
449: if( index == vtactive )
450: isvtswitch( VTKEY_HOME );
451: } else
452: spl(s);
453: #else
454: if (--tp->t_open == 0)
455: ttclose(tp);
456: #endif
457: }
458:
459: /*
460: * Read routine.
461: */
462: isread(dev, iop)
463: dev_t dev;
464: IO *iop;
465: {
466: int index = vtindex(dev);
467: register TTY *tp = vttty[index];
468:
469: ttread(tp, iop, 0);
470: if (tp->t_oq.cq_cc)
471: mmtime(tp);
472: }
473:
474: /*
475: * Ioctl routine.
476: * nb: archaic TIOCSHIFT and TIOCCSHIFT no longer needed/supported.
477: */
478: #ifdef _I386
479: isioctl0(dev, com, vec)
480: dev_t dev;
481: struct sgttyb *vec;
482: {
483: tioc286(dev, com, vec, isioctl);
484: }
485: #endif
486:
487: isioctl(dev, com, vec)
488: dev_t dev;
489: struct sgttyb *vec;
490: {
491: register int s;
492:
493: switch (com) {
494: case TIOCSETF:
495: case TIOCGETF:
496: isfunction(com, (char *)vec);
497: break;
498: case TIOCSETKBT:
499: issettable(vec);
500: break;
501: case TIOCGETKBT:
502: isgettable(vec);
503: break;
504: default: /* pass to TTY driver */
505: s = sphi();
506: ttioctl(vttty[vtindex(dev)], com, vec);
507: spl(s);
508: break;
509: }
510: }
511:
512: /*
513: * Set the in-core keyboard mapping table.
514: * The table is sorted by scan code prior to calling ioctl().
515: * All unused table entries (holes in the scan code map) have
516: * a zero for the k_key field.
517: * This makes key lookup at interrupt time fast by using the scan code
518: * as an index into the table.
519: */
520: issettable(vec)
521: char *vec;
522: {
523: register unsigned i;
524: register int s;
525: int timeout;
526: static KBTBL this_key; /* current key from kbd table */
527: unsigned int cmd_byte;
528: #ifndef _I386
529: register faddr_t faddr; /* address of keyboard table */
530: #endif
531:
532: PRINTV(" TIOCSETKBT");
533: kb_cmd2(K_SCANCODE_CMD, 3); /* select set 3 */
534: kb_cmd(K_ALL_TMB_CMD); /* default: TMB for all keys */
535: #ifndef _I386
536: faddr = kbsegp->s_faddr;
537: #endif
538: for (i = 0; i < MAX_KEYS; ++i) {
539: ukcopy(vec, &this_key, sizeof(this_key));
540: #ifdef _I386
541: kb[i] = this_key; /* store away */
542: #else
543: kfcopy(&this_key, faddr, sizeof(this_key));
544: faddr += sizeof(this_key);
545: #endif
546: vec += sizeof(this_key);
547: if (this_key.k_key != i && this_key.k_key != 0) {
548: printf("kb: incorrect or unsorted table entry %d\n", i);
549: #ifdef _I386
550: u.u_error = EINVAL;
551: #else
552: u.u_error = EBADFMT;
553: #endif
554: return;
555: }
556: if (this_key.k_key != i)
557: continue; /* no key */
558: switch (this_key.k_flags&TMODE) {
559: case T: /* typematic */
560: kb_cmd2(K_KEY_T_CMD, i);
561: break;
562: case M: /* make only */
563: kb_cmd2(K_KEY_M_CMD, i);
564: break;
565: case MB: /* make/break */
566: kb_cmd2(K_KEY_MB_CMD, i);
567: break;
568: case TMB: /* typematic make/break */
569: break; /* this is the default */
570: default:
571: printf("kb: bad key mode\n");
572: }
573: }
574: updleds();
575: kb_cmd2(K_SCANCODE_CMD, 3); /* select set 3 */
576: kb_cmd(K_ENABLE_CMD); /* start scanning */
577: /*
578: * The following code disables translation from the on-board
579: * keyboard/aux controller. Without disabling translation, the
580: * received scan codes still look like code set 1 codes even
581: * though we put the keyboard controller in scan code set 3.
582: * Yes, this is progress....
583: */
584: #if 0
585: while (inb(KBSTS_CMD) & STS_IBUF_FULL)
586: ;
587: outb(KBSTS_CMD, C_READ_CMD); /* read controller cmd byte */
588: while (!(inb(KBSTS_CMD) & STS_OBUF_FULL))
589: ;
590: cmd_byte = inb(KBDATA);
591: KBDEBUG2(" cmd_byte=%x", cmd_byte);
592: #endif
593: timeout = KBTIMEOUT;
594: s = sphi();
595: while ((inb(KBSTS_CMD) & STS_IBUF_FULL) && --timeout > 0)
596: ;
597: outb(KBSTS_CMD, C_WRITE_CMD); /* write controller cmd byte */
598: for (timeout = 50; --timeout > 0;)
599: ;
600: timeout = KBTIMEOUT;
601: while ((inb(KBSTS_CMD) & STS_IBUF_FULL) && --timeout > 0)
602: ;
603: outb(KBDATA, KBCMDBYTE); /* turn off translation */
604: timeout = KBTIMEOUT;
605: while ((inb(KBSTS_CMD) & STS_IBUF_FULL) && --timeout > 0)
606: ;
607: spl(s);
608: #if DEBUG || 1
609: kb_cmd2(K_SCANCODE_CMD, 0); /* query s.c. mode */
610: #endif
611: ++table_loaded;
612: PRINTV("... TIOCSETKBT\n");
613: }
614:
615: /*
616: * Get the in-core keyboard mapping table and pass it to the user.
617: */
618: isgettable(vec)
619: char *vec;
620: {
621: #ifdef _I386
622: KBDEBUG(" TIOCGETKBT");
623: kucopy(kb, vec, sizeof(kb));
624: #else
625: register unsigned i;
626: register faddr_t faddr; /* address of keyboard table */
627: static KBTBL this_key; /* current key from kbd table */
628:
629: KBDEBUG(" TIOCGETKBT");
630: faddr = kbsegp->s_faddr;
631: for (i = 0; i < MAX_KEYS; ++i) {
632: fkcopy(faddr, &this_key, sizeof(this_key));
633: kucopy(&this_key, vec, sizeof(this_key));
634: faddr += sizeof(this_key);
635: vec += sizeof(this_key);
636: }
637: #endif
638: }
639:
640:
641: /*
642: * Set and receive the function keys.
643: */
644: isfunction(c, v)
645: int c;
646: FNKEY *v;
647: {
648: register unsigned char *cp;
649: register unsigned i;
650: unsigned char numkeys = 0;
651:
652: if (c == TIOCGETF) {
653: KBDEBUG(" TIOCGETF");
654: if (!fk_loaded)
655: u.u_error = EINVAL;
656: else
657: kucopy(fnkeys, v, fklength); /* copy ours to user */
658: } else { /* TIOCSETF */
659: /*
660: * If we had a previous function key arena, free it up.
661: * Since we don't know how large the function key arena will
662: * be, we must size it in the user data space prior to
663: * (re)kalloc()'ing it. This is ugly, but a helluva lot better
664: * than the old driver which used a hard coded limit of 150!
665: */
666: KBDEBUG(" TIOCSETF");
667: fk_loaded = 0;
668: if (fnkeys != (FNKEY *)0)
669: kfree(fnkeys); /* free old arena */
670: if (funkeyp != NULL)
671: kfree(funkeyp); /* free old ptr array */
672: ukcopy(&v->k_nfkeys, &numkeys, sizeof(numkeys));
673: fklength = sizeof(FNKEY);
674: cp = v->k_fnval;
675: for (i = 0; i < numkeys; i++) {
676: do {
677: ++fklength;
678: } while (getubd(cp++) != DELIM);
679: }
680: fnkeys = (FNKEY *)kalloc(fklength);
681: funkeyp = (unsigned char **)kalloc(numkeys * sizeof(char *));
682: if (fnkeys == (FNKEY *)0 || funkeyp == NULL) {
683: if (fnkeys != (FNKEY *)0) {
684: kfree(fnkeys);
685: fnkeys = 0;
686: }
687: if (funkeyp != NULL) {
688: kfree(funkeyp);
689: funkeyp = 0;
690: }
691: u.u_error = ENOMEM;
692: return;
693: }
694: cp = fnkeys->k_fnval; /* point to Fn ... */
695: v = v->k_fnval; /* ... key arena */
696: for (i = 0; i < numkeys; i++) {
697: funkeyp[i] = cp; /* save pointer */
698: while ((*cp++ = getubd(v++)) != DELIM) /* copy key */
699: ;
700: }
701: fnkeys->k_nfkeys = numkeys;
702: fk_loaded = 1;
703: }
704: }
705:
706:
707: /*
708: * Poll routine.
709: */
710: ispoll(dev, ev, msec)
711: dev_t dev;
712: int ev;
713: int msec;
714: {
715: register TTY *tp = vttty[vtindex(dev)];
716:
717: return ttpoll(tp, ev, msec);
718: }
719:
720: /*
721: * Receive interrupt.
722: */
723: isrint()
724: {
725: register unsigned c;
726: register unsigned r;
727: static char keyup;
728:
729: /*
730: * Schedule raw input handler if not already active.
731: */
732: if (!isbusy) {
733: defer(isbatch, vttty[vtactive]);
734: isbusy = 1;
735: }
736:
737: /*
738: * Pull character from the data
739: * port. Pulse the KBFLAG in the control
740: * port to reset the data buffer.
741: */
742: r = inb(KBDATA) & 0xFF;
743: c = inb(KBCTRL);
744: outb(KBCTRL, c|KBFLAG);
745: outb(KBCTRL, c);
746:
747: /*
748: * check returned value from keyboard to see if it's a command
749: * or status back to us. If not, it we assume that it's a key code.
750: */
751: KBDEBUG2("\nintr(%x) ", r);
752: switch (r) {
753: case K_BREAK:
754: keyup = 1; /* key going up */
755: break;
756: case K_ECHO_R:
757: case K_BAT_OK:
758: break; /* very nice, but ignored */
759: case K_BAT_BAD:
760: printf("kb: keyboard BAT failed\n");
761: break;
762: case K_RESEND:
763: KBDEBUG("\nkb: request to resend command\n");
764: outb(KBDATA, prev_cmd);
765: break;
766: case K_OVERRUN_23:
767: printf("kb: keyboard buffer overrun\n");
768: break;
769: case K_ACK:
770: /*
771: * we received an ACKnowledgement from the keyboard.
772: * advance the state machine and continue.
773: */
774: KBDEBUG(" ACK ");
775: switch (kbstate) {
776: case KB_IDLE: /* shouldn't happen */
777: printf("vtnkb: ACK while idle ");
778: break;
779: case KB_SINGLE: /* done with 1-byte command */
780: case KB_DOUBLE_2: /* done w/ 2nd of 2-byte cmd */
781: kbstate = KB_IDLE;
782: wakeup(&kbstate);
783: break;
784: case KB_DOUBLE_1:
785: kbstate = KB_DOUBLE_2;
786: outb(KBDATA, cmd2);
787: break;
788: default:
789: printf("kb: bad kbstate %d\n", kbstate);
790: break;
791: }
792: break;
793: default:
794: process_key(r, keyup);
795: keyup = 0;
796: }
797: }
798:
799: /*
800: * Process a key given its scan code and direction.
801: *
802: * In this table driven version of the keyboard driver, we trade off the
803: * code complexity associated with all the black magic that used to be
804: * performed on a per-key basis with the increased memory requirements
805: * associated with the table driven approach.
806: */
807: process_key(key, up)
808: unsigned key;
809: int up;
810: {
811: register unsigned char *cp;
812: KBTBL key_vals; /* table values for this key */
813: unsigned val;
814: unsigned char flags;
815: register TTY *tp = vttty[vtactive];
816: VTDATA *vp = vtdata[vtactive];
817:
818: KBDEBUG3(" proc(%x %s)", key, (up ? "up" : "down"));
819: if (!table_loaded)
820: return; /* throw away key */
821: #ifdef _I386
822: key_vals = kb[key];
823: #else
824: fkcopy(kbsegp->s_faddr + (key * sizeof(KBTBL)),
825: &key_vals, sizeof(key_vals));
826: #endif
827: if (key_vals.k_key != key) /* empty entry */
828: return;
829: flags = key_vals.k_flags;
830:
831: if (flags & S) { /* some shift/lock key ? */
832: switch (key_vals.k_val[BASE]) {
833: case caps:
834: case num:
835: if (!up) {
836: shift ^= (1 << key_vals.k_val[BASE]);
837: updleds2();
838: }
839: break;
840: case scroll:
841: if (!up) {
842: shift ^= (1 << key_vals.k_val[BASE]);
843: updleds2();
844: if (!(tp->t_sgttyb.sg_flags&RAWIN)) {
845: if (tp->t_flags & T_STOP) {
846: isin(tp->t_tchars.t_startc);
847: } else {
848: isin(tp->t_tchars.t_stopc);
849: }
850: }
851: }
852: break;
853: default:
854: if (up)
855: shift &= ~(1 << key_vals.k_val[BASE]);
856: else
857: shift |= (1 << key_vals.k_val[BASE]);
858: break;
859: }
860: /*
861: * Calculate the shift index based upon the state of
862: * the shift and lock keys.
863: */
864: sh_index = BASE; /* default condition */
865: if (shift & (1 << altgr))
866: sh_index = ALT_GR;
867: else {
868: if (shift & ((1 << lalt)|(1 << ralt)))
869: sh_index |= ALT;
870: if (shift & ((1 << lctrl)|(1 << rctrl)))
871: sh_index |= CTRL;
872: if (shift & ((1 << lshift)|(1 << rshift)))
873: sh_index |= SHIFT;
874: }
875: T_CON(2, printf("shift=%x sh_index=%d\n", shift, sh_index));
876: return;
877: } /* if (flags & S) */
878:
879: /*
880: * If the key has no value in the current
881: * shift state, the key is just tossed away.
882: */
883: if (up || key_vals.k_val[sh_index] == none)
884: return;
885:
886: if (((flags & C) && (shift & (1 << caps)))
887: || ((flags & N) && (shift & (1 << num))))
888: val = key_vals.k_val[sh_index^SHIFT];
889: else
890: val = key_vals.k_val[sh_index];
891:
892: /*
893: * Check for function key or special key implemented as
894: * a function key (reboot == f0, tab and back-tab, etc).
895: */
896: if (flags & F) {
897: PRINTV( "<{F%d}>", val );
898: if (VTKEY(val)) {
899: T_CON(4,
900: printf( "<{F%d !!}>\b\b\b\b\b\b\b\b\b\b", val));
901: defer( isvtswitch, val );
902: return;
903: }
904: /* If the tty is not open, ignore it */
905: if( !tp->t_open )
906: return;
907: if (val == 0 && !up && KBBOOT)
908: boot();
909: if (!fk_loaded || val >= fnkeys->k_nfkeys)
910: return;
911: if ((cp = funkeyp[val]) == NULL) /* has a value? */
912: return;
913: while (*cp != DELIM)
914: isin(*cp++); /* queue up Fn key value */
915: return;
916: }
917:
918: /*
919: * Normal key processing.
920: */
921: /* If the tty is not open, ignore it */
922: if( tp->t_open )
923: isin(val); /* send the char */
924: }
925:
926: /**
927: *
928: * void
929: * ismmfunc(c) -- process keyboard related output escape sequences
930: * char c;
931: */
932: void
933: ismmfunc(c)
934: register int c;
935: {
936:
937: switch (c) {
938: case 't': /* Enter numlock */
939: shift |= (1 << num);
940: updleds(); /* update LED status */
941: break;
942: case 'u': /* Leave numlock */
943: shift &= ~(1 << num);
944: updleds(); /* update LED status */
945: break;
946: case '=': /* Enter alternate keypad -- ignored */
947: case '>': /* Exit alternate keypad -- ignored */
948: break;
949: case 'c': /* Reset terminal */
950: islock = 0;
951: break;
952: }
953: }
954:
955: /**
956: *
957: * void
958: * isin(c) -- append character to raw input silo
959: * char c;
960: */
961: static
962: isin(c)
963: register int c;
964: {
965: int cache_it = 1;
966: TTY * tp = vttty[vtactive];
967: void ttstart();
968:
969: /*
970: * If using software incoming flow control, process and
971: * discard t_stopc and t_startc.
972: */
973: if (!ISRIN) {
974: if (ISSTOP) {
975: if ((tp->t_flags&T_STOP) == 0)
976: tp->t_flags |= T_STOP;
977: cache_it = 0;
978: }
979: if (ISSTART) {
980: tp->t_flags &= ~T_STOP;
981: defer(ttstart, tp);
982: cache_it = 0;
983: }
984: }
985:
986: /*
987: * Cache received character.
988: */
989: if (cache_it) {
990: in_silo.si_buf[ in_silo.si_ix ] = c;
991:
992: if (++in_silo.si_ix >= sizeof(in_silo.si_buf))
993: in_silo.si_ix = 0;
994: }
995: }
996:
997: /**
998: *
999: * void
1000: * isbatch() -- raw input conversion routine
1001: *
1002: * Action: Enable the video display.
1003: * Canonize the raw input silo.
1004: *
1005: * Notes: isbatch() was scheduled as a deferred process by isrint().
1006: */
1007: static void
1008: isbatch(tp)
1009: register TTY * tp;
1010: {
1011: register int c;
1012: static int lastc;
1013: VTDATA *vp = tp->t_ddp;
1014:
1015: /*
1016: * Ensure video display is enabled.
1017: */
1018: if( vp->vmm_visible ) {
1019: mm_von(vp);
1020: }
1021: isbusy = 0;
1022:
1023: /*
1024: * Process all cached characters.
1025: */
1026: while (in_silo.si_ix != in_silo.si_ox) {
1027: /*
1028: * Get next cached char.
1029: */
1030: c = in_silo.si_buf[ in_silo.si_ox ];
1031:
1032: if (in_silo.si_ox >= sizeof(in_silo.si_buf) - 1)
1033: in_silo.si_ox = 0;
1034: else
1035: in_silo.si_ox++;
1036:
1037: if ((islock == 0) || ISINTR || ISQUIT) {
1038: ttin(tp, c);
1039: } else if ((c == 'b') && (lastc == '\033')) {
1040: islock = 0;
1041: ttin(tp, lastc);
1042: ttin(tp, c);
1043: } else if ((c == 'c') && (lastc == '\033')) {
1044: ttin(tp, lastc);
1045: ttin(tp, c);
1046: } else
1047: putchar('\007');
1048: lastc = c;
1049: }
1050: }
1051:
1052: /*
1053: * update the keyboard status LEDS.
1054: * we chose the shift/lock key positions so this would be easy.
1055: * this flavor of routine is called while processing a system call on
1056: * behalf of the user.
1057: */
1058: updleds()
1059: {
1060: kb_cmd2(K_LED_CMD, (shift >> 1) & 0x7);
1061: }
1062:
1063: /*
1064: * same as above, but callable from interrupt routines and other places
1065: * which cannot sleep() waiting for the state machine to go idle.
1066: */
1067: updleds2()
1068: {
1069: register timeout;
1070: register int s;
1071:
1072: timeout = KBTIMEOUT;
1073: s = sphi();
1074: while (--timeout > 0 && (inb(KBSTS_CMD) & STS_IBUF_FULL))
1075: ;
1076: kbstate = KB_DOUBLE_1;
1077: cmd2 = (shift >> 1) & 0x7;
1078: prev_cmd = K_LED_CMD;
1079: outb(KBDATA, K_LED_CMD);
1080: spl(s);
1081: }
1082:
1083: /*
1084: * unlock the scroll in case an interrupt character is received
1085: */
1086: kbunscroll()
1087: {
1088: shift &= ~(1 << scroll);
1089: updleds();
1090: }
1091:
1092: /*
1093: * ship a single byte command to the keyboard
1094: */
1095: kb_cmd(cmd)
1096: unsigned cmd;
1097: {
1098: register int timeout;
1099: register int s;
1100:
1101: s = sphi();
1102: KBDEBUG2(" kb_cmd(%x)", cmd);
1103: while (kbstate != KB_IDLE)
1104: v_sleep(&kbstate, CVTTIN, IVTTIN, SVTTIN, "kb a");
1105: kbstate = KB_SINGLE;
1106: timeout = KBTIMEOUT;
1107: while (--timeout > 0 && (inb(KBSTS_CMD) & STS_IBUF_FULL))
1108: ;
1109: if (!timeout)
1110: printf("kb: command timeout\n");
1111: else {
1112: outb(KBDATA, cmd);
1113: while (kbstate != KB_IDLE)
1114: v_sleep(&kbstate, CVTTIN, IVTTIN, SVTTIN, "kb b");
1115: }
1116: spl(s);
1117: }
1118:
1119: /*
1120: * ship a two byte command to the keyboard
1121: */
1122: kb_cmd2(cmd, arg)
1123: unsigned cmd, arg;
1124: {
1125: register int timeout;
1126: register int s;
1127:
1128: s = sphi();
1129: KBDEBUG3(" kb_cmd2(%x, %x)", cmd, arg);
1130: while (kbstate != KB_IDLE)
1131: v_sleep(&kbstate, CVTTIN, IVTTIN, SVTTIN, "kb c");
1132: kbstate = KB_DOUBLE_1;
1133: cmd2 = arg;
1134: prev_cmd = cmd;
1135: timeout = KBTIMEOUT;
1136: while (--timeout > 0 && (inb(KBSTS_CMD) & STS_IBUF_FULL))
1137: ;
1138: if (!timeout)
1139: printf("kb: command timeout\n");
1140: else {
1141: outb(KBDATA, cmd);
1142: while (kbstate != KB_IDLE)
1143: v_sleep(&kbstate, CVTTIN, IVTTIN, SVTTIN, "kb d");
1144: }
1145: spl(s);
1146: }
1147:
1148: /*
1149: ==============================================================================
1150: ==============================================================================
1151: */
1152:
1153: int
1154: VTttyinit(i)
1155: int i;
1156: {
1157: TTY *tp;
1158:
1159: /*
1160: * get pointer to TTY structure from kernal memory space
1161: */
1162: if( (tp = vttty[i] = (TTY *)kalloc(sizeof (TTY))) == NULL )
1163: return(0);
1164: PRINTV( " vttty[%d]: @%x, ", i, tp );
1165:
1166: #if FAR_TTY
1167: /*
1168: * get pointers to the buffers pointed to by the TTY structure
1169: * from user memory space
1170: */
1171: tp->t_buffer = salloc( (fsize_t)NCIB+2*SI_BUFSIZ, SFSYST|SFNSWP );
1172: tp->t_ib = 0;
1173: tp->t_rawin.si_buf = NCIB;
1174: tp->t_rawout.si_buf = NCIB+SI_BUFSIZ;
1175: #endif
1176: tp->t_param = NULL;
1177: tp->t_start = &mmstart;
1178:
1179: #ifndef _I386
1180: #if VT_MAJOR == KB_MAJOR
1181: tp->t_cs_sel = 0;
1182: #else
1183: tp->t_cs_sel = cs_sel();
1184: #endif
1185: #endif
1186: tp->t_ddp = vtdata[i];
1187: PRINTV( "data @%lx\n", tp->t_ddp );
1188: return(1);
1189: }
1190:
1191: vtdatainit(vp)
1192: VTDATA *vp;
1193: {
1194: #ifndef _I386
1195: VT_FARSEG vt_farseg;
1196: #endif
1197: /*
1198: * vtdata init - vmm part
1199: */
1200: vp->vmm_invis = -1; /* cursor invisible */
1201:
1202: #ifdef _I386
1203: vp->vt_buffer = kalloc( TEXTBLOCK );
1204: vp->vmm_seg = vp->vmm_mseg = ds_sel();
1205: vp->vmm_off = vp->vmm_moff = vp->vt_buffer;
1206: #else
1207: vp->vt_buffer = salloc ( (fsize_t)TEXTBLOCK, SFSYST|SFNSWP|SFHIGH );
1208: vp->vmm_seg = vp->vmm_mseg = FP_SEG( vp->vt_buffer->vt_faddr );
1209: vp->vmm_off = vp->vmm_moff = FP_OFF( vp->vt_buffer->vt_faddr );
1210: #endif
1211: PRINTV( "vt@%x init index %d,%d), seg %x, off %x\n",
1212: vp, vp->vt_ind, vp->vmm_mseg, vp->vmm_moff );
1213: /*
1214: * vtdata init - vnkb part
1215: */
1216: /* Make the first memory block active, if present */
1217: vp->vnkb_lastc = 0;
1218: vp->vnkb_fnkeys = 0;
1219: vp->vnkb_funkeyp = 0;
1220: vp->vnkb_fk_loaded = 0; /* no Fn keys yet */
1221: }
1222:
1223: /*
1224: * Given device number, return index for vtdata[], vttty[], etc.
1225: *
1226: * Major number must be VT_MAJOR for CPU to get here.
1227: *
1228: * Minor Number Index Value
1229: * ----- ------ ----- -----
1230: * 0000 0000 vtactive ... device (2,0) is the active screen
1231: * 0000 0001 0
1232: * 0000 0010 1
1233: * 0000 0011 2
1234: * ....
1235: * 0000 1111 14
1236: *
1237: * 0100 xxxx xxxx ... color devices only
1238: * 0101 xxxx xxxx - (# of color devices found) ... monochrome only
1239: *
1240: * Return value is in range 0 to vtcount-1 for valid minor numbers,
1241: * -1 for invalid minor numbers.
1242: */
1243: int
1244: vtindex( dev )
1245: dev_t dev;
1246: {
1247: register int ret = -1;
1248:
1249: if ( dev & VT_PHYSICAL ) {
1250: int hw = ( dev >> 4 ) & 3;
1251: int hw_index = dev & 0x0F;
1252:
1253: if( hw_index < vtHWtable[hw]->found )
1254: ret = vtHWtable[hw]->start + hw_index;
1255: } else {
1256: int lg_index = dev & 0x0F;
1257:
1258: if (lg_index == 0)
1259: ret = vtactive;
1260: if (lg_index > 0 && lg_index <= vtcount )
1261: ret = lg_index-1;
1262: }
1263: if (ret >= 0)
1264: ret %= vtcount;
1265: else
1266: PRINTV( "vtindex: (%x) %d. invalid !\n", dev, ret );
1267: return ret;
1268: }
1269:
1270: /*
1271: *
1272: * void
1273: * isvtswitch() -- deferred virtual terminal switch
1274: *
1275: * Action: - save current shift key status
1276: * - determine new active virtual terminal
1277: * - deactivate shift key status of the current virtual terminal
1278: * - deactivate current virtual terminal
1279: * - activate shift key status of the new virtual terminal with
1280: * the previously saved shift key status
1281: * - activate new virtual terminal
1282: *
1283: * Notes: isvtswitch() was scheduled as a deferred process by
1284: * process_key() which is a function called by isrint().
1285: */
1286: void
1287: isvtswitch(key_val)
1288: {
1289: register int new_index, i;
1290: unsigned lockshift, nolockshift;
1291: VTDATA *vp = vtdata[vtactive];
1292: VTDATA *vp_old, *vp_new;
1293: static int vtprevious;
1294:
1295: T_CON(2, printf("old shift=%x sh_index=%d\n", shift, sh_index));
1296: lockshift = shift & ((1<<scroll)|(1<<num)|(1<<caps));
1297: nolockshift = shift & ~((1<<scroll)|(1<<num)|(1<<caps));
1298:
1299: PRINTV( "F%d: %d", key_val, vtactive );
1300: #if 0
1301: if( key_val == VTKEY_HOME )
1302: new_index = 0;
1303: else if( key_val == VTKEY_NEXT ) {
1304: new_index = vtactive;
1305: for( i = 0; i < vtcount; ++i ) {
1306: new_index = ++new_index % vtcount;
1307: if( vttty[new_index]->t_open )
1308: break;
1309: }
1310: } else {
1311: new_index = vtindex(vtkey_to_dev(key_val));
1312: if( new_index < 0) {
1313: putchar( '\007' );
1314: return;
1315: }
1316: }
1317: #else
1318: switch (key_val) {
1319: case VTKEY_HOME:
1320: new_index = 0;
1321: break;
1322: case VTKEY_NEXT:
1323: new_index = vtactive;
1324: for( i = 0; i < vtcount; ++i ) {
1325: new_index = ++new_index % vtcount;
1326: if( vttty[new_index]->t_open )
1327: break;
1328: }
1329: break;
1330: case VTKEY_PREV:
1331: new_index = vtactive;
1332: for( i = 0; i < vtcount; ++i ) {
1333: new_index = (--new_index+vtcount) % vtcount;
1334: if( vttty[new_index]->t_open )
1335: break;
1336: }
1337: break;
1338: case VTKEY_TOGL:
1339: new_index = vtprevious;
1340: break;
1341: default:
1342: new_index = vtindex(vtkey_to_dev(key_val));
1343: if( new_index < 0) {
1344: putchar( '\007' );
1345: return;
1346: }
1347: }
1348: #endif
1349: T_CON(8, printf("%d->%d ", vtactive, new_index));
1350: if( new_index == vtactive )
1351: return;
1352:
1353: /* Save which locking shift states are in effect. */
1354:
1355: vp_old = vtdata[vtactive];
1356: vp_new = vtdata[new_index];
1357:
1358: vp_old->vnkb_shift = lockshift;
1359: vtdeactivate(vp_new, vp_old); /* deactivate old virtual terminal */
1360:
1361: /* Restore shift lock state, append current momentary shift state. */
1362: shift = vp_new->vnkb_shift | nolockshift;
1363: T_CON(2, printf("new shift=%x sh_index=%d\n", shift, sh_index));
1364: vtactivate(vp_new); /* activate new virtual terminal */
1365: updterminal(new_index);
1366: vtprevious = vtactive;
1367: vtactive = new_index; /* update vtactive */
1368: }
1369:
1370: vtdeactivate(vp_new, vp_old)
1371: register VTDATA *vp_new, *vp_old;
1372: {
1373: register i;
1374: VTDATA *vpi;
1375:
1376: /* store old screen contents in memory segment */
1377: FFCOPY( vp_old->vmm_voff, vp_old->vmm_vseg,
1378: vp_old->vmm_moff, vp_old->vmm_mseg, TEXTBLOCK );
1379:
1380: /*
1381: * if changing to another screen on same video board
1382: * for all screens on same board as new screen
1383: * deactivate, but don't update
1384: * else - changing to a screen on different board
1385: * for all screens NOT on same board as new screen
1386: * deactivate, but don't update
1387: */
1388: if ( vp_old->vmm_port == vp_new->vmm_port ) {
1389: T_CON(8, printf("deactivate on %x ", vp_new->vmm_port));
1390: for (i = 0; i < vtcount; ++i) {
1391: vpi = vtdata[i];
1392: if ( vpi->vmm_port == vp_new->vmm_port ) {
1393: /* deactivate, but don't update */
1394: vpi->vmm_invis = ~0;
1395: vpi->vmm_visible = VNKB_FALSE;
1396: vpi->vmm_seg = vpi->vmm_mseg;
1397: vpi->vmm_off = vpi->vmm_moff;
1398: if( vpi->vmm_seg == 0 )
1399: printf( "[1]vpi->vmm_seg = 0\n" );
1400: PRINTV( "vt.back %d. seg %x off %x\n", i,
1401: vpi->vmm_seg, vpi->vmm_off );
1402: }
1403: }
1404: } else {
1405: T_CON(8, printf("deactivate %x->%x ",
1406: vp_old->vmm_port, vp_new->vmm_port));
1407: for (i = 0; i < vtcount; ++i) {
1408: vpi = vtdata[i];
1409: if ( (vpi->vmm_port != vp_new->vmm_port)
1410: && (vpi->vmm_invis == 0) ) {
1411: /* update, but don't deactivate */
1412: vpi->vmm_invis = ~0;
1413: updscreen(i);
1414: }
1415: }
1416: }
1417: }
1418:
1419: vtactivate(vp)
1420: VTDATA *vp;
1421: {
1422: register VTDATA *vpi;
1423: register i;
1424:
1425: /*
1426: * copy from screen contents from heap segment to video memory
1427: * only if necessary
1428: */
1429: if ( vp->vmm_visible == VNKB_FALSE )
1430: FFCOPY( vp->vmm_moff, vp->vmm_mseg,
1431: vp->vmm_voff, vp->vmm_vseg, TEXTBLOCK );
1432:
1433: for (i = 0; i < vtcount; ++i) {
1434: vpi = vtdata[i];
1435: if (vpi->vmm_port == vp->vmm_port) {
1436: vpi->vmm_invis = -1;
1437: vpi->vmm_visible = VNKB_FALSE;
1438: vpi->vmm_seg = vpi->vmm_mseg;
1439: vpi->vmm_off = vpi->vmm_moff;
1440: if( vpi->vmm_seg == 0 )
1441: printf( "[2]vpi->vmm_seg = 0\n" );
1442: PRINTV( "vt.back seg %x off %x\n",
1443: vpi->vmm_seg, vpi->vmm_off );
1444: }
1445: }
1446: /*
1447: * Set new active terminal
1448: */
1449: vp->vmm_invis = 0;
1450: vp->vmm_visible = VNKB_TRUE;
1451: vp->vmm_seg = vp->vmm_vseg;
1452: vp->vmm_off = vp->vmm_voff;
1453: if( vp->vmm_seg == 0 )
1454: printf( "vp->vmm_seg = 0\n" );
1455: }
1456:
1457: /*
1458: * update the terminal to match vtactive
1459: */
1460: updterminal(index)
1461: int index;
1462: {
1463: updscreen(index);
1464: updleds2();
1465: }
1466:
1467: #undef si
1468: asmdump( cs, ds, es, di, si, bp, sp, bx, dx, cx, i, ip, ax )
1469: int cs, ds, es, di, si, bp, sp, bx, dx, cx, i, ip, ax;
1470: {
1471: if( vt_verbose < 2 )
1472: return;
1473:
1474: printf( "asmdump %d: es %x, ds %x, cs:ip %x:%x\n", i, es, ds, cs, ip );
1475: printf( " ax %x, bx %x, cx %x, dx %x\n", ax, bx, cx, dx );
1476: printf( " di %x, si %x, bp %x, sp %d\n", di, si, bp, sp );
1477: #if USING_RS232
1478: if( vt_verbose > 2 )
1479: getchar();
1480: #endif
1481: }
1482:
1483: vtdataprint( vp )
1484: register VTDATA *vp;
1485: {
1486: if( vt_verbose < 2 )
1487: return;
1488:
1489: printf( "VTDATA: @%x, esc %x, func %x()\n",
1490: vp, vp->vmm_esc, vp->vmm_func );
1491: printf( " hw: port %x, seg %x, off %x\n",
1492: vp->vmm_port, vp->vmm_vseg, vp->vmm_voff );
1493: printf( " memory: size %x, seg %x, off %x\n",
1494: 0/*vp->vmm_size*/, vp->vmm_mseg, vp->vmm_moff );
1495: printf( " cursor: seg %x, off %x, visible %d\n",
1496: vp->vmm_seg, vp->vmm_off, !vp->vmm_invis );
1497: printf( " row %d, col %d = offset %d.\n",
1498: vp->vmm_rowl, vp->vmm_col, vp->vmm_pos );
1499: printf( " saved row %d, col %d\n",
1500: vp->vmm_srow, vp->vmm_scol );
1501: printf( " screen: visible %d, attr %x, wrap %d, slow %d\n",
1502: vp->vmm_visible, vp->vmm_attr, vp->vmm_wrap, vp->vmm_slow );
1503: printf( " row base %d, end %d, limit %d\n",
1504: vp->vmm_brow, vp->vmm_erow, vp->vmm_lrow );
1505: printf( " row initial base %d, initial end %d\n",
1506: vp->vmm_ibrow, vp->vmm_ierow );
1507: #if USING_RS232
1508: if( vt_verbose > 2 )
1509: getchar();
1510: #endif
1511: }
1512:
1513: FFCOPY( src_off, src_seg, dst_off, dst_seg, count )
1514: {
1515: register i;
1516:
1517: #if 0
1518: i = ffcopy( src_off, src_seg, dst_off, dst_seg, count );
1519: #else
1520: for( i = 0; i < count; i += 2 ) {
1521: register word = ffword( src_off, src_seg );
1522: sfword( dst_off, dst_seg, word );
1523: src_off += 2;
1524: dst_off += 2;
1525: }
1526: #endif
1527: return i;
1528: }
1529:
1530: /*
1531: * Given a function key number (e.g. vt0),
1532: * return the corresponding minor device number.
1533: *
1534: * Assume valid key number (VTKEY(fnum) is true) by the time we get here.
1535: */
1536: int
1537: vtkey_to_dev(fnum)
1538: int fnum;
1539: {
1540: if (fnum >=vt0 && fnum <= vt15)
1541: return fnum-vt0+1;
1542: if (fnum >=color0 && fnum <= color15)
1543: return (fnum-color0)|(VT_PHYSICAL|VT_HW_COLOR);
1544: if (fnum >=mono0 && fnum <= mono15)
1545: return (fnum-mono0)|(VT_PHYSICAL|VT_HW_MONO);
1546: printf("vtkey_to_dev(%d)! ", fnum);
1547: return 0;
1548: }
1549: /* End of nkb.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.