com.c revision 1.6 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 *
33 * @(#)com.c 7.5 (Berkeley) 5/16/91
34 *
35 * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
36 * -------------------- ----- ----------------------
37 * CURRENT PATCH LEVEL: 4 00079
38 * -------------------- ----- ----------------------
39 *
40 * 23 Sep 92 Rodney W. Grimes Fix SILO overflow on 16550 UARTS
41 * 30 Aug 92 Poul-Henning Kamp Stabilize SLIP on lossy lines/UARTS
42 * 09 Aug 92 Christoph Robitschko Correct minor number on com ports
43 * 10 Feb 93 Jordan K. Hubbard Added select code
44 */
45 static char rcsid[] = "$Header: /tank/opengrok/rsync2/NetBSD/src/sys/dev/ic/com.c,v 1.6 1993/04/10 12:05:19 glass Exp $";
46
47 #include "com.h"
48 #if NCOM > 0
49 /*
50 * COM driver, based on HP dca driver
51 * uses National Semiconductor NS16450/NS16550AF UART
52 */
53 #include "param.h"
54 #include "systm.h"
55 #include "ioctl.h"
56 #include "tty.h"
57 #include "proc.h"
58 #include "user.h"
59 #include "conf.h"
60 #include "file.h"
61 #include "uio.h"
62 #include "kernel.h"
63 #include "syslog.h"
64 #include "types.h"
65
66 #include "i386/isa/isa_device.h"
67 #include "i386/isa/comreg.h"
68 #include "i386/isa/ic/ns16550.h"
69 #define cominor(d)
70
71 int comprobe(), comattach(), comintr(), comstart(), comparam();
72
73 struct isa_driver comdriver = {
74 comprobe, comattach, "com"
75 };
76
77 int comsoftCAR;
78 int com_active;
79 int com_hasfifo;
80 int ncom = NCOM;
81 #ifdef COMCONSOLE
82 int comconsole = COMCONSOLE;
83 #else
84 int comconsole = -1;
85 #endif
86 int comconsinit;
87 int comdefaultrate = TTYDEF_SPEED;
88 int commajor;
89 short com_addr[NCOM];
90 struct tty com_tty[NCOM];
91
92 struct speedtab comspeedtab[] = {
93 0, 0,
94 50, COMBRD(50),
95 75, COMBRD(75),
96 110, COMBRD(110),
97 134, COMBRD(134),
98 150, COMBRD(150),
99 200, COMBRD(200),
100 300, COMBRD(300),
101 600, COMBRD(600),
102 1200, COMBRD(1200),
103 1800, COMBRD(1800),
104 2400, COMBRD(2400),
105 4800, COMBRD(4800),
106 9600, COMBRD(9600),
107 19200, COMBRD(19200),
108 38400, COMBRD(38400),
109 57600, COMBRD(57600),
110 -1, -1
111 };
112
113 extern struct tty *constty;
114 #ifdef KGDB
115 #include "machine/remote-sl.h"
116
117 extern int kgdb_dev;
118 extern int kgdb_rate;
119 extern int kgdb_debug_init;
120 #endif
121
122 #define UNIT(x) (minor(x))
123
124 comprobe(dev)
125 struct isa_device *dev;
126 {
127 /* force access to id reg */
128 outb(dev->id_iobase+com_cfcr, 0);
129 outb(dev->id_iobase+com_iir, 0);
130 DELAY(100);
131 if ((inb(dev->id_iobase+com_iir) & 0x38) == 0)
132 return(8);
133 return(0);
134 }
135
136
137 int
138 comattach(isdp)
139 struct isa_device *isdp;
140 {
141 struct tty *tp;
142 u_char unit;
143 int port = isdp->id_iobase;
144
145 unit = isdp->id_unit;
146 if (unit == comconsole)
147 DELAY(1000);
148 com_addr[unit] = port;
149 com_active |= 1 << unit;
150 comsoftCAR |= 1 << unit; /* XXX */
151
152 /* look for a NS 16550AF UART with FIFOs */
153 outb(port+com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_4);
154 DELAY(100);
155 if ((inb(port+com_iir) & IIR_FIFO_MASK) == IIR_FIFO_MASK) {
156 com_hasfifo |= 1 << unit;
157 printf("com%d: fifo\n", isdp->id_unit);
158 }
159
160 outb(port+com_ier, 0);
161 outb(port+com_mcr, 0 | MCR_IENABLE);
162 #ifdef KGDB
163 if (kgdb_dev == makedev(commajor, unit)) {
164 if (comconsole == unit)
165 kgdb_dev = -1; /* can't debug over console port */
166 else {
167 (void) cominit(unit, kgdb_rate);
168 if (kgdb_debug_init) {
169 /*
170 * Print prefix of device name,
171 * let kgdb_connect print the rest.
172 */
173 printf("com%d: ", unit);
174 kgdb_connect(1);
175 } else
176 printf("com%d: kgdb enabled\n", unit);
177 }
178 }
179 #endif
180 /*
181 * Need to reset baud rate, etc. of next print so reset comconsinit.
182 * Also make sure console is always "hardwired"
183 */
184 if (unit == comconsole) {
185 comconsinit = 0;
186 comsoftCAR |= (1 << unit);
187 }
188 return (1);
189 }
190
191 /* ARGSUSED */
192 comopen(dev_t dev, int flag, int mode, struct proc *p)
193 {
194 register struct tty *tp;
195 register int unit;
196 int error = 0;
197
198 unit = UNIT(dev);
199 if (unit >= NCOM || (com_active & (1 << unit)) == 0)
200 return (ENXIO);
201 tp = &com_tty[unit];
202 tp->t_oproc = comstart;
203 tp->t_param = comparam;
204 tp->t_dev = dev;
205 if ((tp->t_state & TS_ISOPEN) == 0) {
206 tp->t_state |= TS_WOPEN;
207 ttychars(tp);
208 if (tp->t_ispeed == 0) {
209 tp->t_iflag = TTYDEF_IFLAG;
210 tp->t_oflag = TTYDEF_OFLAG;
211 tp->t_cflag = TTYDEF_CFLAG;
212 tp->t_lflag = TTYDEF_LFLAG;
213 tp->t_ispeed = tp->t_ospeed = comdefaultrate;
214 }
215 comparam(tp, &tp->t_termios);
216 ttsetwater(tp);
217 } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
218 return (EBUSY);
219 (void) spltty();
220 (void) commctl(dev, MCR_DTR | MCR_RTS, DMSET);
221 if ((comsoftCAR & (1 << unit)) || (commctl(dev, 0, DMGET) & MSR_DCD))
222 tp->t_state |= TS_CARR_ON;
223 while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
224 (tp->t_state & TS_CARR_ON) == 0) {
225 tp->t_state |= TS_WOPEN;
226 if (error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH,
227 ttopen, 0))
228 break;
229 }
230 (void) spl0();
231 if (error == 0)
232 error = (*linesw[tp->t_line].l_open)(dev, tp);
233 return (error);
234 }
235
236 /*ARGSUSED*/
237 comclose(dev, flag, mode, p)
238 dev_t dev;
239 int flag, mode;
240 struct proc *p;
241 {
242 register struct tty *tp;
243 register com;
244 register int unit;
245
246 unit = UNIT(dev);
247 com = com_addr[unit];
248 tp = &com_tty[unit];
249 (*linesw[tp->t_line].l_close)(tp, flag);
250 outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK);
251 #ifdef KGDB
252 /* do not disable interrupts if debugging */
253 if (kgdb_dev != makedev(commajor, unit))
254 #endif
255 outb(com+com_ier, 0);
256 if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
257 (tp->t_state&TS_ISOPEN) == 0)
258 (void) commctl(dev, 0, DMSET);
259 ttyclose(tp);
260 return(0);
261 }
262
263 comread(dev, uio, flag)
264 dev_t dev;
265 struct uio *uio;
266 {
267 register struct tty *tp = &com_tty[UNIT(dev)];
268
269 return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
270 }
271
272 comwrite(dev, uio, flag)
273 dev_t dev;
274 struct uio *uio;
275 {
276 int unit = UNIT(dev);
277 register struct tty *tp = &com_tty[unit];
278
279 /*
280 * (XXX) We disallow virtual consoles if the physical console is
281 * a serial port. This is in case there is a display attached that
282 * is not the console. In that situation we don't need/want the X
283 * server taking over the console.
284 */
285 if (constty && unit == comconsole)
286 constty = NULL;
287 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
288 }
289
290 comintr(unit)
291 register int unit;
292 {
293 register com;
294 register u_char code;
295 register struct tty *tp;
296
297 unit;
298 com = com_addr[unit];
299 while (1) {
300 code = inb(com+com_iir);
301 switch (code & IIR_IMASK) {
302 case IIR_NOPEND:
303 return (1);
304 case IIR_RXTOUT:
305 case IIR_RXRDY:
306 tp = &com_tty[unit];
307 /*
308 * Process received bytes. Inline for speed...
309 */
310 #ifdef KGDB
311 #define RCVBYTE() \
312 code = inb(com+com_data); \
313 if ((tp->t_state & TS_ISOPEN) == 0) { \
314 if (kgdb_dev == makedev(commajor, unit) && \
315 code == FRAME_END) \
316 kgdb_connect(0); /* trap into kgdb */ \
317 } else \
318 (*linesw[tp->t_line].l_rint)(code, tp)
319 #else
320 #define RCVBYTE() \
321 code = inb(com+com_data); \
322 if (tp->t_state & TS_ISOPEN) \
323 (*linesw[tp->t_line].l_rint)(code, tp)
324 #endif
325
326 RCVBYTE();
327
328 if (com_hasfifo & (1 << unit))
329 while ((code = inb(com+com_lsr)) & LSR_RCV_MASK) {
330 if (code == LSR_RXRDY) {
331 RCVBYTE();
332 } else
333 comeint(unit, code, com);
334 }
335 break;
336 case IIR_TXRDY:
337 tp = &com_tty[unit];
338 tp->t_state &=~ (TS_BUSY|TS_FLUSH);
339 if (tp->t_line)
340 (*linesw[tp->t_line].l_start)(tp);
341 else
342 comstart(tp);
343 break;
344 case IIR_RLS:
345 comeint(unit, inb(com+com_lsr), com);
346 break;
347 default:
348 if (code & IIR_NOPEND)
349 return (1);
350 log(LOG_WARNING, "com%d: weird interrupt: 0x%x\n",
351 unit, code);
352 /* fall through */
353 case IIR_MLSC:
354 commint(unit, com);
355 break;
356 }
357 }
358 }
359
360 comeint(unit, stat, com)
361 register int unit, stat;
362 register com;
363 {
364 register struct tty *tp;
365 register int c;
366
367 tp = &com_tty[unit];
368 c = inb(com+com_data);
369 if ((tp->t_state & TS_ISOPEN) == 0) {
370 #ifdef KGDB
371 /* we don't care about parity errors */
372 if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) &&
373 kgdb_dev == makedev(commajor, unit) && c == FRAME_END)
374 kgdb_connect(0); /* trap into kgdb */
375 #endif
376 return;
377 }
378 if (stat & (LSR_BI | LSR_FE))
379 c |= TTY_FE;
380 else if (stat & LSR_PE)
381 c |= TTY_PE;
382 else if (stat & LSR_OE) { /* 30 Aug 92*/
383 c |= TTY_PE; /* Ought to have it's own define... */
384 log(LOG_WARNING, "com%d: silo overflow\n", unit);
385 }
386 (*linesw[tp->t_line].l_rint)(c, tp);
387 }
388
389 commint(unit, com)
390 register int unit;
391 register com;
392 {
393 register struct tty *tp;
394 register int stat;
395
396 tp = &com_tty[unit];
397 stat = inb(com+com_msr);
398 if ((stat & MSR_DDCD) && (comsoftCAR & (1 << unit)) == 0) {
399 if (stat & MSR_DCD)
400 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
401 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
402 outb(com+com_mcr,
403 inb(com+com_mcr) & ~(MCR_DTR | MCR_RTS) | MCR_IENABLE);
404 } else if ((stat & MSR_DCTS) && (tp->t_state & TS_ISOPEN) &&
405 (tp->t_flags & CRTSCTS)) {
406 /* the line is up and we want to do rts/cts flow control */
407 if (stat & MSR_CTS) {
408 tp->t_state &=~ TS_TTSTOP;
409 ttstart(tp);
410 } else
411 tp->t_state |= TS_TTSTOP;
412 }
413 }
414
415 comioctl(dev, cmd, data, flag)
416 dev_t dev;
417 caddr_t data;
418 {
419 register struct tty *tp;
420 register int unit = UNIT(dev);
421 register com;
422 register int error;
423
424 tp = &com_tty[unit];
425 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
426 if (error >= 0)
427 return (error);
428 error = ttioctl(tp, cmd, data, flag);
429 if (error >= 0)
430 return (error);
431
432 com = com_addr[unit];
433 switch (cmd) {
434
435 case TIOCSBRK:
436 outb(com+com_cfcr, inb(com+com_cfcr) | CFCR_SBREAK);
437 break;
438
439 case TIOCCBRK:
440 outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK);
441 break;
442
443 case TIOCSDTR:
444 (void) commctl(dev, MCR_DTR | MCR_RTS, DMBIS);
445 break;
446
447 case TIOCCDTR:
448 (void) commctl(dev, MCR_DTR | MCR_RTS, DMBIC);
449 break;
450
451 case TIOCMSET:
452 (void) commctl(dev, *(int *)data, DMSET);
453 break;
454
455 case TIOCMBIS:
456 (void) commctl(dev, *(int *)data, DMBIS);
457 break;
458
459 case TIOCMBIC:
460 (void) commctl(dev, *(int *)data, DMBIC);
461 break;
462
463 case TIOCMGET:
464 *(int *)data = commctl(dev, 0, DMGET);
465 break;
466
467 default:
468 return (ENOTTY);
469 }
470 return (0);
471 }
472
473 comparam(tp, t)
474 register struct tty *tp;
475 register struct termios *t;
476 {
477 register com;
478 register int cfcr, cflag = t->c_cflag;
479 int unit = UNIT(tp->t_dev);
480 int ospeed = ttspeedtab(t->c_ospeed, comspeedtab);
481
482 /* check requested parameters */
483 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
484 return(EINVAL);
485 /* and copy to tty */
486 tp->t_ispeed = t->c_ispeed;
487 tp->t_ospeed = t->c_ospeed;
488 tp->t_cflag = cflag;
489
490 com = com_addr[unit];
491 outb(com+com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS /*| IER_EMSC*/);
492 if (ospeed == 0) {
493 (void) commctl(unit, 0, DMSET); /* hang up line */
494 return(0);
495 }
496 outb(com+com_cfcr, inb(com+com_cfcr) | CFCR_DLAB);
497 outb(com+com_data, ospeed & 0xFF);
498 outb(com+com_ier, ospeed >> 8);
499 switch (cflag&CSIZE) {
500 case CS5:
501 cfcr = CFCR_5BITS; break;
502 case CS6:
503 cfcr = CFCR_6BITS; break;
504 case CS7:
505 cfcr = CFCR_7BITS; break;
506 case CS8:
507 cfcr = CFCR_8BITS; break;
508 }
509 if (cflag&PARENB) {
510 cfcr |= CFCR_PENAB;
511 if ((cflag&PARODD) == 0)
512 cfcr |= CFCR_PEVEN;
513 }
514 if (cflag&CSTOPB)
515 cfcr |= CFCR_STOPB;
516 outb(com+com_cfcr, cfcr);
517
518 if (com_hasfifo & (1 << unit))
519 outb(com+com_fifo, FIFO_ENABLE | FIFO_TRIGGER_4);
520
521 return(0);
522 }
523
524 comstart(tp)
525 register struct tty *tp;
526 {
527 register com;
528 int s, unit, c;
529
530 unit = UNIT(tp->t_dev);
531 com = com_addr[unit];
532 s = spltty();
533 if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
534 goto out;
535 if (RB_LEN(&tp->t_out) <= tp->t_lowat) {
536 if (tp->t_state&TS_ASLEEP) {
537 tp->t_state &= ~TS_ASLEEP;
538 wakeup((caddr_t)&tp->t_out);
539 }
540 if (tp->t_wsel) {
541 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
542 tp->t_wsel = 0;
543 tp->t_state &= ~TS_WCOLL;
544 }
545 }
546 if (RB_LEN(&tp->t_out) == 0)
547 goto out;
548 if (inb(com+com_lsr) & LSR_TXRDY) {
549 c = getc(&tp->t_out);
550 tp->t_state |= TS_BUSY;
551 outb(com+com_data, c);
552 if (com_hasfifo & (1 << unit))
553 for (c = 1; c < 16 && RB_LEN(&tp->t_out); ++c)
554 outb(com+com_data, getc(&tp->t_out));
555 }
556 out:
557 splx(s);
558 }
559
560 /*
561 * Stop output on a line.
562 */
563 /*ARGSUSED*/
564 comstop(tp, flag)
565 register struct tty *tp;
566 {
567 register int s;
568
569 s = spltty();
570 if (tp->t_state & TS_BUSY) {
571 if ((tp->t_state&TS_TTSTOP)==0)
572 tp->t_state |= TS_FLUSH;
573 }
574 splx(s);
575 }
576
577 commctl(dev, bits, how)
578 dev_t dev;
579 int bits, how;
580 {
581 register com;
582 register int unit;
583 int s;
584
585 unit = UNIT(dev);
586 com = com_addr[unit];
587 s = spltty();
588 switch (how) {
589
590 case DMSET:
591 outb(com+com_mcr, bits | MCR_IENABLE);
592 break;
593
594 case DMBIS:
595 outb(com+com_mcr, inb(com+com_mcr) | bits | MCR_IENABLE);
596 break;
597
598 case DMBIC:
599 outb(com+com_mcr, inb(com+com_mcr) & ~bits | MCR_IENABLE);
600 break;
601
602 case DMGET:
603 bits = inb(com+com_msr);
604 break;
605 }
606 (void) splx(s);
607 return(bits);
608 }
609
610 /*
611 * Following are all routines needed for COM to act as console
612 */
613 #include "i386/i386/cons.h"
614
615 comcnprobe(cp)
616 struct consdev *cp;
617 {
618 int unit;
619
620 /* locate the major number */
621 for (commajor = 0; commajor < nchrdev; commajor++)
622 if (cdevsw[commajor].d_open == comopen)
623 break;
624
625 /* XXX: ick */
626 unit = CONUNIT;
627 com_addr[CONUNIT] = CONADDR;
628
629 /* make sure hardware exists? XXX */
630
631 /* initialize required fields */
632 cp->cn_dev = makedev(commajor, unit);
633 cp->cn_tp = &com_tty[unit];
634 #ifdef COMCONSOLE
635 cp->cn_pri = CN_REMOTE; /* Force a serial port console */
636 #else
637 cp->cn_pri = CN_NORMAL;
638 #endif
639 }
640
641 comcninit(cp)
642 struct consdev *cp;
643 {
644 int unit = UNIT(cp->cn_dev);
645
646 cominit(unit, comdefaultrate);
647 comconsole = unit;
648 comconsinit = 1;
649 }
650
651 cominit(unit, rate)
652 int unit, rate;
653 {
654 register int com;
655 int s;
656 short stat;
657
658 #ifdef lint
659 stat = unit; if (stat) return;
660 #endif
661 com = com_addr[unit];
662 s = splhigh();
663 outb(com+com_cfcr, CFCR_DLAB);
664 rate = ttspeedtab(comdefaultrate, comspeedtab);
665 outb(com+com_data, rate & 0xFF);
666 outb(com+com_ier, rate >> 8);
667 outb(com+com_cfcr, CFCR_8BITS);
668 outb(com+com_ier, IER_ERXRDY | IER_ETXRDY);
669 outb(com+com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_4);
670 stat = inb(com+com_iir);
671 splx(s);
672 }
673
674 comcngetc(dev)
675 {
676 register com = com_addr[UNIT(dev)];
677 short stat;
678 int c, s;
679
680 #ifdef lint
681 stat = dev; if (stat) return(0);
682 #endif
683 s = splhigh();
684 while (((stat = inb(com+com_lsr)) & LSR_RXRDY) == 0)
685 ;
686 c = inb(com+com_data);
687 stat = inb(com+com_iir);
688 splx(s);
689 return(c);
690 }
691
692 /*
693 * Console kernel output character routine.
694 */
695 comcnputc(dev, c)
696 dev_t dev;
697 register int c;
698 {
699 register com = com_addr[UNIT(dev)];
700 register int timo;
701 short stat;
702 int s = splhigh();
703
704 #ifdef lint
705 stat = dev; if (stat) return;
706 #endif
707 #ifdef KGDB
708 if (dev != kgdb_dev)
709 #endif
710 if (comconsinit == 0) {
711 (void) cominit(UNIT(dev), comdefaultrate);
712 comconsinit = 1;
713 }
714 /* wait for any pending transmission to finish */
715 timo = 50000;
716 while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo)
717 ;
718 outb(com+com_data, c);
719 /* wait for this transmission to complete */
720 timo = 1500000;
721 while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo)
722 ;
723 /* clear any interrupts generated by this transmission */
724 stat = inb(com+com_iir);
725 splx(s);
726 }
727
728 int
729 comselect(dev, rw, p)
730 dev_t dev;
731 int rw;
732 struct proc *p;
733 {
734 register struct tty *tp = &com_tty[UNIT(dev)];
735 int nread;
736 int s = spltty();
737 struct proc *selp;
738
739 switch (rw) {
740
741 case FREAD:
742 nread = ttnread(tp);
743 if (nread > 0 ||
744 ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0))
745 goto win;
746 if (tp->t_rsel && (selp = pfind(tp->t_rsel)) && selp->p_wchan == (caddr_t)&selwait)
747 tp->t_state |= TS_RCOLL;
748 else
749 tp->t_rsel = p->p_pid;
750 break;
751
752 case FWRITE:
753 if (RB_LEN(&tp->t_out) <= tp->t_lowat)
754 goto win;
755 if (tp->t_wsel && (selp = pfind(tp->t_wsel)) && selp->p_wchan == (caddr_t)&selwait)
756 tp->t_state |= TS_WCOLL;
757 else
758 tp->t_wsel = p->p_pid;
759 break;
760 }
761 splx(s);
762 return (0);
763 win:
764 splx(s);
765 return (1);
766 }
767
768 #endif
769