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