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