1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/interrupt.h> 3 #include <linux/ioport.h> 4 5 #include "spk_types.h" 6 #include "speakup.h" 7 #include "spk_priv.h" 8 #include "serialio.h" 9 10 #include <linux/serial_core.h> 11 /* WARNING: Do not change this to <linux/serial.h> without testing that 12 * SERIAL_PORT_DFNS does get defined to the appropriate value. 13 */ 14 #include <asm/serial.h> 15 16 #ifndef SERIAL_PORT_DFNS 17 #define SERIAL_PORT_DFNS 18 #endif 19 20 static void start_serial_interrupt(int irq); 21 22 static const struct old_serial_port rs_table[] = { 23 SERIAL_PORT_DFNS 24 }; 25 26 static const struct old_serial_port *serstate; 27 static int timeouts; 28 29 static int spk_serial_out(struct spk_synth *in_synth, const char ch); 30 static void spk_serial_send_xchar(char ch); 31 static void spk_serial_tiocmset(unsigned int set, unsigned int clear); 32 static unsigned char spk_serial_in(void); 33 static unsigned char spk_serial_in_nowait(void); 34 static void spk_serial_flush_buffer(void); 35 36 struct spk_io_ops spk_serial_io_ops = { 37 .synth_out = spk_serial_out, 38 .send_xchar = spk_serial_send_xchar, 39 .tiocmset = spk_serial_tiocmset, 40 .synth_in = spk_serial_in, 41 .synth_in_nowait = spk_serial_in_nowait, 42 .flush_buffer = spk_serial_flush_buffer, 43 }; 44 EXPORT_SYMBOL_GPL(spk_serial_io_ops); 45 46 const struct old_serial_port *spk_serial_init(int index) 47 { 48 int baud = 9600, quot = 0; 49 unsigned int cval = 0; 50 int cflag = CREAD | HUPCL | CLOCAL | B9600 | CS8; 51 const struct old_serial_port *ser; 52 int err; 53 54 if (index >= ARRAY_SIZE(rs_table)) { 55 pr_info("no port info for ttyS%d\n", index); 56 return NULL; 57 } 58 ser = rs_table + index; 59 60 /* Divisor, bytesize and parity */ 61 quot = ser->baud_base / baud; 62 cval = cflag & (CSIZE | CSTOPB); 63 #if defined(__powerpc__) || defined(__alpha__) 64 cval >>= 8; 65 #else /* !__powerpc__ && !__alpha__ */ 66 cval >>= 4; 67 #endif /* !__powerpc__ && !__alpha__ */ 68 if (cflag & PARENB) 69 cval |= UART_LCR_PARITY; 70 if (!(cflag & PARODD)) 71 cval |= UART_LCR_EPAR; 72 if (synth_request_region(ser->port, 8)) { 73 /* try to take it back. */ 74 pr_info("Ports not available, trying to steal them\n"); 75 __release_region(&ioport_resource, ser->port, 8); 76 err = synth_request_region(ser->port, 8); 77 if (err) { 78 pr_warn("Unable to allocate port at %x, errno %i", 79 ser->port, err); 80 return NULL; 81 } 82 } 83 84 /* Disable UART interrupts, set DTR and RTS high 85 * and set speed. 86 */ 87 outb(cval | UART_LCR_DLAB, ser->port + UART_LCR); /* set DLAB */ 88 outb(quot & 0xff, ser->port + UART_DLL); /* LS of divisor */ 89 outb(quot >> 8, ser->port + UART_DLM); /* MS of divisor */ 90 outb(cval, ser->port + UART_LCR); /* reset DLAB */ 91 92 /* Turn off Interrupts */ 93 outb(0, ser->port + UART_IER); 94 outb(UART_MCR_DTR | UART_MCR_RTS, ser->port + UART_MCR); 95 96 /* If we read 0xff from the LSR, there is no UART here. */ 97 if (inb(ser->port + UART_LSR) == 0xff) { 98 synth_release_region(ser->port, 8); 99 serstate = NULL; 100 return NULL; 101 } 102 103 mdelay(1); 104 speakup_info.port_tts = ser->port; 105 serstate = ser; 106 107 start_serial_interrupt(ser->irq); 108 109 return ser; 110 } 111 112 static irqreturn_t synth_readbuf_handler(int irq, void *dev_id) 113 { 114 unsigned long flags; 115 int c; 116 117 spin_lock_irqsave(&speakup_info.spinlock, flags); 118 while (inb_p(speakup_info.port_tts + UART_LSR) & UART_LSR_DR) { 119 c = inb_p(speakup_info.port_tts + UART_RX); 120 synth->read_buff_add((u_char)c); 121 } 122 spin_unlock_irqrestore(&speakup_info.spinlock, flags); 123 return IRQ_HANDLED; 124 } 125 126 static void start_serial_interrupt(int irq) 127 { 128 int rv; 129 130 if (!synth->read_buff_add) 131 return; 132 133 rv = request_irq(irq, synth_readbuf_handler, IRQF_SHARED, 134 "serial", (void *)synth_readbuf_handler); 135 136 if (rv) 137 pr_err("Unable to request Speakup serial I R Q\n"); 138 /* Set MCR */ 139 outb(UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2, 140 speakup_info.port_tts + UART_MCR); 141 /* Turn on Interrupts */ 142 outb(UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI, 143 speakup_info.port_tts + UART_IER); 144 inb(speakup_info.port_tts + UART_LSR); 145 inb(speakup_info.port_tts + UART_RX); 146 inb(speakup_info.port_tts + UART_IIR); 147 inb(speakup_info.port_tts + UART_MSR); 148 outb(1, speakup_info.port_tts + UART_FCR); /* Turn FIFO On */ 149 } 150 151 static void spk_serial_send_xchar(char ch) 152 { 153 int timeout = SPK_XMITR_TIMEOUT; 154 155 while (spk_serial_tx_busy()) { 156 if (!--timeout) 157 break; 158 udelay(1); 159 } 160 outb(ch, speakup_info.port_tts); 161 } 162 163 static void spk_serial_tiocmset(unsigned int set, unsigned int clear) 164 { 165 int old = inb(speakup_info.port_tts + UART_MCR); 166 167 outb((old & ~clear) | set, speakup_info.port_tts + UART_MCR); 168 } 169 170 int spk_serial_synth_probe(struct spk_synth *synth) 171 { 172 const struct old_serial_port *ser; 173 int failed = 0; 174 175 if ((synth->ser >= SPK_LO_TTY) && (synth->ser <= SPK_HI_TTY)) { 176 ser = spk_serial_init(synth->ser); 177 if (!ser) { 178 failed = -1; 179 } else { 180 outb_p(0, ser->port); 181 mdelay(1); 182 outb_p('\r', ser->port); 183 } 184 } else { 185 failed = -1; 186 pr_warn("ttyS%i is an invalid port\n", synth->ser); 187 } 188 if (failed) { 189 pr_info("%s: not found\n", synth->long_name); 190 return -ENODEV; 191 } 192 pr_info("%s: ttyS%i, Driver Version %s\n", 193 synth->long_name, synth->ser, synth->version); 194 synth->alive = 1; 195 return 0; 196 } 197 EXPORT_SYMBOL_GPL(spk_serial_synth_probe); 198 199 void spk_stop_serial_interrupt(void) 200 { 201 if (speakup_info.port_tts == 0) 202 return; 203 204 if (!synth->read_buff_add) 205 return; 206 207 /* Turn off interrupts */ 208 outb(0, speakup_info.port_tts + UART_IER); 209 /* Free IRQ */ 210 free_irq(serstate->irq, (void *)synth_readbuf_handler); 211 } 212 EXPORT_SYMBOL_GPL(spk_stop_serial_interrupt); 213 214 int spk_wait_for_xmitr(struct spk_synth *in_synth) 215 { 216 int tmout = SPK_XMITR_TIMEOUT; 217 218 if ((in_synth->alive) && (timeouts >= NUM_DISABLE_TIMEOUTS)) { 219 pr_warn("%s: too many timeouts, deactivating speakup\n", 220 in_synth->long_name); 221 in_synth->alive = 0; 222 /* No synth any more, so nobody will restart TTYs, and we thus 223 * need to do it ourselves. Now that there is no synth we can 224 * let application flood anyway 225 */ 226 speakup_start_ttys(); 227 timeouts = 0; 228 return 0; 229 } 230 while (spk_serial_tx_busy()) { 231 if (--tmout == 0) { 232 pr_warn("%s: timed out (tx busy)\n", 233 in_synth->long_name); 234 timeouts++; 235 return 0; 236 } 237 udelay(1); 238 } 239 tmout = SPK_CTS_TIMEOUT; 240 while (!((inb_p(speakup_info.port_tts + UART_MSR)) & UART_MSR_CTS)) { 241 /* CTS */ 242 if (--tmout == 0) { 243 timeouts++; 244 return 0; 245 } 246 udelay(1); 247 } 248 timeouts = 0; 249 return 1; 250 } 251 252 static unsigned char spk_serial_in(void) 253 { 254 int tmout = SPK_SERIAL_TIMEOUT; 255 256 while (!(inb_p(speakup_info.port_tts + UART_LSR) & UART_LSR_DR)) { 257 if (--tmout == 0) { 258 pr_warn("time out while waiting for input.\n"); 259 return 0xff; 260 } 261 udelay(1); 262 } 263 return inb_p(speakup_info.port_tts + UART_RX); 264 } 265 266 static unsigned char spk_serial_in_nowait(void) 267 { 268 unsigned char lsr; 269 270 lsr = inb_p(speakup_info.port_tts + UART_LSR); 271 if (!(lsr & UART_LSR_DR)) 272 return 0; 273 return inb_p(speakup_info.port_tts + UART_RX); 274 } 275 276 static void spk_serial_flush_buffer(void) 277 { 278 /* TODO: flush the UART 16550 buffer */ 279 } 280 281 static int spk_serial_out(struct spk_synth *in_synth, const char ch) 282 { 283 if (in_synth->alive && spk_wait_for_xmitr(in_synth)) { 284 outb_p(ch, speakup_info.port_tts); 285 return 1; 286 } 287 return 0; 288 } 289 290 const char *spk_serial_synth_immediate(struct spk_synth *synth, 291 const char *buff) 292 { 293 u_char ch; 294 295 while ((ch = *buff)) { 296 if (ch == '\n') 297 ch = synth->procspeech; 298 if (spk_wait_for_xmitr(synth)) 299 outb(ch, speakup_info.port_tts); 300 else 301 return buff; 302 buff++; 303 } 304 return NULL; 305 } 306 EXPORT_SYMBOL_GPL(spk_serial_synth_immediate); 307 308 void spk_serial_release(void) 309 { 310 spk_stop_serial_interrupt(); 311 if (speakup_info.port_tts == 0) 312 return; 313 synth_release_region(speakup_info.port_tts, 8); 314 speakup_info.port_tts = 0; 315 } 316 EXPORT_SYMBOL_GPL(spk_serial_release); 317