com.c revision 1.16 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.7 cgd * from: @(#)com.c 7.5 (Berkeley) 5/16/91
34 1.16 ws * $Id: com.c,v 1.16 1994/01/30 16:41:27 ws Exp $
35 1.1 cgd */
36 1.1 cgd
37 1.1 cgd #include "com.h"
38 1.1 cgd #if NCOM > 0
39 1.1 cgd /*
40 1.1 cgd * COM driver, based on HP dca driver
41 1.1 cgd * uses National Semiconductor NS16450/NS16550AF UART
42 1.1 cgd */
43 1.14 mycroft #include <sys/param.h>
44 1.14 mycroft #include <sys/systm.h>
45 1.14 mycroft #include <sys/ioctl.h>
46 1.14 mycroft #include <sys/select.h>
47 1.14 mycroft #include <sys/tty.h>
48 1.14 mycroft #include <sys/proc.h>
49 1.14 mycroft #include <sys/user.h>
50 1.14 mycroft #include <sys/conf.h>
51 1.14 mycroft #include <sys/file.h>
52 1.14 mycroft #include <sys/uio.h>
53 1.14 mycroft #include <sys/kernel.h>
54 1.14 mycroft #include <sys/syslog.h>
55 1.14 mycroft #include <sys/types.h>
56 1.14 mycroft
57 1.14 mycroft #include <machine/pio.h>
58 1.14 mycroft
59 1.14 mycroft #include <i386/isa/isa_device.h>
60 1.14 mycroft #include <i386/isa/comreg.h>
61 1.14 mycroft #include <i386/isa/ic/ns16550.h>
62 1.14 mycroft
63 1.1 cgd #define cominor(d)
64 1.1 cgd
65 1.12 deraadt int comprobe(), comattach(), comintr(), comparam();
66 1.12 deraadt void comstart();
67 1.1 cgd
68 1.1 cgd struct isa_driver comdriver = {
69 1.1 cgd comprobe, comattach, "com"
70 1.1 cgd };
71 1.1 cgd
72 1.1 cgd int comsoftCAR;
73 1.1 cgd int com_active;
74 1.1 cgd int com_hasfifo;
75 1.1 cgd int ncom = NCOM;
76 1.1 cgd #ifdef COMCONSOLE
77 1.1 cgd int comconsole = COMCONSOLE;
78 1.1 cgd #else
79 1.1 cgd int comconsole = -1;
80 1.1 cgd #endif
81 1.1 cgd int comconsinit;
82 1.1 cgd int comdefaultrate = TTYDEF_SPEED;
83 1.1 cgd int commajor;
84 1.1 cgd short com_addr[NCOM];
85 1.8 deraadt struct tty *com_tty[NCOM];
86 1.1 cgd
87 1.1 cgd struct speedtab comspeedtab[] = {
88 1.1 cgd 0, 0,
89 1.1 cgd 50, COMBRD(50),
90 1.1 cgd 75, COMBRD(75),
91 1.1 cgd 110, COMBRD(110),
92 1.1 cgd 134, COMBRD(134),
93 1.1 cgd 150, COMBRD(150),
94 1.1 cgd 200, COMBRD(200),
95 1.1 cgd 300, COMBRD(300),
96 1.1 cgd 600, COMBRD(600),
97 1.1 cgd 1200, COMBRD(1200),
98 1.1 cgd 1800, COMBRD(1800),
99 1.1 cgd 2400, COMBRD(2400),
100 1.1 cgd 4800, COMBRD(4800),
101 1.1 cgd 9600, COMBRD(9600),
102 1.1 cgd 19200, COMBRD(19200),
103 1.1 cgd 38400, COMBRD(38400),
104 1.1 cgd 57600, COMBRD(57600),
105 1.1 cgd -1, -1
106 1.1 cgd };
107 1.1 cgd
108 1.1 cgd extern struct tty *constty;
109 1.1 cgd #ifdef KGDB
110 1.14 mycroft #include <machine/remote-sl.h>
111 1.1 cgd
112 1.1 cgd extern int kgdb_dev;
113 1.1 cgd extern int kgdb_rate;
114 1.1 cgd extern int kgdb_debug_init;
115 1.1 cgd #endif
116 1.1 cgd
117 1.2 cgd #define UNIT(x) (minor(x))
118 1.1 cgd
119 1.1 cgd comprobe(dev)
120 1.1 cgd struct isa_device *dev;
121 1.1 cgd {
122 1.1 cgd /* force access to id reg */
123 1.1 cgd outb(dev->id_iobase+com_cfcr, 0);
124 1.1 cgd outb(dev->id_iobase+com_iir, 0);
125 1.1 cgd DELAY(100);
126 1.1 cgd if ((inb(dev->id_iobase+com_iir) & 0x38) == 0)
127 1.5 cgd return(8);
128 1.1 cgd return(0);
129 1.1 cgd }
130 1.1 cgd
131 1.1 cgd
132 1.1 cgd int
133 1.1 cgd comattach(isdp)
134 1.1 cgd struct isa_device *isdp;
135 1.1 cgd {
136 1.1 cgd struct tty *tp;
137 1.1 cgd u_char unit;
138 1.1 cgd int port = isdp->id_iobase;
139 1.1 cgd
140 1.2 cgd unit = isdp->id_unit;
141 1.1 cgd if (unit == comconsole)
142 1.1 cgd DELAY(1000);
143 1.1 cgd com_addr[unit] = port;
144 1.1 cgd com_active |= 1 << unit;
145 1.1 cgd comsoftCAR |= 1 << unit; /* XXX */
146 1.1 cgd
147 1.1 cgd /* look for a NS 16550AF UART with FIFOs */
148 1.2 cgd outb(port+com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_4);
149 1.1 cgd DELAY(100);
150 1.1 cgd if ((inb(port+com_iir) & IIR_FIFO_MASK) == IIR_FIFO_MASK) {
151 1.1 cgd com_hasfifo |= 1 << unit;
152 1.4 deraadt printf("com%d: fifo\n", isdp->id_unit);
153 1.1 cgd }
154 1.1 cgd
155 1.1 cgd outb(port+com_ier, 0);
156 1.1 cgd outb(port+com_mcr, 0 | MCR_IENABLE);
157 1.1 cgd #ifdef KGDB
158 1.2 cgd if (kgdb_dev == makedev(commajor, unit)) {
159 1.1 cgd if (comconsole == unit)
160 1.1 cgd kgdb_dev = -1; /* can't debug over console port */
161 1.1 cgd else {
162 1.1 cgd (void) cominit(unit, kgdb_rate);
163 1.1 cgd if (kgdb_debug_init) {
164 1.1 cgd /*
165 1.1 cgd * Print prefix of device name,
166 1.1 cgd * let kgdb_connect print the rest.
167 1.1 cgd */
168 1.1 cgd printf("com%d: ", unit);
169 1.1 cgd kgdb_connect(1);
170 1.1 cgd } else
171 1.1 cgd printf("com%d: kgdb enabled\n", unit);
172 1.1 cgd }
173 1.1 cgd }
174 1.1 cgd #endif
175 1.1 cgd /*
176 1.1 cgd * Need to reset baud rate, etc. of next print so reset comconsinit.
177 1.1 cgd * Also make sure console is always "hardwired"
178 1.1 cgd */
179 1.1 cgd if (unit == comconsole) {
180 1.1 cgd comconsinit = 0;
181 1.1 cgd comsoftCAR |= (1 << unit);
182 1.1 cgd }
183 1.1 cgd return (1);
184 1.1 cgd }
185 1.1 cgd
186 1.1 cgd /* ARGSUSED */
187 1.1 cgd comopen(dev_t dev, int flag, int mode, struct proc *p)
188 1.1 cgd {
189 1.1 cgd register struct tty *tp;
190 1.1 cgd register int unit;
191 1.1 cgd int error = 0;
192 1.1 cgd
193 1.1 cgd unit = UNIT(dev);
194 1.1 cgd if (unit >= NCOM || (com_active & (1 << unit)) == 0)
195 1.1 cgd return (ENXIO);
196 1.8 deraadt if(!com_tty[unit]) {
197 1.11 mycroft tp = com_tty[unit] = ttymalloc();
198 1.8 deraadt } else
199 1.8 deraadt tp = com_tty[unit];
200 1.1 cgd tp->t_oproc = comstart;
201 1.1 cgd tp->t_param = comparam;
202 1.1 cgd tp->t_dev = dev;
203 1.1 cgd if ((tp->t_state & TS_ISOPEN) == 0) {
204 1.1 cgd tp->t_state |= TS_WOPEN;
205 1.1 cgd ttychars(tp);
206 1.16 ws tp->t_iflag = TTYDEF_IFLAG;
207 1.16 ws tp->t_oflag = TTYDEF_OFLAG;
208 1.16 ws tp->t_cflag = TTYDEF_CFLAG;
209 1.16 ws tp->t_lflag = TTYDEF_LFLAG;
210 1.16 ws tp->t_ispeed = tp->t_ospeed = comdefaultrate;
211 1.1 cgd comparam(tp, &tp->t_termios);
212 1.1 cgd ttsetwater(tp);
213 1.1 cgd } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
214 1.1 cgd return (EBUSY);
215 1.1 cgd (void) spltty();
216 1.1 cgd (void) commctl(dev, MCR_DTR | MCR_RTS, DMSET);
217 1.1 cgd if ((comsoftCAR & (1 << unit)) || (commctl(dev, 0, DMGET) & MSR_DCD))
218 1.1 cgd tp->t_state |= TS_CARR_ON;
219 1.1 cgd while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
220 1.1 cgd (tp->t_state & TS_CARR_ON) == 0) {
221 1.1 cgd tp->t_state |= TS_WOPEN;
222 1.11 mycroft if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
223 1.1 cgd ttopen, 0))
224 1.1 cgd break;
225 1.1 cgd }
226 1.1 cgd (void) spl0();
227 1.1 cgd if (error == 0)
228 1.1 cgd error = (*linesw[tp->t_line].l_open)(dev, tp);
229 1.1 cgd return (error);
230 1.1 cgd }
231 1.1 cgd
232 1.1 cgd /*ARGSUSED*/
233 1.1 cgd comclose(dev, flag, mode, p)
234 1.1 cgd dev_t dev;
235 1.1 cgd int flag, mode;
236 1.1 cgd struct proc *p;
237 1.1 cgd {
238 1.1 cgd register struct tty *tp;
239 1.1 cgd register com;
240 1.1 cgd register int unit;
241 1.1 cgd
242 1.1 cgd unit = UNIT(dev);
243 1.1 cgd com = com_addr[unit];
244 1.8 deraadt tp = com_tty[unit];
245 1.1 cgd (*linesw[tp->t_line].l_close)(tp, flag);
246 1.1 cgd outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK);
247 1.1 cgd #ifdef KGDB
248 1.1 cgd /* do not disable interrupts if debugging */
249 1.2 cgd if (kgdb_dev != makedev(commajor, unit))
250 1.1 cgd #endif
251 1.1 cgd outb(com+com_ier, 0);
252 1.1 cgd if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
253 1.1 cgd (tp->t_state&TS_ISOPEN) == 0)
254 1.1 cgd (void) commctl(dev, 0, DMSET);
255 1.1 cgd ttyclose(tp);
256 1.13 cgd #ifdef broken /* session holds a ref to the tty; can't deallocate */
257 1.11 mycroft ttyfree(tp);
258 1.8 deraadt com_tty[unit] = (struct tty *)NULL;
259 1.13 cgd #endif
260 1.1 cgd return(0);
261 1.1 cgd }
262 1.1 cgd
263 1.1 cgd comread(dev, uio, flag)
264 1.1 cgd dev_t dev;
265 1.1 cgd struct uio *uio;
266 1.1 cgd {
267 1.8 deraadt register struct tty *tp = com_tty[UNIT(dev)];
268 1.1 cgd
269 1.1 cgd return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
270 1.1 cgd }
271 1.1 cgd
272 1.1 cgd comwrite(dev, uio, flag)
273 1.1 cgd dev_t dev;
274 1.1 cgd struct uio *uio;
275 1.1 cgd {
276 1.1 cgd int unit = UNIT(dev);
277 1.8 deraadt register struct tty *tp = com_tty[unit];
278 1.1 cgd
279 1.1 cgd /*
280 1.1 cgd * (XXX) We disallow virtual consoles if the physical console is
281 1.1 cgd * a serial port. This is in case there is a display attached that
282 1.1 cgd * is not the console. In that situation we don't need/want the X
283 1.1 cgd * server taking over the console.
284 1.1 cgd */
285 1.1 cgd if (constty && unit == comconsole)
286 1.1 cgd constty = NULL;
287 1.1 cgd return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
288 1.1 cgd }
289 1.1 cgd
290 1.1 cgd comintr(unit)
291 1.1 cgd register int unit;
292 1.1 cgd {
293 1.1 cgd register com;
294 1.1 cgd register u_char code;
295 1.1 cgd register struct tty *tp;
296 1.1 cgd
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.8 deraadt 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.8 deraadt 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.8 deraadt 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.8 deraadt 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.8 deraadt 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.12 deraadt void
524 1.1 cgd comstart(tp)
525 1.1 cgd register struct tty *tp;
526 1.1 cgd {
527 1.1 cgd register com;
528 1.1 cgd int s, unit, c;
529 1.1 cgd
530 1.1 cgd unit = UNIT(tp->t_dev);
531 1.1 cgd com = com_addr[unit];
532 1.1 cgd s = spltty();
533 1.1 cgd if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
534 1.1 cgd goto out;
535 1.11 mycroft if (tp->t_outq.c_cc <= tp->t_lowat) {
536 1.1 cgd if (tp->t_state&TS_ASLEEP) {
537 1.1 cgd tp->t_state &= ~TS_ASLEEP;
538 1.11 mycroft wakeup((caddr_t)&tp->t_outq);
539 1.1 cgd }
540 1.7 cgd selwakeup(&tp->t_wsel);
541 1.1 cgd }
542 1.11 mycroft if (tp->t_outq.c_cc == 0)
543 1.1 cgd goto out;
544 1.1 cgd if (inb(com+com_lsr) & LSR_TXRDY) {
545 1.11 mycroft c = getc(&tp->t_outq);
546 1.1 cgd tp->t_state |= TS_BUSY;
547 1.1 cgd outb(com+com_data, c);
548 1.1 cgd if (com_hasfifo & (1 << unit))
549 1.11 mycroft for (c = 1; c < 16 && tp->t_outq.c_cc; ++c)
550 1.11 mycroft outb(com+com_data, getc(&tp->t_outq));
551 1.1 cgd }
552 1.1 cgd out:
553 1.1 cgd splx(s);
554 1.1 cgd }
555 1.1 cgd
556 1.1 cgd /*
557 1.1 cgd * Stop output on a line.
558 1.1 cgd */
559 1.1 cgd /*ARGSUSED*/
560 1.1 cgd comstop(tp, flag)
561 1.1 cgd register struct tty *tp;
562 1.1 cgd {
563 1.1 cgd register int s;
564 1.1 cgd
565 1.1 cgd s = spltty();
566 1.1 cgd if (tp->t_state & TS_BUSY) {
567 1.1 cgd if ((tp->t_state&TS_TTSTOP)==0)
568 1.1 cgd tp->t_state |= TS_FLUSH;
569 1.1 cgd }
570 1.1 cgd splx(s);
571 1.1 cgd }
572 1.1 cgd
573 1.1 cgd commctl(dev, bits, how)
574 1.1 cgd dev_t dev;
575 1.1 cgd int bits, how;
576 1.1 cgd {
577 1.1 cgd register com;
578 1.1 cgd register int unit;
579 1.1 cgd int s;
580 1.1 cgd
581 1.1 cgd unit = UNIT(dev);
582 1.1 cgd com = com_addr[unit];
583 1.1 cgd s = spltty();
584 1.1 cgd switch (how) {
585 1.1 cgd
586 1.1 cgd case DMSET:
587 1.1 cgd outb(com+com_mcr, bits | MCR_IENABLE);
588 1.1 cgd break;
589 1.1 cgd
590 1.1 cgd case DMBIS:
591 1.1 cgd outb(com+com_mcr, inb(com+com_mcr) | bits | MCR_IENABLE);
592 1.1 cgd break;
593 1.1 cgd
594 1.1 cgd case DMBIC:
595 1.1 cgd outb(com+com_mcr, inb(com+com_mcr) & ~bits | MCR_IENABLE);
596 1.1 cgd break;
597 1.1 cgd
598 1.1 cgd case DMGET:
599 1.1 cgd bits = inb(com+com_msr);
600 1.1 cgd break;
601 1.1 cgd }
602 1.1 cgd (void) splx(s);
603 1.1 cgd return(bits);
604 1.1 cgd }
605 1.1 cgd
606 1.1 cgd /*
607 1.1 cgd * Following are all routines needed for COM to act as console
608 1.1 cgd */
609 1.14 mycroft #include <i386/i386/cons.h>
610 1.1 cgd
611 1.1 cgd comcnprobe(cp)
612 1.1 cgd struct consdev *cp;
613 1.1 cgd {
614 1.1 cgd int unit;
615 1.1 cgd
616 1.1 cgd /* locate the major number */
617 1.1 cgd for (commajor = 0; commajor < nchrdev; commajor++)
618 1.1 cgd if (cdevsw[commajor].d_open == comopen)
619 1.1 cgd break;
620 1.1 cgd
621 1.1 cgd /* XXX: ick */
622 1.1 cgd unit = CONUNIT;
623 1.1 cgd com_addr[CONUNIT] = CONADDR;
624 1.1 cgd
625 1.1 cgd /* make sure hardware exists? XXX */
626 1.1 cgd
627 1.1 cgd /* initialize required fields */
628 1.2 cgd cp->cn_dev = makedev(commajor, unit);
629 1.1 cgd #ifdef COMCONSOLE
630 1.1 cgd cp->cn_pri = CN_REMOTE; /* Force a serial port console */
631 1.1 cgd #else
632 1.1 cgd cp->cn_pri = CN_NORMAL;
633 1.1 cgd #endif
634 1.1 cgd }
635 1.1 cgd
636 1.1 cgd comcninit(cp)
637 1.1 cgd struct consdev *cp;
638 1.1 cgd {
639 1.1 cgd int unit = UNIT(cp->cn_dev);
640 1.1 cgd
641 1.1 cgd cominit(unit, comdefaultrate);
642 1.1 cgd comconsole = unit;
643 1.1 cgd comconsinit = 1;
644 1.1 cgd }
645 1.1 cgd
646 1.1 cgd cominit(unit, rate)
647 1.1 cgd int unit, rate;
648 1.1 cgd {
649 1.1 cgd register int com;
650 1.1 cgd int s;
651 1.1 cgd short stat;
652 1.1 cgd
653 1.1 cgd #ifdef lint
654 1.1 cgd stat = unit; if (stat) return;
655 1.1 cgd #endif
656 1.1 cgd com = com_addr[unit];
657 1.1 cgd s = splhigh();
658 1.1 cgd outb(com+com_cfcr, CFCR_DLAB);
659 1.1 cgd rate = ttspeedtab(comdefaultrate, comspeedtab);
660 1.1 cgd outb(com+com_data, rate & 0xFF);
661 1.1 cgd outb(com+com_ier, rate >> 8);
662 1.1 cgd outb(com+com_cfcr, CFCR_8BITS);
663 1.1 cgd outb(com+com_ier, IER_ERXRDY | IER_ETXRDY);
664 1.2 cgd outb(com+com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_4);
665 1.1 cgd stat = inb(com+com_iir);
666 1.1 cgd splx(s);
667 1.1 cgd }
668 1.1 cgd
669 1.1 cgd comcngetc(dev)
670 1.1 cgd {
671 1.1 cgd register com = com_addr[UNIT(dev)];
672 1.1 cgd short stat;
673 1.1 cgd int c, s;
674 1.1 cgd
675 1.1 cgd #ifdef lint
676 1.1 cgd stat = dev; if (stat) return(0);
677 1.1 cgd #endif
678 1.1 cgd s = splhigh();
679 1.1 cgd while (((stat = inb(com+com_lsr)) & LSR_RXRDY) == 0)
680 1.1 cgd ;
681 1.1 cgd c = inb(com+com_data);
682 1.1 cgd stat = inb(com+com_iir);
683 1.1 cgd splx(s);
684 1.1 cgd return(c);
685 1.1 cgd }
686 1.1 cgd
687 1.1 cgd /*
688 1.1 cgd * Console kernel output character routine.
689 1.1 cgd */
690 1.1 cgd comcnputc(dev, c)
691 1.1 cgd dev_t dev;
692 1.1 cgd register int c;
693 1.1 cgd {
694 1.1 cgd register com = com_addr[UNIT(dev)];
695 1.1 cgd register int timo;
696 1.1 cgd short stat;
697 1.1 cgd int s = splhigh();
698 1.1 cgd
699 1.1 cgd #ifdef lint
700 1.1 cgd stat = dev; if (stat) return;
701 1.1 cgd #endif
702 1.1 cgd #ifdef KGDB
703 1.1 cgd if (dev != kgdb_dev)
704 1.1 cgd #endif
705 1.1 cgd if (comconsinit == 0) {
706 1.1 cgd (void) cominit(UNIT(dev), comdefaultrate);
707 1.1 cgd comconsinit = 1;
708 1.1 cgd }
709 1.1 cgd /* wait for any pending transmission to finish */
710 1.1 cgd timo = 50000;
711 1.1 cgd while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo)
712 1.1 cgd ;
713 1.1 cgd outb(com+com_data, c);
714 1.1 cgd /* wait for this transmission to complete */
715 1.1 cgd timo = 1500000;
716 1.1 cgd while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo)
717 1.1 cgd ;
718 1.1 cgd /* clear any interrupts generated by this transmission */
719 1.1 cgd stat = inb(com+com_iir);
720 1.1 cgd splx(s);
721 1.2 cgd }
722 1.6 glass
723 1.3 cgd #endif
724