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