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
readw(vir_bytes addr)164 readw(vir_bytes addr)
165 {
166 return *((volatile unsigned int *) addr);
167 }
168
169 static inline void
writew(vir_bytes addr,int val)170 writew(vir_bytes addr, int val)
171 {
172 *((volatile unsigned int *) addr) = val;
173 }
174
175 static inline unsigned int
serial_in(rs232_t * rs,int offset)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
serial_out(rs232_t * rs,int offset,int val)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
rs_reset(rs232_t * rs)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
rs_write(register tty_t * tp,int try)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
rs_echo(tty_t * tp,int character)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
rs_ioctl(tty_t * tp,int UNUSED (dummy))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
omap_get_divisor(rs232_t * rs,unsigned int baud)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
termios_baud_rate(struct termios * term)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 }
rs_config(rs232_t * rs)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
rs_init(tty_t * tp)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
rs_interrupt(message * m)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
rs_icancel(tty_t * tp,int UNUSED (dummy))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
rs_ocancel(tty_t * tp,int UNUSED (dummy))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
rs_read(tty_t * tp,int try)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
rs_ostart(rs232_t * rs)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
rs_break_on(tty_t * tp,int UNUSED (dummy))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
rs_break_off(tty_t * tp,int UNUSED (dummy))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
rs_open(tty_t * tp,int UNUSED (dummy))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
rs_close(tty_t * tp,int UNUSED (dummy))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
rs232_handler(struct rs232 * rs)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
read_chars(rs232_t * rs,unsigned int status)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
write_chars(rs232_t * rs)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
check_modem_status(rs232_t * rs)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