|
|
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: /* synth.c: interface functions to the speech synthesizer */ ! 10: ! 11: #include "speech.h" ! 12: ! 13: #ifdef MSDOS ! 14: /* taken from Coherent ins8250.h */ ! 15: #define DREG 0 /* Data Register (DLAB=0) */ ! 16: #define IER 1 /* Interrupt Enable Register (DLAB=0) */ ! 17: #define IIR 2 /* Interrupt Identification Register */ ! 18: #define FCR 2 /* FIFO Control Register */ ! 19: #define LCR 3 /* Line Control Register */ ! 20: #define MCR 4 /* Modem Control Register */ ! 21: #define LSR 5 /* Line Status Register */ ! 22: #define MSR 6 /* Modem Status Register */ ! 23: #define SCR 7 /* Scratch Register */ ! 24: #else ! 25: #include <sys/ins8250.h> ! 26: #endif ! 27: ! 28: #define LDLR 0 /* low divisor latch */ ! 29: #define HDLR 1 /* high divisor latch */ ! 30: ! 31: #ifdef MSDOS ! 32: static int AL_ADDR[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8}; ! 33: #else ! 34: extern int AL_ADDR[]; ! 35: extern int C1BAUD, C2BAUD, C3BAUD, C4BAUD, albaud[]; ! 36: #endif ! 37: ! 38: int sdoverride; /* override bad signals */ ! 39: ! 40: static int crticks, deadbuzz, inxmit; ! 41: static char *xmit_ptr; ! 42: static int i_comport; /* com port with the interrupt active */ ! 43: static short i_combase; /* AL_ADDR[i_comport-1]; */ ! 44: static struct SDCONTROL *i_sdc; ! 45: ! 46: /* replace ? in error message with session number, then print */ ! 47: static fix_ques(s, n) ! 48: char *s; ! 49: { ! 50: extern char *strchr(); ! 51: s = strchr(s,'?'); ! 52: if(s) *s = n+'0'; ! 53: printf(s); ! 54: } /* fix_ques */ ! 55: ! 56: /* init the synthesizer */ ! 57: sdsynth_init(session) ! 58: short session; ! 59: { ! 60: short istate; ! 61: int synth, comport; ! 62: int baud; ! 63: static char emsg1[] = "ERROR: patchable variable sd?synth is out of range"; ! 64: static char emsg2[] = "ERROR: patchable variable sd?comport is out of range"; ! 65: static char emsg3[] = "ERROR: synthesizer must run on a serial port, please patch sd?comport\n"; ! 66: static char emsg4[] = "ERROR: synthesizer cannot run on a serial port, please patch sd?comport to 0\n"; ! 67: static char emsg5[] = "ERROR: only one speech session can be activated, and it must run from the console\n"; ! 68: static char emsg6[] = "ERROR: cannot allocate structure for speech session ?\n"; ! 69: static char emsg7[] = "ERROR: speech session cannot use com?, no UART present\n"; ! 70: /* for each synthesizer, is it external or internal? */ ! 71: static char inout[] = {0, 2}; ! 72: extern int sdintr(); ! 73: ! 74: synth = (&sd0synth)[session]; ! 75: comport = (&sd0comport)[session]; ! 76: ! 77: if(synth < 0 || synth > 1) { ! 78: fix_ques(emsg1, session); ! 79: return; ! 80: } ! 81: ! 82: if(!synth) return; ! 83: ! 84: if(comport < 0 || comport > 4) { ! 85: fix_ques(emsg2, session); ! 86: return; ! 87: } ! 88: ! 89: if(comport && !(inout[synth]&2)) { ! 90: fix_ques(emsg3, session); ! 91: return; ! 92: } ! 93: ! 94: if(!comport && !(inout[synth]&1)) { ! 95: fix_ques(emsg4, session); ! 96: return; ! 97: } ! 98: ! 99: if(session || i_comport) { ! 100: fix_ques(emsg5, session); ! 101: return; ! 102: } ! 103: ! 104: sdcontrol[session] = i_sdc = (struct SDCONTROL *) kalloc(sizeof(struct SDCONTROL)); ! 105: if(!i_sdc) {; /* kalloc failed */ ! 106: fix_ques(emsg6, session); ! 107: return; ! 108: } ! 109: memset(i_sdc, 0, sizeof(struct SDCONTROL)); ! 110: ! 111: if(comport) { /* unit is on a serial port */ ! 112: i_comport = comport; ! 113: i_combase = AL_ADDR[comport-1]; ! 114: ! 115: /* set vector early, to handle any spurious interrupts */ ! 116: setivec((comport&1)+3, sdintr); ! 117: ! 118: #ifndef MSDOS ! 119: if(uart_sense(i_combase) == US_NONE) { ! 120: fix_ques(emsg7, comport); ! 121: fail: ! 122: kfree(i_sdc); ! 123: sdcontrol[session] = 0; ! 124: clrivec((comport&1)+3); ! 125: return; ! 126: } ! 127: printf(" monopolized by console speech session\n"); ! 128: #endif ! 129: ! 130: istate = sphi(); ! 131: /* initialize the UART */ ! 132: /* no transmit interrupt until we start sending text */ ! 133: outb(i_combase+IER, 0); ! 134: outb(i_combase+MCR, 0); ! 135: inb(i_combase+DREG); /* clear any input */ ! 136: inb(i_combase+LSR); ! 137: inb(i_combase+MSR); ! 138: /* set baud rate to 9600 baud */ ! 139: baud = getbaudrate(comport); ! 140: outb(i_combase+LCR, 0x80); ! 141: outb(i_combase+LDLR, baud); ! 142: outb(i_combase+HDLR, baud>>8); ! 143: outb(i_combase+LCR, 3); /* 8 bits, no parity */ ! 144: ! 145: /* set DTR and RTS */ ! 146: /* extra bit (8[4]) is needed to generate interrupts */ ! 147: outb(i_combase+MCR, 15 - ((comport&1) << 2)); ! 148: spl(istate); ! 149: ! 150: /* synthesizer specific initialization sequence here */ ! 151: return; ! 152: } /* on a serial port */ ! 153: ! 154: /* this code not reached */ ! 155: return; /* only serial connections implemented */ ! 156: } /* sdsynth_init */ ! 157: ! 158: /* synthesizer appears to be dead */ ! 159: static synth_dead() ! 160: { ! 161: if(!deadbuzz) sdsound(7); ! 162: deadbuzz = 1; ! 163: i_sdc->rdflag = i_sdc->onesymb = 0; ! 164: i_sdc->drain_lbolt = 0; ! 165: } /* synth_dead */ ! 166: ! 167: /* serial port interrupt handler, runs with interrupts off */ ! 168: sdintr() ! 169: { ! 170: char linestat, c; ! 171: short istate; ! 172: ! 173: istate = sphi(); ! 174: inb(i_combase+IIR); ! 175: linestat = inb(i_combase+LSR); ! 176: if(linestat & 0x20) { ! 177: ! 178: if(inxmit) { ! 179: /* if no data to send then reset tx interrupt and return */ ! 180: if(!xmit_ptr) { ! 181: outb(i_combase+IER, 0); ! 182: inxmit = 0; ! 183: } else { ! 184: c = *xmit_ptr++; ! 185: if(!c) c = '\r', xmit_ptr = 0; ! 186: outb(i_combase+DREG, c); ! 187: } ! 188: } ! 189: } ! 190: ! 191: spl(istate); ! 192: } /* sdintr */ ! 193: ! 194: /* return status of synthesizer, ready for more or not. ! 195: * ideally, the unit is ready when it has spoken everything ! 196: * previously sent to it. the Type & Talk has an ! 197: * annoying delay of about 10 seconds between ready indicated ! 198: * and all input spoken. There is nothing I can do ! 199: * about this. Other units, such as the echo, ! 200: * are out of the question, since their delay is measured ! 201: * in minutes. Someday, a speech unit will indicate clearly when ! 202: * it has spoken all input. */ ! 203: sdready(session) ! 204: /* only works for one session, i_sdc, ignore passed parameter */ ! 205: int session; ! 206: { ! 207: char mstat; ! 208: ! 209: /* are we sending a string? */ ! 210: if(inxmit) return 0; ! 211: ! 212: /* a real time delay, after sending return */ ! 213: if(crticks) { --crticks; return 0; } ! 214: ! 215: if(!i_combase) return 1; ! 216: ! 217: if(!sdoverride) { ! 218: /* check to see if votrax is there and ready (DSR and CTS) */ ! 219: mstat = inb(i_combase+MSR); ! 220: if(!(mstat & 0x20)) { ! 221: synth_dead(); ! 222: return 1; ! 223: } ! 224: deadbuzz = 0; ! 225: if(!(mstat & 0x10)) return 0; ! 226: } ! 227: ! 228: return 1; /* ready */ ! 229: } /* sdready */ ! 230: ! 231: /* send text string to the speech synthesizer. ! 232: * routine assumes the text is to be spoken immediately. ! 233: * once the text is spoken, cts will indicate ready for more. */ ! 234: sdtext(s) ! 235: char *s; ! 236: { ! 237: deadbuzz = 0; ! 238: /* is synthesizer dead? */ ! 239: if(!sdoverride && !(inb(i_combase+MSR) & 0x20)) { ! 240: synth_dead(); ! 241: return; ! 242: } ! 243: ! 244: /* set delay, after text is transmitted, so votrax has time to disable cts */ ! 245: crticks = 1; ! 246: xmit_ptr = s; ! 247: inxmit = 1; /* in transmit state */ ! 248: /* enable transmit interrupt */ ! 249: outb(i_combase+IER, 2); ! 250: } /* sdtext */ ! 251: ! 252: /* shut up and discard accumulated text. ! 253: * annoyingly, type & talk must be "ready" for text, ! 254: * before it will honor the shut up command (break on rs232). ! 255: * Be sure the unit is in the ready (cts high) state. */ ! 256: sdshutup() ! 257: { ! 258: char linectrl = inb(i_combase + LCR); ! 259: outb(i_combase+LCR, linectrl|0x40); ! 260: /* Occasionally an interrupt will come along while we are in break. ! 261: * This will cause the break to be a tad longer. ! 262: * The unbelievably picky Votrax unit may not recognize the break, ! 263: * and it may not shut up, or it may perceive ! 264: * a couple extra garbage characters. ! 265: * But long interrupts don't happen very often, ! 266: * and the short ones are potentially important, ! 267: * such as received characters on a serial port. ! 268: * So we wait with interrupts enabled. */ ! 269: sdpause(2560); ! 270: outb(i_combase+LCR, linectrl); ! 271: } /* sdshutup */ ! 272: ! 273: /* given a port address, is it allocated to a speech unit? */ ! 274: sdport_taken(comport) ! 275: { ! 276: int i; ! 277: ! 278: ++comport; ! 279: ! 280: for(i=0; i<4; ++i) ! 281: if((&sd0synth)[i] && comport == (&sd0comport)[i]) ! 282: return 1; ! 283: ! 284: return 0; ! 285: } /* sdport_taken */ ! 286: ! 287: static getbaudrate(comport) ! 288: { ! 289: int baud; ! 290: #ifdef MSDOS ! 291: baud = 12; ! 292: #else ! 293: switch(comport) { ! 294: case 1: baud = albaud[C1BAUD]; break; ! 295: case 2: baud = albaud[C2BAUD]; break; ! 296: case 3: baud = albaud[C3BAUD]; break; ! 297: case 4: baud = albaud[C4BAUD]; break; ! 298: } ! 299: #endif ! 300: return baud; ! 301: } /* getbaudrate */ ! 302:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.