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