linux/drivers/staging/speakup/serialio.c
<<
>>
Prefs
   1#include <linux/interrupt.h>
   2#include <linux/ioport.h>
   3
   4#include "spk_types.h"
   5#include "speakup.h"
   6#include "spk_priv.h"
   7#include "serialio.h"
   8
   9static void start_serial_interrupt(int irq);
  10
  11static const struct old_serial_port rs_table[] = {
  12        SERIAL_PORT_DFNS
  13};
  14static const struct old_serial_port *serstate;
  15static int timeouts;
  16
  17const struct old_serial_port *spk_serial_init(int index)
  18{
  19        int baud = 9600, quot = 0;
  20        unsigned int cval = 0;
  21        int cflag = CREAD | HUPCL | CLOCAL | B9600 | CS8;
  22        const struct old_serial_port *ser = rs_table + index;
  23        int err;
  24
  25        /*      Divisor, bytesize and parity */
  26        quot = ser->baud_base / baud;
  27        cval = cflag & (CSIZE | CSTOPB);
  28#if defined(__powerpc__) || defined(__alpha__)
  29        cval >>= 8;
  30#else /* !__powerpc__ && !__alpha__ */
  31        cval >>= 4;
  32#endif /* !__powerpc__ && !__alpha__ */
  33        if (cflag & PARENB)
  34                cval |= UART_LCR_PARITY;
  35        if (!(cflag & PARODD))
  36                cval |= UART_LCR_EPAR;
  37        if (synth_request_region(ser->port, 8)) {
  38                /* try to take it back. */
  39                printk(KERN_INFO "Ports not available, trying to steal them\n");
  40                __release_region(&ioport_resource, ser->port, 8);
  41                err = synth_request_region(ser->port, 8);
  42                if (err) {
  43                        pr_warn("Unable to allocate port at %x, errno %i",
  44                                ser->port, err);
  45                        return NULL;
  46                }
  47        }
  48
  49        /*      Disable UART interrupts, set DTR and RTS high
  50         *      and set speed. */
  51        outb(cval | UART_LCR_DLAB, ser->port + UART_LCR);       /* set DLAB */
  52        outb(quot & 0xff, ser->port + UART_DLL);        /* LS of divisor */
  53        outb(quot >> 8, ser->port + UART_DLM);          /* MS of divisor */
  54        outb(cval, ser->port + UART_LCR);               /* reset DLAB */
  55
  56        /* Turn off Interrupts */
  57        outb(0, ser->port + UART_IER);
  58        outb(UART_MCR_DTR | UART_MCR_RTS, ser->port + UART_MCR);
  59
  60        /* If we read 0xff from the LSR, there is no UART here. */
  61        if (inb(ser->port + UART_LSR) == 0xff) {
  62                synth_release_region(ser->port, 8);
  63                serstate = NULL;
  64                return NULL;
  65        }
  66
  67        mdelay(1);
  68        speakup_info.port_tts = ser->port;
  69        serstate = ser;
  70
  71        start_serial_interrupt(ser->irq);
  72
  73        return ser;
  74}
  75
  76static irqreturn_t synth_readbuf_handler(int irq, void *dev_id)
  77{
  78        unsigned long flags;
  79/*printk(KERN_ERR "in irq\n"); */
  80/*pr_warn("in IRQ\n"); */
  81        int c;
  82        spin_lock_irqsave(&speakup_info.spinlock, flags);
  83        while (inb_p(speakup_info.port_tts + UART_LSR) & UART_LSR_DR) {
  84
  85                c = inb_p(speakup_info.port_tts+UART_RX);
  86                synth->read_buff_add((u_char) c);
  87/*printk(KERN_ERR "c = %d\n", c); */
  88/*pr_warn("C = %d\n", c); */
  89        }
  90        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
  91        return IRQ_HANDLED;
  92}
  93
  94static void start_serial_interrupt(int irq)
  95{
  96        int rv;
  97
  98        if (synth->read_buff_add == NULL)
  99                return;
 100
 101        rv = request_irq(irq, synth_readbuf_handler, IRQF_SHARED,
 102                         "serial", (void *) synth_readbuf_handler);
 103
 104        if (rv)
 105                printk(KERN_ERR "Unable to request Speakup serial I R Q\n");
 106        /* Set MCR */
 107        outb(UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2,
 108                        speakup_info.port_tts + UART_MCR);
 109        /* Turn on Interrupts */
 110        outb(UART_IER_MSI|UART_IER_RLSI|UART_IER_RDI,
 111                        speakup_info.port_tts + UART_IER);
 112        inb(speakup_info.port_tts+UART_LSR);
 113        inb(speakup_info.port_tts+UART_RX);
 114        inb(speakup_info.port_tts+UART_IIR);
 115        inb(speakup_info.port_tts+UART_MSR);
 116        outb(1, speakup_info.port_tts + UART_FCR);      /* Turn FIFO On */
 117}
 118
 119void spk_stop_serial_interrupt(void)
 120{
 121        if (speakup_info.port_tts == 0)
 122                return;
 123
 124        if (synth->read_buff_add == NULL)
 125                return;
 126
 127        /* Turn off interrupts */
 128        outb(0, speakup_info.port_tts+UART_IER);
 129        /* Free IRQ */
 130        free_irq(serstate->irq, (void *) synth_readbuf_handler);
 131}
 132
 133int spk_wait_for_xmitr(void)
 134{
 135        int tmout = SPK_XMITR_TIMEOUT;
 136        if ((synth->alive) && (timeouts >= NUM_DISABLE_TIMEOUTS)) {
 137                pr_warn("%s: too many timeouts, deactivating speakup\n",
 138                        synth->long_name);
 139                synth->alive = 0;
 140                /* No synth any more, so nobody will restart TTYs, and we thus
 141                 * need to do it ourselves.  Now that there is no synth we can
 142                 * let application flood anyway */
 143                speakup_start_ttys();
 144                timeouts = 0;
 145                return 0;
 146        }
 147        while (spk_serial_tx_busy()) {
 148                if (--tmout == 0) {
 149                        pr_warn("%s: timed out (tx busy)\n", synth->long_name);
 150                        timeouts++;
 151                        return 0;
 152                }
 153                udelay(1);
 154        }
 155        tmout = SPK_CTS_TIMEOUT;
 156        while (!((inb_p(speakup_info.port_tts + UART_MSR)) & UART_MSR_CTS)) {
 157                /* CTS */
 158                if (--tmout == 0) {
 159                        /* pr_warn("%s: timed out (cts)\n",
 160                         * synth->long_name); */
 161                        timeouts++;
 162                        return 0;
 163                }
 164                udelay(1);
 165        }
 166        timeouts = 0;
 167        return 1;
 168}
 169
 170unsigned char spk_serial_in(void)
 171{
 172        int tmout = SPK_SERIAL_TIMEOUT;
 173
 174        while (!(inb_p(speakup_info.port_tts + UART_LSR) & UART_LSR_DR)) {
 175                if (--tmout == 0) {
 176                        pr_warn("time out while waiting for input.\n");
 177                        return 0xff;
 178                }
 179                udelay(1);
 180        }
 181        return inb_p(speakup_info.port_tts + UART_RX);
 182}
 183EXPORT_SYMBOL_GPL(spk_serial_in);
 184
 185unsigned char spk_serial_in_nowait(void)
 186{
 187        unsigned char lsr;
 188
 189        lsr = inb_p(speakup_info.port_tts + UART_LSR);
 190        if (!(lsr & UART_LSR_DR))
 191                return 0;
 192        return inb_p(speakup_info.port_tts + UART_RX);
 193}
 194EXPORT_SYMBOL_GPL(spk_serial_in_nowait);
 195
 196int spk_serial_out(const char ch)
 197{
 198        if (synth->alive && spk_wait_for_xmitr()) {
 199                outb_p(ch, speakup_info.port_tts);
 200                return 1;
 201        }
 202        return 0;
 203}
 204EXPORT_SYMBOL_GPL(spk_serial_out);
 205
 206void spk_serial_release(void)
 207{
 208        if (speakup_info.port_tts == 0)
 209                return;
 210        synth_release_region(speakup_info.port_tts, 8);
 211        speakup_info.port_tts = 0;
 212}
 213EXPORT_SYMBOL_GPL(spk_serial_release);
 214
 215