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