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