xref: /minix/minix/drivers/tty/tty/arch/earm/rs232.c (revision 7f5f010b)
1 #include <minix/config.h>
2 #include <minix/drivers.h>
3 #include <minix/vm.h>
4 #include <minix/type.h>
5 #include <minix/board.h>
6 #include <sys/mman.h>
7 #include <assert.h>
8 #include <signal.h>
9 #include <termios.h>
10 #include "omap_serial.h"
11 #include "tty.h"
12 
13 #if NR_RS_LINES > 0
14 
15 #define UART_FREQ       48000000L	/* timer frequency */
16 #if 0
17 #define DFLT_BAUD	TSPEED_DEF		/* default baud rate */
18 #else
19 #define DFLT_BAUD	B115200		/* default baud rate */
20 #endif
21 
22 
23 #define RS_IBUFSIZE          40960	/* RS232 input buffer size */
24 #define RS_OBUFSIZE          40960	/* RS232 output buffer size */
25 
26 /* Input buffer watermarks.
27  * The external device is asked to stop sending when the buffer
28  * exactly reaches high water, or when TTY requests it.  Sending restarts
29  * when the input buffer empties below the low watermark.
30  */
31 #define RS_ILOWWATER   (1 * RS_IBUFSIZE / 4)
32 #define RS_IHIGHWATER  (3 * RS_IBUFSIZE / 4)
33 
34 /* Output buffer low watermark.
35  * TTY is notified when the output buffer empties below the low watermark, so
36  * it may continue filling the buffer if doing a large write.
37  */
38 #define RS_OLOWWATER   (1 * RS_OBUFSIZE / 4)
39 
40 /* Macros to handle flow control.
41  * Interrupts must be off when they are used.
42  * Time is critical - already the function call for outb() is annoying.
43  * If outb() can be done in-line, tests to avoid it can be dropped.
44  * istart() tells external device we are ready by raising RTS.
45  * istop() tells external device we are not ready by dropping RTS.
46  * DTR is kept high all the time (it probably should be raised by open and
47  * dropped by close of the device).
48  * OUT2 is also kept high all the time.
49  */
50 #define istart(rs) \
51 	(serial_out((rs), OMAP3_MCR, UART_MCR_OUT2|UART_MCR_RTS|UART_MCR_DTR),\
52 		(rs)->idevready = TRUE)
53 #define istop(rs) \
54 	(serial_out((rs), OMAP3_MCR, UART_MCR_OUT2|UART_MCR_DTR), \
55 		(rs)->idevready = FALSE)
56 
57 /* Macro to tell if device is ready.  The rs->cts field is set to UART_MSR_CTS
58  * if CLOCAL is in effect for a line without a CTS wire.
59  */
60 #define devready(rs) ((serial_in(rs, OMAP3_MSR) | rs->cts) & UART_MSR_CTS)
61 
62 /* Macro to tell if transmitter is ready. */
63 #define txready(rs) (serial_in(rs, OMAP3_LSR) & UART_LSR_THRE)
64 
65 /* RS232 device structure, one per device. */
66 typedef struct rs232 {
67   tty_t *tty;			/* associated TTY structure */
68 
69   int icount;			/* number of bytes in the input buffer */
70   char *ihead;			/* next free spot in input buffer */
71   char *itail;			/* first byte to give to TTY */
72   char idevready;		/* nonzero if we are ready to receive (RTS) */
73   char cts;			/* normally 0, but MS_CTS if CLOCAL is set */
74 
75   unsigned char ostate;		/* combination of flags: */
76 #define ODONE          1	/* output completed (< output enable bits) */
77 #define ORAW           2	/* raw mode for xoff disable (< enab. bits) */
78 #define OWAKEUP        4	/* tty_wakeup() pending (asm code only) */
79 #define ODEVREADY UART_MSR_CTS	/* external device hardware ready (CTS) */
80 #define OQUEUED     0x20	/* output buffer not empty */
81 #define OSWREADY    0x40	/* external device software ready (no xoff) */
82 #define ODEVHUP  UART_MSR_DCD	/* external device has dropped carrier */
83 #define OSOFTBITS  (ODONE | ORAW | OWAKEUP | OQUEUED | OSWREADY)
84 				/* user-defined bits */
85 #if (OSOFTBITS | ODEVREADY | ODEVHUP) == OSOFTBITS
86 				/* a weak sanity check */
87 #error				/* bits are not unique */
88 #endif
89   unsigned char oxoff;		/* char to stop output */
90   char inhibited;		/* output inhibited? (follows tty_inhibited) */
91   char drain;			/* if set drain output and reconfigure line */
92   int ocount;			/* number of bytes in the output buffer */
93   char *ohead;			/* next free spot in output buffer */
94   char *otail;			/* next char to output */
95 
96   phys_bytes phys_base;		/* UART physical base address (I/O map) */
97   unsigned int reg_offset;	/* UART register offset */
98   unsigned int ier;		/* copy of ier register */
99   unsigned int scr;		/* copy of scr register */
100   unsigned int fcr;		/* copy of fcr register */
101   unsigned int dll;		/* copy of dll register */
102   unsigned int dlh;		/* copy of dlh register */
103   unsigned int uartclk;		/* UART clock rate */
104 
105   unsigned char lstatus;	/* last line status */
106   int rx_overrun_events;
107 
108   int irq;			/* irq for this line */
109   int irq_hook_id;		/* interrupt hook */
110   int irq_hook_kernel_id;	/* id as returned from sys_irqsetpolicy */
111 
112   char ibuf[RS_IBUFSIZE];	/* input buffer */
113   char obuf[RS_OBUFSIZE];	/* output buffer */
114 } rs232_t;
115 
116 static rs232_t rs_lines[NR_RS_LINES];
117 
118 typedef struct uart_port {
119 	phys_bytes base_addr;
120 	int irq;
121 } uart_port_t;
122 
123 /* OMAP3 UART base addresses. */
124 static uart_port_t dm37xx_ports[] = {
125   { OMAP3_UART1_BASE, 72},	/* UART1 */
126   { OMAP3_UART2_BASE, 73},	/* UART2 */
127   { OMAP3_UART3_BASE, 74},	/* UART3 */
128   { 0, 0 }
129 };
130 
131 static uart_port_t am335x_ports[] = {
132   {  0x44E09000 , 72 },	/* UART0 */
133   { 0, 0 },
134   { 0, 0 },
135   { 0, 0 }
136 };
137 
138 
139 static int rs_write(tty_t *tp, int try);
140 static void rs_echo(tty_t *tp, int c);
141 static int rs_ioctl(tty_t *tp, int try);
142 static void rs_config(rs232_t *rs);
143 static int rs_read(tty_t *tp, int try);
144 static int rs_icancel(tty_t *tp, int try);
145 static int rs_ocancel(tty_t *tp, int try);
146 static void rs_ostart(rs232_t *rs);
147 static int rs_break_on(tty_t *tp, int try);
148 static int rs_break_off(tty_t *tp, int try);
149 static int rs_close(tty_t *tp, int try);
150 static int rs_open(tty_t *tp, int try);
151 static void rs232_handler(rs232_t *rs);
152 static void rs_reset(rs232_t *rs);
153 static unsigned int check_modem_status(rs232_t *rs);
154 static int termios_baud_rate(struct termios *term);
155 
156 static inline unsigned int readw(vir_bytes addr);
157 static inline unsigned int serial_in(rs232_t *rs, int offset);
158 static inline void serial_out(rs232_t *rs, int offset, int val);
159 static inline void writew(vir_bytes addr, int val);
160 static void write_chars(rs232_t *rs);
161 static void read_chars(rs232_t *rs, unsigned int status);
162 
163 static inline unsigned int
164 readw(vir_bytes addr)
165 {
166 	return *((volatile unsigned int *) addr);
167 }
168 
169 static inline void
170 writew(vir_bytes addr, int val)
171 {
172 	*((volatile unsigned int *) addr) = val;
173 }
174 
175 static inline unsigned int
176 serial_in(rs232_t *rs, int offset)
177 {
178 	offset <<= rs->reg_offset;
179 	return readw(rs->phys_base + offset);
180 }
181 
182 static inline void
183 serial_out(rs232_t *rs, int offset, int val)
184 {
185 	offset <<= rs->reg_offset;
186 	writew(rs->phys_base + offset, val);
187 }
188 
189 static void
190 rs_reset(rs232_t *rs)
191 {
192 	u32_t syss;
193 
194 	serial_out(rs, OMAP3_SYSC, UART_SYSC_SOFTRESET);
195 
196 	/* Poll until done */
197 	do {
198 		syss = serial_in(rs, OMAP3_SYSS);
199 	} while (!(syss & UART_SYSS_RESETDONE));
200 }
201 
202 static int
203 rs_write(register tty_t *tp, int try)
204 {
205 /* (*devwrite)() routine for RS232. */
206 
207 	rs232_t *rs = tp->tty_priv;
208 	int r, count, ocount;
209 
210 	if (rs->inhibited != tp->tty_inhibited) {
211 		/* Inhibition state has changed. */
212 		rs->ostate |= OSWREADY;
213 		if (tp->tty_inhibited) rs->ostate &= ~OSWREADY;
214 		rs->inhibited = tp->tty_inhibited;
215 	}
216 
217 	if (rs->drain) {
218 		/* Wait for the line to drain then reconfigure and continue
219 		 * output. */
220 		if (rs->ocount > 0) return 0;
221 		rs->drain = FALSE;
222 		rs_config(rs);
223 	}
224 	/* While there is something to do. */
225 	for (;;) {
226 		ocount = buflen(rs->obuf) - rs->ocount;
227 		count = bufend(rs->obuf) - rs->ohead;
228 		if (count > ocount) count = ocount;
229 		if (count > tp->tty_outleft) count = tp->tty_outleft;
230 		if (count == 0 || tp->tty_inhibited) {
231 			if (try) return 0;
232 			break;
233 		}
234 
235 		if (try) return 1;
236 
237 		/* Copy from user space to the RS232 output buffer. */
238 		if (tp->tty_outcaller == KERNEL) {
239 			/* We're trying to print on kernel's behalf */
240 			memcpy(rs->ohead,
241 				(char *) tp->tty_outgrant + tp->tty_outcum,
242 				count);
243 		} else {
244 			if ((r = sys_safecopyfrom(tp->tty_outcaller,
245 				tp->tty_outgrant, tp->tty_outcum,
246 				(vir_bytes) rs->ohead, count)) != OK) {
247 				return 0;
248 			}
249 		}
250 
251 		/* Perform output processing on the output buffer. */
252 		out_process(tp, rs->obuf, rs->ohead, bufend(rs->obuf), &count,
253 		    &ocount);
254 		if (count == 0) {
255 			break;
256 		}
257 
258 		/* Assume echoing messed up by output. */
259 		tp->tty_reprint = TRUE;
260 
261 		/* Bookkeeping. */
262 		rs->ocount += ocount;
263 		rs_ostart(rs);
264 		if ((rs->ohead += ocount) >= bufend(rs->obuf))
265 			rs->ohead -= buflen(rs->obuf);
266 		tp->tty_outcum += count;
267 		if ((tp->tty_outleft -= count) == 0) {
268 			/* Output is finished, reply to the writer. */
269 			if (tp->tty_outcaller != KERNEL)
270 				chardriver_reply_task(tp->tty_outcaller,
271 					tp->tty_outid, tp->tty_outcum);
272 			tp->tty_outcum = 0;
273 			tp->tty_outcaller = NONE;
274 		}
275 
276 	}
277 	if (tp->tty_outleft > 0 && tp->tty_termios.c_ospeed == B0) {
278 		/* Oops, the line has hung up. */
279 		if (tp->tty_outcaller != KERNEL)
280 			chardriver_reply_task(tp->tty_outcaller, tp->tty_outid,
281 				EIO);
282 		tp->tty_outleft = tp->tty_outcum = 0;
283 		tp->tty_outcaller = NONE;
284 	}
285 
286 	return 1;
287 }
288 
289 static void
290 rs_echo(tty_t *tp, int character)
291 {
292 /* Echo one character.  (Like rs_write, but only one character, optionally.) */
293 
294 	rs232_t *rs = tp->tty_priv;
295 	int count, ocount;
296 
297 	ocount = buflen(rs->obuf) - rs->ocount;
298 	if (ocount == 0) return;		/* output buffer full */
299 	count = 1;
300 	*rs->ohead = character;			/* add one character */
301 
302 	out_process(tp, rs->obuf, rs->ohead, bufend(rs->obuf), &count, &ocount);
303 	if (count == 0) return;
304 
305 	rs->ocount += ocount;
306 	rs_ostart(rs);
307 	if ((rs->ohead += ocount) >= bufend(rs->obuf))
308 		rs->ohead -= buflen(rs->obuf);
309 }
310 
311 static int
312 rs_ioctl(tty_t *tp, int UNUSED(dummy))
313 {
314 /* Reconfigure the line as soon as the output has drained. */
315 	rs232_t *rs = tp->tty_priv;
316 
317 	rs->drain = TRUE;
318 	return 0;	/* dummy */
319 }
320 
321 static unsigned int
322 omap_get_divisor(rs232_t *rs, unsigned int baud)
323 {
324 /* Calculate divisor value. The 16750 has two oversampling modes to reach
325  * high baud rates with little error rate (see table 17-1 in OMAP TRM).
326  * Baud rates 460800, 921600, 1843200, and 3686400 use 13x oversampling,
327  * the other rates 16x. The baud rate is calculated as follows:
328  * baud rate = (functional clock / oversampling) / divisor.
329  */
330 
331 	unsigned int oversampling;
332 	assert(baud != 0);
333 
334 	switch(baud) {
335 	case B460800:	/* Fall through */
336 	case B921600:	/* Fall through */
337 #if 0
338 	case B1843200:	/* Fall through */
339 	case B3686400:
340 #endif
341 		oversampling = 13; break;
342 	default:	oversampling = 16;
343 	}
344 
345 	return (rs->uartclk / oversampling) / baud;
346 }
347 
348 static int
349 termios_baud_rate(struct termios *term)
350 {
351 	int baud;
352 	switch(term->c_ospeed) {
353 	case B300: baud = 300; break;
354 	case B600: baud = 600; break;
355 	case B1200: baud = 1200; break;
356 	case B2400: baud = 2400; break;
357 	case B4800: baud = 4800; break;
358 	case B9600: baud = 9600; break;
359 	case B38400: baud = 38400; break;
360 	case B57600: baud = 57600; break;
361 	case B115200: baud = 115200; break;
362 	case B0:
363 	default:
364 		/* Reset the speed to the default speed, then call ourselves
365 		 * to convert the default speed to a baudrate. This call will
366 		 * always return a value without inducing another recursive
367 		 * call. */
368 		term->c_ospeed = DFLT_BAUD;
369 		baud = termios_baud_rate(term);
370 	}
371 
372 	return baud;
373 }
374 static void rs_config(rs232_t *rs)
375 {
376 /* Set various line control parameters for RS232 I/O.  */
377 	tty_t *tp = rs->tty;
378 	unsigned int divisor, efr, lcr, mcr, baud;
379 
380 	/* Fifo and DMA settings */
381 	/* See OMAP35x TRM 17.5.1.1.2 */
382 	lcr = serial_in(rs, OMAP3_LCR);				/* 1a */
383 	serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_B);	/* 1b */
384 	efr = serial_in(rs, OMAP3_EFR);				/* 2a */
385 	serial_out(rs, OMAP3_EFR, efr | UART_EFR_ECB);		/* 2b */
386 	serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_A);	/* 3  */
387 	mcr = serial_in(rs, OMAP3_MCR);				/* 4a */
388 	serial_out(rs, OMAP3_MCR, mcr | UART_MCR_TCRTLR);	/* 4b */
389 	/* Set up FIFO  */
390 	rs->fcr = 0;
391 	/* Set FIFO interrupt trigger levels high */
392 	rs->fcr |= (0x3 << OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT);
393 	rs->fcr |= (0x3 << OMAP_UART_FCR_TX_FIFO_TRIG_SHIFT);
394 	rs->fcr |= UART_FCR_ENABLE_FIFO;
395 	serial_out(rs, OMAP3_FCR, rs->fcr);			/* 5  */
396 	serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_B);	/* 6  */
397 	/* DMA triggers, not supported by this driver */	/* 7  */
398 	rs->scr = OMAP_UART_SCR_RX_TRIG_GRANU1_MASK;
399 	serial_out(rs, OMAP3_SCR, rs->scr);			/* 8  */
400 	serial_out(rs, OMAP3_EFR, efr);				/* 9  */
401 	serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_A);	/* 10 */
402 	serial_out(rs, OMAP3_MCR, mcr);				/* 11 */
403 	serial_out(rs, OMAP3_LCR, lcr);				/* 12 */
404 
405 	/* RS232 needs to know the xoff character, and if CTS works. */
406 	rs->oxoff = tp->tty_termios.c_cc[VSTOP];
407 	rs->cts = (tp->tty_termios.c_cflag & CLOCAL) ? UART_MSR_CTS : 0;
408 	baud = termios_baud_rate(&tp->tty_termios);
409 
410 	/* Look up the 16750 rate divisor from the output speed. */
411 	divisor = omap_get_divisor(rs, baud);
412 	rs->dll = divisor & 0xFF;
413 	rs->dlh = divisor >> 8;
414 
415 	/* Compute line control flag bits. */
416 	lcr = 0;
417 	if (tp->tty_termios.c_cflag & PARENB) {
418 		lcr |= UART_LCR_PARITY;
419 		if (!(tp->tty_termios.c_cflag & PARODD)) lcr |= UART_LCR_EPAR;
420   	}
421   	if (tp->tty_termios.c_cflag & CSTOPB) lcr |= UART_LCR_STOP;
422   	switch(tp->tty_termios.c_cflag & CSIZE) {
423   	case CS5:
424   		lcr |= UART_LCR_WLEN5;
425   		break;
426   	case CS6:
427   		lcr |= UART_LCR_WLEN6;
428   		break;
429   	case CS7:
430   		lcr |= UART_LCR_WLEN7;
431   		break;
432   	default:
433   	case CS8:
434   		lcr |= UART_LCR_WLEN8;
435   		break;
436   	}
437 
438 	/* Lock out interrupts while setting the speed. The receiver register
439 	 * is going to be hidden by the div_low register, but the input
440 	 * interrupt handler relies on reading it to clear the interrupt and
441 	 * avoid looping forever.
442 	 */
443 
444 	if (sys_irqdisable(&rs->irq_hook_kernel_id) != OK)
445 		panic("unable to disable interrupts");
446 
447 	/* Select the baud rate divisor registers and change the rate. */
448 	/* See OMAP35x TRM 17.5.1.1.3 */
449 	serial_out(rs, OMAP3_MDR1, OMAP_MDR1_DISABLE);		/* 1  */
450 	serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_B);	/* 2  */
451 	efr = serial_in(rs, OMAP3_EFR);				/* 3a */
452 	serial_out(rs, OMAP3_EFR, efr | UART_EFR_ECB);		/* 3b */
453 	serial_out(rs, OMAP3_LCR, 0);				/* 4  */
454 	serial_out(rs, OMAP3_IER, 0);				/* 5  */
455 	serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_B);	/* 6  */
456 	serial_out(rs, OMAP3_DLL, rs->dll);			/* 7  */
457 	serial_out(rs, OMAP3_DLH, rs->dlh);			/* 7  */
458 	serial_out(rs, OMAP3_LCR, 0);				/* 8  */
459 	serial_out(rs, OMAP3_IER, rs->ier);			/* 9  */
460 	serial_out(rs, OMAP3_LCR, UART_LCR_CONF_MODE_B);	/* 10 */
461 	serial_out(rs, OMAP3_EFR, efr);				/* 11 */
462 	serial_out(rs, OMAP3_LCR, lcr);				/* 12 */
463 	if (baud > 230400 && baud != 3000000)
464 		serial_out(rs, OMAP3_MDR1, OMAP_MDR1_MODE13X);	/* 13 */
465 	else
466 		serial_out(rs, OMAP3_MDR1, OMAP_MDR1_MODE16X);
467 
468 	rs->ostate = devready(rs) | ORAW | OSWREADY;	/* reads MSR */
469 	if ((tp->tty_termios.c_lflag & IXON) && rs->oxoff != _POSIX_VDISABLE)
470 		rs->ostate &= ~ORAW;
471 	(void) serial_in(rs, OMAP3_IIR);
472 
473 	if (sys_irqenable(&rs->irq_hook_kernel_id) != OK)
474 		panic("unable to enable interrupts");
475 }
476 
477 void
478 rs_init(tty_t *tp)
479 {
480 /* Initialize RS232 for one line. */
481 	register rs232_t *rs;
482 	int line;
483 	uart_port_t this_omap3;
484 	char l[10];
485 	struct minix_mem_range mr;
486 	struct machine machine;
487 
488 	/* Associate RS232 and TTY structures. */
489 	line = tp - &tty_table[NR_CONS];
490 
491 	/* See if kernel debugging is enabled; if so, don't initialize this
492 	 * serial line, making tty not look at the irq and returning ENXIO
493 	 * for all requests on it from userland. (The kernel will use it.)
494 	 */
495 	if(env_get_param(SERVARNAME, l, sizeof(l)-1) == OK && atoi(l) == line){
496 		printf("TTY: rs232 line %d not initialized (used by kernel)\n",
497 			line);
498 		return;
499 	}
500 
501 	rs = tp->tty_priv = &rs_lines[line];
502 	rs->tty = tp;
503 
504 	/* Set up input queue. */
505 	rs->ihead = rs->itail = rs->ibuf;
506 
507 	sys_getmachine(&machine);
508 
509 	if (BOARD_IS_BBXM(machine.board_id)){
510 		this_omap3 = dm37xx_ports[line];
511 	} else if (BOARD_IS_BB(machine.board_id)){
512 		this_omap3 = am335x_ports[line];
513 	} else {
514 		return;
515 	}
516 	if (this_omap3.base_addr == 0) return;
517 
518 	/* Configure memory access */
519 	mr.mr_base = rs->phys_base;
520 	mr.mr_limit = rs->phys_base + 0x100;
521 	if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != OK) {
522 		panic("Unable to request access to UART memory");
523 	}
524 	rs->phys_base = (vir_bytes) vm_map_phys(SELF,
525 					(void *) this_omap3.base_addr, 0x100);
526 
527 	if (rs->phys_base ==  (vir_bytes) MAP_FAILED) {
528 		panic("Unable to request access to UART memory");
529 	}
530 	rs->reg_offset = 2;
531 
532 	rs->uartclk = UART_FREQ;
533 	rs->ohead = rs->otail = rs->obuf;
534 
535 	/* Override system default baud rate. We do this because u-boot
536 	 * configures the UART for a baud rate of 115200 b/s and the kernel
537 	 * directly sends data over serial out upon boot up. If we then
538 	 * suddenly change the settings, the output will be garbled during
539 	 * booting.
540 	 */
541 	tp->tty_termios.c_ospeed = DFLT_BAUD;
542 
543 	/* Configure IRQ */
544 	rs->irq = this_omap3.irq;
545 
546 	/* callback with irq line number + 1 because using line number 0
547 	   fails eslewhere */
548 	rs->irq_hook_kernel_id = rs->irq_hook_id = line + 1;
549 
550 	/* sys_irqsetpolicy modifies irq_hook_kernel_id. this modified id
551 	 * needs to be used in sys_irqenable and similar calls.
552 	 */
553 	if (sys_irqsetpolicy(rs->irq, 0, &rs->irq_hook_kernel_id) != OK) {
554 		printf("RS232: Couldn't obtain hook for irq %d\n", rs->irq);
555 	} else {
556 		if (sys_irqenable(&rs->irq_hook_kernel_id) != OK)  {
557 			printf("RS232: Couldn't enable irq %d (hooked)\n",
558 				rs->irq);
559 		}
560 	}
561 
562 	/* When we get called back we get called back using the original
563 	 * hook_id bit set. e.g. if we register with hook_id 5 the callback
564 	 * calls us with the 5 th bit set */
565 	rs_irq_set |= (1 << (rs->irq_hook_id ));
566 
567 	/* Enable interrupts */
568 	rs_reset(rs);
569 	rs->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_MSI;
570 	rs_config(rs);
571 
572 	/* Fill in TTY function hooks. */
573 	tp->tty_devread = rs_read;
574 	tp->tty_devwrite = rs_write;
575 	tp->tty_echo = rs_echo;
576 	tp->tty_icancel = rs_icancel;
577 	tp->tty_ocancel = rs_ocancel;
578 	tp->tty_ioctl = rs_ioctl;
579 	tp->tty_break_on = rs_break_on;
580 	tp->tty_break_off = rs_break_off;
581 	tp->tty_open = rs_open;
582 	tp->tty_close = rs_close;
583 
584 	/* Tell external device we are ready. */
585 	istart(rs);
586 }
587 
588 void
589 rs_interrupt(message *m)
590 {
591 	unsigned long irq_set;
592 	int line;
593 	rs232_t *rs;
594 
595 	irq_set = m->m_notify.interrupts;
596 	for (line = 0, rs = rs_lines; line < NR_RS_LINES; line++, rs++) {
597 		if (irq_set & (1 << rs->irq_hook_id)) {
598 			rs232_handler(rs);
599 			if (sys_irqenable(&rs->irq_hook_kernel_id) != OK)
600 				panic("unable to enable interrupts");
601 		}
602 	}
603 }
604 
605 static int
606 rs_icancel(tty_t *tp, int UNUSED(dummy))
607 {
608 /* Cancel waiting input. */
609 	rs232_t *rs = tp->tty_priv;
610 
611 	rs->icount = 0;
612 	rs->itail = rs->ihead;
613 	istart(rs);
614 	return 0;	/* dummy */
615 }
616 
617 static int
618 rs_ocancel(tty_t *tp, int UNUSED(dummy))
619 {
620 /* Cancel pending output. */
621 	rs232_t *rs = tp->tty_priv;
622 
623 	rs->ostate &= ~(ODONE | OQUEUED);
624 	rs->ocount = 0;
625 	rs->otail = rs->ohead;
626 
627 	return 0;	/* dummy */
628 }
629 
630 static int
631 rs_read(tty_t *tp, int try)
632 {
633 /* Process characters from the circular input buffer. */
634 
635 	rs232_t *rs = tp->tty_priv;
636 	int icount, count, ostate;
637 
638 	if (!(tp->tty_termios.c_cflag & CLOCAL)) {
639 		if (try) return 1;
640 
641 		/* Send a SIGHUP if hangup detected. */
642 		ostate = rs->ostate;
643 		rs->ostate &= ~ODEVHUP;		/* save ostate, clear DEVHUP */
644 		if (ostate & ODEVHUP) {
645 			sigchar(tp, SIGHUP, 1);
646 			tp->tty_termios.c_ospeed = B0;/* Disable further I/O.*/
647 			return 0;
648 		}
649 	}
650 
651 	if (try) {
652 		return(rs->icount > 0);
653 	}
654 
655 	while ((count = rs->icount) > 0) {
656 		icount = bufend(rs->ibuf) - rs->itail;
657 		if (count > icount) count = icount;
658 
659 		/* Perform input processing on (part of) the input buffer. */
660 		if ((count = in_process(tp, rs->itail, count)) == 0) break;
661 		rs->icount -= count;
662 		if (!rs->idevready && rs->icount < RS_ILOWWATER) istart(rs);
663 		if ((rs->itail += count) == bufend(rs->ibuf))
664 			rs->itail = rs->ibuf;
665 	}
666 
667 	return 0;
668 }
669 
670 static void
671 rs_ostart(rs232_t *rs)
672 {
673 /* Tell RS232 there is something waiting in the output buffer. */
674 
675 	rs->ostate |= OQUEUED;
676 	if (txready(rs)) write_chars(rs);
677 }
678 
679 static int
680 rs_break_on(tty_t *tp, int UNUSED(dummy))
681 {
682 /* Raise break condition */
683 	rs232_t *rs = tp->tty_priv;
684 	unsigned int lsr;
685 
686 	lsr = serial_in(rs, OMAP3_LSR);
687 	serial_out(rs, OMAP3_LSR, lsr | UART_LSR_BI);
688 	return 0;	/* dummy */
689 }
690 
691 static int
692 rs_break_off(tty_t *tp, int UNUSED(dummy))
693 {
694 /* Clear break condition */
695 	rs232_t *rs = tp->tty_priv;
696 	unsigned int lsr;
697 
698 	lsr = serial_in(rs, OMAP3_LSR);
699 	serial_out(rs, OMAP3_LSR, lsr & ~UART_LSR_BI);
700 	return 0;	/* dummy */
701 }
702 
703 static int
704 rs_open(tty_t *tp, int UNUSED(dummy))
705 {
706 	/* Set the speed to 115200 by default */
707 	tp->tty_termios.c_ospeed = DFLT_BAUD;
708 	return 0;
709 }
710 
711 static int
712 rs_close(tty_t *tp, int UNUSED(dummy))
713 {
714 /* The line is closed; optionally hang up. */
715 	rs232_t *rs = tp->tty_priv;
716 
717 	if (tp->tty_termios.c_cflag & HUPCL) {
718 		serial_out(rs, OMAP3_MCR, UART_MCR_OUT2|UART_MCR_RTS);
719 		if (rs->ier & UART_IER_THRI) {
720 			rs->ier &= ~UART_IER_THRI;
721 			serial_out(rs, OMAP3_IER, rs->ier);
722 		}
723 	}
724 	return 0;	/* dummy */
725 }
726 
727 /* Low level (interrupt) routines. */
728 
729 static void
730 rs232_handler(struct rs232 *rs)
731 {
732 /* Handle interrupt of a UART port */
733 	unsigned int iir, lsr;
734 
735 	iir = serial_in(rs, OMAP3_IIR);
736 	if (iir & UART_IIR_NO_INT)	/* No interrupt */
737 		return;
738 
739 	lsr = serial_in(rs, OMAP3_LSR);
740 	if (iir & UART_IIR_RDI) {	/* Data ready interrupt */
741 		if (lsr & UART_LSR_DR)  {
742 			read_chars(rs, lsr);
743 		}
744 	}
745 	check_modem_status(rs);
746 	if (iir & UART_IIR_THRI) {
747 		if (lsr & UART_LSR_THRE) {
748 			/* Ready to send and space available */
749 			write_chars(rs);
750 		}
751 	}
752 }
753 
754 static void
755 read_chars(rs232_t *rs, unsigned int status)
756 {
757 	unsigned char c;
758 
759 	if(serial_in(rs,OMAP3_LSR) & OMAP3_LSR_RXOE) {
760 		rs->rx_overrun_events++;
761 	}
762 
763 	/* check the line status to know if there are more chars */
764 	while (serial_in(rs, OMAP3_LSR) &  UART_LSR_DR) {
765 		c = serial_in(rs, OMAP3_RHR);
766 		if (!(rs->ostate & ORAW)) {
767 			if (c == rs->oxoff) {
768 				rs->ostate &= ~OSWREADY;
769 			} else if (!(rs->ostate & OSWREADY)) {
770 				rs->ostate = OSWREADY;
771 			}
772 		}
773 
774 		if (rs->icount == buflen(rs->ibuf)) {
775 			/* no buffer space? keep reading */
776 			continue;
777 		}
778 
779 		if (++rs->icount == RS_IHIGHWATER && rs->idevready) {
780 			 istop(rs);
781 		}
782 
783 		*rs->ihead = c;
784 		if (++rs->ihead == bufend(rs->ibuf)) {
785 			rs->ihead = rs->ibuf;
786 		}
787 
788 		if (rs->icount == 1) {
789 			rs->tty->tty_events = 1;
790 		}
791 	}
792 }
793 
794 static void
795 write_chars(rs232_t *rs)
796 {
797 /* If there is output to do and everything is ready, do it (local device is
798  * known ready).
799  * Notify TTY when the buffer goes empty.
800  */
801 
802 	if (rs->ostate >= (ODEVREADY | OQUEUED | OSWREADY)) {
803 		/* Bit test allows ORAW and requires the others. */
804 		serial_out(rs, OMAP3_THR, *rs->otail);
805 		if (++rs->otail == bufend(rs->obuf))
806 			rs->otail = rs->obuf;
807 		if (--rs->ocount == 0) {
808 			/* Turn on ODONE flag, turn off OQUEUED */
809 			rs->ostate ^= (ODONE | OQUEUED);
810 			rs->tty->tty_events = 1;
811 			if (rs->ier & UART_IER_THRI) {
812 				rs->ier &= ~UART_IER_THRI;
813 				serial_out(rs, OMAP3_IER, rs->ier);
814 			}
815 		} else  {
816 			if (rs->icount == RS_OLOWWATER)
817 				rs->tty->tty_events = 1;
818 			if (!(rs->ier & UART_IER_THRI)) {
819 				rs->ier |= UART_IER_THRI;
820 				serial_out(rs, OMAP3_IER, rs->ier);
821 			}
822 		}
823 	}
824 }
825 
826 static unsigned int
827 check_modem_status(rs232_t *rs)
828 {
829 /* Check modem status */
830 
831 	unsigned int msr;
832 
833 	msr = serial_in(rs, OMAP3_MSR); /* Resets modem interrupt */
834 	if ((msr & (UART_MSR_DCD|UART_MSR_DDCD)) == UART_MSR_DDCD) {
835 		rs->ostate |= ODEVHUP;
836 		rs->tty->tty_events = 1;
837 	}
838 
839 	if (!devready(rs))
840 		rs->ostate &= ~ODEVREADY;
841 	else
842 		rs->ostate |= ODEVREADY;
843 
844 	return msr;
845 }
846 
847 #endif /* NR_RS_LINES > 0 */
848 
849