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