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