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