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 | *---------------------------------------------------------------------------*/
|
---|
6 |
|
---|
7 | #include "../drivers.h"
|
---|
8 | #include <termios.h>
|
---|
9 | #include <signal.h>
|
---|
10 | #include "tty.h"
|
---|
11 |
|
---|
12 | #if NR_RS_LINES > 0
|
---|
13 |
|
---|
14 | #if (MACHINE != IBM_PC) && (MACHINE != ATARI)
|
---|
15 | #error /* rs232.c only supports PC and Atari ST */
|
---|
16 | #endif
|
---|
17 |
|
---|
18 | #if (MACHINE == ATARI)
|
---|
19 | #include "staddr.h"
|
---|
20 | #include "stsound.h"
|
---|
21 | #include "stmfp.h"
|
---|
22 | #if (NR_RS_LINES > 1)
|
---|
23 | #error /* Only one physical RS232 line available */
|
---|
24 | #endif
|
---|
25 | #endif
|
---|
26 |
|
---|
27 | #if (MACHINE == IBM_PC) /* PC/AT 8250/16450 chip combination */
|
---|
28 |
|
---|
29 | /* 8250 constants. */
|
---|
30 | #define UART_FREQ 115200L /* timer frequency */
|
---|
31 |
|
---|
32 | /* Interrupt enable bits. */
|
---|
33 | #define IE_RECEIVER_READY 1
|
---|
34 | #define IE_TRANSMITTER_READY 2
|
---|
35 | #define IE_LINE_STATUS_CHANGE 4
|
---|
36 | #define IE_MODEM_STATUS_CHANGE 8
|
---|
37 |
|
---|
38 | /* Interrupt status bits. */
|
---|
39 | #define IS_MODEM_STATUS_CHANGE 0
|
---|
40 | #define IS_TRANSMITTER_READY 2
|
---|
41 | #define IS_RECEIVER_READY 4
|
---|
42 | #define IS_LINE_STATUS_CHANGE 6
|
---|
43 |
|
---|
44 | /* Line control bits. */
|
---|
45 | #define LC_2STOP_BITS 0x04
|
---|
46 | #define LC_PARITY 0x08
|
---|
47 | #define LC_PAREVEN 0x10
|
---|
48 | #define LC_BREAK 0x40
|
---|
49 | #define LC_ADDRESS_DIVISOR 0x80
|
---|
50 |
|
---|
51 | /* Line status bits. */
|
---|
52 | #define LS_OVERRUN_ERR 2
|
---|
53 | #define LS_PARITY_ERR 4
|
---|
54 | #define LS_FRAMING_ERR 8
|
---|
55 | #define LS_BREAK_INTERRUPT 0x10
|
---|
56 | #define LS_TRANSMITTER_READY 0x20
|
---|
57 |
|
---|
58 | /* Modem control bits. */
|
---|
59 | #define MC_DTR 1
|
---|
60 | #define MC_RTS 2
|
---|
61 | #define MC_OUT2 8 /* required for PC & AT interrupts */
|
---|
62 |
|
---|
63 | /* Modem status bits. */
|
---|
64 | #define MS_CTS 0x10
|
---|
65 | #define MS_RLSD 0x80 /* Received Line Signal Detect */
|
---|
66 | #define MS_DRLSD 0x08 /* RLSD Delta */
|
---|
67 |
|
---|
68 | #else /* MACHINE == ATARI */ /* Atari ST 68901 USART */
|
---|
69 |
|
---|
70 | /* Most of the USART constants are already defined in stmfp.h . The local
|
---|
71 | * definitions made here are for keeping C code changes smaller. --kub
|
---|
72 | */
|
---|
73 |
|
---|
74 | #define UART_FREQ 19200L /* timer frequency */
|
---|
75 |
|
---|
76 | /* Line status bits. */
|
---|
77 | #define LS_OVERRUN_ERR R_OE
|
---|
78 | #define LS_PARITY_ERR R_PE
|
---|
79 | #define LS_FRAMING_ERR R_FE
|
---|
80 | #define LS_BREAK_INTERRUPT R_BREAK
|
---|
81 |
|
---|
82 | /* Modem status bits. */
|
---|
83 | #define MS_CTS IO_SCTS /* 0x04 */
|
---|
84 |
|
---|
85 | #endif /* MACHINE == ATARI */
|
---|
86 |
|
---|
87 | #define DATA_BITS_SHIFT 8 /* amount data bits shifted in mode */
|
---|
88 | #define DEF_BAUD 1200 /* default baud rate */
|
---|
89 |
|
---|
90 | #define RS_IBUFSIZE 1024 /* RS232 input buffer size */
|
---|
91 | #define RS_OBUFSIZE 1024 /* RS232 output buffer size */
|
---|
92 |
|
---|
93 | /* Input buffer watermarks.
|
---|
94 | * The external device is asked to stop sending when the buffer
|
---|
95 | * exactly reaches high water, or when TTY requests it. Sending restarts
|
---|
96 | * when the input buffer empties below the low watermark.
|
---|
97 | */
|
---|
98 | #define RS_ILOWWATER (1 * RS_IBUFSIZE / 4)
|
---|
99 | #define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)
|
---|
100 |
|
---|
101 | /* Output buffer low watermark.
|
---|
102 | * TTY is notified when the output buffer empties below the low watermark, so
|
---|
103 | * it may continue filling the buffer if doing a large write.
|
---|
104 | */
|
---|
105 | #define RS_OLOWWATER (1 * RS_OBUFSIZE / 4)
|
---|
106 |
|
---|
107 | #if (MACHINE == IBM_PC)
|
---|
108 |
|
---|
109 | /* Macros to handle flow control.
|
---|
110 | * Interrupts must be off when they are used.
|
---|
111 | * Time is critical - already the function call for outb() is annoying.
|
---|
112 | * If outb() can be done in-line, tests to avoid it can be dropped.
|
---|
113 | * istart() tells external device we are ready by raising RTS.
|
---|
114 | * istop() tells external device we are not ready by dropping RTS.
|
---|
115 | * DTR is kept high all the time (it probably should be raised by open and
|
---|
116 | * dropped by close of the device).
|
---|
117 | * OUT2 is also kept high all the time.
|
---|
118 | */
|
---|
119 | #define istart(rs) \
|
---|
120 | (sys_outb((rs)->modem_ctl_port, MC_OUT2 | MC_RTS | MC_DTR), \
|
---|
121 | (rs)->idevready = TRUE)
|
---|
122 | #define istop(rs) \
|
---|
123 | (sys_outb((rs)->modem_ctl_port, MC_OUT2 | MC_DTR), \
|
---|
124 | (rs)->idevready = FALSE)
|
---|
125 |
|
---|
126 | /* Macro to tell if device is ready. The rs->cts field is set to MS_CTS if
|
---|
127 | * CLOCAL is in effect for a line without a CTS wire.
|
---|
128 | */
|
---|
129 | #define devready(rs) ((my_inb(rs->modem_status_port) | rs->cts) & MS_CTS)
|
---|
130 |
|
---|
131 | /* Macro to tell if transmitter is ready. */
|
---|
132 | #define txready(rs) (my_inb(rs->line_status_port) & LS_TRANSMITTER_READY)
|
---|
133 |
|
---|
134 | /* Macro to tell if carrier has dropped.
|
---|
135 | * The RS232 Carrier Detect (CD) line is usually connected to the 8250
|
---|
136 | * Received Line Signal Detect pin, reflected by bit MS_RLSD in the Modem
|
---|
137 | * Status Register. The MS_DRLSD bit tells if MS_RLSD has just changed state.
|
---|
138 | * So if MS_DRLSD is set and MS_RLSD cleared, we know that carrier has just
|
---|
139 | * dropped.
|
---|
140 | */
|
---|
141 | #define devhup(rs) \
|
---|
142 | ((my_inb(rs->modem_status_port) & (MS_RLSD|MS_DRLSD)) == MS_DRLSD)
|
---|
143 |
|
---|
144 | #else /* MACHINE == ATARI */
|
---|
145 |
|
---|
146 | /* Macros to handle flow control.
|
---|
147 | * Time is critical - already the function call for lock()/restore() is
|
---|
148 | * annoying.
|
---|
149 | * istart() tells external device we are ready by raising RTS.
|
---|
150 | * istop() tells external device we are not ready by dropping RTS.
|
---|
151 | * DTR is kept high all the time (it probably should be raised by open and
|
---|
152 | * dropped by close of the device). NOTE: The modem lines are active low.
|
---|
153 | */
|
---|
154 | #define set_porta(msk,val) { register int s = lock(); \
|
---|
155 | SOUND->sd_selr = YM_IOA; \
|
---|
156 | SOUND->sd_wdat = \
|
---|
157 | SOUND->sd_rdat & (msk) | (val); \
|
---|
158 | restore(s); }
|
---|
159 | #define istart(rs) { set_porta( ~(PA_SRTS|PA_SDTR),0 ); \
|
---|
160 | (rs)->idevready = TRUE; }
|
---|
161 | #define istop(rs) { set_porta( ~PA_SDTR, PA_SRTS ); \
|
---|
162 | (rs)->idevready = FALSE; }
|
---|
163 |
|
---|
164 | /* Macro to tell if device is ready. The rs->cts field is set to MS_CTS if
|
---|
165 | * CLOCAL is in effect for a line without a CTS wire.
|
---|
166 | */
|
---|
167 | #define devready(rs) ((~MFP->mf_gpip | rs->cts) & MS_CTS)
|
---|
168 |
|
---|
169 | /* Transmitter ready test */
|
---|
170 | #define txready(rs) (MFP->mf_tsr & (T_EMPTY | T_UE))
|
---|
171 |
|
---|
172 | #endif /* MACHINE == ATARI */
|
---|
173 |
|
---|
174 | /* Types. */
|
---|
175 | typedef unsigned char bool_t; /* boolean */
|
---|
176 |
|
---|
177 | /* RS232 device structure, one per device. */
|
---|
178 | typedef struct rs232 {
|
---|
179 | tty_t *tty; /* associated TTY structure */
|
---|
180 |
|
---|
181 | int icount; /* number of bytes in the input buffer */
|
---|
182 | char *ihead; /* next free spot in input buffer */
|
---|
183 | char *itail; /* first byte to give to TTY */
|
---|
184 | bool_t idevready; /* nonzero if we are ready to receive (RTS) */
|
---|
185 | char cts; /* normally 0, but MS_CTS if CLOCAL is set */
|
---|
186 |
|
---|
187 | unsigned char ostate; /* combination of flags: */
|
---|
188 | #define ODONE 1 /* output completed (< output enable bits) */
|
---|
189 | #define ORAW 2 /* raw mode for xoff disable (< enab. bits) */
|
---|
190 | #define OWAKEUP 4 /* tty_wakeup() pending (asm code only) */
|
---|
191 | #define ODEVREADY MS_CTS /* external device hardware ready (CTS) */
|
---|
192 | #define OQUEUED 0x20 /* output buffer not empty */
|
---|
193 | #define OSWREADY 0x40 /* external device software ready (no xoff) */
|
---|
194 | #define ODEVHUP MS_RLSD /* external device has dropped carrier */
|
---|
195 | #define OSOFTBITS (ODONE | ORAW | OWAKEUP | OQUEUED | OSWREADY)
|
---|
196 | /* user-defined bits */
|
---|
197 | #if (OSOFTBITS | ODEVREADY | ODEVHUP) == OSOFTBITS
|
---|
198 | /* a weak sanity check */
|
---|
199 | #error /* bits are not unique */
|
---|
200 | #endif
|
---|
201 | unsigned char oxoff; /* char to stop output */
|
---|
202 | bool_t inhibited; /* output inhibited? (follows tty_inhibited) */
|
---|
203 | bool_t drain; /* if set drain output and reconfigure line */
|
---|
204 | int ocount; /* number of bytes in the output buffer */
|
---|
205 | char *ohead; /* next free spot in output buffer */
|
---|
206 | char *otail; /* next char to output */
|
---|
207 |
|
---|
208 | #if (MACHINE == IBM_PC)
|
---|
209 | port_t xmit_port; /* i/o ports */
|
---|
210 | port_t recv_port;
|
---|
211 | port_t div_low_port;
|
---|
212 | port_t div_hi_port;
|
---|
213 | port_t int_enab_port;
|
---|
214 | port_t int_id_port;
|
---|
215 | port_t line_ctl_port;
|
---|
216 | port_t modem_ctl_port;
|
---|
217 | port_t line_status_port;
|
---|
218 | port_t modem_status_port;
|
---|
219 | #endif
|
---|
220 |
|
---|
221 | unsigned char lstatus; /* last line status */
|
---|
222 | unsigned char pad; /* ensure alignment for 16-bit ints */
|
---|
223 | unsigned framing_errors; /* error counts (no reporting yet) */
|
---|
224 | unsigned overrun_errors;
|
---|
225 | unsigned parity_errors;
|
---|
226 | unsigned break_interrupts;
|
---|
227 |
|
---|
228 | int irq; /* irq for this line */
|
---|
229 | int irq_hook_id; /* interrupt hook */
|
---|
230 |
|
---|
231 | char ibuf[RS_IBUFSIZE]; /* input buffer */
|
---|
232 | char obuf[RS_OBUFSIZE]; /* output buffer */
|
---|
233 | } rs232_t;
|
---|
234 |
|
---|
235 | PUBLIC rs232_t rs_lines[NR_RS_LINES];
|
---|
236 |
|
---|
237 | /* Table and macro to translate an RS232 line number to its rs_lines entry. */
|
---|
238 | PRIVATE rs232_t *p_rs_addr[NR_RS_LINES];
|
---|
239 |
|
---|
240 | #define rs_addr(line) (p_rs_addr[line])
|
---|
241 |
|
---|
242 | #if (MACHINE == IBM_PC)
|
---|
243 | /* 8250 base addresses. */
|
---|
244 | PRIVATE port_t addr_8250[] = {
|
---|
245 | 0x3F8, /* COM1 */
|
---|
246 | 0x2F8, /* COM2 */
|
---|
247 | 0x3E8, /* COM3 */
|
---|
248 | 0x2E8, /* COM4 */
|
---|
249 | };
|
---|
250 | #endif
|
---|
251 |
|
---|
252 | FORWARD _PROTOTYPE( void in_int, (rs232_t *rs) );
|
---|
253 | FORWARD _PROTOTYPE( void line_int, (rs232_t *rs) );
|
---|
254 | FORWARD _PROTOTYPE( void modem_int, (rs232_t *rs) );
|
---|
255 | FORWARD _PROTOTYPE( int rs_write, (tty_t *tp, int try) );
|
---|
256 | FORWARD _PROTOTYPE( void rs_echo, (tty_t *tp, int c) );
|
---|
257 | FORWARD _PROTOTYPE( int rs_ioctl, (tty_t *tp, int try) );
|
---|
258 | FORWARD _PROTOTYPE( void rs_config, (rs232_t *rs) );
|
---|
259 | FORWARD _PROTOTYPE( int rs_read, (tty_t *tp, int try) );
|
---|
260 | FORWARD _PROTOTYPE( int rs_icancel, (tty_t *tp, int try) );
|
---|
261 | FORWARD _PROTOTYPE( int rs_ocancel, (tty_t *tp, int try) );
|
---|
262 | FORWARD _PROTOTYPE( void rs_ostart, (rs232_t *rs) );
|
---|
263 | FORWARD _PROTOTYPE( int rs_break, (tty_t *tp, int try) );
|
---|
264 | FORWARD _PROTOTYPE( int rs_close, (tty_t *tp, int try) );
|
---|
265 | FORWARD _PROTOTYPE( void out_int, (rs232_t *rs) );
|
---|
266 | FORWARD _PROTOTYPE( void rs232_handler, (rs232_t *rs) );
|
---|
267 |
|
---|
268 | /* XXX */
|
---|
269 | PRIVATE void lock(void) {}
|
---|
270 | PRIVATE void unlock(void) {}
|
---|
271 |
|
---|
272 | PRIVATE int my_inb(port_t port)
|
---|
273 | {
|
---|
274 | int r;
|
---|
275 | unsigned long v = 0;
|
---|
276 | r = sys_inb(port, &v);
|
---|
277 | if (r != OK)
|
---|
278 | printf("RS232 warning: failed inb 0x%x\n", port);
|
---|
279 |
|
---|
280 | return (int) v;
|
---|
281 | }
|
---|
282 |
|
---|
283 | /*===========================================================================*
|
---|
284 | * rs_write *
|
---|
285 | *===========================================================================*/
|
---|
286 | PRIVATE int rs_write(tp, try)
|
---|
287 | register tty_t *tp;
|
---|
288 | int try;
|
---|
289 | {
|
---|
290 | /* (*devwrite)() routine for RS232. */
|
---|
291 |
|
---|
292 | rs232_t *rs = tp->tty_priv;
|
---|
293 | int count, ocount;
|
---|
294 |
|
---|
295 | if (rs->inhibited != tp->tty_inhibited) {
|
---|
296 | /* Inhibition state has changed. */
|
---|
297 | lock();
|
---|
298 | rs->ostate |= OSWREADY;
|
---|
299 | if (tp->tty_inhibited) rs->ostate &= ~OSWREADY;
|
---|
300 | unlock();
|
---|
301 | rs->inhibited = tp->tty_inhibited;
|
---|
302 | }
|
---|
303 |
|
---|
304 | if (rs->drain) {
|
---|
305 | /* Wait for the line to drain then reconfigure and continue output. */
|
---|
306 | if (rs->ocount > 0) return 0;
|
---|
307 | rs->drain = FALSE;
|
---|
308 | rs_config(rs);
|
---|
309 | }
|
---|
310 |
|
---|
311 | /* While there is something to do. */
|
---|
312 | for (;;) {
|
---|
313 | ocount = buflen(rs->obuf) - rs->ocount;
|
---|
314 | count = bufend(rs->obuf) - rs->ohead;
|
---|
315 | if (count > ocount) count = ocount;
|
---|
316 | if (count > tp->tty_outleft) count = tp->tty_outleft;
|
---|
317 | if (count == 0 || tp->tty_inhibited) {
|
---|
318 | if (try) return 0;
|
---|
319 | break;
|
---|
320 | }
|
---|
321 | if (try) return 1;
|
---|
322 |
|
---|
323 | /* Copy from user space to the RS232 output buffer. */
|
---|
324 | sys_vircopy(tp->tty_outproc, D, (vir_bytes) tp->tty_out_vir,
|
---|
325 | SELF, D, (vir_bytes) rs->ohead, (phys_bytes) count);
|
---|
326 |
|
---|
327 | /* Perform output processing on the output buffer. */
|
---|
328 | out_process(tp, rs->obuf, rs->ohead, bufend(rs->obuf), &count, &ocount);
|
---|
329 | if (count == 0) break;
|
---|
330 |
|
---|
331 | /* Assume echoing messed up by output. */
|
---|
332 | tp->tty_reprint = TRUE;
|
---|
333 |
|
---|
334 | /* Bookkeeping. */
|
---|
335 | lock(); /* protect interrupt sensitive rs->ocount */
|
---|
336 | rs->ocount += ocount;
|
---|
337 | rs_ostart(rs);
|
---|
338 | unlock();
|
---|
339 | if ((rs->ohead += ocount) >= bufend(rs->obuf))
|
---|
340 | rs->ohead -= buflen(rs->obuf);
|
---|
341 | tp->tty_out_vir += count;
|
---|
342 | tp->tty_outcum += count;
|
---|
343 | if ((tp->tty_outleft -= count) == 0) {
|
---|
344 | /* Output is finished, reply to the writer. */
|
---|
345 | tty_reply(tp->tty_outrepcode, tp->tty_outcaller,
|
---|
346 | tp->tty_outproc, tp->tty_outcum);
|
---|
347 | tp->tty_outcum = 0;
|
---|
348 | }
|
---|
349 | }
|
---|
350 | if (tp->tty_outleft > 0 && tp->tty_termios.c_ospeed == B0) {
|
---|
351 | /* Oops, the line has hung up. */
|
---|
352 | tty_reply(tp->tty_outrepcode, tp->tty_outcaller, tp->tty_outproc, EIO);
|
---|
353 | tp->tty_outleft = tp->tty_outcum = 0;
|
---|
354 | }
|
---|
355 |
|
---|
356 | return 1;
|
---|
357 | }
|
---|
358 |
|
---|
359 | /*===========================================================================*
|
---|
360 | * rs_echo *
|
---|
361 | *===========================================================================*/
|
---|
362 | PRIVATE void rs_echo(tp, c)
|
---|
363 | tty_t *tp; /* which TTY */
|
---|
364 | int c; /* character to echo */
|
---|
365 | {
|
---|
366 | /* Echo one character. (Like rs_write, but only one character, optionally.) */
|
---|
367 |
|
---|
368 | rs232_t *rs = tp->tty_priv;
|
---|
369 | int count, ocount;
|
---|
370 |
|
---|
371 | ocount = buflen(rs->obuf) - rs->ocount;
|
---|
372 | if (ocount == 0) return; /* output buffer full */
|
---|
373 | count = 1;
|
---|
374 | *rs->ohead = c; /* add one character */
|
---|
375 |
|
---|
376 | out_process(tp, rs->obuf, rs->ohead, bufend(rs->obuf), &count, &ocount);
|
---|
377 | if (count == 0) return;
|
---|
378 |
|
---|
379 | lock();
|
---|
380 | rs->ocount += ocount;
|
---|
381 | rs_ostart(rs);
|
---|
382 | unlock();
|
---|
383 | if ((rs->ohead += ocount) >= bufend(rs->obuf)) rs->ohead -= buflen(rs->obuf);
|
---|
384 | }
|
---|
385 |
|
---|
386 | /*===========================================================================*
|
---|
387 | * rs_ioctl *
|
---|
388 | *===========================================================================*/
|
---|
389 | PRIVATE int rs_ioctl(tp, dummy)
|
---|
390 | tty_t *tp; /* which TTY */
|
---|
391 | int dummy;
|
---|
392 | {
|
---|
393 | /* Reconfigure the line as soon as the output has drained. */
|
---|
394 | rs232_t *rs = tp->tty_priv;
|
---|
395 |
|
---|
396 | rs->drain = TRUE;
|
---|
397 | return 0; /* dummy */
|
---|
398 | }
|
---|
399 |
|
---|
400 | /*===========================================================================*
|
---|
401 | * rs_config *
|
---|
402 | *===========================================================================*/
|
---|
403 | PRIVATE void rs_config(rs)
|
---|
404 | rs232_t *rs; /* which line */
|
---|
405 | {
|
---|
406 | /* Set various line control parameters for RS232 I/O.
|
---|
407 | * If DataBits == 5 and StopBits == 2, 8250 will generate 1.5 stop bits.
|
---|
408 | * The 8250 can't handle split speed, so we use the input speed.
|
---|
409 | */
|
---|
410 |
|
---|
411 | tty_t *tp = rs->tty;
|
---|
412 | int divisor;
|
---|
413 | int line_controls;
|
---|
414 | static struct speed2divisor {
|
---|
415 | speed_t speed;
|
---|
416 | int divisor;
|
---|
417 | } s2d[] = {
|
---|
418 | #if (MACHINE == IBM_PC)
|
---|
419 | { B50, UART_FREQ / 50 },
|
---|
420 | #endif
|
---|
421 | { B75, UART_FREQ / 75 },
|
---|
422 | { B110, UART_FREQ / 110 },
|
---|
423 | { B134, UART_FREQ * 10 / 1345 },
|
---|
424 | { B150, UART_FREQ / 150 },
|
---|
425 | { B200, UART_FREQ / 200 },
|
---|
426 | { B300, UART_FREQ / 300 },
|
---|
427 | { B600, UART_FREQ / 600 },
|
---|
428 | { B1200, UART_FREQ / 1200 },
|
---|
429 | #if (MACHINE == IBM_PC)
|
---|
430 | { B1800, UART_FREQ / 1800 },
|
---|
431 | #endif
|
---|
432 | { B2400, UART_FREQ / 2400 },
|
---|
433 | { B4800, UART_FREQ / 4800 },
|
---|
434 | { B9600, UART_FREQ / 9600 },
|
---|
435 | { B19200, UART_FREQ / 19200 },
|
---|
436 | #if (MACHINE == IBM_PC)
|
---|
437 | { B38400, UART_FREQ / 38400 },
|
---|
438 | { B57600, UART_FREQ / 57600 },
|
---|
439 | { B115200, UART_FREQ / 115200L },
|
---|
440 | #endif
|
---|
441 | };
|
---|
442 | struct speed2divisor *s2dp;
|
---|
443 |
|
---|
444 | /* RS232 needs to know the xoff character, and if CTS works. */
|
---|
445 | rs->oxoff = tp->tty_termios.c_cc[VSTOP];
|
---|
446 | rs->cts = (tp->tty_termios.c_cflag & CLOCAL) ? MS_CTS : 0;
|
---|
447 |
|
---|
448 | /* Look up the 8250 rate divisor from the output speed. */
|
---|
449 | divisor = 0;
|
---|
450 | for (s2dp = s2d; s2dp < s2d + sizeof(s2d)/sizeof(s2d[0]); s2dp++) {
|
---|
451 | if (s2dp->speed == tp->tty_termios.c_ospeed) divisor = s2dp->divisor;
|
---|
452 | }
|
---|
453 | if (divisor == 0) return; /* B0? */
|
---|
454 |
|
---|
455 | #if (MACHINE == IBM_PC)
|
---|
456 | /* Compute line control flag bits. */
|
---|
457 | line_controls = 0;
|
---|
458 | if (tp->tty_termios.c_cflag & PARENB) {
|
---|
459 | line_controls |= LC_PARITY;
|
---|
460 | if (!(tp->tty_termios.c_cflag & PARODD)) line_controls |= LC_PAREVEN;
|
---|
461 | }
|
---|
462 | if (divisor >= (UART_FREQ / 110)) line_controls |= LC_2STOP_BITS;
|
---|
463 | line_controls |= (tp->tty_termios.c_cflag & CSIZE) >> 2;
|
---|
464 |
|
---|
465 | /* Lock out interrupts while setting the speed. The receiver register is
|
---|
466 | * going to be hidden by the div_low register, but the input interrupt
|
---|
467 | * handler relies on reading it to clear the interrupt and avoid looping
|
---|
468 | * forever.
|
---|
469 | */
|
---|
470 | lock();
|
---|
471 |
|
---|
472 | /* Select the baud rate divisor registers and change the rate. */
|
---|
473 | sys_outb(rs->line_ctl_port, LC_ADDRESS_DIVISOR);
|
---|
474 | sys_outb(rs->div_low_port, divisor);
|
---|
475 | sys_outb(rs->div_hi_port, divisor >> 8);
|
---|
476 |
|
---|
477 | /* Change the line controls and reselect the usual registers. */
|
---|
478 | sys_outb(rs->line_ctl_port, line_controls);
|
---|
479 |
|
---|
480 | rs->ostate = devready(rs) | ORAW | OSWREADY; /* reads modem_ctl_port */
|
---|
481 | if ((tp->tty_termios.c_lflag & IXON) && rs->oxoff != _POSIX_VDISABLE)
|
---|
482 | rs->ostate &= ~ORAW;
|
---|
483 |
|
---|
484 | unlock();
|
---|
485 |
|
---|
486 | #else /* MACHINE == ATARI */
|
---|
487 |
|
---|
488 | line_controls = U_Q16;
|
---|
489 | if (tp->tty_termios.c_cflag & PARENB) {
|
---|
490 | line_controls |= U_PAR;
|
---|
491 | if (!(tp->tty_termios.c_cflag & PARODD)) line_controls |= U_EVEN;
|
---|
492 | }
|
---|
493 | line_controls |= (divisor >= (UART_FREQ / 110)) ? U_ST2 : U_ST1;
|
---|
494 |
|
---|
495 | switch (tp->tty_termios.c_cflag & CSIZE) { /* XXX - are U_Dn like CSn? */
|
---|
496 | case CS5: line_controls |= U_D5; break;
|
---|
497 | case CS5: line_controls |= U_D6; break;
|
---|
498 | case CS5: line_controls |= U_D7; break;
|
---|
499 | case CS5: line_controls |= U_D8; break;
|
---|
500 | }
|
---|
501 | lock();
|
---|
502 | MFP->mf_ucr = line_controls;
|
---|
503 | MFP->mf_tddr = divisor;
|
---|
504 | unlock();
|
---|
505 | #endif /* MACHINE == ATARI */
|
---|
506 | }
|
---|
507 |
|
---|
508 | /*===========================================================================*
|
---|
509 | * rs_init *
|
---|
510 | *===========================================================================*/
|
---|
511 | PUBLIC void rs_init(tp)
|
---|
512 | tty_t *tp; /* which TTY */
|
---|
513 | {
|
---|
514 | unsigned long dummy;
|
---|
515 | /* Initialize RS232 for one line. */
|
---|
516 |
|
---|
517 | register rs232_t *rs;
|
---|
518 | int line;
|
---|
519 | #if (MACHINE == IBM_PC)
|
---|
520 | port_t this_8250;
|
---|
521 | int irq;
|
---|
522 | long v;
|
---|
523 | #endif
|
---|
524 |
|
---|
525 | /* Associate RS232 and TTY structures. */
|
---|
526 | line = tp - &tty_table[NR_CONS];
|
---|
527 | rs = tp->tty_priv = &rs_lines[line];
|
---|
528 | rs->tty = tp;
|
---|
529 |
|
---|
530 | /* Set up input queue. */
|
---|
531 | rs->ihead = rs->itail = rs->ibuf;
|
---|
532 |
|
---|
533 | #if (MACHINE == IBM_PC)
|
---|
534 | /* Precalculate port numbers for speed. Magic numbers in the code (once). */
|
---|
535 | this_8250 = addr_8250[line];
|
---|
536 | rs->xmit_port = this_8250 + 0;
|
---|
537 | rs->recv_port = this_8250 + 0;
|
---|
538 | rs->div_low_port = this_8250 + 0;
|
---|
539 | rs->div_hi_port = this_8250 + 1;
|
---|
540 | rs->int_enab_port = this_8250 + 1;
|
---|
541 | rs->int_id_port = this_8250 + 2;
|
---|
542 | rs->line_ctl_port = this_8250 + 3;
|
---|
543 | rs->modem_ctl_port = this_8250 + 4;
|
---|
544 | rs->line_status_port = this_8250 + 5;
|
---|
545 | rs->modem_status_port = this_8250 + 6;
|
---|
546 | #endif
|
---|
547 |
|
---|
548 | /* Set up the hardware to a base state, in particular
|
---|
549 | * o turn off DTR (MC_DTR) to try to stop the external device.
|
---|
550 | * o be careful about the divisor latch. Some BIOS's leave it enabled
|
---|
551 | * here and that caused trouble (no interrupts) in version 1.5 by
|
---|
552 | * hiding the interrupt enable port in the next step, and worse trouble
|
---|
553 | * (continual interrupts) in an old version by hiding the receiver
|
---|
554 | * port in the first interrupt. Call rs_ioctl() early to avoid this.
|
---|
555 | * o disable interrupts at the chip level, to force an edge transition
|
---|
556 | * on the 8259 line when interrupts are next enabled and active.
|
---|
557 | * RS232 interrupts are guaranteed to be disabled now by the 8259
|
---|
558 | * mask, but there used to be trouble if the mask was set without
|
---|
559 | * handling a previous interrupt.
|
---|
560 | */
|
---|
561 | istop(rs); /* sets modem_ctl_port */
|
---|
562 | rs_config(rs);
|
---|
563 | #if (MACHINE == IBM_PC)
|
---|
564 | sys_outb(rs->int_enab_port, 0);
|
---|
565 | #endif
|
---|
566 |
|
---|
567 | /* Clear any harmful leftover interrupts. An output interrupt is harmless
|
---|
568 | * and will occur when interrupts are enabled anyway. Set up the output
|
---|
569 | * queue using the status from clearing the modem status interrupt.
|
---|
570 | */
|
---|
571 | #if (MACHINE == IBM_PC)
|
---|
572 | sys_inb(rs->line_status_port, &dummy);
|
---|
573 | sys_inb(rs->recv_port, &dummy);
|
---|
574 | #endif
|
---|
575 | rs->ostate = devready(rs) | ORAW | OSWREADY; /* reads modem_ctl_port */
|
---|
576 | rs->ohead = rs->otail = rs->obuf;
|
---|
577 |
|
---|
578 | #if (MACHINE == IBM_PC)
|
---|
579 | /* Enable interrupts for both interrupt controller and device. */
|
---|
580 | irq = (line & 1) == 0 ? RS232_IRQ : SECONDARY_IRQ;
|
---|
581 |
|
---|
582 | rs->irq = irq;
|
---|
583 | rs->irq_hook_id = rs->irq; /* call back with irq line number */
|
---|
584 | if (sys_irqsetpolicy(irq, IRQ_REENABLE, &rs->irq_hook_id) != OK) {
|
---|
585 | printf("RS232: Couldn't obtain hook for irq %d\n", irq);
|
---|
586 | } else {
|
---|
587 | if (sys_irqenable(&rs->irq_hook_id) != OK) {
|
---|
588 | printf("RS232: Couldn't enable irq %d (hooked)\n", irq);
|
---|
589 | }
|
---|
590 | }
|
---|
591 |
|
---|
592 | rs_irq_set |= (1 << irq);
|
---|
593 |
|
---|
594 | sys_outb(rs->int_enab_port, IE_LINE_STATUS_CHANGE | IE_MODEM_STATUS_CHANGE
|
---|
595 | | IE_RECEIVER_READY | IE_TRANSMITTER_READY);
|
---|
596 | #else /* MACHINE == ATARI */
|
---|
597 | /* Initialize the 68901 chip, then enable interrupts. */
|
---|
598 | MFP->mf_scr = 0x00;
|
---|
599 | MFP->mf_tcdcr |= T_Q004;
|
---|
600 | MFP->mf_rsr = R_ENA;
|
---|
601 | MFP->mf_tsr = T_ENA;
|
---|
602 | MFP->mf_aer = (MFP->mf_aer | (IO_SCTS|IO_SDCD)) ^
|
---|
603 | (MFP->mf_gpip & (IO_SCTS|IO_SDCD));
|
---|
604 | MFP->mf_ddr = (MFP->mf_ddr & ~ (IO_SCTS|IO_SDCD));
|
---|
605 | MFP->mf_iera |= (IA_RRDY|IA_RERR|IA_TRDY|IA_TERR);
|
---|
606 | MFP->mf_imra |= (IA_RRDY|IA_RERR|IA_TRDY|IA_TERR);
|
---|
607 | MFP->mf_ierb |= (IB_SCTS|IB_SDCD);
|
---|
608 | MFP->mf_imrb |= (IB_SCTS|IB_SDCD);
|
---|
609 | #endif /* MACHINE == ATARI */
|
---|
610 |
|
---|
611 | /* Fill in TTY function hooks. */
|
---|
612 | tp->tty_devread = rs_read;
|
---|
613 | tp->tty_devwrite = rs_write;
|
---|
614 | tp->tty_echo = rs_echo;
|
---|
615 | tp->tty_icancel = rs_icancel;
|
---|
616 | tp->tty_ocancel = rs_ocancel;
|
---|
617 | tp->tty_ioctl = rs_ioctl;
|
---|
618 | tp->tty_break = rs_break;
|
---|
619 | tp->tty_close = rs_close;
|
---|
620 |
|
---|
621 | /* Tell external device we are ready. */
|
---|
622 | istart(rs);
|
---|
623 |
|
---|
624 | }
|
---|
625 |
|
---|
626 | /*===========================================================================*
|
---|
627 | * rs_interrupt *
|
---|
628 | *===========================================================================*/
|
---|
629 | PUBLIC void rs_interrupt(m)
|
---|
630 | message *m; /* which TTY */
|
---|
631 | {
|
---|
632 | unsigned long irq_set;
|
---|
633 | int i;
|
---|
634 | rs232_t *rs;
|
---|
635 |
|
---|
636 | irq_set= m->NOTIFY_ARG;
|
---|
637 | for (i= 0, rs = rs_lines; i<NR_RS_LINES; i++, rs++)
|
---|
638 | {
|
---|
639 | if (irq_set & (1 << rs->irq))
|
---|
640 | rs232_handler(rs);
|
---|
641 | }
|
---|
642 | }
|
---|
643 |
|
---|
644 | /*===========================================================================*
|
---|
645 | * rs_icancel *
|
---|
646 | *===========================================================================*/
|
---|
647 | PRIVATE int rs_icancel(tp, dummy)
|
---|
648 | tty_t *tp; /* which TTY */
|
---|
649 | int dummy;
|
---|
650 | {
|
---|
651 | /* Cancel waiting input. */
|
---|
652 | rs232_t *rs = tp->tty_priv;
|
---|
653 |
|
---|
654 | lock();
|
---|
655 | rs->icount = 0;
|
---|
656 | rs->itail = rs->ihead;
|
---|
657 | istart(rs);
|
---|
658 | unlock();
|
---|
659 |
|
---|
660 | return 0; /* dummy */
|
---|
661 | }
|
---|
662 |
|
---|
663 | /*===========================================================================*
|
---|
664 | * rs_ocancel *
|
---|
665 | *===========================================================================*/
|
---|
666 | PRIVATE int rs_ocancel(tp, dummy)
|
---|
667 | tty_t *tp; /* which TTY */
|
---|
668 | int dummy;
|
---|
669 | {
|
---|
670 | /* Cancel pending output. */
|
---|
671 | rs232_t *rs = tp->tty_priv;
|
---|
672 |
|
---|
673 | lock();
|
---|
674 | rs->ostate &= ~(ODONE | OQUEUED);
|
---|
675 | rs->ocount = 0;
|
---|
676 | rs->otail = rs->ohead;
|
---|
677 | unlock();
|
---|
678 |
|
---|
679 | return 0; /* dummy */
|
---|
680 | }
|
---|
681 |
|
---|
682 | /*===========================================================================*
|
---|
683 | * rs_read *
|
---|
684 | *===========================================================================*/
|
---|
685 | PRIVATE int rs_read(tp, try)
|
---|
686 | tty_t *tp; /* which tty */
|
---|
687 | int try;
|
---|
688 | {
|
---|
689 | /* Process characters from the circular input buffer. */
|
---|
690 |
|
---|
691 | rs232_t *rs = tp->tty_priv;
|
---|
692 | int icount, count, ostate;
|
---|
693 |
|
---|
694 | if (!(tp->tty_termios.c_cflag & CLOCAL)) {
|
---|
695 | if (try) return 1;
|
---|
696 | /* Send a SIGHUP if hangup detected. */
|
---|
697 | lock();
|
---|
698 | ostate = rs->ostate;
|
---|
699 | rs->ostate &= ~ODEVHUP; /* save ostate, clear DEVHUP */
|
---|
700 | unlock();
|
---|
701 | if (ostate & ODEVHUP) {
|
---|
702 | sigchar(tp, SIGHUP);
|
---|
703 | tp->tty_termios.c_ospeed = B0; /* Disable further I/O. */
|
---|
704 | return;
|
---|
705 | }
|
---|
706 | }
|
---|
707 |
|
---|
708 | if (try) {
|
---|
709 | if (rs->icount > 0)
|
---|
710 | return 1;
|
---|
711 | return 0;
|
---|
712 | }
|
---|
713 |
|
---|
714 | while ((count = rs->icount) > 0) {
|
---|
715 | icount = bufend(rs->ibuf) - rs->itail;
|
---|
716 | if (count > icount) count = icount;
|
---|
717 |
|
---|
718 | /* Perform input processing on (part of) the input buffer. */
|
---|
719 | if ((count = in_process(tp, rs->itail, count)) == 0) break;
|
---|
720 |
|
---|
721 | lock(); /* protect interrupt sensitive variables */
|
---|
722 | rs->icount -= count;
|
---|
723 | if (!rs->idevready && rs->icount < RS_ILOWWATER) istart(rs);
|
---|
724 | unlock();
|
---|
725 | if ((rs->itail += count) == bufend(rs->ibuf)) rs->itail = rs->ibuf;
|
---|
726 | }
|
---|
727 | }
|
---|
728 |
|
---|
729 | /*===========================================================================*
|
---|
730 | * rs_ostart *
|
---|
731 | *===========================================================================*/
|
---|
732 | PRIVATE void rs_ostart(rs)
|
---|
733 | rs232_t *rs; /* which rs line */
|
---|
734 | {
|
---|
735 | /* Tell RS232 there is something waiting in the output buffer. */
|
---|
736 |
|
---|
737 | rs->ostate |= OQUEUED;
|
---|
738 | if (txready(rs)) out_int(rs);
|
---|
739 | }
|
---|
740 |
|
---|
741 | /*===========================================================================*
|
---|
742 | * rs_break *
|
---|
743 | *===========================================================================*/
|
---|
744 | PRIVATE int rs_break(tp, dummy)
|
---|
745 | tty_t *tp; /* which tty */
|
---|
746 | int dummy;
|
---|
747 | {
|
---|
748 | /* Generate a break condition by setting the BREAK bit for 0.4 sec. */
|
---|
749 | rs232_t *rs = tp->tty_priv;
|
---|
750 | unsigned long line_controls;
|
---|
751 |
|
---|
752 | sys_inb(rs->line_ctl_port, &line_controls);
|
---|
753 | sys_outb(rs->line_ctl_port, line_controls | LC_BREAK);
|
---|
754 | /* XXX */
|
---|
755 | /* milli_delay(400); */ /* ouch */
|
---|
756 | printf("RS232 break\n");
|
---|
757 | sys_outb(rs->line_ctl_port, line_controls);
|
---|
758 | return 0; /* dummy */
|
---|
759 | }
|
---|
760 |
|
---|
761 | /*===========================================================================*
|
---|
762 | * rs_close *
|
---|
763 | *===========================================================================*/
|
---|
764 | PRIVATE int rs_close(tp, dummy)
|
---|
765 | tty_t *tp; /* which tty */
|
---|
766 | int dummy;
|
---|
767 | {
|
---|
768 | /* The line is closed; optionally hang up. */
|
---|
769 | rs232_t *rs = tp->tty_priv;
|
---|
770 | int r;
|
---|
771 |
|
---|
772 | if (tp->tty_termios.c_cflag & HUPCL) {
|
---|
773 | sys_outb(rs->modem_ctl_port, MC_OUT2 | MC_RTS);
|
---|
774 | }
|
---|
775 | return 0; /* dummy */
|
---|
776 | }
|
---|
777 |
|
---|
778 | /* Low level (interrupt) routines. */
|
---|
779 |
|
---|
780 | #if (MACHINE == IBM_PC)
|
---|
781 | /*===========================================================================*
|
---|
782 | * rs232_handler *
|
---|
783 | *===========================================================================*/
|
---|
784 | PRIVATE void rs232_handler(rs)
|
---|
785 | struct rs232 *rs;
|
---|
786 | {
|
---|
787 | /* Interrupt hander for RS232. */
|
---|
788 |
|
---|
789 | while (TRUE) {
|
---|
790 | unsigned long v;
|
---|
791 | /* Loop to pick up ALL pending interrupts for device.
|
---|
792 | * This usually just wastes time unless the hardware has a buffer
|
---|
793 | * (and then we have to worry about being stuck in the loop too long).
|
---|
794 | * Unfortunately, some serial cards lock up without this.
|
---|
795 | */
|
---|
796 | sys_inb(rs->int_id_port, &v);
|
---|
797 | switch (v) {
|
---|
798 | case IS_RECEIVER_READY:
|
---|
799 | in_int(rs);
|
---|
800 | continue;
|
---|
801 | case IS_TRANSMITTER_READY:
|
---|
802 | out_int(rs);
|
---|
803 | continue;
|
---|
804 | case IS_MODEM_STATUS_CHANGE:
|
---|
805 | modem_int(rs);
|
---|
806 | continue;
|
---|
807 | case IS_LINE_STATUS_CHANGE:
|
---|
808 | line_int(rs);
|
---|
809 | continue;
|
---|
810 | }
|
---|
811 | return;
|
---|
812 | }
|
---|
813 | }
|
---|
814 | #endif /* MACHINE == IBM_PC */
|
---|
815 |
|
---|
816 | #if (MACHINE == ATARI)
|
---|
817 | /*===========================================================================*
|
---|
818 | * siaint *
|
---|
819 | *===========================================================================*/
|
---|
820 | PRIVATE void siaint(type)
|
---|
821 | int type; /* interrupt type */
|
---|
822 | {
|
---|
823 | /* siaint is the rs232 interrupt procedure for Atari ST's. For ST there are
|
---|
824 | * as much as 5 interrupt lines used for rs232. The trap type byte left on the
|
---|
825 | * stack by the assembler interrupt handler identifies the interrupt cause.
|
---|
826 | */
|
---|
827 |
|
---|
828 | register unsigned char code;
|
---|
829 | register rs232_t *rs = &rs_lines[0];
|
---|
830 | int s = lock();
|
---|
831 |
|
---|
832 | switch (type & 0x00FF)
|
---|
833 | {
|
---|
834 | case 0x00: /* receive buffer full */
|
---|
835 | in_int(rs);
|
---|
836 | break;
|
---|
837 | case 0x01: /* receive error */
|
---|
838 | line_int(rs);
|
---|
839 | break;
|
---|
840 | case 0x02: /* transmit buffer empty */
|
---|
841 | out_int(rs);
|
---|
842 | break;
|
---|
843 | case 0x03: /* transmit error */
|
---|
844 | code = MFP->mf_tsr;
|
---|
845 | if (code & ~(T_ENA | T_UE | T_EMPTY))
|
---|
846 | {
|
---|
847 | printf("sia: transmit error: status=%x\r\n", code);
|
---|
848 | /* MFP->mf_udr = lastchar; */ /* retry */
|
---|
849 | }
|
---|
850 | break;
|
---|
851 | case 0x04: /* modem lines change */
|
---|
852 | modem_int(rs);
|
---|
853 | break;
|
---|
854 | }
|
---|
855 | restore(s);
|
---|
856 | }
|
---|
857 | #endif /* MACHINE == ATARI */
|
---|
858 |
|
---|
859 | /*===========================================================================*
|
---|
860 | * in_int *
|
---|
861 | *===========================================================================*/
|
---|
862 | PRIVATE void in_int(rs)
|
---|
863 | register rs232_t *rs; /* line with input interrupt */
|
---|
864 | {
|
---|
865 | /* Read the data which just arrived.
|
---|
866 | * If it is the oxoff char, clear OSWREADY, else if OSWREADY was clear, set
|
---|
867 | * it and restart output (any char does this, not just xon).
|
---|
868 | * Put data in the buffer if room, otherwise discard it.
|
---|
869 | * Set a flag for the clock interrupt handler to eventually notify TTY.
|
---|
870 | */
|
---|
871 |
|
---|
872 | unsigned long c;
|
---|
873 |
|
---|
874 | #if (MACHINE == IBM_PC)
|
---|
875 | sys_inb(rs->recv_port, &c);
|
---|
876 | #else /* MACHINE == ATARI */
|
---|
877 | c = MFP->mf_udr;
|
---|
878 | #endif
|
---|
879 |
|
---|
880 | if (!(rs->ostate & ORAW)) {
|
---|
881 | if (c == rs->oxoff) {
|
---|
882 | rs->ostate &= ~OSWREADY;
|
---|
883 | } else
|
---|
884 | if (!(rs->ostate & OSWREADY)) {
|
---|
885 | rs->ostate |= OSWREADY;
|
---|
886 | if (txready(rs)) out_int(rs);
|
---|
887 | }
|
---|
888 | }
|
---|
889 |
|
---|
890 | if (rs->icount == buflen(rs->ibuf))
|
---|
891 | {
|
---|
892 | printf("in_int: discarding byte\n");
|
---|
893 | return; /* input buffer full, discard */
|
---|
894 | }
|
---|
895 |
|
---|
896 | if (++rs->icount == RS_IHIGHWATER && rs->idevready) istop(rs);
|
---|
897 | *rs->ihead = c;
|
---|
898 | if (++rs->ihead == bufend(rs->ibuf)) rs->ihead = rs->ibuf;
|
---|
899 | if (rs->icount == 1) {
|
---|
900 | rs->tty->tty_events = 1;
|
---|
901 | force_timeout();
|
---|
902 | }
|
---|
903 | else
|
---|
904 | printf("in_int: icount = %d\n", rs->icount);
|
---|
905 | }
|
---|
906 |
|
---|
907 | /*===========================================================================*
|
---|
908 | * line_int *
|
---|
909 | *===========================================================================*/
|
---|
910 | PRIVATE void line_int(rs)
|
---|
911 | register rs232_t *rs; /* line with line status interrupt */
|
---|
912 | {
|
---|
913 | /* Check for and record errors. */
|
---|
914 |
|
---|
915 | unsigned long s;
|
---|
916 | #if (MACHINE == IBM_PC)
|
---|
917 | sys_inb(rs->line_status_port, &s);
|
---|
918 | rs->lstatus = s;
|
---|
919 | #else /* MACHINE == ATARI */
|
---|
920 | rs->lstatus = MFP->mf_rsr;
|
---|
921 | MFP->mf_rsr &= R_ENA;
|
---|
922 | rs->pad = MFP->mf_udr; /* discard char in case of LS_OVERRUN_ERR */
|
---|
923 | #endif /* MACHINE == ATARI */
|
---|
924 | if (rs->lstatus & LS_FRAMING_ERR) ++rs->framing_errors;
|
---|
925 | if (rs->lstatus & LS_OVERRUN_ERR) ++rs->overrun_errors;
|
---|
926 | if (rs->lstatus & LS_PARITY_ERR) ++rs->parity_errors;
|
---|
927 | if (rs->lstatus & LS_BREAK_INTERRUPT) ++rs->break_interrupts;
|
---|
928 | }
|
---|
929 |
|
---|
930 | /*===========================================================================*
|
---|
931 | * modem_int *
|
---|
932 | *===========================================================================*/
|
---|
933 | PRIVATE void modem_int(rs)
|
---|
934 | register rs232_t *rs; /* line with modem interrupt */
|
---|
935 | {
|
---|
936 | /* Get possibly new device-ready status, and clear ODEVREADY if necessary.
|
---|
937 | * If the device just became ready, restart output.
|
---|
938 | */
|
---|
939 |
|
---|
940 | #if (MACHINE == ATARI)
|
---|
941 | /* Set active edge interrupt so that next change causes a new interrupt */
|
---|
942 | MFP->mf_aer = (MFP->mf_aer | (IO_SCTS|IO_SDCD)) ^
|
---|
943 | (MFP->mf_gpip & (IO_SCTS|IO_SDCD));
|
---|
944 | #endif
|
---|
945 |
|
---|
946 | if (devhup(rs)) {
|
---|
947 | rs->ostate |= ODEVHUP;
|
---|
948 | rs->tty->tty_events = 1;
|
---|
949 | force_timeout();
|
---|
950 | }
|
---|
951 |
|
---|
952 | if (!devready(rs))
|
---|
953 | rs->ostate &= ~ODEVREADY;
|
---|
954 | else if (!(rs->ostate & ODEVREADY)) {
|
---|
955 | rs->ostate |= ODEVREADY;
|
---|
956 | if (txready(rs)) out_int(rs);
|
---|
957 | }
|
---|
958 | }
|
---|
959 |
|
---|
960 | /*===========================================================================*
|
---|
961 | * out_int *
|
---|
962 | *===========================================================================*/
|
---|
963 | PRIVATE void out_int(rs)
|
---|
964 | register rs232_t *rs; /* line with output interrupt */
|
---|
965 | {
|
---|
966 | /* If there is output to do and everything is ready, do it (local device is
|
---|
967 | * known ready).
|
---|
968 | * Notify TTY when the buffer goes empty.
|
---|
969 | */
|
---|
970 |
|
---|
971 | if (rs->ostate >= (ODEVREADY | OQUEUED | OSWREADY)) {
|
---|
972 | /* Bit test allows ORAW and requires the others. */
|
---|
973 | #if (MACHINE == IBM_PC)
|
---|
974 | sys_outb(rs->xmit_port, *rs->otail);
|
---|
975 | #else /* MACHINE == ATARI */
|
---|
976 | MFP->mf_udr = *rs->otail;
|
---|
977 | #endif
|
---|
978 | if (++rs->otail == bufend(rs->obuf)) rs->otail = rs->obuf;
|
---|
979 | if (--rs->ocount == 0) {
|
---|
980 | rs->ostate ^= (ODONE | OQUEUED); /* ODONE on, OQUEUED off */
|
---|
981 | rs->tty->tty_events = 1;
|
---|
982 | force_timeout();
|
---|
983 | } else
|
---|
984 | if (rs->ocount == RS_OLOWWATER) { /* running low? */
|
---|
985 | rs->tty->tty_events = 1;
|
---|
986 | force_timeout();
|
---|
987 | }
|
---|
988 | }
|
---|
989 | }
|
---|
990 | #endif /* NR_RS_LINES > 0 */
|
---|
991 |
|
---|