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