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