1 #include <minix/config.h>
2 /*---------------------------------------------------------------------------*
3 * rs232.c - serial driver for 8250 and 16450 UARTs *
4 * Added support for Atari ST M68901 and YM-2149 --kub *
5 *---------------------------------------------------------------------------*/
7 #include <minix/drivers.h>
15 #define UART_FREQ 115200L /* timer frequency */
17 /* Interrupt enable bits. */
18 #define IE_RECEIVER_READY 1
19 #define IE_TRANSMITTER_READY 2
20 #define IE_LINE_STATUS_CHANGE 4
21 #define IE_MODEM_STATUS_CHANGE 8
23 /* Interrupt status bits. */
24 #define IS_MODEM_STATUS_CHANGE 0
25 #define IS_TRANSMITTER_READY 2
26 #define IS_RECEIVER_READY 4
27 #define IS_LINE_STATUS_CHANGE 6
29 /* Line control bits. */
30 #define LC_2STOP_BITS 0x04
31 #define LC_PARITY 0x08
32 #define LC_PAREVEN 0x10
34 #define LC_ADDRESS_DIVISOR 0x80
36 /* Line status bits. */
37 #define LS_OVERRUN_ERR 2
38 #define LS_PARITY_ERR 4
39 #define LS_FRAMING_ERR 8
40 #define LS_BREAK_INTERRUPT 0x10
41 #define LS_TRANSMITTER_READY 0x20
43 /* Modem control bits. */
46 #define MC_OUT2 8 /* required for PC & AT interrupts */
48 /* Modem status bits. */
50 #define MS_RLSD 0x80 /* Received Line Signal Detect */
51 #define MS_DRLSD 0x08 /* RLSD Delta */
53 #define DATA_BITS_SHIFT 8 /* amount data bits shifted in mode */
54 #define DEF_BAUD 1200 /* default baud rate */
56 #define RS_IBUFSIZE 1024 /* RS232 input buffer size */
57 #define RS_OBUFSIZE 1024 /* RS232 output buffer size */
59 /* Input buffer watermarks.
60 * The external device is asked to stop sending when the buffer
61 * exactly reaches high water, or when TTY requests it. Sending restarts
62 * when the input buffer empties below the low watermark.
64 #define RS_ILOWWATER (1 * RS_IBUFSIZE / 4)
65 #define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)
67 /* Output buffer low watermark.
68 * TTY is notified when the output buffer empties below the low watermark, so
69 * it may continue filling the buffer if doing a large write.
71 #define RS_OLOWWATER (1 * RS_OBUFSIZE / 4)
73 /* Macros to handle flow control.
74 * Interrupts must be off when they are used.
75 * Time is critical - already the function call for outb() is annoying.
76 * If outb() can be done in-line, tests to avoid it can be dropped.
77 * istart() tells external device we are ready by raising RTS.
78 * istop() tells external device we are not ready by dropping RTS.
79 * DTR is kept high all the time (it probably should be raised by open and
80 * dropped by close of the device).
81 * OUT2 is also kept high all the time.
84 (sys_outb((rs)->modem_ctl_port, MC_OUT2 | MC_RTS | MC_DTR), \
85 (rs)->idevready = TRUE)
87 (sys_outb((rs)->modem_ctl_port, MC_OUT2 | MC_DTR), \
88 (rs)->idevready = FALSE)
90 /* Macro to tell if device is ready. The rs->cts field is set to MS_CTS if
91 * CLOCAL is in effect for a line without a CTS wire.
93 #define devready(rs) ((my_inb(rs->modem_status_port) | rs->cts) & MS_CTS)
95 /* Macro to tell if transmitter is ready. */
96 #define txready(rs) (my_inb(rs->line_status_port) & LS_TRANSMITTER_READY)
98 /* Macro to tell if carrier has dropped.
99 * The RS232 Carrier Detect (CD) line is usually connected to the 8250
100 * Received Line Signal Detect pin, reflected by bit MS_RLSD in the Modem
101 * Status Register. The MS_DRLSD bit tells if MS_RLSD has just changed state.
102 * So if MS_DRLSD is set and MS_RLSD cleared, we know that carrier has just
106 ((my_inb(rs->modem_status_port) & (MS_RLSD|MS_DRLSD)) == MS_DRLSD)
109 typedef unsigned char bool_t
; /* boolean */
111 /* RS232 device structure, one per device. */
112 typedef struct rs232
{
113 tty_t
*tty
; /* associated TTY structure */
115 int icount
; /* number of bytes in the input buffer */
116 char *ihead
; /* next free spot in input buffer */
117 char *itail
; /* first byte to give to TTY */
118 bool_t idevready
; /* nonzero if we are ready to receive (RTS) */
119 char cts
; /* normally 0, but MS_CTS if CLOCAL is set */
121 unsigned char ostate
; /* combination of flags: */
122 #define ODONE 1 /* output completed (< output enable bits) */
123 #define ORAW 2 /* raw mode for xoff disable (< enab. bits) */
124 #define OWAKEUP 4 /* tty_wakeup() pending (asm code only) */
125 #define ODEVREADY MS_CTS /* external device hardware ready (CTS) */
126 #define OQUEUED 0x20 /* output buffer not empty */
127 #define OSWREADY 0x40 /* external device software ready (no xoff) */
128 #define ODEVHUP MS_RLSD /* external device has dropped carrier */
129 #define OSOFTBITS (ODONE | ORAW | OWAKEUP | OQUEUED | OSWREADY)
130 /* user-defined bits */
131 #if (OSOFTBITS | ODEVREADY | ODEVHUP) == OSOFTBITS
132 /* a weak sanity check */
133 #error /* bits are not unique */
135 unsigned char oxoff
; /* char to stop output */
136 bool_t inhibited
; /* output inhibited? (follows tty_inhibited) */
137 bool_t drain
; /* if set drain output and reconfigure line */
138 int ocount
; /* number of bytes in the output buffer */
139 char *ohead
; /* next free spot in output buffer */
140 char *otail
; /* next char to output */
142 #if defined(__i386__)
143 port_t xmit_port
; /* i/o ports */
147 port_t int_enab_port
;
149 port_t line_ctl_port
;
150 port_t modem_ctl_port
;
151 port_t line_status_port
;
152 port_t modem_status_port
;
155 unsigned char lstatus
; /* last line status */
156 unsigned char pad
; /* ensure alignment for 16-bit ints */
157 unsigned framing_errors
; /* error counts (no reporting yet) */
158 unsigned overrun_errors
;
159 unsigned parity_errors
;
160 unsigned break_interrupts
;
162 int irq
; /* irq for this line */
163 int irq_hook_id
; /* interrupt hook */
165 char ibuf
[RS_IBUFSIZE
]; /* input buffer */
166 char obuf
[RS_OBUFSIZE
]; /* output buffer */
169 static rs232_t rs_lines
[NR_RS_LINES
];
171 #if defined(__i386__)
172 /* 8250 base addresses. */
173 static port_t addr_8250
[] = {
181 static void in_int(rs232_t
*rs
);
182 static void line_int(rs232_t
*rs
);
183 static void modem_int(rs232_t
*rs
);
184 static int rs_write(tty_t
*tp
, int try);
185 static void rs_echo(tty_t
*tp
, int c
);
186 static int rs_ioctl(tty_t
*tp
, int try);
187 static void rs_config(rs232_t
*rs
);
188 static int rs_read(tty_t
*tp
, int try);
189 static int rs_icancel(tty_t
*tp
, int try);
190 static int rs_ocancel(tty_t
*tp
, int try);
191 static void rs_ostart(rs232_t
*rs
);
192 static int rs_break(tty_t
*tp
, int try);
193 static int rs_close(tty_t
*tp
, int try);
194 static void out_int(rs232_t
*rs
);
195 static void rs232_handler(rs232_t
*rs
);
198 static void lock(void) {}
199 static void unlock(void) {}
201 static int my_inb(port_t port
)
205 r
= sys_inb(port
, &v
);
207 printf("RS232 warning: failed inb 0x%x\n", port
);
212 /*===========================================================================*
214 *===========================================================================*/
215 static int rs_write(register tty_t
*tp
, int try)
217 /* (*devwrite)() routine for RS232. */
219 rs232_t
*rs
= tp
->tty_priv
;
220 int r
, count
, ocount
;
222 if (rs
->inhibited
!= tp
->tty_inhibited
) {
223 /* Inhibition state has changed. */
225 rs
->ostate
|= OSWREADY
;
226 if (tp
->tty_inhibited
) rs
->ostate
&= ~OSWREADY
;
228 rs
->inhibited
= tp
->tty_inhibited
;
232 /* Wait for the line to drain then reconfigure and continue output. */
233 if (rs
->ocount
> 0) return 0;
238 /* While there is something to do. */
240 ocount
= buflen(rs
->obuf
) - rs
->ocount
;
241 count
= bufend(rs
->obuf
) - rs
->ohead
;
242 if (count
> ocount
) count
= ocount
;
243 if (count
> tp
->tty_outleft
) count
= tp
->tty_outleft
;
244 if (count
== 0 || tp
->tty_inhibited
) {
250 /* Copy from user space to the RS232 output buffer. */
251 if ((r
= sys_safecopyfrom(tp
->tty_outcaller
, tp
->tty_outgrant
,
252 tp
->tty_outoffset
, (vir_bytes
) rs
->ohead
, count
)) != OK
)
253 printf("TTY: sys_safecopyfrom() failed: %d", r
);
255 /* Perform output processing on the output buffer. */
256 out_process(tp
, rs
->obuf
, rs
->ohead
, bufend(rs
->obuf
), &count
, &ocount
);
257 if (count
== 0) break;
259 /* Assume echoing messed up by output. */
260 tp
->tty_reprint
= TRUE
;
263 lock(); /* protect interrupt sensitive rs->ocount */
264 rs
->ocount
+= ocount
;
267 if ((rs
->ohead
+= ocount
) >= bufend(rs
->obuf
))
268 rs
->ohead
-= buflen(rs
->obuf
);
269 tp
->tty_outoffset
+= count
;
270 tp
->tty_outcum
+= count
;
271 if ((tp
->tty_outleft
-= count
) == 0) {
272 /* Output is finished, reply to the writer. */
273 if(tp
->tty_outrepcode
== TTY_REVIVE
) {
274 notify(tp
->tty_outcaller
);
275 tp
->tty_outrevived
= 1;
277 tty_reply(tp
->tty_outrepcode
, tp
->tty_outcaller
,
278 tp
->tty_outproc
, tp
->tty_outcum
);
283 if (tp
->tty_outleft
> 0 && tp
->tty_termios
.c_ospeed
== B0
) {
284 /* Oops, the line has hung up. */
285 if(tp
->tty_outrepcode
== TTY_REVIVE
) {
286 notify(tp
->tty_outcaller
);
287 tp
->tty_outrevived
= 1;
289 tty_reply(tp
->tty_outrepcode
, tp
->tty_outcaller
,
290 tp
->tty_outproc
, EIO
);
291 tp
->tty_outleft
= tp
->tty_outcum
= 0;
298 /*===========================================================================*
300 *===========================================================================*/
301 static void rs_echo(tp
, c
)
302 tty_t
*tp
; /* which TTY */
303 int c
; /* character to echo */
305 /* Echo one character. (Like rs_write, but only one character, optionally.) */
307 rs232_t
*rs
= tp
->tty_priv
;
310 ocount
= buflen(rs
->obuf
) - rs
->ocount
;
311 if (ocount
== 0) return; /* output buffer full */
313 *rs
->ohead
= c
; /* add one character */
315 out_process(tp
, rs
->obuf
, rs
->ohead
, bufend(rs
->obuf
), &count
, &ocount
);
316 if (count
== 0) return;
319 rs
->ocount
+= ocount
;
322 if ((rs
->ohead
+= ocount
) >= bufend(rs
->obuf
)) rs
->ohead
-= buflen(rs
->obuf
);
325 /*===========================================================================*
327 *===========================================================================*/
328 static int rs_ioctl(tty_t
*tp
, int UNUSED(dummy
))
331 /* Reconfigure the line as soon as the output has drained. */
332 rs232_t
*rs
= tp
->tty_priv
;
335 return 0; /* dummy */
338 /*===========================================================================*
340 *===========================================================================*/
341 static void rs_config(rs232_t
*rs
)
344 /* Set various line control parameters for RS232 I/O.
345 * If DataBits == 5 and StopBits == 2, 8250 will generate 1.5 stop bits.
346 * The 8250 can't handle split speed, so we use the input speed.
352 static struct speed2divisor
{
356 #if defined(__i386__)
357 { B50
, UART_FREQ
/ 50 },
359 { B75
, UART_FREQ
/ 75 },
360 { B110
, UART_FREQ
/ 110 },
361 { B134
, UART_FREQ
* 10 / 1345 },
362 { B150
, UART_FREQ
/ 150 },
363 { B200
, UART_FREQ
/ 200 },
364 { B300
, UART_FREQ
/ 300 },
365 { B600
, UART_FREQ
/ 600 },
366 { B1200
, UART_FREQ
/ 1200 },
367 #if defined(__i386__)
368 { B1800
, UART_FREQ
/ 1800 },
370 { B2400
, UART_FREQ
/ 2400 },
371 { B4800
, UART_FREQ
/ 4800 },
372 { B9600
, UART_FREQ
/ 9600 },
373 { B19200
, UART_FREQ
/ 19200 },
374 #if defined(__i386__)
375 { B38400
, UART_FREQ
/ 38400 },
376 { B57600
, UART_FREQ
/ 57600 },
377 { B115200
, UART_FREQ
/ 115200L },
380 struct speed2divisor
*s2dp
;
382 /* RS232 needs to know the xoff character, and if CTS works. */
383 rs
->oxoff
= tp
->tty_termios
.c_cc
[VSTOP
];
384 rs
->cts
= (tp
->tty_termios
.c_cflag
& CLOCAL
) ? MS_CTS
: 0;
386 /* Look up the 8250 rate divisor from the output speed. */
388 for (s2dp
= s2d
; s2dp
< s2d
+ sizeof(s2d
)/sizeof(s2d
[0]); s2dp
++) {
389 if (s2dp
->speed
== tp
->tty_termios
.c_ospeed
) divisor
= s2dp
->divisor
;
391 if (divisor
== 0) return; /* B0? */
393 /* Compute line control flag bits. */
395 if (tp
->tty_termios
.c_cflag
& PARENB
) {
396 line_controls
|= LC_PARITY
;
397 if (!(tp
->tty_termios
.c_cflag
& PARODD
)) line_controls
|= LC_PAREVEN
;
399 if (divisor
>= (UART_FREQ
/ 110)) line_controls
|= LC_2STOP_BITS
;
400 line_controls
|= (tp
->tty_termios
.c_cflag
& CSIZE
) >> 2;
402 /* Lock out interrupts while setting the speed. The receiver register is
403 * going to be hidden by the div_low register, but the input interrupt
404 * handler relies on reading it to clear the interrupt and avoid looping
409 /* Select the baud rate divisor registers and change the rate. */
410 sys_outb(rs
->line_ctl_port
, LC_ADDRESS_DIVISOR
);
411 sys_outb(rs
->div_low_port
, divisor
);
412 sys_outb(rs
->div_hi_port
, divisor
>> 8);
414 /* Change the line controls and reselect the usual registers. */
415 sys_outb(rs
->line_ctl_port
, line_controls
);
417 rs
->ostate
= devready(rs
) | ORAW
| OSWREADY
; /* reads modem_ctl_port */
418 if ((tp
->tty_termios
.c_lflag
& IXON
) && rs
->oxoff
!= _POSIX_VDISABLE
)
424 /*===========================================================================*
426 *===========================================================================*/
427 void rs_init(tty_t
*tp
)
431 /* Initialize RS232 for one line. */
433 register rs232_t
*rs
;
439 /* Associate RS232 and TTY structures. */
440 line
= tp
- &tty_table
[NR_CONS
];
442 /* See if kernel debugging is enabled; if so, don't initialize this
443 * serial line, making tty not look at the irq and returning ENXIO
444 * for all requests on it from userland. (The kernel will use it.)
446 if(env_get_param(SERVARNAME
, l
, sizeof(l
)-1) == OK
&& atoi(l
) == line
) {
447 printf("TTY: not initializing rs232 line %d (in use by kernel)\n",
452 rs
= tp
->tty_priv
= &rs_lines
[line
];
455 /* Set up input queue. */
456 rs
->ihead
= rs
->itail
= rs
->ibuf
;
458 /* Precalculate port numbers for speed. Magic numbers in the code (once). */
459 this_8250
= addr_8250
[line
];
460 rs
->xmit_port
= this_8250
+ 0;
461 rs
->recv_port
= this_8250
+ 0;
462 rs
->div_low_port
= this_8250
+ 0;
463 rs
->div_hi_port
= this_8250
+ 1;
464 rs
->int_enab_port
= this_8250
+ 1;
465 rs
->int_id_port
= this_8250
+ 2;
466 rs
->line_ctl_port
= this_8250
+ 3;
467 rs
->modem_ctl_port
= this_8250
+ 4;
468 rs
->line_status_port
= this_8250
+ 5;
469 rs
->modem_status_port
= this_8250
+ 6;
471 /* Set up the hardware to a base state, in particular
472 * o turn off DTR (MC_DTR) to try to stop the external device.
473 * o be careful about the divisor latch. Some BIOS's leave it enabled
474 * here and that caused trouble (no interrupts) in version 1.5 by
475 * hiding the interrupt enable port in the next step, and worse trouble
476 * (continual interrupts) in an old version by hiding the receiver
477 * port in the first interrupt. Call rs_ioctl() early to avoid this.
478 * o disable interrupts at the chip level, to force an edge transition
479 * on the 8259 line when interrupts are next enabled and active.
480 * RS232 interrupts are guaranteed to be disabled now by the 8259
481 * mask, but there used to be trouble if the mask was set without
482 * handling a previous interrupt.
484 istop(rs
); /* sets modem_ctl_port */
486 sys_outb(rs
->int_enab_port
, 0);
488 /* Clear any harmful leftover interrupts. An output interrupt is harmless
489 * and will occur when interrupts are enabled anyway. Set up the output
490 * queue using the status from clearing the modem status interrupt.
492 if ((s
= sys_inb(rs
->line_status_port
, &dummy
)) != OK
)
493 printf("TTY: sys_inb() failed: %d", s
);
494 if ((s
= sys_inb(rs
->recv_port
, &dummy
)) != OK
)
495 printf("TTY: sys_inb() failed: %d", s
);
496 rs
->ostate
= devready(rs
) | ORAW
| OSWREADY
; /* reads modem_ctl_port */
497 rs
->ohead
= rs
->otail
= rs
->obuf
;
499 /* Enable interrupts for both interrupt controller and device. */
500 irq
= (line
& 1) == 0 ? RS232_IRQ
: SECONDARY_IRQ
;
503 rs
->irq_hook_id
= rs
->irq
; /* call back with irq line number */
504 if (sys_irqsetpolicy(irq
, IRQ_REENABLE
, &rs
->irq_hook_id
) != OK
) {
505 printf("RS232: Couldn't obtain hook for irq %d\n", irq
);
507 if (sys_irqenable(&rs
->irq_hook_id
) != OK
) {
508 printf("RS232: Couldn't enable irq %d (hooked)\n", irq
);
512 rs_irq_set
|= (1 << irq
);
514 sys_outb(rs
->int_enab_port
, IE_LINE_STATUS_CHANGE
| IE_MODEM_STATUS_CHANGE
515 | IE_RECEIVER_READY
| IE_TRANSMITTER_READY
);
517 /* Fill in TTY function hooks. */
518 tp
->tty_devread
= rs_read
;
519 tp
->tty_devwrite
= rs_write
;
520 tp
->tty_echo
= rs_echo
;
521 tp
->tty_icancel
= rs_icancel
;
522 tp
->tty_ocancel
= rs_ocancel
;
523 tp
->tty_ioctl
= rs_ioctl
;
524 tp
->tty_break
= rs_break
;
525 tp
->tty_close
= rs_close
;
527 /* Tell external device we are ready. */
532 /*===========================================================================*
534 *===========================================================================*/
535 void rs_interrupt(message
*m
)
537 unsigned long irq_set
;
541 irq_set
= m
->NOTIFY_ARG
;
542 for (i
= 0, rs
= rs_lines
; i
<NR_RS_LINES
; i
++, rs
++)
544 if (irq_set
& (1 << rs
->irq
))
549 /*===========================================================================*
551 *===========================================================================*/
552 static int rs_icancel(tty_t
*tp
, int UNUSED(dummy
))
554 /* Cancel waiting input. */
555 rs232_t
*rs
= tp
->tty_priv
;
559 rs
->itail
= rs
->ihead
;
563 return 0; /* dummy */
566 /*===========================================================================*
568 *===========================================================================*/
569 static int rs_ocancel(tty_t
*tp
, int UNUSED(dummy
))
571 /* Cancel pending output. */
572 rs232_t
*rs
= tp
->tty_priv
;
575 rs
->ostate
&= ~(ODONE
| OQUEUED
);
577 rs
->otail
= rs
->ohead
;
580 return 0; /* dummy */
583 /*===========================================================================*
585 *===========================================================================*/
586 static int rs_read(tty_t
*tp
, int try)
588 /* Process characters from the circular input buffer. */
590 rs232_t
*rs
= tp
->tty_priv
;
591 int icount
, count
, ostate
;
593 if (!(tp
->tty_termios
.c_cflag
& CLOCAL
)) {
595 /* Send a SIGHUP if hangup detected. */
598 rs
->ostate
&= ~ODEVHUP
; /* save ostate, clear DEVHUP */
600 if (ostate
& ODEVHUP
) {
601 sigchar(tp
, SIGHUP
, 1);
602 tp
->tty_termios
.c_ospeed
= B0
; /* Disable further I/O. */
613 while ((count
= rs
->icount
) > 0) {
614 icount
= bufend(rs
->ibuf
) - rs
->itail
;
615 if (count
> icount
) count
= icount
;
617 /* Perform input processing on (part of) the input buffer. */
618 if ((count
= in_process(tp
, rs
->itail
, count
, -1)) == 0) break;
620 lock(); /* protect interrupt sensitive variables */
622 if (!rs
->idevready
&& rs
->icount
< RS_ILOWWATER
) istart(rs
);
624 if ((rs
->itail
+= count
) == bufend(rs
->ibuf
)) rs
->itail
= rs
->ibuf
;
630 /*===========================================================================*
632 *===========================================================================*/
633 static void rs_ostart(rs232_t
*rs
)
635 /* Tell RS232 there is something waiting in the output buffer. */
637 rs
->ostate
|= OQUEUED
;
638 if (txready(rs
)) out_int(rs
);
641 /*===========================================================================*
643 *===========================================================================*/
644 static int rs_break(tty_t
*tp
, int UNUSED(dummy
))
646 /* Generate a break condition by setting the BREAK bit for 0.4 sec. */
647 rs232_t
*rs
= tp
->tty_priv
;
651 if ((s
= sys_inb(rs
->line_ctl_port
, &line_controls
)) != OK
)
652 printf("TTY: sys_inb() failed: %d", s
);
653 sys_outb(rs
->line_ctl_port
, line_controls
| LC_BREAK
);
655 /* milli_delay(400); */ /* ouch */
656 printf("RS232 break\n");
657 sys_outb(rs
->line_ctl_port
, line_controls
);
658 return 0; /* dummy */
661 /*===========================================================================*
663 *===========================================================================*/
664 static int rs_close(tty_t
*tp
, int UNUSED(dummy
))
666 /* The line is closed; optionally hang up. */
667 rs232_t
*rs
= tp
->tty_priv
;
669 if (tp
->tty_termios
.c_cflag
& HUPCL
) {
670 sys_outb(rs
->modem_ctl_port
, MC_OUT2
| MC_RTS
);
672 return 0; /* dummy */
675 /* Low level (interrupt) routines. */
677 /*===========================================================================*
679 *===========================================================================*/
680 static void rs232_handler(struct rs232
*rs
)
682 /* Interrupt hander for RS232. */
687 /* Loop to pick up ALL pending interrupts for device.
688 * This usually just wastes time unless the hardware has a buffer
689 * (and then we have to worry about being stuck in the loop too long).
690 * Unfortunately, some serial cards lock up without this.
692 if ((s
= sys_inb(rs
->int_id_port
, &v
)) != OK
)
693 printf("TTY: sys_inb() failed: %d", s
);
695 case IS_RECEIVER_READY
:
698 case IS_TRANSMITTER_READY
:
701 case IS_MODEM_STATUS_CHANGE
:
704 case IS_LINE_STATUS_CHANGE
:
712 /*===========================================================================*
714 *===========================================================================*/
715 static void in_int(register rs232_t
*rs
)
716 /* rs line with input interrupt */
718 /* Read the data which just arrived.
719 * If it is the oxoff char, clear OSWREADY, else if OSWREADY was clear, set
720 * it and restart output (any char does this, not just xon).
721 * Put data in the buffer if room, otherwise discard it.
722 * Set a flag for the clock interrupt handler to eventually notify TTY.
727 #if 0 /* Enable this if you want serial input in the kernel */
731 if ((s
= sys_inb(rs
->recv_port
, &c
)) != OK
)
732 printf("TTY: sys_inb() failed: %d", s
);
734 if (!(rs
->ostate
& ORAW
)) {
735 if (c
== rs
->oxoff
) {
736 rs
->ostate
&= ~OSWREADY
;
738 if (!(rs
->ostate
& OSWREADY
)) {
739 rs
->ostate
|= OSWREADY
;
740 if (txready(rs
)) out_int(rs
);
744 if (rs
->icount
== buflen(rs
->ibuf
))
746 printf("in_int: discarding byte\n");
747 return; /* input buffer full, discard */
750 if (++rs
->icount
== RS_IHIGHWATER
&& rs
->idevready
) istop(rs
);
752 if (++rs
->ihead
== bufend(rs
->ibuf
)) rs
->ihead
= rs
->ibuf
;
753 if (rs
->icount
== 1) {
754 rs
->tty
->tty_events
= 1;
758 printf("in_int: icount = %d\n", rs
->icount
);
761 /*===========================================================================*
763 *===========================================================================*/
764 static void line_int(register rs232_t
*rs
)
765 /* rs line with line status interrupt */
767 /* Check for and record errors. */
771 if ((r
= sys_inb(rs
->line_status_port
, &s
)) != OK
)
772 printf("TTY: sys_inb() failed: %d", r
);
774 if (rs
->lstatus
& LS_FRAMING_ERR
) ++rs
->framing_errors
;
775 if (rs
->lstatus
& LS_OVERRUN_ERR
) ++rs
->overrun_errors
;
776 if (rs
->lstatus
& LS_PARITY_ERR
) ++rs
->parity_errors
;
777 if (rs
->lstatus
& LS_BREAK_INTERRUPT
) ++rs
->break_interrupts
;
780 /*===========================================================================*
782 *===========================================================================*/
783 static void modem_int(register rs232_t
*rs
)
784 /* rs line with modem interrupt */
786 /* Get possibly new device-ready status, and clear ODEVREADY if necessary.
787 * If the device just became ready, restart output.
791 rs
->ostate
|= ODEVHUP
;
792 rs
->tty
->tty_events
= 1;
797 rs
->ostate
&= ~ODEVREADY
;
798 else if (!(rs
->ostate
& ODEVREADY
)) {
799 rs
->ostate
|= ODEVREADY
;
800 if (txready(rs
)) out_int(rs
);
804 /*===========================================================================*
806 *===========================================================================*/
807 static void out_int(register rs232_t
*rs
)
808 /* rs; line with output interrupt */
810 /* If there is output to do and everything is ready, do it (local device is
812 * Notify TTY when the buffer goes empty.
815 if (rs
->ostate
>= (ODEVREADY
| OQUEUED
| OSWREADY
)) {
816 /* Bit test allows ORAW and requires the others. */
817 sys_outb(rs
->xmit_port
, *rs
->otail
);
818 if (++rs
->otail
== bufend(rs
->obuf
)) rs
->otail
= rs
->obuf
;
819 if (--rs
->ocount
== 0) {
820 rs
->ostate
^= (ODONE
| OQUEUED
); /* ODONE on, OQUEUED off */
821 rs
->tty
->tty_events
= 1;
824 if (rs
->ocount
== RS_OLOWWATER
) { /* running low? */
825 rs
->tty
->tty_events
= 1;
830 #endif /* NR_RS_LINES > 0 */