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