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