|
|
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.