diff options
Diffstat (limited to 'drivers/staging/speakup/serialio.c')
-rw-r--r-- | drivers/staging/speakup/serialio.c | 108 |
1 files changed, 92 insertions, 16 deletions
diff --git a/drivers/staging/speakup/serialio.c b/drivers/staging/speakup/serialio.c index ef89dc1..ba060d0 100644 --- a/drivers/staging/speakup/serialio.c +++ b/drivers/staging/speakup/serialio.c @@ -21,9 +21,21 @@ static void start_serial_interrupt(int irq); static const struct old_serial_port rs_table[] = { SERIAL_PORT_DFNS }; + static const struct old_serial_port *serstate; static int timeouts; +static int spk_serial_out(struct spk_synth *in_synth, const char ch); +static void spk_serial_send_xchar(char ch); +static void spk_serial_tiocmset(unsigned int set, unsigned int clear); + +struct spk_io_ops spk_serial_io_ops = { + .synth_out = spk_serial_out, + .send_xchar = spk_serial_send_xchar, + .tiocmset = spk_serial_tiocmset, +}; +EXPORT_SYMBOL_GPL(spk_serial_io_ops); + const struct old_serial_port *spk_serial_init(int index) { int baud = 9600, quot = 0; @@ -97,8 +109,7 @@ static irqreturn_t synth_readbuf_handler(int irq, void *dev_id) spin_lock_irqsave(&speakup_info.spinlock, flags); while (inb_p(speakup_info.port_tts + UART_LSR) & UART_LSR_DR) { - - c = inb_p(speakup_info.port_tts+UART_RX); + c = inb_p(speakup_info.port_tts + UART_RX); synth->read_buff_add((u_char)c); } spin_unlock_irqrestore(&speakup_info.spinlock, flags); @@ -119,17 +130,64 @@ static void start_serial_interrupt(int irq) pr_err("Unable to request Speakup serial I R Q\n"); /* Set MCR */ outb(UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2, - speakup_info.port_tts + UART_MCR); + speakup_info.port_tts + UART_MCR); /* Turn on Interrupts */ outb(UART_IER_MSI|UART_IER_RLSI|UART_IER_RDI, speakup_info.port_tts + UART_IER); - inb(speakup_info.port_tts+UART_LSR); - inb(speakup_info.port_tts+UART_RX); - inb(speakup_info.port_tts+UART_IIR); - inb(speakup_info.port_tts+UART_MSR); + inb(speakup_info.port_tts + UART_LSR); + inb(speakup_info.port_tts + UART_RX); + inb(speakup_info.port_tts + UART_IIR); + inb(speakup_info.port_tts + UART_MSR); outb(1, speakup_info.port_tts + UART_FCR); /* Turn FIFO On */ } +static void spk_serial_send_xchar(char ch) +{ + int timeout = SPK_XMITR_TIMEOUT; + + while (spk_serial_tx_busy()) { + if (!--timeout) + break; + udelay(1); + } + outb(ch, speakup_info.port_tts); +} + +static void spk_serial_tiocmset(unsigned int set, unsigned int clear) +{ + int old = inb(speakup_info.port_tts + UART_MCR); + outb((old & ~clear) | set, speakup_info.port_tts + UART_MCR); +} + +int spk_serial_synth_probe(struct spk_synth *synth) +{ + const struct old_serial_port *ser; + int failed = 0; + + if ((synth->ser >= SPK_LO_TTY) && (synth->ser <= SPK_HI_TTY)) { + ser = spk_serial_init(synth->ser); + if (!ser) { + failed = -1; + } else { + outb_p(0, ser->port); + mdelay(1); + outb_p('\r', ser->port); + } + } else { + failed = -1; + pr_warn("ttyS%i is an invalid port\n", synth->ser); + } + if (failed) { + pr_info("%s: not found\n", synth->long_name); + return -ENODEV; + } + pr_info("%s: ttyS%i, Driver Version %s\n", + synth->long_name, synth->ser, synth->version); + synth->alive = 1; + return 0; +} +EXPORT_SYMBOL_GPL(spk_serial_synth_probe); + void spk_stop_serial_interrupt(void) { if (speakup_info.port_tts == 0) @@ -139,19 +197,20 @@ void spk_stop_serial_interrupt(void) return; /* Turn off interrupts */ - outb(0, speakup_info.port_tts+UART_IER); + outb(0, speakup_info.port_tts + UART_IER); /* Free IRQ */ free_irq(serstate->irq, (void *)synth_readbuf_handler); } +EXPORT_SYMBOL_GPL(spk_stop_serial_interrupt); -int spk_wait_for_xmitr(void) +int spk_wait_for_xmitr(struct spk_synth *in_synth) { int tmout = SPK_XMITR_TIMEOUT; - if ((synth->alive) && (timeouts >= NUM_DISABLE_TIMEOUTS)) { + if ((in_synth->alive) && (timeouts >= NUM_DISABLE_TIMEOUTS)) { pr_warn("%s: too many timeouts, deactivating speakup\n", - synth->long_name); - synth->alive = 0; + in_synth->long_name); + in_synth->alive = 0; /* No synth any more, so nobody will restart TTYs, and we thus * need to do it ourselves. Now that there is no synth we can * let application flood anyway @@ -162,7 +221,7 @@ int spk_wait_for_xmitr(void) } while (spk_serial_tx_busy()) { if (--tmout == 0) { - pr_warn("%s: timed out (tx busy)\n", synth->long_name); + pr_warn("%s: timed out (tx busy)\n", in_synth->long_name); timeouts++; return 0; } @@ -207,18 +266,35 @@ unsigned char spk_serial_in_nowait(void) } EXPORT_SYMBOL_GPL(spk_serial_in_nowait); -int spk_serial_out(const char ch) +static int spk_serial_out(struct spk_synth *in_synth, const char ch) { - if (synth->alive && spk_wait_for_xmitr()) { + if (in_synth->alive && spk_wait_for_xmitr(in_synth)) { outb_p(ch, speakup_info.port_tts); return 1; } return 0; } -EXPORT_SYMBOL_GPL(spk_serial_out); + +const char *spk_serial_synth_immediate(struct spk_synth *synth, const char *buff) +{ + u_char ch; + + while ((ch = *buff)) { + if (ch == '\n') + ch = synth->procspeech; + if (spk_wait_for_xmitr(synth)) + outb(ch, speakup_info.port_tts); + else + return buff; + buff++; + } + return NULL; +} +EXPORT_SYMBOL_GPL(spk_serial_synth_immediate); void spk_serial_release(void) { + spk_stop_serial_interrupt(); if (speakup_info.port_tts == 0) return; synth_release_region(speakup_info.port_tts, 8); |