com.c revision 1.17 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.17 cgd * $Id: com.c,v 1.17 1994/02/01 03:42:08 cgd 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.8 deraadt register struct tty *tp = com_tty[unit];
277 1.1 cgd
278 1.1 cgd return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
279 1.1 cgd }
280 1.1 cgd
281 1.1 cgd comintr(unit)
282 1.1 cgd register int unit;
283 1.1 cgd {
284 1.1 cgd register com;
285 1.1 cgd register u_char code;
286 1.1 cgd register struct tty *tp;
287 1.1 cgd
288 1.1 cgd com = com_addr[unit];
289 1.1 cgd while (1) {
290 1.1 cgd code = inb(com+com_iir);
291 1.1 cgd switch (code & IIR_IMASK) {
292 1.1 cgd case IIR_NOPEND:
293 1.1 cgd return (1);
294 1.1 cgd case IIR_RXTOUT:
295 1.1 cgd case IIR_RXRDY:
296 1.8 deraadt tp = com_tty[unit];
297 1.1 cgd /*
298 1.1 cgd * Process received bytes. Inline for speed...
299 1.1 cgd */
300 1.1 cgd #ifdef KGDB
301 1.1 cgd #define RCVBYTE() \
302 1.1 cgd code = inb(com+com_data); \
303 1.1 cgd if ((tp->t_state & TS_ISOPEN) == 0) { \
304 1.2 cgd if (kgdb_dev == makedev(commajor, unit) && \
305 1.1 cgd code == FRAME_END) \
306 1.1 cgd kgdb_connect(0); /* trap into kgdb */ \
307 1.1 cgd } else \
308 1.1 cgd (*linesw[tp->t_line].l_rint)(code, tp)
309 1.1 cgd #else
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) \
313 1.1 cgd (*linesw[tp->t_line].l_rint)(code, tp)
314 1.1 cgd #endif
315 1.1 cgd
316 1.1 cgd RCVBYTE();
317 1.1 cgd
318 1.1 cgd if (com_hasfifo & (1 << unit))
319 1.1 cgd while ((code = inb(com+com_lsr)) & LSR_RCV_MASK) {
320 1.1 cgd if (code == LSR_RXRDY) {
321 1.1 cgd RCVBYTE();
322 1.1 cgd } else
323 1.1 cgd comeint(unit, code, com);
324 1.1 cgd }
325 1.1 cgd break;
326 1.1 cgd case IIR_TXRDY:
327 1.8 deraadt tp = com_tty[unit];
328 1.1 cgd tp->t_state &=~ (TS_BUSY|TS_FLUSH);
329 1.1 cgd if (tp->t_line)
330 1.1 cgd (*linesw[tp->t_line].l_start)(tp);
331 1.1 cgd else
332 1.1 cgd comstart(tp);
333 1.1 cgd break;
334 1.1 cgd case IIR_RLS:
335 1.1 cgd comeint(unit, inb(com+com_lsr), com);
336 1.1 cgd break;
337 1.1 cgd default:
338 1.1 cgd if (code & IIR_NOPEND)
339 1.1 cgd return (1);
340 1.1 cgd log(LOG_WARNING, "com%d: weird interrupt: 0x%x\n",
341 1.1 cgd unit, code);
342 1.1 cgd /* fall through */
343 1.1 cgd case IIR_MLSC:
344 1.1 cgd commint(unit, com);
345 1.1 cgd break;
346 1.1 cgd }
347 1.1 cgd }
348 1.1 cgd }
349 1.1 cgd
350 1.1 cgd comeint(unit, stat, com)
351 1.1 cgd register int unit, stat;
352 1.1 cgd register com;
353 1.1 cgd {
354 1.1 cgd register struct tty *tp;
355 1.1 cgd register int c;
356 1.1 cgd
357 1.8 deraadt tp = com_tty[unit];
358 1.1 cgd c = inb(com+com_data);
359 1.1 cgd if ((tp->t_state & TS_ISOPEN) == 0) {
360 1.1 cgd #ifdef KGDB
361 1.1 cgd /* we don't care about parity errors */
362 1.1 cgd if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) &&
363 1.2 cgd kgdb_dev == makedev(commajor, unit) && c == FRAME_END)
364 1.1 cgd kgdb_connect(0); /* trap into kgdb */
365 1.1 cgd #endif
366 1.1 cgd return;
367 1.1 cgd }
368 1.1 cgd if (stat & (LSR_BI | LSR_FE))
369 1.1 cgd c |= TTY_FE;
370 1.1 cgd else if (stat & LSR_PE)
371 1.1 cgd c |= TTY_PE;
372 1.2 cgd else if (stat & LSR_OE) { /* 30 Aug 92*/
373 1.2 cgd c |= TTY_PE; /* Ought to have it's own define... */
374 1.1 cgd log(LOG_WARNING, "com%d: silo overflow\n", unit);
375 1.2 cgd }
376 1.1 cgd (*linesw[tp->t_line].l_rint)(c, tp);
377 1.1 cgd }
378 1.1 cgd
379 1.1 cgd commint(unit, com)
380 1.1 cgd register int unit;
381 1.1 cgd register com;
382 1.1 cgd {
383 1.1 cgd register struct tty *tp;
384 1.1 cgd register int stat;
385 1.1 cgd
386 1.8 deraadt tp = com_tty[unit];
387 1.1 cgd stat = inb(com+com_msr);
388 1.1 cgd if ((stat & MSR_DDCD) && (comsoftCAR & (1 << unit)) == 0) {
389 1.1 cgd if (stat & MSR_DCD)
390 1.1 cgd (void)(*linesw[tp->t_line].l_modem)(tp, 1);
391 1.1 cgd else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
392 1.1 cgd outb(com+com_mcr,
393 1.1 cgd inb(com+com_mcr) & ~(MCR_DTR | MCR_RTS) | MCR_IENABLE);
394 1.1 cgd } else if ((stat & MSR_DCTS) && (tp->t_state & TS_ISOPEN) &&
395 1.1 cgd (tp->t_flags & CRTSCTS)) {
396 1.1 cgd /* the line is up and we want to do rts/cts flow control */
397 1.1 cgd if (stat & MSR_CTS) {
398 1.1 cgd tp->t_state &=~ TS_TTSTOP;
399 1.1 cgd ttstart(tp);
400 1.1 cgd } else
401 1.1 cgd tp->t_state |= TS_TTSTOP;
402 1.1 cgd }
403 1.1 cgd }
404 1.1 cgd
405 1.1 cgd comioctl(dev, cmd, data, flag)
406 1.1 cgd dev_t dev;
407 1.1 cgd caddr_t data;
408 1.1 cgd {
409 1.1 cgd register struct tty *tp;
410 1.1 cgd register int unit = UNIT(dev);
411 1.1 cgd register com;
412 1.1 cgd register int error;
413 1.1 cgd
414 1.8 deraadt tp = com_tty[unit];
415 1.1 cgd error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
416 1.1 cgd if (error >= 0)
417 1.1 cgd return (error);
418 1.1 cgd error = ttioctl(tp, cmd, data, flag);
419 1.1 cgd if (error >= 0)
420 1.1 cgd return (error);
421 1.1 cgd
422 1.1 cgd com = com_addr[unit];
423 1.1 cgd switch (cmd) {
424 1.1 cgd
425 1.1 cgd case TIOCSBRK:
426 1.1 cgd outb(com+com_cfcr, inb(com+com_cfcr) | CFCR_SBREAK);
427 1.1 cgd break;
428 1.1 cgd
429 1.1 cgd case TIOCCBRK:
430 1.1 cgd outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK);
431 1.1 cgd break;
432 1.1 cgd
433 1.1 cgd case TIOCSDTR:
434 1.1 cgd (void) commctl(dev, MCR_DTR | MCR_RTS, DMBIS);
435 1.1 cgd break;
436 1.1 cgd
437 1.1 cgd case TIOCCDTR:
438 1.1 cgd (void) commctl(dev, MCR_DTR | MCR_RTS, DMBIC);
439 1.1 cgd break;
440 1.1 cgd
441 1.1 cgd case TIOCMSET:
442 1.1 cgd (void) commctl(dev, *(int *)data, DMSET);
443 1.1 cgd break;
444 1.1 cgd
445 1.1 cgd case TIOCMBIS:
446 1.1 cgd (void) commctl(dev, *(int *)data, DMBIS);
447 1.1 cgd break;
448 1.1 cgd
449 1.1 cgd case TIOCMBIC:
450 1.1 cgd (void) commctl(dev, *(int *)data, DMBIC);
451 1.1 cgd break;
452 1.1 cgd
453 1.1 cgd case TIOCMGET:
454 1.1 cgd *(int *)data = commctl(dev, 0, DMGET);
455 1.1 cgd break;
456 1.1 cgd
457 1.1 cgd default:
458 1.1 cgd return (ENOTTY);
459 1.1 cgd }
460 1.1 cgd return (0);
461 1.1 cgd }
462 1.1 cgd
463 1.1 cgd comparam(tp, t)
464 1.1 cgd register struct tty *tp;
465 1.1 cgd register struct termios *t;
466 1.1 cgd {
467 1.1 cgd register com;
468 1.1 cgd register int cfcr, cflag = t->c_cflag;
469 1.1 cgd int unit = UNIT(tp->t_dev);
470 1.1 cgd int ospeed = ttspeedtab(t->c_ospeed, comspeedtab);
471 1.1 cgd
472 1.1 cgd /* check requested parameters */
473 1.1 cgd if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
474 1.1 cgd return(EINVAL);
475 1.1 cgd /* and copy to tty */
476 1.1 cgd tp->t_ispeed = t->c_ispeed;
477 1.1 cgd tp->t_ospeed = t->c_ospeed;
478 1.1 cgd tp->t_cflag = cflag;
479 1.1 cgd
480 1.1 cgd com = com_addr[unit];
481 1.1 cgd outb(com+com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS /*| IER_EMSC*/);
482 1.1 cgd if (ospeed == 0) {
483 1.1 cgd (void) commctl(unit, 0, DMSET); /* hang up line */
484 1.1 cgd return(0);
485 1.1 cgd }
486 1.1 cgd outb(com+com_cfcr, inb(com+com_cfcr) | CFCR_DLAB);
487 1.1 cgd outb(com+com_data, ospeed & 0xFF);
488 1.1 cgd outb(com+com_ier, ospeed >> 8);
489 1.1 cgd switch (cflag&CSIZE) {
490 1.1 cgd case CS5:
491 1.1 cgd cfcr = CFCR_5BITS; break;
492 1.1 cgd case CS6:
493 1.1 cgd cfcr = CFCR_6BITS; break;
494 1.1 cgd case CS7:
495 1.1 cgd cfcr = CFCR_7BITS; break;
496 1.1 cgd case CS8:
497 1.1 cgd cfcr = CFCR_8BITS; break;
498 1.1 cgd }
499 1.1 cgd if (cflag&PARENB) {
500 1.1 cgd cfcr |= CFCR_PENAB;
501 1.1 cgd if ((cflag&PARODD) == 0)
502 1.1 cgd cfcr |= CFCR_PEVEN;
503 1.1 cgd }
504 1.1 cgd if (cflag&CSTOPB)
505 1.1 cgd cfcr |= CFCR_STOPB;
506 1.1 cgd outb(com+com_cfcr, cfcr);
507 1.1 cgd
508 1.1 cgd if (com_hasfifo & (1 << unit))
509 1.2 cgd outb(com+com_fifo, FIFO_ENABLE | FIFO_TRIGGER_4);
510 1.1 cgd
511 1.1 cgd return(0);
512 1.1 cgd }
513 1.1 cgd
514 1.12 deraadt void
515 1.1 cgd comstart(tp)
516 1.1 cgd register struct tty *tp;
517 1.1 cgd {
518 1.1 cgd register com;
519 1.1 cgd int s, unit, c;
520 1.1 cgd
521 1.1 cgd unit = UNIT(tp->t_dev);
522 1.1 cgd com = com_addr[unit];
523 1.1 cgd s = spltty();
524 1.1 cgd if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
525 1.1 cgd goto out;
526 1.11 mycroft if (tp->t_outq.c_cc <= tp->t_lowat) {
527 1.1 cgd if (tp->t_state&TS_ASLEEP) {
528 1.1 cgd tp->t_state &= ~TS_ASLEEP;
529 1.11 mycroft wakeup((caddr_t)&tp->t_outq);
530 1.1 cgd }
531 1.7 cgd selwakeup(&tp->t_wsel);
532 1.1 cgd }
533 1.11 mycroft if (tp->t_outq.c_cc == 0)
534 1.1 cgd goto out;
535 1.1 cgd if (inb(com+com_lsr) & LSR_TXRDY) {
536 1.11 mycroft c = getc(&tp->t_outq);
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.11 mycroft for (c = 1; c < 16 && tp->t_outq.c_cc; ++c)
541 1.11 mycroft outb(com+com_data, getc(&tp->t_outq));
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.17 cgd #include <dev/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.2 cgd cp->cn_dev = makedev(commajor, unit);
620 1.1 cgd #ifdef COMCONSOLE
621 1.1 cgd cp->cn_pri = CN_REMOTE; /* Force a serial port console */
622 1.1 cgd #else
623 1.1 cgd cp->cn_pri = CN_NORMAL;
624 1.1 cgd #endif
625 1.1 cgd }
626 1.1 cgd
627 1.1 cgd comcninit(cp)
628 1.1 cgd struct consdev *cp;
629 1.1 cgd {
630 1.1 cgd int unit = UNIT(cp->cn_dev);
631 1.1 cgd
632 1.1 cgd cominit(unit, comdefaultrate);
633 1.1 cgd comconsole = unit;
634 1.1 cgd comconsinit = 1;
635 1.1 cgd }
636 1.1 cgd
637 1.1 cgd cominit(unit, rate)
638 1.1 cgd int unit, rate;
639 1.1 cgd {
640 1.1 cgd register int com;
641 1.1 cgd int s;
642 1.1 cgd short stat;
643 1.1 cgd
644 1.1 cgd #ifdef lint
645 1.1 cgd stat = unit; if (stat) return;
646 1.1 cgd #endif
647 1.1 cgd com = com_addr[unit];
648 1.1 cgd s = splhigh();
649 1.1 cgd outb(com+com_cfcr, CFCR_DLAB);
650 1.1 cgd rate = ttspeedtab(comdefaultrate, comspeedtab);
651 1.1 cgd outb(com+com_data, rate & 0xFF);
652 1.1 cgd outb(com+com_ier, rate >> 8);
653 1.1 cgd outb(com+com_cfcr, CFCR_8BITS);
654 1.1 cgd outb(com+com_ier, IER_ERXRDY | IER_ETXRDY);
655 1.2 cgd outb(com+com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_4);
656 1.1 cgd stat = inb(com+com_iir);
657 1.1 cgd splx(s);
658 1.1 cgd }
659 1.1 cgd
660 1.1 cgd comcngetc(dev)
661 1.1 cgd {
662 1.1 cgd register com = com_addr[UNIT(dev)];
663 1.1 cgd short stat;
664 1.1 cgd int c, s;
665 1.1 cgd
666 1.1 cgd #ifdef lint
667 1.1 cgd stat = dev; if (stat) return(0);
668 1.1 cgd #endif
669 1.1 cgd s = splhigh();
670 1.1 cgd while (((stat = inb(com+com_lsr)) & LSR_RXRDY) == 0)
671 1.1 cgd ;
672 1.1 cgd c = inb(com+com_data);
673 1.1 cgd stat = inb(com+com_iir);
674 1.1 cgd splx(s);
675 1.1 cgd return(c);
676 1.1 cgd }
677 1.1 cgd
678 1.1 cgd /*
679 1.1 cgd * Console kernel output character routine.
680 1.1 cgd */
681 1.1 cgd comcnputc(dev, c)
682 1.1 cgd dev_t dev;
683 1.1 cgd register int c;
684 1.1 cgd {
685 1.1 cgd register com = com_addr[UNIT(dev)];
686 1.1 cgd register int timo;
687 1.1 cgd short stat;
688 1.1 cgd int s = splhigh();
689 1.1 cgd
690 1.1 cgd #ifdef lint
691 1.1 cgd stat = dev; if (stat) return;
692 1.1 cgd #endif
693 1.1 cgd #ifdef KGDB
694 1.1 cgd if (dev != kgdb_dev)
695 1.1 cgd #endif
696 1.1 cgd if (comconsinit == 0) {
697 1.1 cgd (void) cominit(UNIT(dev), comdefaultrate);
698 1.1 cgd comconsinit = 1;
699 1.1 cgd }
700 1.1 cgd /* wait for any pending transmission to finish */
701 1.1 cgd timo = 50000;
702 1.1 cgd while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo)
703 1.1 cgd ;
704 1.1 cgd outb(com+com_data, c);
705 1.1 cgd /* wait for this transmission to complete */
706 1.1 cgd timo = 1500000;
707 1.1 cgd while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo)
708 1.1 cgd ;
709 1.1 cgd /* clear any interrupts generated by this transmission */
710 1.1 cgd stat = inb(com+com_iir);
711 1.1 cgd splx(s);
712 1.2 cgd }
713 1.6 glass
714 1.3 cgd #endif
715