TIOCTIMESTAMP capability. The port in question must be configured with
[unix-history] / sys / i386 / isa / sio.c
CommitLineData
15637ed4
RG
1/*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
d7136515 33 * from: @(#)com.c 7.5 (Berkeley) 5/16/91
01a70cf7 34 * $Id: sio.c,v 1.28 1994/02/07 18:37:21 ache Exp $
15637ed4 35 */
15637ed4
RG
36
37#include "sio.h"
38#if NSIO > 0
39/*
55116fbc 40 * Serial driver, based on 386BSD-0.1 com driver.
15637ed4
RG
41 * Mostly rewritten to use pseudo-DMA.
42 * Works for National Semiconductor NS8250-NS16550AF UARTs.
55116fbc 43 * COM driver, based on HP dca driver.
15637ed4
RG
44 */
45#include "param.h"
46#include "systm.h"
47#include "ioctl.h"
48#include "tty.h"
49#include "proc.h"
50#include "user.h"
51#include "conf.h"
52#include "file.h"
53#include "uio.h"
54#include "kernel.h"
55#include "syslog.h"
56
57#include "i386/isa/isa.h"
58#include "i386/isa/isa_device.h"
59#include "i386/isa/comreg.h"
60#include "i386/isa/ic/ns16550.h"
61
55116fbc 62#define FAKE_DCD(unit) ((unit) == comconsole)
15637ed4
RG
63#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */
64#define RB_I_HIGH_WATER (RBSZ - 2 * RS_IBUFSIZE)
65#define RB_I_LOW_WATER ((RBSZ - 2 * RS_IBUFSIZE) * 7 / 8)
66#define RS_IBUFSIZE 256
15637ed4
RG
67#define TTY_BI TTY_FE /* XXX */
68#define TTY_OE TTY_PE /* XXX */
55116fbc 69
15637ed4
RG
70#ifndef COM_BIDIR
71#define UNIT(x) (minor(x)) /* XXX */
72#else /* COM_BIDIR */
73#define COM_UNITMASK 0x7f
beb52b92 74#define COM_CALLOUTMASK 0x80 /* for both minor and dev */
15637ed4
RG
75#define UNIT(x) (minor(x) & COM_UNITMASK)
76#define CALLOUT(x) (minor(x) & COM_CALLOUTMASK)
77#endif /* COM_BIDIR */
78
79#ifdef COM_MULTIPORT
80/* checks in flags for multiport and which is multiport "master chip"
81 * for a given card
82 */
83#define COM_ISMULTIPORT(dev) ((dev)->id_flags & 0x01)
84#define COM_MPMASTER(dev) (((dev)->id_flags >> 8) & 0x0ff)
85#endif /* COM_MULTIPORT */
7a4091d6 86#define COM_NOFIFO(dev) ((dev)->id_flags & 0x02)
15637ed4 87
142126f9
AC
88#ifndef FIFO_TRIGGER
89/*
90 * This driver is fast enough to work with any value and for high values
91 * to be only slightly more efficient. Low values may be better because
92 * they give lower latency.
93 * TODO: always use low values for low speeds. Mouse movements are jerky
94 * if more than one packet arrives at once. The low speeds used for
95 * serial mice help avoid this, but not if (large) fifos are enabled.
96 */
97#define FIFO_TRIGGER FIFO_TRIGGER_14
98#endif
99
15637ed4 100#define com_scr 7 /* scratch register for 16450-16550 (R/W) */
beb52b92 101#define setsofttty() (ipending |= 1 << 4) /* XXX */
15637ed4
RG
102
103/*
104 * Input buffer watermarks.
105 * The external device is asked to stop sending when the buffer exactly reaches
106 * high water, or when the high level requests it.
107 * The high level is notified immediately (rather than at a later clock tick)
108 * when this watermark is reached.
109 * The buffer size is chosen so the watermark should almost never be reached.
110 * The low watermark is invisibly 0 since the buffer is always emptied all at
111 * once.
112 */
113#define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)
114
115/*
116 * com state bits.
117 * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher
118 * than the other bits so that they can be tested as a group without masking
119 * off the low bits.
120 *
121 * The following com and tty flags correspond closely:
122 * TS_BUSY = CS_BUSY (maintained by comstart() and comflush())
123 * CS_TTGO = ~TS_TTSTOP (maintained by comstart() and siostop())
124 * CS_CTS_OFLOW = CCTS_OFLOW (maintained by comparam())
125 * CS_RTS_IFLOW = CRTS_IFLOW (maintained by comparam())
126 * TS_FLUSH is not used.
127 * Bug: I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON.
128 */
129#define CS_BUSY 0x80 /* output in progress */
130#define CS_TTGO 0x40 /* output not stopped by XOFF */
131#define CS_ODEVREADY 0x20 /* external device h/w ready (CTS) */
132#define CS_CHECKMSR 1 /* check of MSR scheduled */
133#define CS_CTS_OFLOW 2 /* use CTS output flow control */
134#define CS_ODONE 4 /* output completed */
135#define CS_RTS_IFLOW 8 /* use RTS input flow control */
136
137static char *error_desc[] = {
138#define CE_OVERRUN 0
139 "silo overflow",
140#define CE_INTERRUPT_BUF_OVERFLOW 1
141 "interrupt-level buffer overflow",
142#define CE_TTY_BUF_OVERFLOW 2
143 "tty-level buffer overflow",
144};
145
146#define CE_NTYPES 3
147#define CE_RECORD(com, errnum) (++(com)->delta_error_counts[errnum])
148
149/* types. XXX - should be elsewhere */
150typedef u_int Port_t; /* hardware port */
15637ed4
RG
151typedef u_char bool_t; /* boolean */
152
153/* com device structure */
154struct com_s {
155 u_char state; /* miscellaneous flag bits */
156 u_char cfcr_image; /* copy of value written to CFCR */
157 bool_t hasfifo; /* nonzero for 16550 UARTs */
158 u_char mcr_image; /* copy of value written to MCR */
15637ed4
RG
159#ifdef COM_BIDIR
160 bool_t bidir; /* is this unit bidirectional? */
161 bool_t active; /* is the port active _at all_? */
162 bool_t active_in; /* is the incoming port in use? */
163 bool_t active_out; /* is the outgoing port in use? */
164#endif /* COM_BIDIR */
165#ifdef COM_MULTIPORT
166 bool_t multiport; /* is this unit part of a multiport device? */
167#endif /* COM_MULTIPORT */
55116fbc 168 int dtr_wait; /* time to hold DTR down on close (* 1/HZ) */
beb52b92 169 u_int tx_fifo_size;
15637ed4
RG
170
171 /*
172 * The high level of the driver never reads status registers directly
173 * because there would be too many side effects to handle conveniently.
174 * Instead, it reads copies of the registers stored here by the
175 * interrupt handler.
176 */
177 u_char last_modem_status; /* last MSR read by intr handler */
178 u_char prev_modem_status; /* last MSR handled by high level */
179
180 u_char *ibuf; /* start of input buffer */
181 u_char *ibufend; /* end of input buffer */
182 u_char *ihighwater; /* threshold in input buffer */
183 u_char *iptr; /* next free spot in input buffer */
184
185 u_char *obufend; /* end of output buffer */
186 int ocount; /* original count for current output */
187 u_char *optr; /* next char to output */
188
189 Port_t data_port; /* i/o ports */
190 Port_t int_id_port;
191 Port_t iobase;
192 Port_t modem_ctl_port;
193 Port_t line_status_port;
194 Port_t modem_status_port;
195
196 struct tty *tp; /* cross reference */
197
198 u_long bytes_in; /* statistics */
199 u_long bytes_out;
200 u_int delta_error_counts[CE_NTYPES];
201 u_int error_counts[CE_NTYPES];
202
203 /*
204 * Ping-pong input buffers. The extra factor of 2 in the sizes is
205 * to allow for an error byte for each input byte.
206 */
207#define CE_INPUT_OFFSET RS_IBUFSIZE
208 u_char ibuf1[2 * RS_IBUFSIZE];
209 u_char ibuf2[2 * RS_IBUFSIZE];
01a70cf7
PHK
210 int do_timestamp;
211 struct timeval timestamp;
15637ed4
RG
212};
213
15637ed4
RG
214/*
215 * These functions in the com module ought to be declared (with a prototype)
216 * in a com-driver system header. The void ones may need to be int to match
217 * ancient devswitch declarations, but they don't actually return anything.
218 */
219#define Dev_t int /* promoted dev_t */
220struct consdev;
221
222int sioclose __P((Dev_t dev, int fflag, int devtype,
223 struct proc *p));
224void siointr __P((int unit));
15637ed4
RG
225int sioioctl __P((Dev_t dev, int cmd, caddr_t data,
226 int fflag, struct proc *p));
227int siocngetc __P((Dev_t dev));
228void siocninit __P((struct consdev *cp));
229void siocnprobe __P((struct consdev *cp));
230void siocnputc __P((Dev_t dev, int c));
231int sioopen __P((Dev_t dev, int oflags, int devtype,
232 struct proc *p));
beb52b92 233void siopoll __P((void));
15637ed4 234int sioread __P((Dev_t dev, struct uio *uio, int ioflag));
55116fbc 235int sioselect __P((Dev_t dev, int rw, struct proc *p));
15637ed4
RG
236void siostop __P((struct tty *tp, int rw));
237int siowrite __P((Dev_t dev, struct uio *uio, int ioflag));
15637ed4 238void softsio1 __P((void));
15637ed4
RG
239
240static int sioattach __P((struct isa_device *dev));
241static void comflush __P((struct com_s *com));
242static void comhardclose __P((struct com_s *com));
243static void cominit __P((int unit, int rate));
beb52b92 244static void comintr1 __P((struct com_s *com));
142126f9 245static void commctl __P((struct com_s *com, int bits, int how));
15637ed4
RG
246static int comparam __P((struct tty *tp, struct termios *t));
247static int sioprobe __P((struct isa_device *dev));
142126f9
AC
248static void comstart __P((struct tty *tp));
249static void comwakeup __P((caddr_t chan, int ticks));
55116fbc 250static int tiocm_xxx2mcr __P((int tiocm_xxx));
15637ed4
RG
251
252/* table and macro for fast conversion from a unit number to its com struct */
253static struct com_s *p_com_addr[NSIO];
254#define com_addr(unit) (p_com_addr[unit])
255
256static struct com_s com_structs[NSIO];
257
01a70cf7
PHK
258static struct timeval intr_timestamp;
259
15637ed4
RG
260struct isa_driver siodriver = {
261 sioprobe, sioattach, "sio"
262};
263
264#ifdef COMCONSOLE
265static int comconsole = COMCONSOLE;
266#else
267static int comconsole = -1;
268#endif
269static bool_t comconsinit;
270static speed_t comdefaultrate = TTYDEF_SPEED;
271static u_int com_events; /* input chars + weighted output completions */
272static int commajor;
273struct tty sio_tty[NSIO];
274extern struct tty *constty;
275extern u_int ipending; /* XXX */
276extern int tk_nin; /* XXX */
277extern int tk_rawcc; /* XXX */
278
279#ifdef KGDB
280#include "machine/remote-sl.h"
281
282extern int kgdb_dev;
283extern int kgdb_rate;
284extern int kgdb_debug_init;
285#endif
286
287static struct speedtab comspeedtab[] = {
288 0, 0,
289 50, COMBRD(50),
290 75, COMBRD(75),
291 110, COMBRD(110),
292 134, COMBRD(134),
293 150, COMBRD(150),
294 200, COMBRD(200),
295 300, COMBRD(300),
296 600, COMBRD(600),
297 1200, COMBRD(1200),
298 1800, COMBRD(1800),
299 2400, COMBRD(2400),
300 4800, COMBRD(4800),
301 9600, COMBRD(9600),
302 19200, COMBRD(19200),
303 38400, COMBRD(38400),
304 57600, COMBRD(57600),
305 115200, COMBRD(115200),
306 -1, -1
307};
308
309/* XXX - configure this list */
310static Port_t likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, };
311
312static int
313sioprobe(dev)
314 struct isa_device *dev;
315{
142126f9 316 static bool_t already_init;
15637ed4
RG
317 Port_t *com_ptr;
318 Port_t iobase;
319 int result;
320
321 if (!already_init) {
322 /*
323 * Turn off MCR_IENABLE for all likely serial ports. An unused
324 * port with its MCR_IENABLE gate open will inhibit interrupts
325 * from any used port that shares the interrupt vector.
326 */
327 for (com_ptr = likely_com_ports;
328 com_ptr < &likely_com_ports[sizeof likely_com_ports
329 / sizeof likely_com_ports[0]];
330 ++com_ptr)
331 outb(*com_ptr + com_mcr, 0);
332 already_init = TRUE;
333 }
334 iobase = dev->id_iobase;
142126f9 335 result = IO_COMSIZE;
15637ed4
RG
336
337 /*
338 * We don't want to get actual interrupts, just masked ones.
339 * Interrupts from this line should already be masked in the ICU,
340 * but mask them in the processor as well in case there are some
341 * (misconfigured) shared interrupts.
342 */
343 disable_intr();
344
345 /*
142126f9
AC
346 * Initialize the speed so that any junk in the THR or output fifo will
347 * be transmitted in a known time. (There may be lots of junk after a
348 * soft reboot, and output interrupts don't work right after a master
349 * reset, at least for 16550s. (The speed is undefined after MR, but
350 * MR empties the THR and the TSR so it's not clear why this matters)).
15637ed4
RG
351 * Enable output interrupts (only) and check the following:
352 * o the CFCR, IER and MCR in UART hold the values written to them
353 * (the values happen to be all distinct - this is good for
354 * avoiding false positive tests from bus echoes).
355 * o an output interrupt is generated and its vector is correct.
356 * o the interrupt goes away when the IIR in the UART is read.
357 */
142126f9
AC
358 outb(iobase + com_cfcr, CFCR_DLAB);
359 outb(iobase + com_dlbl, COMBRD(9600) & 0xff);
360 outb(iobase + com_dlbh, (u_int) COMBRD(9600) >> 8);
15637ed4
RG
361 outb(iobase + com_cfcr, CFCR_8BITS); /* ensure IER is addressed */
362 outb(iobase + com_mcr, MCR_IENABLE); /* open gate early */
142126f9 363 outb(iobase + com_ier, 0); /* ensure edge on next intr */
15637ed4 364 outb(iobase + com_ier, IER_ETXRDY); /* generate interrupt */
142126f9 365 DELAY((16 + 1) * 9600 / 10); /* enough to drain 16 bytes */
15637ed4
RG
366 if ( inb(iobase + com_cfcr) != CFCR_8BITS
367 || inb(iobase + com_ier) != IER_ETXRDY
368 || inb(iobase + com_mcr) != MCR_IENABLE
55116fbc
AC
369#ifndef COM_MULTIPORT /* XXX - need to do more to enable interrupts */
370 || !isa_irq_pending(dev)
371#endif
15637ed4
RG
372 || (inb(iobase + com_iir) & IIR_IMASK) != IIR_TXRDY
373 || isa_irq_pending(dev)
6460ff3d 374 || !(inb(iobase + com_iir) & IIR_NOPEND))
15637ed4
RG
375 result = 0;
376
377 /*
378 * Turn off all device interrupts and check that they go off properly.
379 * Leave MCR_IENABLE set. It gates the OUT2 output of the UART to
380 * the ICU input. Closing the gate would give a floating ICU input
381 * (unless there is another device driving at) and spurious interrupts.
382 * (On the system that this was first tested on, the input floats high
383 * and gives a (masked) interrupt as soon as the gate is closed.)
384 */
385 outb(iobase + com_ier, 0);
386 outb(iobase + com_mcr, MCR_IENABLE); /* dummy to avoid bus echo */
387 if ( inb(iobase + com_ier) != 0
388 || isa_irq_pending(dev)
6460ff3d 389 || !(inb(iobase + com_iir) & IIR_NOPEND))
15637ed4 390 result = 0;
beb52b92
AC
391 if (result == 0)
392 outb(iobase + com_mcr, 0);
15637ed4
RG
393
394 enable_intr();
15637ed4
RG
395 return (result);
396}
397
beb52b92 398static int
15637ed4
RG
399sioattach(isdp)
400 struct isa_device *isdp;
401{
402 struct com_s *com;
403 static bool_t comwakeup_started = FALSE;
404 Port_t iobase;
405 int s;
15637ed4
RG
406 int unit;
407
408 iobase = isdp->id_iobase;
409 unit = isdp->id_unit;
410 if (unit == comconsole)
411 DELAY(1000); /* XXX */
412 s = spltty();
413
414 /*
415 * sioprobe() has initialized the device registers as follows:
416 * o cfcr = CFCR_8BITS.
417 * It is most important that CFCR_DLAB is off, so that the
418 * data port is not hidden when we enable interrupts.
419 * o ier = 0.
420 * Interrupts are only enabled when the line is open.
421 * o mcr = MCR_IENABLE.
422 * Keeping MCR_DTR and MCR_RTS off might stop the external
423 * device from sending before we are ready.
424 */
425
426 com = &com_structs[unit];
427 com->cfcr_image = CFCR_8BITS;
428 com->mcr_image = MCR_IENABLE;
ff30ea45 429 com->dtr_wait = 200;
beb52b92 430 com->tx_fifo_size = 1;
15637ed4
RG
431 com->iptr = com->ibuf = com->ibuf1;
432 com->ibufend = com->ibuf1 + RS_IBUFSIZE;
433 com->ihighwater = com->ibuf1 + RS_IHIGHWATER;
434 com->iobase = iobase;
435 com->data_port = iobase + com_data;
436 com->int_id_port = iobase + com_iir;
437 com->modem_ctl_port = iobase + com_mcr;
438 com->line_status_port = iobase + com_lsr;
439 com->modem_status_port = iobase + com_msr;
440 com->tp = &sio_tty[unit];
15637ed4
RG
441
442 /* attempt to determine UART type */
87362236 443 printf("sio%d: type", unit);
482dcdb3 444#ifdef COM_MULTIPORT
55116fbc 445 if (!COM_ISMULTIPORT(isdp))
482dcdb3 446#endif
55116fbc
AC
447 {
448 u_char scr;
449 u_char scr1;
450 u_char scr2;
451
452 scr = inb(iobase + com_scr);
453 outb(iobase + com_scr, 0xa5);
454 scr1 = inb(iobase + com_scr);
455 outb(iobase + com_scr, 0x5a);
456 scr2 = inb(iobase + com_scr);
457 outb(iobase + com_scr, scr);
458 if (scr1 != 0xa5 || scr2 != 0x5a) {
142126f9 459 printf(" 8250");
55116fbc 460 goto determined_type;
15637ed4 461 }
15637ed4 462 }
55116fbc
AC
463 outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14);
464 DELAY(100);
142126f9 465 switch (inb(com->int_id_port) & IIR_FIFO_MASK) {
55116fbc 466 case FIFO_TRIGGER_1:
142126f9 467 printf(" 16450");
55116fbc
AC
468 break;
469 case FIFO_TRIGGER_4:
142126f9 470 printf(" 16450?");
55116fbc
AC
471 break;
472 case FIFO_TRIGGER_8:
142126f9 473 printf(" 16550?");
55116fbc
AC
474 break;
475 case FIFO_TRIGGER_14:
142126f9 476 printf(" 16550A");
7a4091d6
DG
477 if (COM_NOFIFO(isdp)) {
478 printf(" fifo software disabled");
479 } else {
480 com->hasfifo = TRUE;
beb52b92 481 com->tx_fifo_size = 16;
7a4091d6 482 }
55116fbc
AC
483 break;
484 }
485 outb(iobase + com_fifo, 0);
486determined_type: ;
487
15637ed4
RG
488#ifdef COM_MULTIPORT
489 if (COM_ISMULTIPORT(isdp)) {
490 struct isa_device *masterdev;
491
492 com->multiport = TRUE;
493 printf(" (multiport)");
494
495 /* set the master's common-interrupt-enable reg.,
496 * as appropriate. YYY See your manual
497 */
498 /* enable only common interrupt for port */
142126f9 499 outb(com->modem_ctl_port, com->mcr_image = 0);
15637ed4
RG
500
501 masterdev = find_isadev(isa_devtab_tty, &siodriver,
502 COM_MPMASTER(isdp));
142126f9 503 outb(masterdev->id_iobase + com_scr, 0x80);
beb52b92 504 } else
15637ed4
RG
505 com->multiport = FALSE;
506#endif /* COM_MULTIPORT */
87362236 507 printf("\n");
15637ed4
RG
508
509#ifdef KGDB
510 if (kgdb_dev == makedev(commajor, unit)) {
511 if (comconsole == unit)
512 kgdb_dev = -1; /* can't debug over console port */
513 else {
514 cominit(unit, kgdb_rate);
515 if (kgdb_debug_init) {
516 /*
517 * Print prefix of device name,
518 * let kgdb_connect print the rest.
519 */
55116fbc 520 printf("sio%d: ", unit);
15637ed4 521 kgdb_connect(1);
beb52b92 522 } else
55116fbc 523 printf("sio%d: kgdb enabled\n", unit);
15637ed4
RG
524 }
525 }
526#endif
527
528 /*
529 * Need to reset baud rate, etc. of next print so reset comconsinit.
15637ed4 530 */
55116fbc 531 if (unit == comconsole)
15637ed4 532 comconsinit = FALSE;
15637ed4
RG
533
534 com_addr(unit) = com;
15637ed4 535 splx(s);
15637ed4 536 if (!comwakeup_started) {
55116fbc 537 comwakeup((caddr_t) NULL, 0);
15637ed4
RG
538 comwakeup_started = TRUE;
539 }
15637ed4
RG
540 return (1);
541}
542
543/* ARGSUSED */
544int
545sioopen(dev, flag, mode, p)
546 dev_t dev;
547 int flag;
548 int mode;
549 struct proc *p;
550{
142126f9
AC
551#ifdef COM_BIDIR
552 bool_t callout;
553#endif /* COM_BIDIR */
15637ed4
RG
554 struct com_s *com;
555 int error = 0;
556 Port_t iobase;
557 int s;
558 struct tty *tp;
142126f9
AC
559 int unit;
560
561 unit = UNIT(dev);
15637ed4
RG
562 if ((u_int) unit >= NSIO || (com = com_addr(unit)) == NULL)
563 return (ENXIO);
564#ifdef COM_BIDIR
565 /* if it's a callout device, and bidir not possible on that dev, die */
142126f9 566 callout = CALLOUT(dev);
15637ed4
RG
567 if (callout && !(com->bidir))
568 return (ENXIO);
569#endif /* COM_BIDIR */
570
571 tp = com->tp;
572 s = spltty();
573
574#ifdef COM_BIDIR
575
576bidir_open_top:
577 /* if it's bidirectional, we've gotta deal with it... */
578 if (com->bidir) {
579 if (callout) {
580 if (com->active_in) {
581 /* it's busy. die */
582 splx(s);
583 return (EBUSY);
584 } else {
585 /* it's ours. lock it down, and set it up */
586 com->active_out = TRUE;
15637ed4
RG
587 }
588 } else {
589 if (com->active_out) {
590 /* it's busy, outgoing. wait, if possible */
591 if (flag & O_NONBLOCK) {
592 /* can't wait; bail */
593 splx(s);
594 return (EBUSY);
595 } else {
596 /* wait for it... */
55116fbc 597 error = tsleep((caddr_t)&com->active_out,
15637ed4 598 TTIPRI|PCATCH,
55116fbc 599 "siooth",
15637ed4
RG
600 0);
601 /* if there was an error, take off. */
602 if (error != 0) {
603 splx(s);
604 return (error);
605 }
606 /* else take it from the top */
607 goto bidir_open_top;
608 }
55116fbc
AC
609 } else if (com->prev_modem_status & MSR_DCD
610 || FAKE_DCD(unit)) {
15637ed4
RG
611 /* there's a carrier on the line; we win */
612 com->active_in = TRUE;
15637ed4
RG
613 } else {
614 /* there is no carrier on the line */
615 if (flag & O_NONBLOCK) {
616 /* can't wait; let it open */
617 com->active_in = TRUE;
15637ed4
RG
618 } else {
619 /* put DTR & RTS up */
55116fbc 620 /* XXX - bring up RTS earlier? */
142126f9 621 commctl(com, MCR_DTR | MCR_RTS, DMSET);
15637ed4 622 outb(com->iobase + com_ier, IER_EMSC);
142126f9 623
15637ed4 624 /* wait for it... */
55116fbc 625 error = tsleep((caddr_t)&com->active_in,
15637ed4 626 TTIPRI|PCATCH,
55116fbc 627 "siodcd",
15637ed4
RG
628 0);
629
142126f9
AC
630 /* if not active, turn intrs and DTR off */
631 if (!com->active) {
632 outb(com->iobase + com_ier, 0);
633 commctl(com, MCR_DTR, DMBIC);
634 }
15637ed4
RG
635
636 /* if there was an error, take off. */
637 if (error != 0) {
638 splx(s);
639 return (error);
640 }
641 /* else take it from the top */
642 goto bidir_open_top;
643 }
644 }
645 }
646 }
647
648 com->active = TRUE;
649#endif /* COM_BIDIR */
650
651 tp->t_oproc = comstart;
652 tp->t_param = comparam;
653 tp->t_dev = dev;
654 if (!(tp->t_state & TS_ISOPEN)) {
655 tp->t_state |= TS_WOPEN;
656 ttychars(tp);
657 if (tp->t_ispeed == 0) {
658 /*
659 * We no longer use the flags from <sys/ttydefaults.h>
660 * since those are only relevant for logins. It's
661 * important to have echo off initially so that the
662 * line doesn't start blathering before the echo flag
142126f9 663 * can be turned off.
15637ed4
RG
664 */
665 tp->t_iflag = 0;
beb52b92 666 tp->t_oflag = 0;
8e67d327 667#ifdef COMCONSOLE
beb52b92 668 if (unit == comconsole)
8e67d327 669 tp->t_oflag = TTYDEF_OFLAG;
8e67d327 670#endif
142126f9 671 tp->t_cflag = CREAD | CS8 | HUPCL;
15637ed4
RG
672 tp->t_lflag = 0;
673 tp->t_ispeed = tp->t_ospeed = comdefaultrate;
674 }
142126f9
AC
675
676 /*
677 * XXX the full state after a first open() needs to be
678 * programmable and separate for callin and callout.
679 */
8e82ace6 680#ifdef COM_BIDIR
2879af99 681 if (com->bidir) {
8e82ace6
AC
682 if (callout)
683 tp->t_cflag |= CLOCAL;
684 else
685 tp->t_cflag &= ~CLOCAL;
2879af99 686 }
8e82ace6 687#endif
142126f9
AC
688
689 commctl(com, MCR_DTR | MCR_RTS, DMSET);
15637ed4
RG
690 error = comparam(tp, &tp->t_termios);
691 if (error != 0)
692 goto out;
693 ttsetwater(tp);
694 iobase = com->iobase;
142126f9 695 if (com->hasfifo) {
15637ed4 696 /* (re)enable and drain FIFO */
142126f9 697 outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER
15637ed4 698 | FIFO_RCV_RST | FIFO_XMT_RST);
142126f9
AC
699 DELAY(100);
700 }
701 disable_intr();
15637ed4
RG
702 (void) inb(com->line_status_port);
703 (void) inb(com->data_port);
704 com->last_modem_status =
705 com->prev_modem_status = inb(com->modem_status_port);
706 outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS
707 | IER_EMSC);
708 enable_intr();
55116fbc 709 if (com->prev_modem_status & MSR_DCD || FAKE_DCD(unit))
15637ed4 710 tp->t_state |= TS_CARR_ON;
beb52b92 711 } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
15637ed4
RG
712 splx(s);
713 return (EBUSY);
714 }
715 while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL)
716#ifdef COM_BIDIR
717 /* We went through a lot of trouble to open it,
718 * but it's certain we have a carrier now, so
719 * don't spend any time on it now.
720 */
142126f9 721 && !(com->bidir)
15637ed4 722#endif /* COM_BIDIR */
142126f9 723 && !(tp->t_state & TS_CARR_ON)) {
15637ed4
RG
724 tp->t_state |= TS_WOPEN;
725 error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH,
726 ttopen, 0);
727 if (error != 0)
728 break;
729 }
730out:
731 splx(s);
732 if (error == 0)
4c45483e 733 error = (*linesw[tp->t_line].l_open)(dev, tp, 0);
15637ed4
RG
734
735#ifdef COM_BIDIR
736 /* wakeup sleepers */
737 wakeup((caddr_t) &com->active_in);
738#endif /* COM_BIDIR */
739
740 /*
741 * XXX - the next step was once not done, so interrupts, DTR and RTS
55116fbc 742 * remained hot if the process was killed while it was sleeping
15637ed4
RG
743 * waiting for carrier. Now there is the opposite problem. If several
744 * processes are sleeping waiting for carrier on the same line and one
745 * is killed, interrupts are turned off so the other processes will
746 * never see the carrier rise.
747 */
748 if (error != 0 && !(tp->t_state & TS_ISOPEN))
15637ed4 749 comhardclose(com);
15637ed4
RG
750 tp->t_state &= ~TS_WOPEN;
751
752 return (error);
753}
754
755/*ARGSUSED*/
756int
757sioclose(dev, flag, mode, p)
758 dev_t dev;
759 int flag;
760 int mode;
761 struct proc *p;
762{
763 struct com_s *com;
764 struct tty *tp;
765
766 com = com_addr(UNIT(dev));
767 tp = com->tp;
768 (*linesw[tp->t_line].l_close)(tp, flag);
769 comhardclose(com);
770 ttyclose(tp);
771 return (0);
772}
773
55116fbc 774static void
15637ed4
RG
775comhardclose(com)
776 struct com_s *com;
777{
778 Port_t iobase;
779 int s;
780 struct tty *tp;
beb52b92 781 int unit;
15637ed4
RG
782
783 s = spltty();
784 iobase = com->iobase;
01a70cf7 785 com->do_timestamp = 0;
15637ed4 786 outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
beb52b92 787 unit = com - &com_structs[0];
15637ed4 788#ifdef KGDB
142126f9 789 /* do not disable interrupts or hang up if debugging */
beb52b92 790 if (kgdb_dev != makedev(commajor, unit))
15637ed4 791#endif
142126f9 792 {
15637ed4 793 outb(iobase + com_ier, 0);
142126f9
AC
794 tp = com->tp;
795 if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN
beb52b92 796 || !(com->prev_modem_status & MSR_DCD) && !FAKE_DCD(unit)
142126f9
AC
797 || !(tp->t_state & TS_ISOPEN)) {
798 commctl(com, MCR_RTS, DMSET);
799 if (com->dtr_wait != 0)
800 /*
801 * Uninterruptible sleep since we want to
802 * wait a fixed time.
803 * XXX - delay in open() (if necessary),
804 * not here (always).
805 */
806 tsleep((caddr_t)&com->dtr_wait, TTIPRI,
807 "sioclose", com->dtr_wait);
808 }
55116fbc
AC
809 }
810
15637ed4
RG
811#ifdef COM_BIDIR
812 com->active = com->active_in = com->active_out = FALSE;
15637ed4
RG
813
814 /* wakeup sleepers who are waiting for out to finish */
815 wakeup((caddr_t) &com->active_out);
816#endif /* COM_BIDIR */
817
818 splx(s);
819}
820
821int
822sioread(dev, uio, flag)
823 dev_t dev;
824 struct uio *uio;
825 int flag;
826{
827 struct tty *tp = com_addr(UNIT(dev))->tp;
828
829 return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
830}
831
832int
833siowrite(dev, uio, flag)
834 dev_t dev;
835 struct uio *uio;
836 int flag;
837{
838 int unit = UNIT(dev);
839 struct tty *tp = com_addr(unit)->tp;
840
841 /*
842 * (XXX) We disallow virtual consoles if the physical console is
843 * a serial port. This is in case there is a display attached that
844 * is not the console. In that situation we don't need/want the X
845 * server taking over the console.
846 */
847 if (constty && unit == comconsole)
848 constty = NULL;
849 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
850}
851
01a70cf7
PHK
852/* Interrupt routine for timekeeping purposes */
853void
854siointrts(int unit)
855{
856 microtime(&intr_timestamp);
857 siointr(unit);
858}
859
15637ed4
RG
860void
861siointr(unit)
862 int unit;
863{
864 struct com_s *com;
15637ed4 865
fe4b242a 866#ifndef COM_MULTIPORT
15637ed4 867 com = com_addr(unit);
fe4b242a
AC
868 if (com != NULL)
869 comintr1(com);
15637ed4 870#else /* COM_MULTIPORT */
142126f9 871 bool_t possibly_more_intrs;
15637ed4 872
55116fbc
AC
873 /*
874 * Loop until there is no activity on any port. This is necessary
875 * to get an interrupt edge more than to avoid another interrupt.
876 * If the IRQ signal is just an OR of the IRQ signals from several
877 * devices, then the edge from one may be lost because another is
142126f9 878 * on.
55116fbc 879 */
15637ed4 880 do {
142126f9
AC
881 possibly_more_intrs = FALSE;
882 for (unit = 0; unit < NSIO; ++unit) {
883 com = com_addr(unit);
6460ff3d
AC
884 if (com != NULL
885 && !(inb(com->int_id_port) & IIR_NOPEND)) {
142126f9
AC
886 /*
887 * XXX call comintr1() instead of here from
888 * comwakeup(). The interrupt edge problem
55116fbc 889 * only exists for real interrupts.
15637ed4 890 */
beb52b92 891 comintr1(com);
6460ff3d 892 possibly_more_intrs = TRUE;
15637ed4
RG
893 }
894 }
142126f9 895 } while (possibly_more_intrs);
fe4b242a 896#endif /* COM_MULTIPORT */
15637ed4 897}
55116fbc 898
beb52b92 899static void
55116fbc
AC
900comintr1(com)
901 struct com_s *com;
15637ed4
RG
902{
903 u_char line_status;
904 u_char modem_status;
905 u_char *ioptr;
906 u_char recv_data;
15637ed4 907
01a70cf7
PHK
908 if(com->do_timestamp)
909 com->timestamp = intr_timestamp;
15637ed4
RG
910 while (TRUE) {
911 line_status = inb(com->line_status_port);
912
913 /* input event? (check first to help avoid overruns) */
914 while (line_status & LSR_RCV_MASK) {
915 /* break/unnattached error bits or real input? */
15637ed4
RG
916 if (!(line_status & LSR_RXRDY))
917 recv_data = 0;
918 else
919 recv_data = inb(com->data_port);
920 ++com->bytes_in;
921#ifdef KGDB
922 /* trap into kgdb? (XXX - needs testing and optim) */
923 if (recv_data == FRAME_END
924 && !(com->tp->t_state & TS_ISOPEN)
925 && kgdb_dev == makedev(commajor, unit)) {
926 kgdb_connect(0);
927 continue;
928 }
929#endif /* KGDB */
930 ioptr = com->iptr;
931 if (ioptr >= com->ibufend)
932 CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW);
933 else {
934 ++com_events;
beb52b92 935#if 0 /* for testing input latency vs efficiency */
142126f9 936if (com->iptr - com->ibuf == 8)
beb52b92 937 setsofttty();
142126f9 938#endif
15637ed4
RG
939 ioptr[0] = recv_data;
940 ioptr[CE_INPUT_OFFSET] = line_status;
941 com->iptr = ++ioptr;
942 if (ioptr == com->ihighwater
943 && com->state & CS_RTS_IFLOW)
944 outb(com->modem_ctl_port,
945 com->mcr_image &= ~MCR_RTS);
55116fbc
AC
946 /* XXX - move this out of isr */
947 if (line_status & LSR_OE)
948 CE_RECORD(com, CE_OVERRUN);
15637ed4
RG
949 }
950
951 /*
952 * "& 0x7F" is to avoid the gcc-1.40 generating a slow
953 * jump from the top of the loop to here
954 */
955 line_status = inb(com->line_status_port) & 0x7F;
956 }
957
958 /* modem status change? (always check before doing output) */
959 modem_status = inb(com->modem_status_port);
960 if (modem_status != com->last_modem_status) {
961 /*
962 * Schedule high level to handle DCD changes. Note
963 * that we don't use the delta bits anywhere. Some
964 * UARTs mess them up, and it's easy to remember the
965 * previous bits and calculate the delta.
966 */
15637ed4
RG
967 com->last_modem_status = modem_status;
968 if (!(com->state & CS_CHECKMSR)) {
969 com_events += LOTS_OF_EVENTS;
970 com->state |= CS_CHECKMSR;
beb52b92 971 setsofttty();
15637ed4
RG
972 }
973
974 /* handle CTS change immediately for crisp flow ctl */
975 if (com->state & CS_CTS_OFLOW) {
976 if (modem_status & MSR_CTS)
977 com->state |= CS_ODEVREADY;
978 else
979 com->state &= ~CS_ODEVREADY;
980 }
981 }
982
983 /* output queued and everything ready? */
984 if (line_status & LSR_TXRDY
985 && com->state >= (CS_ODEVREADY | CS_BUSY | CS_TTGO)) {
15637ed4 986 ioptr = com->optr;
beb52b92
AC
987 if (com->tx_fifo_size > 1) {
988 u_int ocount;
989
990 ocount = com->obufend - ioptr;
991 if (ocount > com->tx_fifo_size)
992 ocount = com->tx_fifo_size;
993 com->bytes_out += ocount;
994 do
995 outb(com->data_port, *ioptr++);
996 while (--ocount != 0);
997 } else {
998 outb(com->data_port, *ioptr++);
15637ed4 999 ++com->bytes_out;
beb52b92
AC
1000 }
1001 com->optr = ioptr;
15637ed4
RG
1002 if (ioptr >= com->obufend) {
1003 /* output just completed */
1004 com_events += LOTS_OF_EVENTS;
1005 com->state ^= (CS_ODONE | CS_BUSY);
beb52b92 1006 setsofttty(); /* handle at high level ASAP */
15637ed4
RG
1007 }
1008 }
1009
1010 /* finished? */
beb52b92 1011#ifndef COM_MULTIPORT
6460ff3d 1012 if (inb(com->int_id_port) & IIR_NOPEND)
15637ed4 1013#endif /* COM_MULTIPORT */
beb52b92 1014 return;
15637ed4
RG
1015 }
1016}
1017
70a6bf52 1018static int
55116fbc
AC
1019tiocm_xxx2mcr(tiocm_xxx)
1020 int tiocm_xxx;
70a6bf52 1021{
55116fbc
AC
1022 int mcr;
1023
1024 mcr = 0;
1025 if (tiocm_xxx & TIOCM_DTR)
1026 mcr |= MCR_DTR;
1027 if (tiocm_xxx & TIOCM_RTS)
1028 mcr |= MCR_RTS;
1029 return (mcr);
70a6bf52 1030}
55116fbc 1031
15637ed4
RG
1032int
1033sioioctl(dev, cmd, data, flag, p)
1034 dev_t dev;
1035 int cmd;
1036 caddr_t data;
1037 int flag;
1038 struct proc *p;
1039{
1040 struct com_s *com;
1041 int error;
1042 Port_t iobase;
55116fbc
AC
1043 int mcr;
1044 int msr;
15637ed4 1045 int s;
55116fbc 1046 int tiocm_xxx;
15637ed4
RG
1047 struct tty *tp;
1048
1049 com = com_addr(UNIT(dev));
1050 tp = com->tp;
1051 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
1052 if (error >= 0)
1053 return (error);
1054 error = ttioctl(tp, cmd, data, flag);
4dda0a99 1055
beb52b92
AC
1056#ifdef COM_BIDIR
1057 /* XXX: plug security hole while sticky bits not yet implemented */
142126f9 1058 if (com->bidir && com->active_in && p->p_ucred->cr_uid != 0)
4dda0a99 1059 tp->t_cflag &= ~CLOCAL;
4dda0a99 1060#endif
beb52b92
AC
1061
1062 if (error >= 0)
142126f9 1063 return (error);
4dda0a99 1064
142126f9
AC
1065 iobase = com->iobase;
1066 s = spltty();
15637ed4
RG
1067 switch (cmd) {
1068 case TIOCSBRK:
1069 outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK);
1070 break;
1071 case TIOCCBRK:
1072 outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
1073 break;
1074 case TIOCSDTR:
142126f9 1075 commctl(com, MCR_DTR, DMBIS);
15637ed4
RG
1076 break;
1077 case TIOCCDTR:
142126f9 1078 commctl(com, MCR_DTR, DMBIC);
15637ed4
RG
1079 break;
1080 case TIOCMSET:
142126f9 1081 commctl(com, tiocm_xxx2mcr(*(int *)data), DMSET);
15637ed4
RG
1082 break;
1083 case TIOCMBIS:
142126f9 1084 commctl(com, tiocm_xxx2mcr(*(int *)data), DMBIS);
15637ed4
RG
1085 break;
1086 case TIOCMBIC:
142126f9 1087 commctl(com, tiocm_xxx2mcr(*(int *)data), DMBIC);
15637ed4
RG
1088 break;
1089 case TIOCMGET:
55116fbc
AC
1090 tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */
1091 mcr = com->mcr_image;
1092 if (mcr & MCR_DTR)
1093 tiocm_xxx |= TIOCM_DTR;
1094 if (mcr & MCR_RTS)
1095 tiocm_xxx |= TIOCM_RTS;
1096 msr = com->prev_modem_status;
1097 if (msr & MSR_CTS)
1098 tiocm_xxx |= TIOCM_CTS;
1099 if (msr & MSR_DCD)
1100 tiocm_xxx |= TIOCM_CD;
1101 if (msr & MSR_DSR)
1102 tiocm_xxx |= TIOCM_DSR;
142126f9
AC
1103 /*
1104 * XXX - MSR_RI is naturally volatile, and we make MSR_TERI
1105 * more volatile by reading the modem status a lot. Perhaps
1106 * we should latch both bits until the status is read here.
1107 */
55116fbc
AC
1108 if (msr & (MSR_RI | MSR_TERI))
1109 tiocm_xxx |= TIOCM_RI;
1110 *(int *)data = tiocm_xxx;
15637ed4
RG
1111 break;
1112#ifdef COM_BIDIR
1113 case TIOCMSBIDIR:
1114 /* must be root to set bidir. capability */
142126f9
AC
1115 error = suser(p->p_ucred, &p->p_acflag);
1116 if (error != 0) {
1117 splx(s);
15637ed4 1118 return(EPERM);
142126f9 1119 }
15637ed4 1120
142126f9
AC
1121 /* if it's the console, can't do it (XXX why?) */
1122 if (UNIT(dev) == comconsole) {
1123 splx(s);
15637ed4 1124 return(ENOTTY);
142126f9 1125 }
15637ed4 1126
142126f9
AC
1127#if 0
1128 /* XXX - can't do the next, for obvious reasons...
15637ed4
RG
1129 * but there are problems to be looked at...
1130 */
15637ed4 1131 /* if the port is active, don't do it */
142126f9
AC
1132 if (com->active) {
1133 splx(s);
1134 return(EBUSY);
1135 }
1136#endif
15637ed4
RG
1137
1138 com->bidir = *(int *)data;
1139 break;
1140 case TIOCMGBIDIR:
1141 *(int *)data = com->bidir;
1142 break;
1143#endif /* COM_BIDIR */
55116fbc 1144 case TIOCMSDTRWAIT:
142126f9
AC
1145 /* must be root since the wait applies to following logins */
1146 error = suser(p->p_ucred, &p->p_acflag);
1147 if (error != 0) {
1148 splx(s);
55116fbc 1149 return(EPERM);
142126f9 1150 }
55116fbc
AC
1151
1152 /* if it's the console, can't do it (XXX why?) */
142126f9
AC
1153 if (UNIT(dev) == comconsole) {
1154 splx(s);
55116fbc 1155 return(ENOTTY);
142126f9 1156 }
55116fbc
AC
1157
1158 com->dtr_wait = *(int *)data;
1159 break;
1160 case TIOCMGDTRWAIT:
1161 *(int *)data = com->dtr_wait;
1162 break;
01a70cf7
PHK
1163 case TIOCTIMESTAMP:
1164 com->do_timestamp = 1;
1165 *(struct timeval *)data = com->timestamp;
1166 break;
15637ed4
RG
1167 default:
1168 splx(s);
1169 return (ENOTTY);
1170 }
1171 splx(s);
1172 return (0);
1173}
1174
1175/* cancel pending output */
1176static void
1177comflush(com)
1178 struct com_s *com;
1179{
1180 struct ringb *rbp;
1181
1182 disable_intr();
1183 if (com->state & CS_ODONE)
1184 com_events -= LOTS_OF_EVENTS;
1185 com->state &= ~(CS_ODONE | CS_BUSY);
1186 enable_intr();
1187 rbp = &com->tp->t_out;
1188 rbp->rb_hd += com->ocount;
1189 rbp->rb_hd = RB_ROLLOVER(rbp, rbp->rb_hd);
1190 com->ocount = 0;
1191 com->tp->t_state &= ~TS_BUSY;
1192}
1193
beb52b92
AC
1194void
1195siopoll()
15637ed4
RG
1196{
1197 static bool_t awake = FALSE;
15637ed4
RG
1198 int s;
1199 int unit;
1200
1201 if (com_events == 0)
1202 return;
1203 disable_intr();
1204 if (awake) {
1205 enable_intr();
1206 return;
1207 }
1208 awake = TRUE;
1209 enable_intr();
1210 s = spltty();
1211repeat:
1212 for (unit = 0; unit < NSIO; ++unit) {
142126f9 1213 u_char *buf;
beb52b92 1214 struct com_s *com;
15637ed4
RG
1215 u_char *ibuf;
1216 int incc;
1217 struct tty *tp;
1218
1219 com = com_addr(unit);
1220 if (com == NULL)
1221 continue;
1222 tp = com->tp;
1223
1224 /* switch the role of the low-level input buffers */
beb52b92
AC
1225 if (com->iptr == (ibuf = com->ibuf)) {
1226 buf = NULL; /* not used, but compiler can't tell */
15637ed4 1227 incc = 0;
beb52b92 1228 } else {
15637ed4
RG
1229 buf = ibuf;
1230 disable_intr();
1231 incc = com->iptr - buf;
1232 com_events -= incc;
1233 if (ibuf == com->ibuf1)
1234 ibuf = com->ibuf2;
1235 else
1236 ibuf = com->ibuf1;
1237 com->ibufend = ibuf + RS_IBUFSIZE;
1238 com->ihighwater = ibuf + RS_IHIGHWATER;
1239 com->iptr = ibuf;
1240
1241 /*
1242 * There is now room for another low-level buffer full
1243 * of input, so enable RTS if it is now disabled and
1244 * there is room in the high-level buffer.
1245 */
1246 if (!(com->mcr_image & MCR_RTS)
55116fbc 1247 && !(tp->t_state & TS_RTS_IFLOW))
15637ed4
RG
1248 outb(com->modem_ctl_port,
1249 com->mcr_image |= MCR_RTS);
1250 enable_intr();
1251 com->ibuf = ibuf;
1252 }
1253
1254 if (com->state & CS_CHECKMSR) {
1255 u_char delta_modem_status;
1256
1257 disable_intr();
1258 delta_modem_status = com->last_modem_status
1259 ^ com->prev_modem_status;
1260 com->prev_modem_status = com->last_modem_status;
1261 com_events -= LOTS_OF_EVENTS;
1262 com->state &= ~CS_CHECKMSR;
1263 enable_intr();
55116fbc 1264 if (delta_modem_status & MSR_DCD && !FAKE_DCD(unit)) {
15637ed4
RG
1265 if (com->prev_modem_status & MSR_DCD) {
1266 (*linesw[tp->t_line].l_modem)(tp, 1);
55116fbc 1267#ifdef COM_BIDIR
15637ed4 1268 wakeup((caddr_t) &com->active_in);
15637ed4 1269#endif /* COM_BIDIR */
beb52b92 1270 } else
55116fbc 1271 (*linesw[tp->t_line].l_modem)(tp, 0);
15637ed4
RG
1272 }
1273 }
1274
1275 /* XXX */
1276 if (TRUE) {
1277 u_int delta;
15637ed4
RG
1278 int errnum;
1279 u_long total;
1280
beb52b92 1281 for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
15637ed4 1282 disable_intr();
beb52b92
AC
1283 delta = com->delta_error_counts[errnum];
1284 com->delta_error_counts[errnum] = 0;
15637ed4 1285 enable_intr();
15637ed4
RG
1286 if (delta != 0) {
1287 total =
1288 com->error_counts[errnum] += delta;
1289 log(LOG_WARNING,
55116fbc 1290 "sio%d: %u more %s%s (total %lu)\n",
15637ed4
RG
1291 unit, delta, error_desc[errnum],
1292 delta == 1 ? "" : "s", total);
1293 }
1294 }
1295 }
1296 if (com->state & CS_ODONE) {
1297 comflush(com);
1298 /* XXX - why isn't the table used for t_line == 0? */
1299 if (tp->t_line != 0)
1300 (*linesw[tp->t_line].l_start)(tp);
1301 else
1302 comstart(tp);
1303 }
1304 if (incc <= 0 || !(tp->t_state & TS_ISOPEN))
1305 continue;
1306 if (com->state & CS_RTS_IFLOW
1307 && RB_LEN(&tp->t_raw) + incc >= RB_I_HIGH_WATER
55116fbc 1308 && !(tp->t_state & TS_RTS_IFLOW)
15637ed4
RG
1309 /*
1310 * XXX - need RTS flow control for all line disciplines.
1311 * Only have it in standard one now.
1312 */
1313 && linesw[tp->t_line].l_rint == ttyinput) {
55116fbc 1314 tp->t_state |= TS_RTS_IFLOW;
15637ed4
RG
1315 ttstart(tp);
1316 }
1317 /*
1318 * Avoid the grotesquely inefficient lineswitch routine
1319 * (ttyinput) in "raw" mode. It usually takes about 450
1320 * instructions (that's without canonical processing or echo!).
1321 * slinput is reasonably fast (usually 40 instructions plus
1322 * call overhead).
1323 */
1324 if (!(tp->t_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP
1325 | IXOFF | IXON))
1326 && !(tp->t_lflag & (ECHO | ECHONL | ICANON | IEXTEN | ISIG
1327 | PENDIN))
1328 && !(tp->t_state & (TS_CNTTB | TS_LNCH))
1329 && linesw[tp->t_line].l_rint == ttyinput) {
1330 tk_nin += incc;
1331 tk_rawcc += incc;
1332 tp->t_rawcc += incc;
1333 com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
1334 += incc - rb_write(&tp->t_raw, (char *) buf,
1335 incc);
1336 ttwakeup(tp);
1337 if (tp->t_state & TS_TTSTOP
1338 && (tp->t_iflag & IXANY
1339 || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
1340 tp->t_state &= ~TS_TTSTOP;
1341 tp->t_lflag &= ~FLUSHO;
1342 ttstart(tp);
1343 }
beb52b92 1344 } else {
15637ed4
RG
1345 do {
1346 u_char line_status;
1347 int recv_data;
1348
1349 line_status = (u_char) buf[CE_INPUT_OFFSET];
1350 recv_data = (u_char) *buf++;
1351 if (line_status
1352 & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
1353 if (line_status & LSR_BI)
1354 recv_data |= TTY_BI;
1355 if (line_status & LSR_FE)
1356 recv_data |= TTY_FE;
1357 if (line_status & LSR_OE)
1358 recv_data |= TTY_OE;
1359 if (line_status & LSR_PE)
1360 recv_data |= TTY_PE;
1361 }
1362 (*linesw[tp->t_line].l_rint)(recv_data, tp);
1363 } while (--incc > 0);
1364 }
1365 if (com_events == 0)
1366 break;
1367 }
1368 if (com_events >= LOTS_OF_EVENTS)
1369 goto repeat;
1370 splx(s);
1371 awake = FALSE;
1372}
1373
1374static int
1375comparam(tp, t)
1376 struct tty *tp;
1377 struct termios *t;
1378{
1379 u_int cfcr;
1380 int cflag;
1381 struct com_s *com;
1382 int divisor;
1383 int error;
1384 Port_t iobase;
1385 int s;
1386 int unit;
1387
1388 /* check requested parameters */
1389 divisor = ttspeedtab(t->c_ospeed, comspeedtab);
142126f9
AC
1390 if (t->c_ispeed == 0)
1391 t->c_ispeed = t->c_ospeed;
1392 if (divisor < 0 || t->c_ispeed != t->c_ospeed)
15637ed4
RG
1393 return (EINVAL);
1394
1395 /* parameters are OK, convert them to the com struct and the device */
1396 unit = UNIT(tp->t_dev);
1397 com = com_addr(unit);
1398 iobase = com->iobase;
1399 s = spltty();
142126f9
AC
1400 if (divisor == 0)
1401 commctl(com, MCR_DTR, DMBIC); /* hang up line */
1402 else
1403 commctl(com, MCR_DTR, DMBIS);
15637ed4
RG
1404 cflag = t->c_cflag;
1405 switch (cflag & CSIZE) {
1406 case CS5:
1407 cfcr = CFCR_5BITS;
1408 break;
1409 case CS6:
1410 cfcr = CFCR_6BITS;
1411 break;
1412 case CS7:
1413 cfcr = CFCR_7BITS;
1414 break;
1415 default:
1416 cfcr = CFCR_8BITS;
1417 break;
1418 }
1419 if (cflag & PARENB) {
1420 cfcr |= CFCR_PENAB;
1421 if (!(cflag & PARODD))
1422 cfcr |= CFCR_PEVEN;
1423 }
1424 if (cflag & CSTOPB)
1425 cfcr |= CFCR_STOPB;
1426
1427 /*
1428 * Some UARTs lock up if the divisor latch registers are selected
1429 * while the UART is doing output (they refuse to transmit anything
1430 * more until given a hard reset). Fix this by stopping filling
1431 * the device buffers and waiting for them to drain. Reading the
1432 * line status port outside of siointr() might lose some receiver
1433 * error bits, but that is acceptable here.
1434 */
1435 disable_intr();
55116fbc 1436retry:
15637ed4
RG
1437 com->state &= ~CS_TTGO;
1438 enable_intr();
1439 while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
1440 != (LSR_TSRE | LSR_TXRDY)) {
1441 error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH,
55116fbc 1442 "sioparam", 1);
15637ed4
RG
1443 if (error != 0 && error != EAGAIN) {
1444 if (!(tp->t_state & TS_TTSTOP)) {
1445 disable_intr();
1446 com->state |= CS_TTGO;
1447 enable_intr();
1448 }
1449 splx(s);
1450 return (error);
1451 }
1452 }
1453
1454 disable_intr(); /* very important while com_data is hidden */
55116fbc
AC
1455
1456 /*
1457 * XXX - clearing CS_TTGO is not sufficient to stop further output,
beb52b92
AC
1458 * because siopoll() calls comstart() which usually sets it again
1459 * because TS_TTSTOP is clear. Setting TS_TTSTOP would not be
1460 * sufficient, for similar reasons.
55116fbc
AC
1461 */
1462 if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
1463 != (LSR_TSRE | LSR_TXRDY))
1464 goto retry;
1465
142126f9
AC
1466 if (divisor != 0) {
1467 outb(iobase + com_cfcr, cfcr | CFCR_DLAB);
1468 outb(iobase + com_dlbl, divisor & 0xFF);
1469 outb(iobase + com_dlbh, (u_int) divisor >> 8);
1470 }
15637ed4
RG
1471 outb(iobase + com_cfcr, com->cfcr_image = cfcr);
1472 if (!(tp->t_state & TS_TTSTOP))
1473 com->state |= CS_TTGO;
1474 if (cflag & CRTS_IFLOW)
1475 com->state |= CS_RTS_IFLOW; /* XXX - secondary changes? */
1476 else
1477 com->state &= ~CS_RTS_IFLOW;
1478
1479 /*
1480 * Set up state to handle output flow control.
1481 * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
1482 * Now has 16+ msec latency, while CTS flow has 50- usec latency.
15637ed4
RG
1483 */
1484 com->state &= ~CS_CTS_OFLOW;
1485 com->state |= CS_ODEVREADY;
1486 if (cflag & CCTS_OFLOW) {
1487 com->state |= CS_CTS_OFLOW;
55116fbc 1488 if (!(com->last_modem_status & MSR_CTS))
15637ed4
RG
1489 com->state &= ~CS_ODEVREADY;
1490 }
1491
beb52b92
AC
1492 /*
1493 * Recover from fiddling with CS_TTGO. We used to call siointr()
1494 * unconditionally, but that defeated the careful discarding of
1495 * stale input in sioopen().
1496 *
1497 * XXX sioopen() is not careful waiting for carrier for the callout
1498 * case.
1499 */
1500 if (com->state >= (CS_BUSY | CS_TTGO))
fe4b242a 1501 comintr1(com);
beb52b92 1502
55116fbc 1503 enable_intr();
15637ed4
RG
1504 splx(s);
1505 return (0);
1506}
1507
4c45483e 1508static void
15637ed4
RG
1509comstart(tp)
1510 struct tty *tp;
1511{
1512 struct com_s *com;
1513 int s;
1514 int unit;
1515
1516 unit = UNIT(tp->t_dev);
1517 com = com_addr(unit);
1518 s = spltty();
1519 disable_intr();
1520 if (tp->t_state & TS_TTSTOP)
1521 com->state &= ~CS_TTGO;
1522 else
1523 com->state |= CS_TTGO;
55116fbc 1524 if (tp->t_state & TS_RTS_IFLOW) {
15637ed4
RG
1525 if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
1526 outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
beb52b92 1527 } else {
55116fbc 1528 if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater)
15637ed4
RG
1529 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
1530 }
1531 enable_intr();
1532 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
1533 goto out;
1534 if (RB_LEN(&tp->t_out) <= tp->t_lowat) {
1535 if (tp->t_state & TS_ASLEEP) {
1536 tp->t_state &= ~TS_ASLEEP;
1537 wakeup((caddr_t)&tp->t_out);
1538 }
1539 if (tp->t_wsel) {
1540 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
1541 tp->t_wsel = 0;
1542 tp->t_state &= ~TS_WCOLL;
1543 }
1544 }
1545 if (com->ocount != 0) {
1546 disable_intr();
fe4b242a 1547 comintr1(com);
15637ed4 1548 enable_intr();
beb52b92 1549 } else if (RB_LEN(&tp->t_out) != 0) {
15637ed4
RG
1550 tp->t_state |= TS_BUSY;
1551 com->ocount = RB_CONTIGGET(&tp->t_out);
1552 disable_intr();
1553 com->obufend = (com->optr = (u_char *) tp->t_out.rb_hd)
1554 + com->ocount;
1555 com->state |= CS_BUSY;
fe4b242a 1556 comintr1(com); /* fake interrupt to start output */
15637ed4
RG
1557 enable_intr();
1558 }
1559out:
1560 splx(s);
15637ed4
RG
1561}
1562
1563void
1564siostop(tp, rw)
1565 struct tty *tp;
1566 int rw;
1567{
1568 struct com_s *com;
1569
1570 com = com_addr(UNIT(tp->t_dev));
1571 if (rw & FWRITE)
1572 comflush(com);
1573 disable_intr();
87129df8
AC
1574 if (rw & FREAD) {
1575 com_events -= (com->iptr - com->ibuf);
1576 com->iptr = com->ibuf;
1577 }
15637ed4
RG
1578 if (tp->t_state & TS_TTSTOP)
1579 com->state &= ~CS_TTGO;
1580 else
1581 com->state |= CS_TTGO;
1582 enable_intr();
1583}
1584
beb52b92
AC
1585int
1586sioselect(dev, rw, p)
1587 dev_t dev;
1588 int rw;
1589 struct proc *p;
1590{
ce6af053 1591#ifdef COM_BIDIR
beb52b92 1592 return ttselect(dev & ~COM_CALLOUTMASK, rw, p);
ce6af053
AC
1593#else
1594 return ttselect(dev, rw, p);
1595#endif
beb52b92
AC
1596}
1597
142126f9 1598static void
15637ed4
RG
1599commctl(com, bits, how)
1600 struct com_s *com;
1601 int bits;
1602 int how;
1603{
1604 disable_intr();
1605 switch (how) {
1606 case DMSET:
142126f9
AC
1607 outb(com->modem_ctl_port,
1608 com->mcr_image = bits | (com->mcr_image & MCR_IENABLE));
15637ed4
RG
1609 break;
1610 case DMBIS:
1611 outb(com->modem_ctl_port, com->mcr_image |= bits);
1612 break;
1613 case DMBIC:
55116fbc 1614 outb(com->modem_ctl_port, com->mcr_image &= ~bits);
15637ed4
RG
1615 break;
1616 }
1617 enable_intr();
15637ed4
RG
1618}
1619
4c45483e 1620static void
55116fbc
AC
1621comwakeup(chan, ticks)
1622 caddr_t chan;
1623 int ticks;
15637ed4 1624{
15637ed4
RG
1625 int unit;
1626
142126f9 1627 timeout(comwakeup, (caddr_t) NULL, hz / 100);
15637ed4 1628 if (com_events != 0)
beb52b92
AC
1629 /* schedule siopoll() to run when the cpl allows */
1630 setsofttty();
15637ed4
RG
1631
1632 /* recover from lost output interrupts */
1633 for (unit = 0; unit < NSIO; ++unit) {
beb52b92
AC
1634 struct com_s *com;
1635
15637ed4
RG
1636 com = com_addr(unit);
1637 if (com != NULL && com->state >= (CS_BUSY | CS_TTGO)) {
1638 disable_intr();
fe4b242a 1639 comintr1(com);
15637ed4
RG
1640 enable_intr();
1641 }
1642 }
4c45483e 1643 return;
15637ed4
RG
1644}
1645
1646void
55116fbc
AC
1647softsio1()
1648{
beb52b92 1649 siopoll();
55116fbc 1650}
15637ed4
RG
1651
1652/*
142126f9 1653 * Following are all routines needed for SIO to act as console
15637ed4 1654 * XXX - not tested in this version
142126f9 1655 * XXX - i386/cons.c only knows about the com driver (NCOM and not NSIO)
15637ed4
RG
1656 * XXX - check that the corresponding serial interrupts are never enabled
1657 */
1658#include "i386/i386/cons.h"
1659
1660void
1661siocnprobe(cp)
1662 struct consdev *cp;
1663{
1664 int unit;
1665
1666 /* locate the major number */
1667 for (commajor = 0; commajor < nchrdev; commajor++)
4c45483e 1668 if (cdevsw[commajor].d_open == sioopen)
15637ed4
RG
1669 break;
1670
1671 /* XXX: ick */
142126f9 1672 unit = UNIT(CONUNIT);
15637ed4
RG
1673 com_addr(unit) = &com_structs[unit];
1674 com_addr(unit)->iobase = CONADDR;
1675
1676 /* make sure hardware exists? XXX */
1677
1678 /* initialize required fields */
1679 cp->cn_dev = makedev(commajor, unit);
15637ed4
RG
1680#ifdef COMCONSOLE
1681 cp->cn_pri = CN_REMOTE; /* Force a serial port console */
1682#else
1683 cp->cn_pri = CN_NORMAL;
1684#endif
1685}
1686
1687void
1688siocninit(cp)
1689 struct consdev *cp;
1690{
1691 int unit;
1692
1693 unit = UNIT(cp->cn_dev);
1694 cominit(unit, comdefaultrate);
1695 comconsole = unit;
1696 comconsinit = TRUE;
1697}
1698
1699static void
1700cominit(unit, rate)
1701 int unit;
1702 int rate;
1703{
1704 Port_t iobase;
1705 int s;
1706
1707 iobase = com_addr(unit)->iobase;
1708 s = splhigh();
1709 outb(iobase + com_cfcr, CFCR_DLAB);
1710 rate = ttspeedtab(comdefaultrate, comspeedtab);
142126f9
AC
1711 outb(iobase + com_dlbl, rate & 0xFF);
1712 outb(iobase + com_dlbh, rate >> 8);
15637ed4 1713 outb(iobase + com_cfcr, CFCR_8BITS);
142126f9
AC
1714 outb(iobase + com_fifo,
1715 FIFO_ENABLE | FIFO_TRIGGER | FIFO_RCV_RST | FIFO_XMT_RST);
1716 DELAY(100);
1717 (void) inb(iobase + com_lsr);
1718 (void) inb(iobase + com_data);
1719 (void) inb(iobase + com_msr);
15637ed4
RG
1720
1721 /*
1722 * XXX - fishy to enable interrupts and then poll.
1723 * It shouldn't be necessary to ready the iir.
1724 */
1725 outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC);
15637ed4
RG
1726 (void) inb(iobase + com_iir);
1727 splx(s);
1728}
1729
1730int
1731siocngetc(dev)
1732 dev_t dev;
1733{
1734 int c;
1735 Port_t iobase;
1736 int s;
1737
1738 iobase = com_addr(UNIT(dev))->iobase;
1739 s = splhigh();
1740 while (!(inb(iobase + com_lsr) & LSR_RXRDY))
1741 ;
1742 c = inb(iobase + com_data);
1743 (void) inb(iobase + com_iir);
1744 splx(s);
1745 return (c);
1746}
1747
1748void
1749siocnputc(dev, c)
1750 dev_t dev;
1751 int c;
1752{
1753 Port_t iobase;
1754 int s;
1755 int timo;
1756
1757 iobase = com_addr(UNIT(dev))->iobase;
1758 s = splhigh();
1759#ifdef KGDB
1760 if (dev != kgdb_dev)
1761#endif
1762 if (!comconsinit) {
142126f9 1763 cominit(UNIT(dev), comdefaultrate);
15637ed4
RG
1764 comconsinit = TRUE;
1765 }
1766 /* wait for any pending transmission to finish */
1767 timo = 50000;
1768 while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo)
1769 ;
1770 outb(iobase + com_data, c);
1771 /* wait for this transmission to complete */
1772 timo = 1500000;
1773 while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo)
1774 ;
1775 /* clear any interrupts generated by this transmission */
1776 (void) inb(iobase + com_iir);
1777 splx(s);
1778}
1779
15637ed4 1780#endif /* NSIO > 0 */