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 spk_lock(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 spk_unlock(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 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 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 && 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