|
|
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: /* init the synthesizer */
47: sdsynth_init(session)
48: short session;
49: {
50: short istate;
51: int synth, comport;
52: int baud;
53: extern int sdintr();
54:
55: synth = (&sd0synth)[session];
56: comport = (&sd0comport)[session];
57: /* range check synth and comport */
58: if(synth < 1 || synth > 1 ||
59: comport < 1 || comport > 4 ||
60: comport && i_comport)
61: return 0;
62:
63: sdcontrol[session] = i_sdc = (struct SDCONTROL *) kalloc(sizeof(struct SDCONTROL));
64: if(!i_sdc) return; /* kalloc failed */
65: memset(i_sdc, 0, sizeof(struct SDCONTROL));
66:
67: if(comport) { /* unit is on a serial port */
68: i_comport = comport;
69: i_combase = AL_ADDR[comport-1];
70:
71: istate = sphi();
72: /* initialize the UART */
73: /* no transmit interrupt until we start sending text */
74: outb(i_combase+IER, 0);
75: outb(i_combase+MCR, 0);
76: inb(i_combase+DREG); /* clear any input */
77: inb(i_combase+LSR);
78: inb(i_combase+MSR);
79: /* set baud rate to 9600 baud */
80: baud = getbaudrate(comport);
81: outb(i_combase+LCR, 0x80);
82: outb(i_combase+LDLR, baud);
83: outb(i_combase+HDLR, baud>>8);
84: outb(i_combase+LCR, 3); /* 8 bits, no parity */
85:
86: setivec((comport&1)+3, sdintr);
87:
88: /* set DTR and RTS */
89: /* extra bit (8[4]) is needed to generate interrupts */
90: outb(i_combase+MCR, 15 - ((comport&1) << 2));
91: spl(istate);
92:
93: /* synthesizer specific initialization sequence here */
94: return;
95: } /* on a serial port */
96:
97: /* this code not reached */
98: return 1; /* only serial connections implemented */
99: } /* sdsynth_init */
100:
101: /* synthesizer appears to be dead */
102: static synth_dead()
103: {
104: if(!deadbuzz) sdsound(7);
105: deadbuzz = 1;
106: i_sdc->rdflag = i_sdc->onesymb = 0;
107: i_sdc->drain_lbolt = 0;
108: } /* synth_dead */
109:
110: /* serial port interrupt handler, runs with interrupts off */
111: sdintr()
112: {
113: char linestat, c;
114: short istate;
115:
116: istate = sphi();
117: inb(i_combase+IIR);
118: linestat = inb(i_combase+LSR);
119: if(!(linestat & 0x20)) return;
120:
121: /* if no data to send then reset tx interrupt and return */
122: if(!xmit_ptr) {
123: outb(i_combase+IER, 0);
124: inxmit = 0;
125: } else {
126: c = *xmit_ptr++;
127: if(!c) c = '\r', xmit_ptr = 0;
128: outb(i_combase+DREG, c);
129: }
130:
131: spl(istate);
132: } /* sdintr */
133:
134: /* return status of synthesizer, ready for more or not.
135: * ideally, the unit is ready when it has spoken everything
136: * previously sent to it. the Type & Talk has an
137: * annoying delay of about 10 seconds between ready indicated
138: * and all input spoken. There is nothing I can do
139: * about this. Other units, such as the echo,
140: * are out of the question, since their delay is measured
141: * in minutes. Someday, a speech unit will indicate clearly when
142: * it has spoken all input. */
143: sdready()
144: {
145: char mstat;
146:
147: /* are we sending a string? */
148: if(inxmit) return 0;
149:
150: /* a real time delay, after sending return */
151: if(crticks) { --crticks; return 0; }
152:
153: if(!i_combase) return 1;
154:
155: if(!sdoverride) {
156: /* check to see if votrax is there and ready (DSR and CTS) */
157: mstat = inb(i_combase+MSR);
158: if(!(mstat & 0x20)) {
159: synth_dead();
160: return 1;
161: }
162: deadbuzz = 0;
163: if(!(mstat & 0x10)) return 0;
164: }
165:
166: return 1; /* ready */
167: } /* sdready */
168:
169: /* send text string to the speech synthesizer.
170: * routine assumes the text is to be spoken immediately.
171: * once the text is spoken, cts will indicate ready for more. */
172: sdtext(s)
173: char *s;
174: {
175: deadbuzz = 0;
176: /* is synthesizer dead? */
177: if(!sdoverride && !(inb(i_combase+MSR) & 0x20)) {
178: synth_dead();
179: return;
180: }
181:
182: /* set delay, after text is transmitted, so votrax has time to disable cts */
183: crticks = 1;
184: xmit_ptr = s;
185: inxmit = 1; /* in transmit state */
186: /* enable transmit interrupt */
187: outb(i_combase+IER, 2);
188: } /* sdtext */
189:
190: /* shut up and discard accumulated text.
191: * annoyingly, type & talk must be "ready" for text,
192: * before it will honor the shut up command (break on rs232).
193: * Be sure the unit is in the ready (cts high) state. */
194: sdshutup()
195: {
196: char linectrl = inb(i_combase + LCR);
197: outb(i_combase+LCR, linectrl|0x40);
198: /* Occasionally an interrupt will come along while we are in break.
199: * This will cause the break to be a tad longer.
200: * The unbelievably picky Votrax unit may not recognize the break,
201: * and it may not shut up, or it may perceive
202: * a couple extra garbage characters.
203: * But long interrupts don't happen very often,
204: * and the short ones are potentially important,
205: * such as received characters on a serial port.
206: * So we wait with interrupts enabled. */
207: sdpause(2560);
208: outb(i_combase+LCR, linectrl);
209: } /* sdshutup */
210:
211: /* given a port address, is it allocated to a speech unit? */
212: sdport_taken(comport)
213: {
214: int i;
215:
216: ++comport;
217:
218: for(i=0; i<4; ++i)
219: if((&sd0synth)[i] && comport == (&sd0comport)[i])
220: return 1;
221:
222: return 0;
223: } /* sdport_taken */
224:
225: static getbaudrate(comport)
226: {
227: int baud;
228: #ifdef MSDOS
229: baud = 12;
230: #else
231: switch(comport) {
232: case 1: baud = albaud[C1BAUD]; break;
233: case 2: baud = albaud[C2BAUD]; break;
234: case 3: baud = albaud[C3BAUD]; break;
235: case 4: baud = albaud[C4BAUD]; break;
236: }
237: #endif
238: return baud;
239: } /* getbaudrate */
240:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.