|
|
1.1 root 1: /*-----------------------------------------------------------------------------
2: Talking BIOS device driver for the AT&T PC6300.
3: Copyright (C) Karl Dahlke 1987
4: This software may be freely used and distributed
5: for any non-profit purpose.
6: *-----------------------------------------------------------------------------
7: */
8:
9: /* interfac.c: interface function to kernel and device drivers */
10:
11: /* This file contains routines to speak letters, words, single lines,
12: * and the entire screen/buffer.
13: * These routines are called at interrupt level, but they may take
14: * as long as they wish. A frozen view of pointers is presented,
15: * and I know of no way they can change while these routines are executing
16: * (though there may be an obscure scenario).
17: * A separate stack of around 200 bytes is provided,
18: * but there's no stack checking, so be careful.
19: * Also, this stack is not aligned with the data segment,
20: * so don't use the address of any auto variable.
21: */
22:
23: #ifndef MSDOS
24: #include <sgtty.h>
25: #else
26: /* taken from Coherent sgtty.h */
27: #define TIOCSDSIZE 0140
28: #define TIOCSDGETBUF 0141
29: #endif
30:
31: #include "speech.h"
32:
33: /* control variables for each of 5 concurrent sessions: console + 4 comports */
34: struct SDCONTROL *sdcontrol[5];
35: struct SDCONTROL *sdc; /* set to sdcontrol[sdsession] */
36: int sdsession; /* current session, 0 for the console, 1-4 for the comports */
37: char sdw[WORDLEN*2]; /* word to be spoken */
38:
39: /* patchable variables that establish synthesizer, comport,
40: * and size of internal circular buffer, for each of 5 possible sessions.
41: * The 5 configured synthesizers */
42: int sd0synth = 0, sd1synth = 0, sd2synth = 0, sd3synth = 0, sd4synth = 0;
43: int sd0comport = 0, sd1comport = 0, sd2comport = 0, sd3comport = 0, sd4comport = 0;
44: unsigned int sd0cbufsz = 0, sd1cbufsz = 0, sd2cbufsz = 0, sd3cbufsz = 0, sd4cbufsz = 0;
45:
46: #ifdef MSDOS
47: static char far *doslineptr;
48: skipwhite()
49: {
50: char c;
51: c = *doslineptr;
52: while(c == ' ' || c == '\t') c = *++doslineptr;
53: } /* skipwhite */
54:
55: /* a version of strtol, to help crack the dos parameters */
56: static unsigned int nextparm()
57: {
58: unsigned int n = 0;
59: char c;
60:
61: skipwhite();
62: c = *doslineptr;
63:
64: while(isdigit(c)) {
65: n = 10*n + c - '0';
66: c = *++doslineptr;
67: } /* n is built */
68:
69: return n;
70: } /* nextparm */
71:
72: /* interpret line in config.sys, DOS only.
73: * Coherent just patches the global variables to set parameters. */
74: dosline(line)
75: char far *line;
76: {
77: char c;
78:
79: /* skip past command name and set doslineptr */
80: c = *line;
81: while(c != ' ' && c != '\t' && c != '\r')
82: c = *++line;
83: doslineptr = line;
84:
85: sd0cbufsz = nextparm();
86: sd0comport = nextparm();
87: sd0synth = nextparm();
88:
89: skipwhite();
90: c = *doslineptr;
91: if(c != '\r') /* error message about command line format */;
92: } /* dosline */
93: #endif
94:
95: /* interface function, called from isload() */
96: sdload()
97: {
98: char *bufstart;
99: int i;
100: unsigned int reqsz;
101: struct SDCONTROL *o;
102: extern isin();
103: static char defkeymap[] = {
104: 12,13,14,15,16,
105: 17,18,23,22,28};
106: static char defpuncmap[] = "\
107: null~~~~~~\
108: escape~~~~\
109: askie 1c~~\
110: askie 1d~~\
111: askie 1e~~\
112: askie 1f~~\
113: space~~~~~\
114: bang~~~~~~\
115: quoat~~~~~\
116: pound~~~~~\
117: doller~~~~\
118: percent~~~\
119: and~~~~~~~\
120: single~~~~\
121: left paren\
122: rite paren\
123: star~~~~~~\
124: plus~~~~~~\
125: comma~~~~~\
126: mighnus~~~\
127: periud~~~~\
128: slash~~~~~\
129: colen~~~~~\
130: semmy~~~~~\
131: less~~~~~~\
132: eequal~~~~\
133: greater~~~\
134: question~~\
135: at sign~~~\
136: left b~~~~\
137: backslash~\
138: rite b~~~~\
139: up airow~~\
140: underline~\
141: backquoat~\
142: left brace\
143: vertical~~\
144: rite brace\
145: tillda~~~~\
146: deleet~~~~\
147: ";
148:
149: /* allocate word replacement and macro definition areas */
150: sdtblload();
151:
152: /* find and establish screen memory */
153: sdscrnset();
154:
155: for(i=0; i<5; ++i) {
156: sdsynth_init(i);
157: if(!(o = sdcontrol[i])) continue; /* kalloc failed */
158:
159: /* I/O functions. */
160: o->dev_in = isin;
161:
162: /* initialize the punctuation pronunciation table */
163: memcpy(o->punctab, defpuncmap, 40*10);
164:
165: /* initialize the key mappings */
166: memcpy(o->keymap+0x3b, defkeymap, 10);
167:
168: /* circular buffer */
169: reqsz = (&sd0cbufsz)[i];
170: if(reqsz < 400) reqsz = 400;
171: if(!(bufstart = kalloc(reqsz))) {
172: reqsz = sizeof(o->defcbuf);
173: bufstart = o->defcbuf;
174: }
175: o->bufbot =
176: o->bufhead =
177: o->buftail =
178: o->bufcur =
179: bufstart;
180: o->buftop = bufstart + reqsz;
181:
182: /* modes that are set */
183: o->dev_ok = 1;
184: o->buf_ok = 1;
185: } /* end loop initializing structures */
186:
187: /* startup sound.
188: * More than just cute, we need to do this, or something like it,
189: * to enable the speaker, so that subsequen noises,
190: * produce by system output, before going multiuser,
191: * generates audio feedback. */
192: sdsound(8);
193: } /* sdload */
194:
195: #ifndef MSDOS
196: /* interface function, called from isuload() */
197: sduload()
198: {
199: int i;
200: struct SDCONTROL *o;
201: int comport;
202: extern char *sdscreenmem;
203:
204: for(i=0; i<5; ++i) {
205: if(!(o = sdcontrol[i])) continue;
206:
207: comport = (&sd0comport)[i];
208: if(comport)
209: clrivec((comport&1)+3);
210:
211: if(o->bufbot != o->defcbuf)
212: kfree(o->bufbot);
213: kfree(o);
214: sdcontrol[i] = 0;
215: } /* end loop over sessions */
216:
217: unmap_pv(sdscreenmem);
218: } /* sduload */
219: #endif
220:
221: /* ioctl call, only used to save the buffer to a file */
222: #ifdef MSDOS
223: sdioctl(session, v)
224: char far * far *v;
225: {
226: struct SDCONTROL *o = sdcontrol[session];
227: extern char far *sdscreenmem;
228:
229: if(!o) return -1;
230:
231: if(!session && sdscreenmode) {
232: v[0] = sdscreenmem;
233: v[1] = 0; /* indicate scren mode */
234: } else {
235: v[0] = (char far *)o->bufbot;
236: v[1] = (char far *)o->buftop;
237: v[2] = (char far *)o->buftail;
238: v[3] = (char far *)o->bufhead;
239: }
240:
241: return 0;
242: } /* sdioctl */
243: #else
244: sdioctl(session, cmd, v)
245: char *v;
246: {
247: struct SDCONTROL *o = sdcontrol[session];
248: char *cp;
249: int i, j;
250: extern char *sdscreenmem;
251:
252: if(!o) return -1;
253:
254: switch(cmd) {
255: case TIOCSDSIZE: /* get size of buffer */
256: if(!session && sdscreenmode)
257: putuwd(v, (80+1)*25 + 1);
258: else
259: putuwd(v, (&sd0cbufsz)[session]);
260: break;
261:
262: case TIOCSDGETBUF: /* get text buffer */
263: if(!session && sdscreenmode) {
264: cp = sdscreenmem;
265: for(i=0; i<25; ++i) {
266: for(j=0; j<80; ++j) {
267: putubd(v++, *cp);
268: cp += 2;
269: }
270: putubd(v++, '\r');
271: }
272: } else {
273: cp = o->buftail;
274: while(cp != o->bufhead) {
275: putubd(v, *cp);
276: ++v;
277: if(++cp == o->buftop)
278: cp = o->bufbot;
279: } /* end copying buffer */
280: }
281: /* end of text indicator, sign bit never makes it into the text buffer */
282: putubd(v, -1);
283: break;
284:
285: default:
286: return -1;
287: } /* end switch on command */
288:
289: return 0;
290: } /* sdioctl */
291: #endif
292:
293: /* interface function, executed every 0.01 or 0.055 seconds */
294: sdtime()
295: {
296: int session, c;
297: struct SDCONTROL *o;
298: short istate;
299:
300: chkfifo();
301:
302: for(session=0; session<5; ++session) {
303: o = sdcontrol[session];
304: if(!o || o->xparent) continue;
305:
306: if(o->talkcmd) {
307: if(!keycmd_start(session)) continue;
308: istate = sphi();
309: c = o->talkcmd;
310: o->talkcmd = o->talkcmd2;
311: o->talkcmd2 = 0;
312: spl(istate);
313: keycmd( 128 | c);
314: keycmd_end();
315: } /* o->talkcmd set */
316:
317: if(o->rdflag | o->onesymb) {
318: if(keycmd_start(session)) {
319: reading();
320: keycmd_end();
321: }
322: }
323: } /* end loop over 5 sessions */
324: } /* sdtime */
325:
326: /* before a byte is written to the screen,
327: * place it in the internal circular buffer.
328: * runs with interrupts off. */
329: static bufstore(o, c)
330: struct SDCONTROL *o;
331: char c;
332: {
333: char *bufbot = o->bufbot, *buftop = o->buftop,
334: *bufhead = o->bufhead, *buftail = o->buftail,
335: *bufcur = o->bufcur;
336: char *t;
337:
338: if(!o->ctrl_ok && c != 7 && c != '\r') {
339: /* control h removes the last byte in the buffer */
340: if(c == 8 && bufhead != buftail) {
341: if((t = bufhead) == bufbot) t = buftop;
342: if(*--t != '\r') {
343: /* ok to back up */
344: bufhead = t;
345: if(t == bufcur && t != buftail) {
346: if(t == bufbot) t = buftop;
347: bufcur = --t;
348: }
349: }
350: } /* backing up for control-h */
351:
352: if(c < ' ') goto done;
353: } /* control charactercheck */
354:
355: t = bufhead;
356: *t = c;
357: if(++t == buftop) t = bufbot;
358: bufhead = t;
359: if(t == buftail) { /* buffer full */
360: /* drop oldest character */
361: if(++t == buftop) t = bufbot;
362: if(buftail == bufcur) bufcur = t;
363: buftail = t;
364: } /* full buffer */
365:
366: done: /* copy pointers */
367: o->bufcur = bufcur;
368: o->bufhead = bufhead;
369: o->buftail = buftail;
370: } /* bufstore */
371:
372: /* interface routine, called from mmgo1() or ih_bsc() */
373: /* bits returned mean:
374: * 0: display character on device
375: * 1: display an escape before displaying the character
376: * 2: need to take a 10ms real time break before processing this character.
377: * 3: musical output, take a longer real time break. */
378: int sdoutchar(session, c)
379: char c;
380: {
381: struct SDCONTROL *o = sdcontrol[session];
382: short istate;
383: int rc = 0;
384:
385: if(!o) return 1; /* not active */
386:
387: c &= 0x7f;
388:
389: if(!o->xparent) {
390: /* check for esc{x sequences */
391: if(o->esc_lc) {
392: o->esc_lc = 0;
393: c-='@';
394: if(c > 0 && c < N_CMDS)
395: multikey(session, 0, 0, c);
396: return 0;
397: }
398:
399: if(o->esc) {
400: o->esc = 0;
401: if(c == '{') {
402: o->esc_lc = 1;
403: return 0;
404: } else rc = 2;
405: } else {
406: if(multikey(session, 0, c, 0))
407: return 0;
408: }
409:
410: if(c == '\033') {
411: o->esc = 1;
412: if(!rc) return 0;
413: rc = 0;
414: }
415: } /* end transparent mode check */
416:
417: if(o->buf_ok) {
418: /* Coherent could run bufstore() with interrupts on, but MSDOS cannot.
419: * This is because a sdtime() reading function could take place
420: * during a real time interrupt, while the head/tail buffer
421: * pointers are being modified. */
422: #ifdef MSDOS
423: istate = sphi();
424: #endif
425: if(rc) bufstore(o, '\033');
426: bufstore(o, c);
427: #ifdef MSDOS
428: spl(istate);
429: #endif
430: }
431:
432: if(o->xparent) return 1;
433:
434: if(o->dev_ok) rc |= 1;
435: else rc = 0;
436:
437: if(!session) {
438: /* make sound accompanying output byte */
439: if(sdnoises|sdtones)
440: rc |= sdcharsnd(c);
441: if(c == 7) rc &= 0xe;
442: }
443:
444: return rc;
445: } /* sdoutchar */
446:
447: /* entered character, via keyboard or terminal.
448: * do not call this if the session is null, because
449: * this routine is suppose to call the lower level keyboard input routine.
450: * Note the difference between input and output.
451: * In output, we return 1 and let the calling
452: * routine display the character by calling its own device driver routines.
453: * But on input, we might want to expand a macro, sending a string of
454: * accumulated characters to the input queue.
455: * So we set o->dev_in to the appropriate device driver input
456: * routine, and invoke it as needed. */
457: sdinkey(session, key)
458: {
459: struct SDCONTROL *o = sdcontrol[session];
460: int rc;
461: int cmd, xcmd;
462:
463: /* hardcoded transparent mode toggle, cannot be reassigned */
464: if(key == 0x8300) {
465: o->xparent ^= 1;
466: if(!session) sdsound(o->xparent+5);
467: return;
468: }
469:
470: xcmd = cmd = transkey(key);
471: if(cmd) cmd = o->keymap[cmd];
472:
473: if(rc = multikey(session, 1, key, cmd)) {
474: if(!session) sdsound(rc);
475: } else {
476: mexpand(session, key, xcmd);
477: }
478: } /* sdinkey */
479:
480: #ifndef MSDOS
481: /* The prexisting system was written for Dos, with Dos key conventions in place.
482: * In order to use the same software, I convert the Coherent representation
483: * of key codes into Dos representation. My appologies to you purists.
484: * Thus function and alt keys become 0 followed by the scan code.
485: * Coherent doesn't allow for shift-fkey or ctrl-fkey, but the Dos
486: * driver lets you map speech to these keys. Coherent must therefore pass the
487: * shift state in, so that we can check for shift-F3 etc. */
488: sdinkey_coh(c, scan, shift)
489: {
490: int key;
491: static char numpad[] = "789x456x1230.";
492: char numlock;
493:
494: key = c;
495:
496: /* check for Coherent special code or alt key, indicated by the sign bit */
497: if(c&0x80) {
498: if(scan >= 59 && scan <= 68) { /* function key */
499: /* adjust scan codes for shift or control or alt.
500: * Check with Coherent kb.c to make sure the bits in shift are correct. */
501: if(shift&8) scan += 0x2d;
502: else if(shift & 4) scan += 0x23;
503: else if(shift & 3) scan += 0x19;
504: } /* end fkey */
505:
506: /* MSDOS has a strange code for alt-= */
507: if(scan == 13) scan = 0x83;
508:
509: /* scan code now the same as Dos */
510: key = scan<<8;
511:
512: /* turn numlock-keypad back to a number */
513: if(scan >= 71 && scan <= 83) { /* on the keypad */
514: /* exactly one of numlock and shift should be set */
515: numlock = shift | (shift>>1);
516: numlock ^= (shift >> 5);
517: numlock &= ~(shift>>6);
518: if(numlock&1) key = numpad[scan-71];
519: } /* end keypad */
520: } /* end special code */
521:
522: /* call sdinkey if the session is active and not in transparent mode,
523: * or if this key would release an active session from transparent mode */
524: if(sdcontrol[0] &&
525: (!sdcontrol[0]->xparent || key == 0x8300)) {
526: sdinkey(0, key);
527: return 1;
528: }
529:
530: return 0; /* you handle it */
531: } /* sdinkey_coh */
532: #endif
533:
534: /* is this key part of a multikey sequence?
535: * Return nonzero iff this key is absorbed.
536: * This nonzero value also indicates the sound (e.g. error tone) that should be produced.
537: * A return value of 1 requires no sound. */
538: static multikey(session, input, key, cmd)
539: /* Are we processing input or output characters?
540: * If the characters represent input, entered from the keyboard,
541: * this routine is running at interrupt level.
542: * Output comes from the device driver, at process level. */
543: int input;
544: /* The character entered at the keyboard (input = 1)
545: * or produced by the running process (input = 0) and destined for the screen.
546: * For evolutionary reasons, we follow the DOS convention for
547: * representing special input characters. Thus F1 = 0x3b00. */
548: int key;
549: /* Instead of an output character, we may send a command directly,
550: * as when esc{A is translated into a speech command. */
551: char cmd;
552: {
553: struct SDCONTROL *o = sdcontrol[session];
554: struct MULTIKEY *a = input ? &o->indata : &o->outdata;
555: char lastcmd, c;
556: int i, rc;
557: struct SDCMD *cmdp;
558:
559: rc = 0;
560: if(!o->xparent) {
561: if(a->nextchar | a->nextline) {
562: cmd = 0;
563: rc = 1;
564: lastcmd = a->lastcmd;
565: a->nextchar = 0;
566: a->support = key;
567: c = key;
568: if(!c && lastcmd != 20 && lastcmd != 21)
569: return 3;
570:
571: if(a->nextline) {
572: if(c == '\33') { a->nextline = 0; return 2; }
573: /* input line becomes null-terminated string */
574: if(c == '\r' || c == '\n') c = 0;
575: i = a->textlen;
576: a->text[i] = c;
577: if(c) {
578: if(++i == LINELEN)
579: return 4;
580: a->textlen = i;
581: return 1;
582: } /* test for cr */
583: a->nextline = 0;
584: rc = 2;
585: } /* absorbing a line */
586: cmd = lastcmd; /* extra data gathered, ready for the command */
587: } /* end nextchar or nextline mode */
588: else if(cmd) {
589: /* comand supplied directly */
590: cmdp = &sdcmds[cmd];
591: rc = 1;
592: if(cmdp->nextkey | cmdp->nextline) {
593: a->nextchar = cmdp->nextkey;
594: if(a->nextline = cmdp->nextline) rc = 5;
595: a->lastcmd = cmd;
596: a->textlen = 0;
597: cmd = 0;
598: }
599: } /* a valid speech command */
600:
601: if(cmd) {
602: if(input) {
603: /* speech command from the keyboard */
604: /* interrupt level, defer command */
605: if(o->talkcmd) {
606: if(o->talkcmd2) o->talkcmd = o->talkcmd2;
607: o->talkcmd2 = cmd;
608: }
609: else o->talkcmd = cmd;
610: #ifndef MSDOS
611: mmhasten();
612: #endif
613: } else {
614: /* speech commands are executed immediately when they come via output characters */
615: while(!keycmd_start(session)) ;
616: keycmd(cmd);
617: keycmd_end();
618: } /* end input/output test */
619: } /* cmd to run */
620: } /* xparent test */
621:
622: return rc;
623: } /* multikey */
624:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.