RS: invoke a shell explicitly for scripts
[minix.git] / drivers / tty / arch / arm / rs232.c
blob3a3b256bd711129481ab6916169f4a7a3f3e1de0
1 #include <minix/config.h>
2 #include <minix/drivers.h>
3 #include <minix/vm.h>
4 #include <sys/mman.h>
5 #include <assert.h>
6 #include <signal.h>
7 #include <termios.h>
8 #include "omap_serial.h"
9 #include "tty.h"
11 #if NR_RS_LINES > 0
13 #define UART_FREQ 48000000L /* timer frequency */
14 #if 0
15 #define DFLT_BAUD TSPEED_DEF /* default baud rate */
16 #else
17 #define DFLT_BAUD B115200 /* default baud rate */
18 #endif
21 #define RS_IBUFSIZE 1024 /* RS232 input buffer size */
22 #define RS_OBUFSIZE 1024 /* RS232 output buffer size */
24 /* Input buffer watermarks.
25 * The external device is asked to stop sending when the buffer
26 * exactly reaches high water, or when TTY requests it. Sending restarts
27 * when the input buffer empties below the low watermark.
29 #define RS_ILOWWATER (1 * RS_IBUFSIZE / 4)
30 #define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)
32 /* Output buffer low watermark.
33 * TTY is notified when the output buffer empties below the low watermark, so
34 * it may continue filling the buffer if doing a large write.
36 #define RS_OLOWWATER (1 * RS_OBUFSIZE / 4)
38 /* Macros to handle flow control.
39 * Interrupts must be off when they are used.
40 * Time is critical - already the function call for outb() is annoying.
41 * If outb() can be done in-line, tests to avoid it can be dropped.
42 * istart() tells external device we are ready by raising RTS.
43 * istop() tells external device we are not ready by dropping RTS.
44 * DTR is kept high all the time (it probably should be raised by open and
45 * dropped by close of the device).
46 * OUT2 is also kept high all the time.
48 #define istart(rs) \
49 (serial_out((rs), OMAP3_MCR, UART_MCR_OUT2|UART_MCR_RTS|UART_MCR_DTR),\
50 (rs)->idevready = TRUE)
51 #define istop(rs) \
52 (serial_out((rs), OMAP3_MCR, UART_MCR_OUT2|UART_MCR_DTR), \
53 (rs)->idevready = FALSE)
55 /* Macro to tell if device is ready. The rs->cts field is set to UART_MSR_CTS
56 * if CLOCAL is in effect for a line without a CTS wire.
58 #define devready(rs) ((serial_in(rs, OMAP3_MSR) | rs->cts) & UART_MSR_CTS)
60 /* Macro to tell if transmitter is ready. */
61 #define txready(rs) (serial_in(rs, OMAP3_LSR) & UART_LSR_THRE)
63 /* RS232 device structure, one per device. */
64 typedef struct rs232 {
65 tty_t *tty; /* associated TTY structure */
67 int icount; /* number of bytes in the input buffer */
68 char *ihead; /* next free spot in input buffer */
69 char *itail; /* first byte to give to TTY */
70 char idevready; /* nonzero if we are ready to receive (RTS) */
71 char cts; /* normally 0, but MS_CTS if CLOCAL is set */
73 unsigned char ostate; /* combination of flags: */
74 #define ODONE 1 /* output completed (< output enable bits) */
75 #define ORAW 2 /* raw mode for xoff disable (< enab. bits) */
76 #define OWAKEUP 4 /* tty_wakeup() pending (asm code only) */
77 #define ODEVREADY UART_MSR_CTS /* external device hardware ready (CTS) */
78 #define OQUEUED 0x20 /* output buffer not empty */
79 #define OSWREADY 0x40 /* external device software ready (no xoff) */
80 #define ODEVHUP UART_MSR_DCD /* external device has dropped carrier */
81 #define OSOFTBITS (ODONE | ORAW | OWAKEUP | OQUEUED | OSWREADY)
82 /* user-defined bits */
83 #if (OSOFTBITS | ODEVREADY | ODEVHUP) == OSOFTBITS
84 /* a weak sanity check */
85 #error /* bits are not unique */
86 #endif
87 unsigned char oxoff; /* char to stop output */
88 char inhibited; /* output inhibited? (follows tty_inhibited) */
89 char drain; /* if set drain output and reconfigure line */
90 int ocount; /* number of bytes in the output buffer */
91 char *ohead; /* next free spot in output buffer */
92 char *otail; /* next char to output */
94 phys_bytes phys_base; /* UART physical base address (I/O map) */
95 unsigned int reg_offset; /* UART register offset */
96 unsigned int ier; /* copy of ier register */
97 unsigned int scr; /* copy of scr register */
98 unsigned int fcr; /* copy of fcr register */
99 unsigned int dll; /* copy of dll register */
100 unsigned int dlh; /* copy of dlh register */
101 unsigned int uartclk; /* UART clock rate */
103 unsigned char lstatus; /* last line status */
104 unsigned framing_errors; /* error counts (no reporting yet) */
105 unsigned overrun_errors;
106 unsigned parity_errors;
107 unsigned break_interrupts;
109 int irq; /* irq for this line */
110 int irq_hook_id; /* interrupt hook */
112 char ibuf[RS_IBUFSIZE]; /* input buffer */
113 char obuf[RS_OBUFSIZE]; /* output buffer */
114 } rs232_t;
116 static rs232_t rs_lines[NR_RS_LINES];
118 typedef struct uart_port {
119 phys_bytes base_addr;
120 int irq;
121 } uart_port_t;
123 /* OMAP3 UART base addresses. */
124 static uart_port_t omap3[] = {
125 { OMAP3_UART1_BASE, 72}, /* UART1 */
126 { OMAP3_UART2_BASE, 73}, /* UART2 */
127 { OMAP3_UART3_BASE, 74}, /* UART3 */
128 { 0, 0 }
131 static int rs_write(tty_t *tp, int try);
132 static void rs_echo(tty_t *tp, int c);
133 static int rs_ioctl(tty_t *tp, int try);
134 static void rs_config(rs232_t *rs);
135 static int rs_read(tty_t *tp, int try);
136 static int rs_icancel(tty_t *tp, int try);
137 static int rs_ocancel(tty_t *tp, int try);
138 static void rs_ostart(rs232_t *rs);
139 static int rs_break(tty_t *tp, int try);
140 static int rs_close(tty_t *tp, int try);
141 static int rs_open(tty_t *tp, int try);
142 static void rs232_handler(rs232_t *rs);
143 static void rs_reset(rs232_t *rs);
144 static unsigned int check_modem_status(rs232_t *rs);
145 static int termios_baud_rate(struct termios *term);
147 static inline unsigned int readw(vir_bytes addr);
148 static inline unsigned int serial_in(rs232_t *rs, int offset);
149 static inline void serial_out(rs232_t *rs, int offset, int val);
150 static inline void writew(vir_bytes addr, int val);
151 static void write_chars(rs232_t *rs);
152 static void read_chars(rs232_t *rs, unsigned int status);
154 static inline unsigned int
155 readw(vir_bytes addr)
157 return *((volatile unsigned int *) addr);
160 static inline void
161 writew(vir_bytes addr, int val)
163 *((volatile unsigned int *) addr) = val;
166 static inline unsigned int
167 serial_in(rs232_t *rs, int offset)
169 offset <<= rs->reg_offset;
170 return readw(rs->phys_base + offset);
173 static inline void
174 serial_out(rs232_t *rs, int offset, int val)
176 offset <<= rs->reg_offset;
177 writew(rs->phys_base + offset, val);
180 static void
181 rs_reset(rs232_t *rs)
183 u32_t syss;
185 serial_out(rs, OMAP3_SYSC, UART_SYSC_SOFTRESET);
187 /* Poll until done */
188 do {
189 syss = serial_in(rs, OMAP3_SYSS);
190 } while (!(syss & UART_SYSS_RESETDONE));
193 static int
194 rs_write(register tty_t *tp, int try)
196 /* (*devwrite)() routine for RS232. */
198 rs232_t *rs = tp->tty_priv;
199 int r, count, ocount;
201 if (rs->inhibited != tp->tty_inhibited) {
202 /* Inhibition state has changed. */
203 rs->ostate |= OSWREADY;
204 if (tp->tty_inhibited) rs->ostate &= ~OSWREADY;
205 rs->inhibited = tp->tty_inhibited;
208 if (rs->drain) {
209 /* Wait for the line to drain then reconfigure and continue
210 * output. */
211 if (rs->ocount > 0) return 0;
212 rs->drain = FALSE;
213 rs_config(rs);
215 /* While there is something to do. */
216 for (;;) {
217 ocount = buflen(rs->obuf) - rs->ocount;
218 count = bufend(rs->obuf) - rs->ohead;
219 if (count > ocount) count = ocount;
220 if (count > tp->tty_outleft) count = tp->tty_outleft;
221 if (count == 0 || tp->tty_inhibited) {
222 if (try) return 0;
223 break;
226 if (try) return 1;
228 /* Copy from user space to the RS232 output buffer. */
229 if (tp->tty_outcaller == KERNEL) {
230 /* We're trying to print on kernel's behalf */
231 memcpy(rs->ohead,
232 (void *) tp->tty_outgrant + tp->tty_outoffset,
233 count);
234 } else {
235 if ((r = sys_safecopyfrom(tp->tty_outcaller,
236 tp->tty_outgrant, tp->tty_outoffset,
237 (vir_bytes) rs->ohead, count)) != OK) {
238 return 0;
242 /* Perform output processing on the output buffer. */
243 out_process(tp, rs->obuf, rs->ohead, bufend(rs->obuf), &count,
244 &ocount);
245 if (count == 0) {
246 break;
249 /* Assume echoing messed up by output. */
250 tp->tty_reprint = TRUE;
252 /* Bookkeeping. */
253 rs->ocount += ocount;
254 rs_ostart(rs);
255 if ((rs->ohead += ocount) >= bufend(rs->obuf))
256 rs->ohead -= buflen(rs->obuf);
257 tp->tty_outoffset += count;
258 tp->tty_outcum += count;
259 if ((tp->tty_outleft -= count) == 0) {
260 /* Output is finished, reply to the writer. */
261 if(tp->tty_outrepcode == TTY_REVIVE) {
262 notify(tp->tty_outcaller);
263 tp->tty_outrevived = 1;
264 } else {
265 tty_reply(tp->tty_outrepcode, tp->tty_outcaller,
266 tp->tty_outproc, tp->tty_outcum);
267 tp->tty_outcum = 0;
272 if (tp->tty_outleft > 0 && tp->tty_termios.c_ospeed == B0) {
273 /* Oops, the line has hung up. */
274 if(tp->tty_outrepcode == TTY_REVIVE) {
275 notify(tp->tty_outcaller);
276 tp->tty_outrevived = 1;
277 } else {
278 tty_reply(tp->tty_outrepcode, tp->tty_outcaller,
279 tp->tty_outproc, EIO);
280 tp->tty_outleft = tp->tty_outcum = 0;
284 return 1;
287 static void
288 rs_echo(tty_t *tp, int character)
290 /* Echo one character. (Like rs_write, but only one character, optionally.) */
292 rs232_t *rs = tp->tty_priv;
293 int count, ocount;
295 ocount = buflen(rs->obuf) - rs->ocount;
296 if (ocount == 0) return; /* output buffer full */
297 count = 1;
298 *rs->ohead = character; /* add one character */
300 out_process(tp, rs->obuf, rs->ohead, bufend(rs->obuf), &count, &ocount);
301 if (count == 0) return;
303 rs->ocount += ocount;
304 rs_ostart(rs);
305 if ((rs->ohead += ocount) >= bufend(rs->obuf))
306 rs->ohead -= buflen(rs->obuf);
309 static int
310 rs_ioctl(tty_t *tp, int UNUSED(dummy))
312 /* Reconfigure the line as soon as the output has drained. */
313 rs232_t *rs = tp->tty_priv;
315 rs->drain = TRUE;
316 return 0; /* dummy */
319 static unsigned int
320 omap_get_divisor(rs232_t *rs, unsigned int baud)
322 /* Calculate divisor value. The 16750 has two oversampling modes to reach
323 * high baud rates with little error rate (see table 17-1 in OMAP TRM).
324 * Baud rates 460800, 921600, 1843200, and 3686400 use 13x oversampling,
325 * the other rates 16x. The baud rate is calculated as follows:
326 * baud rate = (functional clock / oversampling) / divisor.
329 unsigned int oversampling;
330 assert(baud != 0);
332 switch(baud) {
333 case B460800: /* Fall through */
334 case B921600: /* Fall through */
335 case B1843200: /* Fall through */
336 case B3686400: oversampling = 13; break;
337 default: oversampling = 16;
340 return (rs->uartclk / oversampling) / baud;
343 static int
344 termios_baud_rate(struct termios *term)
346 int baud;
347 switch(term->c_ospeed) {
348 case B0: term->c_ospeed = DFLT_BAUD; baud = termios_baud_rate(term);
349 case B300: baud = 300; break;
350 case B600: baud = 600; break;
351 case B1200: baud = 1200; break;
352 case B2400: baud = 2400; break;
353 case B4800: baud = 4800; break;
354 case B9600: baud = 9600; break;
355 case B38400: baud = 38400; break;
356 case B57600: baud = 57600; break;
357 case B115200: baud = 115200; break;
358 default: term->c_ospeed = DFLT_BAUD; baud = termios_baud_rate(term);
361 return baud;
363 static void rs_config(rs232_t *rs)
365 /* Set various line control parameters for RS232 I/O. */
366 tty_t *tp = rs->tty;
367 unsigned int divisor, efr, lcr, mcr, baud;
369 /* Fifo and DMA settings */
370 /* See OMAP35x TRM 17.5.1.1.2 */
371 lcr = serial_in(rs, OMAP3_LCR); /* 1a */
372 serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_B); /* 1b */
373 efr = serial_in(rs, OMAP3_EFR); /* 2a */
374 serial_out(rs, OMAP3_EFR, efr | UART_EFR_ECB); /* 2b */
375 serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_A); /* 3 */
376 mcr = serial_in(rs, OMAP3_MCR); /* 4a */
377 serial_out(rs, OMAP3_MCR, mcr | UART_MCR_TCRTLR); /* 4b */
378 /* Set up FIFO for 1 byte */
379 rs->fcr = 0;
380 rs->fcr &= ~OMAP_UART_FCR_RX_FIFO_TRIG_MASK;
381 rs->fcr |= (0x1 << OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT);
382 serial_out(rs, OMAP3_FCR, rs->fcr); /* 5 */
383 serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_B); /* 6 */
384 /* DMA triggers, not supported by this driver */ /* 7 */
385 rs->scr = OMAP_UART_SCR_RX_TRIG_GRANU1_MASK;
386 serial_out(rs, OMAP3_SCR, rs->scr); /* 8 */
387 serial_out(rs, OMAP3_EFR, efr); /* 9 */
388 serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_A); /* 10 */
389 serial_out(rs, OMAP3_MCR, mcr); /* 11 */
390 serial_out(rs, OMAP3_LCR, lcr); /* 12 */
392 /* RS232 needs to know the xoff character, and if CTS works. */
393 rs->oxoff = tp->tty_termios.c_cc[VSTOP];
394 rs->cts = (tp->tty_termios.c_cflag & CLOCAL) ? UART_MSR_CTS : 0;
395 baud = termios_baud_rate(&tp->tty_termios);
397 /* Look up the 16750 rate divisor from the output speed. */
398 divisor = omap_get_divisor(rs, baud);
399 rs->dll = divisor & 0xFF;
400 rs->dlh = divisor >> 8;
402 /* Compute line control flag bits. */
403 lcr = 0;
404 if (tp->tty_termios.c_cflag & PARENB) {
405 lcr |= UART_LCR_PARITY;
406 if (!(tp->tty_termios.c_cflag & PARODD)) lcr |= UART_LCR_EPAR;
408 if (tp->tty_termios.c_cflag & CSTOPB) lcr |= UART_LCR_STOP;
409 switch(tp->tty_termios.c_cflag & CSIZE) {
410 case CS5:
411 lcr |= UART_LCR_WLEN5;
412 break;
413 case CS6:
414 lcr |= UART_LCR_WLEN6;
415 break;
416 case CS7:
417 lcr |= UART_LCR_WLEN7;
418 break;
419 default:
420 case CS8:
421 lcr |= UART_LCR_WLEN8;
422 break;
425 /* Lock out interrupts while setting the speed. The receiver register
426 * is going to be hidden by the div_low register, but the input
427 * interrupt handler relies on reading it to clear the interrupt and
428 * avoid looping forever.
431 if (sys_irqdisable(&rs->irq_hook_id) != OK)
432 panic("unable to disable interrupts");
434 /* Select the baud rate divisor registers and change the rate. */
435 /* See OMAP35x TRM 17.5.1.1.3 */
436 serial_out(rs, OMAP3_MDR1, OMAP_MDR1_DISABLE); /* 1 */
437 serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_B); /* 2 */
438 efr = serial_in(rs, OMAP3_EFR); /* 3a */
439 serial_out(rs, OMAP3_EFR, efr | UART_EFR_ECB); /* 3b */
440 serial_out(rs, OMAP3_LCR, 0); /* 4 */
441 serial_out(rs, OMAP3_IER, 0); /* 5 */
442 serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_B); /* 6 */
443 serial_out(rs, OMAP3_DLL, rs->dll); /* 7 */
444 serial_out(rs, OMAP3_DLH, rs->dlh); /* 7 */
445 serial_out(rs, OMAP3_LCR, 0); /* 8 */
446 serial_out(rs, OMAP3_IER, rs->ier); /* 9 */
447 serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_B); /* 10 */
448 serial_out(rs, OMAP3_EFR, efr); /* 11 */
449 serial_out(rs, OMAP3_LCR, lcr); /* 12 */
450 if (baud > 230400 && baud != 3000000)
451 serial_out(rs, OMAP3_MDR1, OMAP_MDR1_MODE13X); /* 13 */
452 else
453 serial_out(rs, OMAP3_MDR1, OMAP_MDR1_MODE16X);
455 rs->ostate = devready(rs) | ORAW | OSWREADY; /* reads MSR */
456 if ((tp->tty_termios.c_lflag & IXON) && rs->oxoff != _POSIX_VDISABLE)
457 rs->ostate &= ~ORAW;
458 (void) serial_in(rs, OMAP3_IIR);
459 if (sys_irqenable(&rs->irq_hook_id) != OK)
460 panic("unable to enable interrupts");
463 void
464 rs_init(tty_t *tp)
466 /* Initialize RS232 for one line. */
467 register rs232_t *rs;
468 int line;
469 uart_port_t this_omap3;
470 char l[10];
471 struct minix_mem_range mr;
473 /* Associate RS232 and TTY structures. */
474 line = tp - &tty_table[NR_CONS];
476 /* See if kernel debugging is enabled; if so, don't initialize this
477 * serial line, making tty not look at the irq and returning ENXIO
478 * for all requests on it from userland. (The kernel will use it.)
480 if(env_get_param(SERVARNAME, l, sizeof(l)-1) == OK && atoi(l) == line){
481 printf("TTY: rs232 line %d not initialized (used by kernel)\n",
482 line);
483 return;
486 rs = tp->tty_priv = &rs_lines[line];
487 rs->tty = tp;
489 /* Set up input queue. */
490 rs->ihead = rs->itail = rs->ibuf;
492 this_omap3 = omap3[line];
493 if (this_omap3.base_addr == 0) return;
495 /* Configure memory access */
496 mr.mr_base = rs->phys_base;
497 mr.mr_limit = rs->phys_base + 0x100;
498 if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != OK) {
499 panic("Unable to request access to UART memory");
501 rs->phys_base = (vir_bytes) vm_map_phys(SELF,
502 (void *) this_omap3.base_addr, 0x100);
504 if (rs->phys_base == (vir_bytes) MAP_FAILED) {
505 panic("Unable to request access to UART memory");
507 rs->reg_offset = 2;
509 rs->uartclk = UART_FREQ;
510 rs->ohead = rs->otail = rs->obuf;
512 /* Override system default baud rate. We do this because u-boot
513 * configures the UART for a baud rate of 115200 b/s and the kernel
514 * directly sends data over serial out upon boot up. If we then
515 * suddenly change the settings, the output will be garbled during
516 * booting.
518 tp->tty_termios.c_ospeed = DFLT_BAUD;
520 /* Configure IRQ */
521 rs->irq = this_omap3.irq;
522 rs->irq_hook_id = 1 << line; /* call back with irq line number */
523 if (sys_irqsetpolicy(rs->irq, 0, &rs->irq_hook_id) != OK) {
524 printf("RS232: Couldn't obtain hook for irq %d\n", rs->irq);
525 } else {
526 if (sys_irqenable(&rs->irq_hook_id) != OK) {
527 printf("RS232: Couldn't enable irq %d (hooked)\n",
528 rs->irq);
531 rs_irq_set |= (1 << (rs->irq_hook_id + 1));
533 /* Enable interrupts */
534 rs_reset(rs);
535 rs->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_MSI;
536 rs_config(rs);
538 /* Fill in TTY function hooks. */
539 tp->tty_devread = rs_read;
540 tp->tty_devwrite = rs_write;
541 tp->tty_echo = rs_echo;
542 tp->tty_icancel = rs_icancel;
543 tp->tty_ocancel = rs_ocancel;
544 tp->tty_ioctl = rs_ioctl;
545 tp->tty_break = rs_break;
546 tp->tty_open = rs_open;
547 tp->tty_close = rs_close;
549 /* Tell external device we are ready. */
550 istart(rs);
553 void
554 rs_interrupt(message *m)
556 unsigned long irq_set;
557 int line;
558 rs232_t *rs;
560 irq_set = m->NOTIFY_ARG;
561 for (line = 0, rs = rs_lines; line < NR_RS_LINES; line++, rs++) {
562 if (irq_set & (1 << (rs->irq_hook_id+1))) {
563 rs232_handler(rs);
564 if (sys_irqenable(&rs->irq_hook_id) != OK)
565 panic("unable to enable interrupts");
570 static int
571 rs_icancel(tty_t *tp, int UNUSED(dummy))
573 /* Cancel waiting input. */
574 rs232_t *rs = tp->tty_priv;
576 rs->icount = 0;
577 rs->itail = rs->ihead;
578 istart(rs);
579 return 0; /* dummy */
582 static int
583 rs_ocancel(tty_t *tp, int UNUSED(dummy))
585 /* Cancel pending output. */
586 rs232_t *rs = tp->tty_priv;
588 rs->ostate &= ~(ODONE | OQUEUED);
589 rs->ocount = 0;
590 rs->otail = rs->ohead;
592 return 0; /* dummy */
595 static int
596 rs_read(tty_t *tp, int try)
598 /* Process characters from the circular input buffer. */
600 rs232_t *rs = tp->tty_priv;
601 int icount, count, ostate;
603 if (!(tp->tty_termios.c_cflag & CLOCAL)) {
604 if (try) return 1;
606 /* Send a SIGHUP if hangup detected. */
607 ostate = rs->ostate;
608 rs->ostate &= ~ODEVHUP; /* save ostate, clear DEVHUP */
609 if (ostate & ODEVHUP) {
610 sigchar(tp, SIGHUP, 1);
611 tp->tty_termios.c_ospeed = B0;/* Disable further I/O.*/
612 return 0;
616 if (try) {
617 return(rs->icount > 0);
620 while ((count = rs->icount) > 0) {
621 icount = bufend(rs->ibuf) - rs->itail;
622 if (count > icount) count = icount;
624 /* Perform input processing on (part of) the input buffer. */
625 if ((count = in_process(tp, rs->itail, count, -1)) == 0) break;
626 rs->icount -= count;
627 if (!rs->idevready && rs->icount < RS_ILOWWATER) istart(rs);
628 if ((rs->itail += count) == bufend(rs->ibuf))
629 rs->itail = rs->ibuf;
632 return 0;
635 static void
636 rs_ostart(rs232_t *rs)
638 /* Tell RS232 there is something waiting in the output buffer. */
640 rs->ostate |= OQUEUED;
641 if (txready(rs)) write_chars(rs);
644 static int
645 rs_break(tty_t *tp, int UNUSED(dummy))
647 /* Generate a break condition by setting the BREAK bit for 0.4 sec. */
648 rs232_t *rs = tp->tty_priv;
649 unsigned int lsr;
651 lsr = serial_in(rs, OMAP3_LSR);
652 serial_out(rs, OMAP3_LSR, lsr | UART_LSR_BI);
653 /* XXX */
654 /* milli_delay(400); */ /* ouch */
655 serial_out(rs, OMAP3_LSR, lsr);
656 return 0; /* dummy */
659 static int
660 rs_open(tty_t *tp, int UNUSED(dummy))
662 /* Set the speed to 115200 by default */
663 tp->tty_termios.c_ospeed = DFLT_BAUD;
664 return 0;
667 static int
668 rs_close(tty_t *tp, int UNUSED(dummy))
670 /* The line is closed; optionally hang up. */
671 rs232_t *rs = tp->tty_priv;
673 if (tp->tty_termios.c_cflag & HUPCL) {
674 serial_out(rs, OMAP3_MCR, UART_MCR_OUT2|UART_MCR_RTS);
675 if (rs->ier & UART_IER_THRI) {
676 rs->ier &= ~UART_IER_THRI;
677 serial_out(rs, OMAP3_IER, rs->ier);
680 return 0; /* dummy */
683 /* Low level (interrupt) routines. */
685 static void
686 rs232_handler(struct rs232 *rs)
688 /* Handle interrupt of a UART port */
689 unsigned int iir, lsr;
691 iir = serial_in(rs, OMAP3_IIR);
692 if (iir & UART_IIR_NO_INT) /* No interrupt */
693 return;
695 lsr = serial_in(rs, OMAP3_LSR);
696 if (iir & UART_IIR_RDI) { /* Data ready interrupt */
697 if (lsr & UART_LSR_DR) {
698 read_chars(rs, lsr);
701 check_modem_status(rs);
702 if (iir & UART_IIR_THRI) {
703 if (lsr & UART_LSR_THRE) {
704 /* Ready to send and space available */
705 write_chars(rs);
710 static void
711 read_chars(rs232_t *rs, unsigned int status)
713 unsigned char c;
714 unsigned int lsr;
716 lsr = status;
718 if (lsr & UART_LSR_DR) {
719 c = serial_in(rs, OMAP3_RHR);
720 if (!(rs->ostate & ORAW)) {
721 if (c == rs->oxoff) {
722 rs->ostate &= ~OSWREADY;
723 } else if (!(rs->ostate & OSWREADY)) {
724 rs->ostate = OSWREADY;
728 if (rs->icount == buflen(rs->ibuf)) {
729 printf("%s:%d buffer full, discarding byte\n",
730 __FUNCTION__, __LINE__);
731 return;
734 if (++rs->icount == RS_IHIGHWATER && rs->idevready) istop(rs);
735 *rs->ihead = c;
736 if (++rs->ihead == bufend(rs->ibuf)) rs->ihead = rs->ibuf;
737 if (rs->icount == 1) {
738 rs->tty->tty_events = 1;
743 static void
744 write_chars(rs232_t *rs)
746 /* If there is output to do and everything is ready, do it (local device is
747 * known ready).
748 * Notify TTY when the buffer goes empty.
751 if (rs->ostate >= (ODEVREADY | OQUEUED | OSWREADY)) {
752 /* Bit test allows ORAW and requires the others. */
753 serial_out(rs, OMAP3_THR, *rs->otail);
754 if (++rs->otail == bufend(rs->obuf))
755 rs->otail = rs->obuf;
756 if (--rs->ocount == 0) {
757 /* Turn on ODONE flag, turn off OQUEUED */
758 rs->ostate ^= (ODONE | OQUEUED);
759 rs->tty->tty_events = 1;
760 if (rs->ier & UART_IER_THRI) {
761 rs->ier &= ~UART_IER_THRI;
762 serial_out(rs, OMAP3_IER, rs->ier);
764 } else {
765 if (rs->icount == RS_OLOWWATER)
766 rs->tty->tty_events = 1;
767 if (!(rs->ier & UART_IER_THRI)) {
768 rs->ier |= UART_IER_THRI;
769 serial_out(rs, OMAP3_IER, rs->ier);
775 static unsigned int
776 check_modem_status(rs232_t *rs)
778 /* Check modem status */
780 unsigned int msr;
782 msr = serial_in(rs, OMAP3_MSR); /* Resets modem interrupt */
783 if ((msr & (UART_MSR_DCD|UART_MSR_DDCD)) == UART_MSR_DDCD) {
784 rs->ostate |= ODEVHUP;
785 rs->tty->tty_events = 1;
788 if (!devready(rs))
789 rs->ostate &= ~ODEVREADY;
790 else
791 rs->ostate |= ODEVREADY;
793 return msr;
796 #endif /* NR_RS_LINES > 0 */