ser.c revision 1.42 1 1.42 mhitch /* $NetBSD: ser.c,v 1.42 1997/10/04 03:59:59 mhitch Exp $ */
2 1.23 cgd
3 1.1 mw /*
4 1.1 mw * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
5 1.1 mw * All rights reserved.
6 1.1 mw *
7 1.1 mw * Redistribution and use in source and binary forms, with or without
8 1.1 mw * modification, are permitted provided that the following conditions
9 1.1 mw * are met:
10 1.1 mw * 1. Redistributions of source code must retain the above copyright
11 1.1 mw * notice, this list of conditions and the following disclaimer.
12 1.1 mw * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 mw * notice, this list of conditions and the following disclaimer in the
14 1.1 mw * documentation and/or other materials provided with the distribution.
15 1.1 mw * 3. All advertising materials mentioning features or use of this software
16 1.1 mw * must display the following acknowledgement:
17 1.1 mw * This product includes software developed by the University of
18 1.1 mw * California, Berkeley and its contributors.
19 1.1 mw * 4. Neither the name of the University nor the names of its contributors
20 1.1 mw * may be used to endorse or promote products derived from this software
21 1.1 mw * without specific prior written permission.
22 1.1 mw *
23 1.1 mw * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 1.1 mw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 1.1 mw * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 1.1 mw * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 1.1 mw * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 1.1 mw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 1.1 mw * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 1.1 mw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 1.1 mw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 1.1 mw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 1.1 mw * SUCH DAMAGE.
34 1.1 mw *
35 1.4 mw * @(#)ser.c 7.12 (Berkeley) 6/27/91
36 1.15 chopps */
37 1.15 chopps /*
38 1.32 is * XXX This file needs major cleanup it will never service more than one
39 1.15 chopps * XXX unit.
40 1.1 mw */
41 1.1 mw
42 1.10 chopps #include <sys/param.h>
43 1.10 chopps #include <sys/systm.h>
44 1.10 chopps #include <sys/ioctl.h>
45 1.15 chopps #include <sys/device.h>
46 1.10 chopps #include <sys/tty.h>
47 1.10 chopps #include <sys/proc.h>
48 1.10 chopps #include <sys/file.h>
49 1.10 chopps #include <sys/malloc.h>
50 1.10 chopps #include <sys/uio.h>
51 1.10 chopps #include <sys/kernel.h>
52 1.10 chopps #include <sys/syslog.h>
53 1.13 chopps #include <sys/queue.h>
54 1.15 chopps #include <machine/cpu.h>
55 1.15 chopps #include <amiga/amiga/device.h>
56 1.10 chopps #include <amiga/dev/serreg.h>
57 1.10 chopps #include <amiga/amiga/custom.h>
58 1.10 chopps #include <amiga/amiga/cia.h>
59 1.10 chopps #include <amiga/amiga/cc.h>
60 1.1 mw
61 1.14 chopps #include <dev/cons.h>
62 1.14 chopps
63 1.31 veego #include <sys/conf.h>
64 1.31 veego #include <machine/conf.h>
65 1.31 veego
66 1.15 chopps #include "ser.h"
67 1.15 chopps #if NSER > 0
68 1.14 chopps
69 1.15 chopps void serattach __P((struct device *, struct device *, void *));
70 1.39 veego int sermatch __P((struct device *, struct cfdata *, void *));
71 1.15 chopps
72 1.28 jtc struct ser_softc {
73 1.28 jtc struct device dev;
74 1.28 jtc struct tty *ser_tty;
75 1.28 jtc };
76 1.28 jtc
77 1.29 thorpej struct cfattach ser_ca = {
78 1.30 mhitch sizeof(struct ser_softc), sermatch, serattach
79 1.29 thorpej };
80 1.29 thorpej
81 1.29 thorpej struct cfdriver ser_cd = {
82 1.29 thorpej NULL, "ser", DV_TTY, NULL, 0
83 1.29 thorpej };
84 1.15 chopps
85 1.26 chopps #ifndef SEROBUF_SIZE
86 1.15 chopps #define SEROBUF_SIZE 32
87 1.26 chopps #endif
88 1.26 chopps #ifndef SERIBUF_SIZE
89 1.15 chopps #define SERIBUF_SIZE 512
90 1.26 chopps #endif
91 1.26 chopps
92 1.26 chopps #define splser() spl5()
93 1.1 mw
94 1.31 veego void serstart __P((struct tty *));
95 1.31 veego int serparam __P((struct tty *, struct termios *));
96 1.31 veego void serintr __P((int));
97 1.31 veego int serhwiflow __P((struct tty *, int));
98 1.31 veego int sermctl __P((dev_t dev, int, int));
99 1.31 veego void ser_fastint __P((void));
100 1.31 veego void sereint __P((int, int));
101 1.31 veego static void ser_putchar __P((struct tty *, u_short));
102 1.31 veego void ser_outintr __P((void));
103 1.31 veego void sercnprobe __P((struct consdev *));
104 1.31 veego void sercninit __P((struct consdev *));
105 1.31 veego void serinit __P((int, int));
106 1.31 veego int sercngetc __P((dev_t dev));
107 1.31 veego void sercnputc __P((dev_t, int));
108 1.31 veego void sercnpollc __P((dev_t, int));
109 1.31 veego
110 1.1 mw int ser_active;
111 1.1 mw int ser_hasfifo;
112 1.1 mw int nser = NSER;
113 1.1 mw #ifdef SERCONSOLE
114 1.1 mw int serconsole = SERCONSOLE;
115 1.1 mw #else
116 1.1 mw int serconsole = -1;
117 1.1 mw #endif
118 1.1 mw int serconsinit;
119 1.1 mw int serdefaultrate = TTYDEF_SPEED;
120 1.1 mw int sermajor;
121 1.14 chopps int serswflags;
122 1.14 chopps #define SWFLAGS(dev) (serswflags | (DIALOUT(dev) ? TIOCFLAG_SOFTCAR : 0))
123 1.14 chopps
124 1.5 mw struct vbl_node ser_vbl_node[NSER];
125 1.1 mw struct tty ser_cons;
126 1.27 chopps struct tty *ser_tty[NSER];
127 1.1 mw
128 1.14 chopps /*
129 1.14 chopps * Since this UART is not particularly bright (to put it nicely), we'll
130 1.14 chopps * have to do parity stuff on our own. This table contains the 8th bit
131 1.14 chopps * in 7bit character mode, for even parity. If you want odd parity,
132 1.14 chopps * flip the bit. (for generation of the table, see genpar.c)
133 1.14 chopps */
134 1.14 chopps
135 1.14 chopps u_char even_parity[] = {
136 1.14 chopps 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
137 1.14 chopps 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
138 1.14 chopps 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
139 1.14 chopps 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
140 1.14 chopps 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
141 1.14 chopps 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
142 1.14 chopps 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
143 1.14 chopps 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
144 1.1 mw };
145 1.1 mw
146 1.14 chopps /*
147 1.14 chopps * Since we don't get interrupts for changes on the modem control line,
148 1.14 chopps * we'll have to fake them by comparing current settings to the settings
149 1.14 chopps * we remembered on last invocation.
150 1.14 chopps */
151 1.14 chopps
152 1.14 chopps u_char last_ciab_pra;
153 1.14 chopps
154 1.14 chopps extern struct tty *constty;
155 1.1 mw
156 1.42 mhitch extern int ser_open_speed; /* current speed of open serial device */
157 1.42 mhitch
158 1.1 mw #ifdef KGDB
159 1.10 chopps #include <machine/remote-sl.h>
160 1.1 mw
161 1.1 mw extern dev_t kgdb_dev;
162 1.1 mw extern int kgdb_rate;
163 1.1 mw extern int kgdb_debug_init;
164 1.1 mw #endif
165 1.1 mw
166 1.1 mw #ifdef DEBUG
167 1.1 mw long fifoin[17];
168 1.1 mw long fifoout[17];
169 1.1 mw long serintrcount[16];
170 1.1 mw long sermintcount[16];
171 1.1 mw #endif
172 1.1 mw
173 1.14 chopps void sermint __P((register int unit));
174 1.5 mw
175 1.5 mw int
176 1.39 veego sermatch(pdp, cfp, auxp)
177 1.15 chopps struct device *pdp;
178 1.39 veego struct cfdata *cfp;
179 1.39 veego void *auxp;
180 1.15 chopps {
181 1.29 thorpej
182 1.15 chopps if (matchname("ser", (char *)auxp) == 0 || cfp->cf_unit != 0)
183 1.15 chopps return(0);
184 1.15 chopps if (serconsole != 0 && amiga_realconfig == 0)
185 1.15 chopps return(0);
186 1.15 chopps return(1);
187 1.15 chopps }
188 1.15 chopps
189 1.15 chopps
190 1.15 chopps void
191 1.15 chopps serattach(pdp, dp, auxp)
192 1.15 chopps struct device *pdp, *dp;
193 1.15 chopps void *auxp;
194 1.1 mw {
195 1.15 chopps u_short ir;
196 1.14 chopps
197 1.14 chopps ir = custom.intenar;
198 1.15 chopps if (serconsole == 0)
199 1.14 chopps DELAY(100000);
200 1.14 chopps
201 1.15 chopps ser_active |= 1;
202 1.15 chopps ser_vbl_node[0].function = (void (*) (void *)) sermint;
203 1.15 chopps add_vbl_function(&ser_vbl_node[0], SER_VBL_PRIORITY, (void *) 0);
204 1.1 mw #ifdef KGDB
205 1.15 chopps if (kgdb_dev == makedev(sermajor, 0)) {
206 1.15 chopps if (serconsole == 0)
207 1.14 chopps kgdb_dev = NODEV; /* can't debug over console port */
208 1.14 chopps else {
209 1.15 chopps (void) serinit(0, kgdb_rate);
210 1.14 chopps serconsinit = 1; /* don't re-init in serputc */
211 1.14 chopps if (kgdb_debug_init == 0)
212 1.38 christos printf(" kgdb enabled\n");
213 1.14 chopps else {
214 1.14 chopps /*
215 1.14 chopps * Print prefix of device name,
216 1.14 chopps * let kgdb_connect print the rest.
217 1.14 chopps */
218 1.38 christos printf("ser0: ");
219 1.14 chopps kgdb_connect(1);
220 1.14 chopps }
221 1.14 chopps }
222 1.14 chopps }
223 1.5 mw #endif
224 1.14 chopps /*
225 1.14 chopps * Need to reset baud rate, etc. of next print so reset serconsinit.
226 1.14 chopps */
227 1.15 chopps if (0 == serconsole)
228 1.14 chopps serconsinit = 0;
229 1.15 chopps if (dp)
230 1.38 christos printf(": input fifo %d output fifo %d\n", SERIBUF_SIZE,
231 1.15 chopps SEROBUF_SIZE);
232 1.1 mw }
233 1.1 mw
234 1.14 chopps
235 1.1 mw /* ARGSUSED */
236 1.5 mw int
237 1.1 mw seropen(dev, flag, mode, p)
238 1.14 chopps dev_t dev;
239 1.14 chopps int flag, mode;
240 1.14 chopps struct proc *p;
241 1.1 mw {
242 1.14 chopps struct tty *tp;
243 1.14 chopps int unit, error, s;
244 1.14 chopps
245 1.14 chopps error = 0;
246 1.14 chopps unit = SERUNIT(dev);
247 1.14 chopps
248 1.14 chopps if (unit >= NSER || (ser_active & (1 << unit)) == 0)
249 1.14 chopps return (ENXIO);
250 1.14 chopps
251 1.14 chopps s = spltty();
252 1.14 chopps
253 1.14 chopps if (ser_tty[unit])
254 1.14 chopps tp = ser_tty[unit];
255 1.35 mhitch else {
256 1.29 thorpej tp = ((struct ser_softc *)ser_cd.cd_devs[unit])->ser_tty =
257 1.28 jtc ser_tty[unit] = ttymalloc();
258 1.35 mhitch tty_attach(tp);
259 1.35 mhitch }
260 1.14 chopps
261 1.14 chopps tp->t_oproc = (void (*) (struct tty *)) serstart;
262 1.14 chopps tp->t_param = serparam;
263 1.14 chopps tp->t_dev = dev;
264 1.22 chopps tp->t_hwiflow = serhwiflow;
265 1.14 chopps
266 1.14 chopps if ((tp->t_state & TS_ISOPEN) == 0) {
267 1.14 chopps tp->t_state |= TS_WOPEN;
268 1.14 chopps ttychars(tp);
269 1.14 chopps if (tp->t_ispeed == 0) {
270 1.14 chopps /*
271 1.14 chopps * only when cleared do we reset to defaults.
272 1.14 chopps */
273 1.14 chopps tp->t_iflag = TTYDEF_IFLAG;
274 1.14 chopps tp->t_oflag = TTYDEF_OFLAG;
275 1.14 chopps tp->t_cflag = TTYDEF_CFLAG;
276 1.14 chopps tp->t_lflag = TTYDEF_LFLAG;
277 1.14 chopps tp->t_ispeed = tp->t_ospeed = serdefaultrate;
278 1.14 chopps }
279 1.14 chopps /*
280 1.14 chopps * do these all the time
281 1.14 chopps */
282 1.14 chopps if (serswflags & TIOCFLAG_CLOCAL)
283 1.14 chopps tp->t_cflag |= CLOCAL;
284 1.14 chopps if (serswflags & TIOCFLAG_CRTSCTS)
285 1.14 chopps tp->t_cflag |= CRTSCTS;
286 1.14 chopps if (serswflags & TIOCFLAG_MDMBUF)
287 1.14 chopps tp->t_cflag |= MDMBUF;
288 1.14 chopps serparam(tp, &tp->t_termios);
289 1.14 chopps ttsetwater(tp);
290 1.14 chopps
291 1.14 chopps (void)sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMSET);
292 1.14 chopps if ((SWFLAGS(dev) & TIOCFLAG_SOFTCAR) ||
293 1.14 chopps (sermctl(dev, 0, DMGET) & TIOCM_CD))
294 1.14 chopps tp->t_state |= TS_CARR_ON;
295 1.14 chopps else
296 1.14 chopps tp->t_state &= ~TS_CARR_ON;
297 1.14 chopps } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
298 1.14 chopps splx(s);
299 1.14 chopps return(EBUSY);
300 1.14 chopps }
301 1.14 chopps
302 1.14 chopps /*
303 1.14 chopps * if NONBLOCK requested, ignore carrier
304 1.14 chopps */
305 1.14 chopps if (flag & O_NONBLOCK)
306 1.14 chopps goto done;
307 1.14 chopps
308 1.14 chopps /*
309 1.14 chopps * block waiting for carrier
310 1.14 chopps */
311 1.14 chopps while ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) {
312 1.14 chopps tp->t_state |= TS_WOPEN;
313 1.14 chopps error = ttysleep(tp, (caddr_t)&tp->t_rawq,
314 1.14 chopps TTIPRI | PCATCH, ttopen, 0);
315 1.14 chopps if (error) {
316 1.14 chopps splx(s);
317 1.14 chopps return(error);
318 1.14 chopps }
319 1.1 mw }
320 1.14 chopps done:
321 1.22 chopps /* This is a way to handle lost XON characters */
322 1.22 chopps if ((flag & O_TRUNC) && (tp->t_state & TS_TTSTOP)) {
323 1.22 chopps tp->t_state &= ~TS_TTSTOP;
324 1.22 chopps ttstart (tp);
325 1.22 chopps }
326 1.22 chopps
327 1.14 chopps splx(s);
328 1.14 chopps /*
329 1.14 chopps * Reset the tty pointer, as there could have been a dialout
330 1.14 chopps * use of the tty with a dialin open waiting.
331 1.14 chopps */
332 1.14 chopps tp->t_dev = dev;
333 1.42 mhitch ser_open_speed = tp->t_ispeed;
334 1.14 chopps return((*linesw[tp->t_line].l_open)(dev, tp));
335 1.1 mw }
336 1.14 chopps
337 1.1 mw /*ARGSUSED*/
338 1.5 mw int
339 1.1 mw serclose(dev, flag, mode, p)
340 1.14 chopps dev_t dev;
341 1.14 chopps int flag, mode;
342 1.14 chopps struct proc *p;
343 1.14 chopps {
344 1.14 chopps struct tty *tp;
345 1.14 chopps int unit;
346 1.41 is int closebits;
347 1.14 chopps
348 1.14 chopps unit = SERUNIT(dev);
349 1.14 chopps
350 1.14 chopps tp = ser_tty[unit];
351 1.14 chopps (*linesw[tp->t_line].l_close)(tp, flag);
352 1.14 chopps custom.adkcon = ADKCONF_UARTBRK; /* clear break */
353 1.1 mw #ifdef KGDB
354 1.14 chopps /*
355 1.14 chopps * do not disable interrupts if debugging
356 1.14 chopps */
357 1.14 chopps if (dev != kgdb_dev)
358 1.1 mw #endif
359 1.14 chopps custom.intena = INTF_RBF | INTF_TBE; /* disable interrups */
360 1.14 chopps custom.intreq = INTF_RBF | INTF_TBE; /* clear intr request */
361 1.14 chopps
362 1.14 chopps /*
363 1.41 is * If HUPCL is not set, leave DTR unchanged.
364 1.14 chopps */
365 1.41 is if (tp->t_cflag & HUPCL)
366 1.41 is closebits = 0;
367 1.41 is else
368 1.41 is closebits = sermctl(dev, 0, DMGET) & TIOCM_DTR;
369 1.41 is
370 1.41 is (void) sermctl(dev, closebits, DMSET);
371 1.41 is
372 1.41 is /*
373 1.41 is * Idea from dev/isa/com.c:
374 1.41 is * sleep a bit so that other side will notice, even if we reopen
375 1.41 is * immediately.
376 1.41 is */
377 1.41 is (void) tsleep(tp, TTIPRI, ttclos, hz);
378 1.14 chopps ttyclose(tp);
379 1.14 chopps #if not_yet
380 1.14 chopps if (tp != &ser_cons) {
381 1.14 chopps remove_vbl_function(&ser_vbl_node[unit]);
382 1.14 chopps ttyfree(tp);
383 1.14 chopps ser_tty[unit] = (struct tty *) NULL;
384 1.14 chopps }
385 1.3 mw #endif
386 1.42 mhitch ser_open_speed = tp->t_ispeed;
387 1.14 chopps return (0);
388 1.1 mw }
389 1.14 chopps
390 1.5 mw int
391 1.1 mw serread(dev, uio, flag)
392 1.14 chopps dev_t dev;
393 1.14 chopps struct uio *uio;
394 1.14 chopps int flag;
395 1.1 mw {
396 1.14 chopps struct tty *tp;
397 1.14 chopps if ((tp = ser_tty[SERUNIT(dev)]) == NULL)
398 1.14 chopps return(ENXIO);
399 1.14 chopps return((*linesw[tp->t_line].l_read)(tp, uio, flag));
400 1.14 chopps }
401 1.1 mw
402 1.5 mw int
403 1.1 mw serwrite(dev, uio, flag)
404 1.14 chopps dev_t dev;
405 1.14 chopps struct uio *uio;
406 1.14 chopps int flag;
407 1.1 mw {
408 1.14 chopps struct tty *tp;
409 1.14 chopps
410 1.14 chopps if((tp = ser_tty[SERUNIT(dev)]) == NULL)
411 1.14 chopps return(ENXIO);
412 1.14 chopps return((*linesw[tp->t_line].l_write)(tp, uio, flag));
413 1.1 mw }
414 1.3 mw
415 1.27 chopps struct tty *
416 1.27 chopps sertty(dev)
417 1.27 chopps dev_t dev;
418 1.27 chopps {
419 1.27 chopps return (ser_tty[SERUNIT(dev)]);
420 1.27 chopps }
421 1.3 mw
422 1.14 chopps /*
423 1.14 chopps * We don't do any processing of data here, so we store the raw code
424 1.14 chopps * obtained from the uart register. In theory, 110kBaud gives you
425 1.14 chopps * 11kcps, so 16k buffer should be more than enough, interrupt
426 1.14 chopps * latency of 1s should never happen, or something is seriously
427 1.14 chopps * wrong..
428 1.14 chopps */
429 1.14 chopps
430 1.3 mw static u_short serbuf[SERIBUF_SIZE];
431 1.3 mw static u_short *sbrpt = serbuf;
432 1.3 mw static u_short *sbwpt = serbuf;
433 1.22 chopps static u_short sbcnt;
434 1.18 chopps static u_short sbovfl;
435 1.3 mw
436 1.14 chopps /*
437 1.14 chopps * This is a replacement for the lack of a hardware fifo. 32k should be
438 1.14 chopps * enough (there's only one unit anyway, so this is not going to
439 1.14 chopps * accumulate).
440 1.14 chopps */
441 1.3 mw void
442 1.14 chopps ser_fastint()
443 1.3 mw {
444 1.14 chopps /*
445 1.14 chopps * We're at RBE-level, which is higher than VBL-level which is used
446 1.14 chopps * to periodically transmit contents of this buffer up one layer,
447 1.14 chopps * so no spl-raising is necessary.
448 1.14 chopps */
449 1.14 chopps register u_short ints, code;
450 1.14 chopps
451 1.14 chopps ints = custom.intreqr & INTF_RBF;
452 1.14 chopps if (ints == 0)
453 1.14 chopps return;
454 1.14 chopps
455 1.40 mhitch /*
456 1.40 mhitch * this register contains both data and status bits!
457 1.40 mhitch */
458 1.40 mhitch code = custom.serdatr;
459 1.40 mhitch
460 1.14 chopps /*
461 1.14 chopps * clear interrupt
462 1.14 chopps */
463 1.14 chopps custom.intreq = ints;
464 1.14 chopps
465 1.14 chopps /*
466 1.14 chopps * check for buffer overflow.
467 1.14 chopps */
468 1.22 chopps if (sbcnt == SERIBUF_SIZE) {
469 1.18 chopps ++sbovfl;
470 1.14 chopps return;
471 1.14 chopps }
472 1.14 chopps /*
473 1.14 chopps * store in buffer
474 1.14 chopps */
475 1.14 chopps *sbwpt++ = code;
476 1.14 chopps if (sbwpt == serbuf + SERIBUF_SIZE)
477 1.14 chopps sbwpt = serbuf;
478 1.22 chopps ++sbcnt;
479 1.26 chopps if (sbcnt > SERIBUF_SIZE - 20)
480 1.22 chopps CLRRTS(ciab.pra); /* drop RTS if buffer almost full */
481 1.3 mw }
482 1.3 mw
483 1.3 mw
484 1.31 veego void
485 1.14 chopps serintr(unit)
486 1.14 chopps int unit;
487 1.1 mw {
488 1.18 chopps int s1, s2, ovfl;
489 1.22 chopps struct tty *tp = ser_tty[unit];
490 1.1 mw
491 1.14 chopps /*
492 1.14 chopps * Make sure we're not interrupted by another
493 1.14 chopps * vbl, but allow level5 ints
494 1.14 chopps */
495 1.14 chopps s1 = spltty();
496 1.1 mw
497 1.14 chopps /*
498 1.14 chopps * pass along any acumulated information
499 1.14 chopps */
500 1.22 chopps while (sbcnt > 0 && (tp->t_state & TS_TBLOCK) == 0) {
501 1.14 chopps /*
502 1.14 chopps * no collision with ser_fastint()
503 1.14 chopps */
504 1.22 chopps sereint(unit, *sbrpt++);
505 1.14 chopps
506 1.18 chopps ovfl = 0;
507 1.14 chopps /* lock against ser_fastint() */
508 1.26 chopps s2 = splser();
509 1.22 chopps sbcnt--;
510 1.14 chopps if (sbrpt == serbuf + SERIBUF_SIZE)
511 1.14 chopps sbrpt = serbuf;
512 1.18 chopps if (sbovfl != 0) {
513 1.18 chopps ovfl = sbovfl;
514 1.18 chopps sbovfl = 0;
515 1.18 chopps }
516 1.14 chopps splx(s2);
517 1.18 chopps if (ovfl != 0)
518 1.21 chopps log(LOG_WARNING, "ser0: %d ring buffer overflows.\n",
519 1.21 chopps ovfl);
520 1.14 chopps }
521 1.33 is s2 = splser();
522 1.22 chopps if (sbcnt == 0 && (tp->t_state & TS_TBLOCK) == 0)
523 1.22 chopps SETRTS(ciab.pra); /* start accepting data again */
524 1.33 is splx(s2);
525 1.14 chopps splx(s1);
526 1.1 mw }
527 1.1 mw
528 1.31 veego void
529 1.15 chopps sereint(unit, stat)
530 1.14 chopps int unit, stat;
531 1.1 mw {
532 1.14 chopps struct tty *tp;
533 1.14 chopps u_char ch;
534 1.14 chopps int c;
535 1.14 chopps
536 1.14 chopps tp = ser_tty[unit];
537 1.14 chopps ch = stat & 0xff;
538 1.14 chopps c = ch;
539 1.14 chopps
540 1.14 chopps if ((tp->t_state & TS_ISOPEN) == 0) {
541 1.1 mw #ifdef KGDB
542 1.14 chopps /* we don't care about parity errors */
543 1.14 chopps if (kgdb_dev == makedev(sermajor, unit) && c == FRAME_END)
544 1.14 chopps kgdb_connect(0); /* trap into kgdb */
545 1.1 mw #endif
546 1.14 chopps return;
547 1.14 chopps }
548 1.14 chopps
549 1.14 chopps /*
550 1.14 chopps * Check for break and (if enabled) parity error.
551 1.14 chopps */
552 1.14 chopps if ((stat & 0x1ff) == 0)
553 1.14 chopps c |= TTY_FE;
554 1.14 chopps else if ((tp->t_cflag & PARENB) &&
555 1.14 chopps (((ch >> 7) + even_parity[ch & 0x7f]
556 1.14 chopps + !!(tp->t_cflag & PARODD)) & 1))
557 1.14 chopps c |= TTY_PE;
558 1.14 chopps
559 1.14 chopps if (stat & SERDATRF_OVRUN)
560 1.15 chopps log(LOG_WARNING, "ser0: silo overflow\n");
561 1.1 mw
562 1.14 chopps (*linesw[tp->t_line].l_rint)(c, tp);
563 1.14 chopps }
564 1.14 chopps
565 1.14 chopps /*
566 1.14 chopps * This interrupt is periodically invoked in the vertical blank
567 1.14 chopps * interrupt. It's used to keep track of the modem control lines
568 1.14 chopps * and (new with the fast_int code) to move accumulated data
569 1.14 chopps * up into the tty layer.
570 1.14 chopps */
571 1.3 mw void
572 1.14 chopps sermint(unit)
573 1.14 chopps int unit;
574 1.1 mw {
575 1.14 chopps struct tty *tp;
576 1.14 chopps u_char stat, last, istat;
577 1.14 chopps
578 1.14 chopps tp = ser_tty[unit];
579 1.14 chopps if (!tp)
580 1.14 chopps return;
581 1.14 chopps
582 1.14 chopps if ((tp->t_state & (TS_ISOPEN | TS_WOPEN)) == 0) {
583 1.14 chopps sbrpt = sbwpt = serbuf;
584 1.14 chopps return;
585 1.14 chopps }
586 1.14 chopps /*
587 1.14 chopps * empty buffer
588 1.14 chopps */
589 1.14 chopps serintr(unit);
590 1.14 chopps
591 1.14 chopps stat = ciab.pra;
592 1.14 chopps last = last_ciab_pra;
593 1.14 chopps last_ciab_pra = stat;
594 1.14 chopps
595 1.14 chopps /*
596 1.14 chopps * check whether any interesting signal changed state
597 1.14 chopps */
598 1.14 chopps istat = stat ^ last;
599 1.1 mw
600 1.14 chopps if ((istat & CIAB_PRA_CD) &&
601 1.14 chopps (SWFLAGS(tp->t_dev) & TIOCFLAG_SOFTCAR) == 0) {
602 1.14 chopps if (ISDCD(stat))
603 1.14 chopps (*linesw[tp->t_line].l_modem)(tp, 1);
604 1.14 chopps else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
605 1.14 chopps CLRDTR(stat);
606 1.14 chopps CLRRTS(stat);
607 1.14 chopps ciab.pra = stat;
608 1.14 chopps last_ciab_pra = stat;
609 1.14 chopps }
610 1.14 chopps }
611 1.14 chopps if ((istat & CIAB_PRA_CTS) && (tp->t_state & TS_ISOPEN) &&
612 1.14 chopps (tp->t_cflag & CRTSCTS)) {
613 1.5 mw #if 0
614 1.14 chopps /* the line is up and we want to do rts/cts flow control */
615 1.14 chopps if (ISCTS(stat)) {
616 1.14 chopps tp->t_state &= ~TS_TTSTOP;
617 1.14 chopps ttstart(tp);
618 1.14 chopps /* cause tbe-int if we were stuck there */
619 1.14 chopps custom.intreq = INTF_SETCLR | INTF_TBE;
620 1.14 chopps } else
621 1.14 chopps tp->t_state |= TS_TTSTOP;
622 1.5 mw #else
623 1.14 chopps /* do this on hardware level, not with tty driver */
624 1.14 chopps if (ISCTS(stat)) {
625 1.14 chopps tp->t_state &= ~TS_TTSTOP;
626 1.14 chopps /* cause TBE interrupt */
627 1.14 chopps custom.intreq = INTF_SETCLR | INTF_TBE;
628 1.14 chopps }
629 1.14 chopps #endif
630 1.5 mw }
631 1.1 mw }
632 1.1 mw
633 1.5 mw int
634 1.8 chopps serioctl(dev, cmd, data, flag, p)
635 1.24 chopps dev_t dev;
636 1.24 chopps u_long cmd;
637 1.8 chopps caddr_t data;
638 1.24 chopps int flag;
639 1.8 chopps struct proc *p;
640 1.1 mw {
641 1.14 chopps register struct tty *tp;
642 1.14 chopps register int unit = SERUNIT(dev);
643 1.14 chopps register int error;
644 1.14 chopps
645 1.14 chopps tp = ser_tty[unit];
646 1.14 chopps if (!tp)
647 1.14 chopps return ENXIO;
648 1.14 chopps
649 1.14 chopps error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
650 1.14 chopps if (error >= 0)
651 1.14 chopps return(error);
652 1.14 chopps
653 1.14 chopps error = ttioctl(tp, cmd, data, flag, p);
654 1.14 chopps if (error >= 0)
655 1.14 chopps return(error);
656 1.14 chopps
657 1.14 chopps switch (cmd) {
658 1.14 chopps case TIOCSBRK:
659 1.14 chopps custom.adkcon = ADKCONF_SETCLR | ADKCONF_UARTBRK;
660 1.14 chopps break;
661 1.14 chopps
662 1.14 chopps case TIOCCBRK:
663 1.14 chopps custom.adkcon = ADKCONF_UARTBRK;
664 1.14 chopps break;
665 1.14 chopps
666 1.14 chopps case TIOCSDTR:
667 1.14 chopps (void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
668 1.14 chopps break;
669 1.14 chopps
670 1.14 chopps case TIOCCDTR:
671 1.14 chopps (void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
672 1.14 chopps break;
673 1.14 chopps
674 1.14 chopps case TIOCMSET:
675 1.14 chopps (void) sermctl(dev, *(int *) data, DMSET);
676 1.14 chopps break;
677 1.14 chopps
678 1.14 chopps case TIOCMBIS:
679 1.14 chopps (void) sermctl(dev, *(int *) data, DMBIS);
680 1.14 chopps break;
681 1.14 chopps
682 1.14 chopps case TIOCMBIC:
683 1.14 chopps (void) sermctl(dev, *(int *) data, DMBIC);
684 1.14 chopps break;
685 1.14 chopps
686 1.14 chopps case TIOCMGET:
687 1.14 chopps *(int *)data = sermctl(dev, 0, DMGET);
688 1.14 chopps break;
689 1.14 chopps case TIOCGFLAGS:
690 1.14 chopps *(int *)data = SWFLAGS(dev);
691 1.14 chopps break;
692 1.14 chopps case TIOCSFLAGS:
693 1.14 chopps error = suser(p->p_ucred, &p->p_acflag);
694 1.14 chopps if (error != 0)
695 1.14 chopps return(EPERM);
696 1.14 chopps
697 1.14 chopps serswflags = *(int *)data;
698 1.14 chopps serswflags &= /* only allow valid flags */
699 1.14 chopps (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
700 1.14 chopps break;
701 1.14 chopps default:
702 1.14 chopps return(ENOTTY);
703 1.14 chopps }
704 1.1 mw
705 1.14 chopps return(0);
706 1.1 mw }
707 1.1 mw
708 1.5 mw int
709 1.1 mw serparam(tp, t)
710 1.14 chopps struct tty *tp;
711 1.14 chopps struct termios *t;
712 1.1 mw {
713 1.34 veego int cflag, unit, ospeed = 0;
714 1.14 chopps
715 1.14 chopps cflag = t->c_cflag;
716 1.14 chopps unit = SERUNIT(tp->t_dev);
717 1.14 chopps
718 1.32 is if (t->c_ospeed > 0) {
719 1.32 is if (t->c_ospeed < 110)
720 1.32 is return(EINVAL);
721 1.32 is ospeed = SERBRD(t->c_ospeed);
722 1.32 is }
723 1.32 is
724 1.32 is if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
725 1.14 chopps return(EINVAL);
726 1.14 chopps
727 1.14 chopps /*
728 1.14 chopps * copy to tty
729 1.14 chopps */
730 1.14 chopps tp->t_ispeed = t->c_ispeed;
731 1.14 chopps tp->t_ospeed = t->c_ospeed;
732 1.14 chopps tp->t_cflag = cflag;
733 1.42 mhitch ser_open_speed = tp->t_ispeed;
734 1.14 chopps
735 1.14 chopps /*
736 1.14 chopps * enable interrupts
737 1.14 chopps */
738 1.14 chopps custom.intena = INTF_SETCLR | INTF_RBF | INTF_TBE;
739 1.14 chopps last_ciab_pra = ciab.pra;
740 1.14 chopps
741 1.32 is if (t->c_ospeed == 0)
742 1.14 chopps (void)sermctl(tp->t_dev, 0, DMSET); /* hang up line */
743 1.14 chopps else {
744 1.14 chopps /*
745 1.14 chopps * (re)enable DTR
746 1.14 chopps * and set baud rate. (8 bit mode)
747 1.14 chopps */
748 1.14 chopps (void)sermctl(tp->t_dev, TIOCM_DTR | TIOCM_RTS, DMSET);
749 1.14 chopps custom.serper = (0 << 15) | ospeed;
750 1.14 chopps }
751 1.14 chopps return(0);
752 1.1 mw }
753 1.3 mw
754 1.22 chopps int serhwiflow(tp, flag)
755 1.22 chopps struct tty *tp;
756 1.22 chopps int flag;
757 1.22 chopps {
758 1.22 chopps #if 0
759 1.38 christos printf ("serhwiflow %d\n", flag);
760 1.22 chopps #endif
761 1.22 chopps if (flag)
762 1.22 chopps CLRRTS(ciab.pra);
763 1.22 chopps else
764 1.22 chopps SETRTS(ciab.pra);
765 1.22 chopps return 1;
766 1.22 chopps }
767 1.3 mw
768 1.3 mw static void
769 1.14 chopps ser_putchar(tp, c)
770 1.14 chopps struct tty *tp;
771 1.14 chopps u_short c;
772 1.14 chopps {
773 1.14 chopps if ((tp->t_cflag & CSIZE) == CS7 || (tp->t_cflag & PARENB))
774 1.14 chopps c &= 0x7f;
775 1.14 chopps
776 1.14 chopps /*
777 1.14 chopps * handle parity if necessary
778 1.14 chopps */
779 1.14 chopps if (tp->t_cflag & PARENB) {
780 1.14 chopps if (even_parity[c])
781 1.14 chopps c |= 0x80;
782 1.14 chopps if (tp->t_cflag & PARODD)
783 1.14 chopps c ^= 0x80;
784 1.14 chopps }
785 1.14 chopps /*
786 1.14 chopps * add stop bit(s)
787 1.14 chopps */
788 1.14 chopps if (tp->t_cflag & CSTOPB)
789 1.14 chopps c |= 0x300;
790 1.14 chopps else
791 1.14 chopps c |= 0x100;
792 1.14 chopps
793 1.14 chopps custom.serdat = c;
794 1.3 mw }
795 1.3 mw
796 1.3 mw
797 1.3 mw static u_char ser_outbuf[SEROBUF_SIZE];
798 1.14 chopps static u_char *sob_ptr = ser_outbuf, *sob_end = ser_outbuf;
799 1.14 chopps
800 1.3 mw void
801 1.14 chopps ser_outintr()
802 1.3 mw {
803 1.14 chopps struct tty *tp = ser_tty[0];
804 1.14 chopps int s;
805 1.14 chopps
806 1.14 chopps tp = ser_tty[0];
807 1.14 chopps s = spltty();
808 1.14 chopps
809 1.14 chopps if (tp == 0)
810 1.14 chopps goto out;
811 1.14 chopps
812 1.14 chopps if ((custom.intreqr & INTF_TBE) == 0)
813 1.14 chopps goto out;
814 1.14 chopps
815 1.14 chopps /*
816 1.14 chopps * clear interrupt
817 1.14 chopps */
818 1.14 chopps custom.intreq = INTF_TBE;
819 1.14 chopps
820 1.14 chopps if (sob_ptr == sob_end) {
821 1.14 chopps tp->t_state &= ~(TS_BUSY | TS_FLUSH);
822 1.14 chopps if (tp->t_line)
823 1.14 chopps (*linesw[tp->t_line].l_start)(tp);
824 1.14 chopps else
825 1.14 chopps serstart(tp);
826 1.14 chopps goto out;
827 1.14 chopps }
828 1.14 chopps
829 1.14 chopps /*
830 1.14 chopps * Do hardware flow control here. if the CTS line goes down, don't
831 1.14 chopps * transmit anything. That way, we'll be restarted by the periodic
832 1.14 chopps * interrupt when CTS comes back up.
833 1.14 chopps */
834 1.14 chopps if (ISCTS(ciab.pra))
835 1.14 chopps ser_putchar(tp, *sob_ptr++);
836 1.22 chopps else
837 1.22 chopps CLRCTS(last_ciab_pra); /* Remember that CTS is off */
838 1.5 mw out:
839 1.14 chopps splx(s);
840 1.3 mw }
841 1.14 chopps
842 1.31 veego void
843 1.1 mw serstart(tp)
844 1.14 chopps struct tty *tp;
845 1.1 mw {
846 1.14 chopps int cc, s, unit, hiwat;
847 1.14 chopps
848 1.14 chopps hiwat = 0;
849 1.14 chopps
850 1.14 chopps if ((tp->t_state & TS_ISOPEN) == 0)
851 1.14 chopps return;
852 1.14 chopps
853 1.14 chopps unit = SERUNIT(tp->t_dev);
854 1.1 mw
855 1.14 chopps s = spltty();
856 1.14 chopps if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
857 1.14 chopps goto out;
858 1.14 chopps
859 1.14 chopps cc = tp->t_outq.c_cc;
860 1.14 chopps if (cc <= tp->t_lowat) {
861 1.14 chopps if (tp->t_state & TS_ASLEEP) {
862 1.14 chopps tp->t_state &= ~TS_ASLEEP;
863 1.14 chopps wakeup((caddr_t) & tp->t_outq);
864 1.14 chopps }
865 1.14 chopps selwakeup(&tp->t_wsel);
866 1.14 chopps }
867 1.14 chopps if (cc == 0 || (tp->t_state & TS_BUSY))
868 1.14 chopps goto out;
869 1.14 chopps
870 1.14 chopps /*
871 1.14 chopps * We only do bulk transfers if using CTSRTS flow control, not for
872 1.14 chopps * (probably sloooow) ixon/ixoff devices.
873 1.14 chopps */
874 1.14 chopps if ((tp->t_cflag & CRTSCTS) == 0)
875 1.14 chopps cc = 1;
876 1.14 chopps
877 1.14 chopps /*
878 1.14 chopps * Limit the amount of output we do in one burst
879 1.14 chopps * to prevent hogging the CPU.
880 1.14 chopps */
881 1.14 chopps if (cc > SEROBUF_SIZE) {
882 1.14 chopps hiwat++;
883 1.14 chopps cc = SEROBUF_SIZE;
884 1.14 chopps }
885 1.14 chopps cc = q_to_b(&tp->t_outq, ser_outbuf, cc);
886 1.14 chopps if (cc > 0) {
887 1.14 chopps tp->t_state |= TS_BUSY;
888 1.14 chopps
889 1.14 chopps sob_ptr = ser_outbuf;
890 1.14 chopps sob_end = ser_outbuf + cc;
891 1.14 chopps
892 1.14 chopps /*
893 1.14 chopps * Get first character out, then have TBE-interrupts blow out
894 1.14 chopps * further characters, until buffer is empty, and TS_BUSY gets
895 1.14 chopps * cleared.
896 1.14 chopps */
897 1.14 chopps ser_putchar(tp, *sob_ptr++);
898 1.14 chopps }
899 1.14 chopps out:
900 1.14 chopps splx(s);
901 1.1 mw }
902 1.14 chopps
903 1.1 mw /*
904 1.1 mw * Stop output on a line.
905 1.1 mw */
906 1.1 mw /*ARGSUSED*/
907 1.36 mycroft void
908 1.1 mw serstop(tp, flag)
909 1.14 chopps struct tty *tp;
910 1.31 veego int flag;
911 1.1 mw {
912 1.14 chopps int s;
913 1.1 mw
914 1.14 chopps s = spltty();
915 1.14 chopps if (tp->t_state & TS_BUSY) {
916 1.14 chopps if ((tp->t_state & TS_TTSTOP) == 0)
917 1.14 chopps tp->t_state |= TS_FLUSH;
918 1.14 chopps }
919 1.14 chopps splx(s);
920 1.1 mw }
921 1.14 chopps
922 1.5 mw int
923 1.1 mw sermctl(dev, bits, how)
924 1.14 chopps dev_t dev;
925 1.14 chopps int bits, how;
926 1.1 mw {
927 1.14 chopps int unit, s;
928 1.31 veego u_char ub = 0;
929 1.14 chopps
930 1.14 chopps unit = SERUNIT(dev);
931 1.14 chopps
932 1.14 chopps /*
933 1.14 chopps * convert TIOCM* mask into CIA mask
934 1.14 chopps * which is active low
935 1.14 chopps */
936 1.14 chopps if (how != DMGET) {
937 1.14 chopps ub = 0;
938 1.14 chopps if (bits & TIOCM_DTR)
939 1.14 chopps ub |= CIAB_PRA_DTR;
940 1.14 chopps if (bits & TIOCM_RTS)
941 1.14 chopps ub |= CIAB_PRA_RTS;
942 1.14 chopps if (bits & TIOCM_CTS)
943 1.14 chopps ub |= CIAB_PRA_CTS;
944 1.14 chopps if (bits & TIOCM_CD)
945 1.14 chopps ub |= CIAB_PRA_CD;
946 1.14 chopps if (bits & TIOCM_RI)
947 1.14 chopps ub |= CIAB_PRA_SEL; /* collision with /dev/par ! */
948 1.14 chopps if (bits & TIOCM_DSR)
949 1.14 chopps ub |= CIAB_PRA_DSR;
950 1.14 chopps }
951 1.14 chopps s = spltty();
952 1.14 chopps switch (how) {
953 1.14 chopps case DMSET:
954 1.14 chopps /* invert and set */
955 1.14 chopps ciab.pra = ~ub;
956 1.14 chopps break;
957 1.14 chopps
958 1.14 chopps case DMBIC:
959 1.14 chopps ciab.pra |= ub;
960 1.14 chopps ub = ~ciab.pra;
961 1.14 chopps break;
962 1.14 chopps
963 1.14 chopps case DMBIS:
964 1.14 chopps ciab.pra &= ~ub;
965 1.14 chopps ub = ~ciab.pra;
966 1.14 chopps break;
967 1.14 chopps
968 1.14 chopps case DMGET:
969 1.14 chopps ub = ~ciab.pra;
970 1.14 chopps break;
971 1.14 chopps }
972 1.14 chopps (void)splx(s);
973 1.14 chopps
974 1.14 chopps bits = 0;
975 1.14 chopps if (ub & CIAB_PRA_DTR)
976 1.14 chopps bits |= TIOCM_DTR;
977 1.14 chopps if (ub & CIAB_PRA_RTS)
978 1.14 chopps bits |= TIOCM_RTS;
979 1.14 chopps if (ub & CIAB_PRA_CTS)
980 1.14 chopps bits |= TIOCM_CTS;
981 1.14 chopps if (ub & CIAB_PRA_CD)
982 1.14 chopps bits |= TIOCM_CD;
983 1.14 chopps if (ub & CIAB_PRA_SEL)
984 1.14 chopps bits |= TIOCM_RI;
985 1.14 chopps if (ub & CIAB_PRA_DSR)
986 1.14 chopps bits |= TIOCM_DSR;
987 1.14 chopps
988 1.14 chopps return(bits);
989 1.1 mw }
990 1.1 mw
991 1.1 mw /*
992 1.1 mw * Following are all routines needed for SER to act as console
993 1.1 mw */
994 1.31 veego void
995 1.1 mw sercnprobe(cp)
996 1.1 mw struct consdev *cp;
997 1.1 mw {
998 1.14 chopps int unit = CONUNIT;
999 1.14 chopps
1000 1.14 chopps /* locate the major number */
1001 1.14 chopps for (sermajor = 0; sermajor < nchrdev; sermajor++)
1002 1.14 chopps if (cdevsw[sermajor].d_open == (void *)seropen)
1003 1.14 chopps break;
1004 1.14 chopps
1005 1.14 chopps
1006 1.14 chopps unit = CONUNIT; /* XXX: ick */
1007 1.14 chopps
1008 1.14 chopps /*
1009 1.14 chopps * initialize required fields
1010 1.14 chopps */
1011 1.14 chopps cp->cn_dev = makedev(sermajor, unit);
1012 1.14 chopps if (serconsole == unit)
1013 1.14 chopps cp->cn_pri = CN_REMOTE;
1014 1.14 chopps else
1015 1.14 chopps cp->cn_pri = CN_NORMAL;
1016 1.1 mw #ifdef KGDB
1017 1.14 chopps if (major(kgdb_dev) == 1) /* XXX */
1018 1.14 chopps kgdb_dev = makedev(sermajor, minor(kgdb_dev));
1019 1.1 mw #endif
1020 1.1 mw }
1021 1.1 mw
1022 1.31 veego void
1023 1.1 mw sercninit(cp)
1024 1.1 mw struct consdev *cp;
1025 1.1 mw {
1026 1.14 chopps int unit;
1027 1.1 mw
1028 1.14 chopps unit = SERUNIT(cp->cn_dev);
1029 1.14 chopps
1030 1.14 chopps serinit(unit, serdefaultrate);
1031 1.14 chopps serconsole = unit;
1032 1.14 chopps serconsinit = 1;
1033 1.1 mw }
1034 1.1 mw
1035 1.31 veego void
1036 1.1 mw serinit(unit, rate)
1037 1.1 mw int unit, rate;
1038 1.1 mw {
1039 1.14 chopps int s;
1040 1.1 mw
1041 1.26 chopps s = splser();
1042 1.14 chopps /*
1043 1.14 chopps * might want to fiddle with the CIA later ???
1044 1.14 chopps */
1045 1.32 is custom.serper = (rate>=110 ? SERBRD(rate) : 0);
1046 1.14 chopps splx(s);
1047 1.1 mw }
1048 1.1 mw
1049 1.31 veego int
1050 1.1 mw sercngetc(dev)
1051 1.31 veego dev_t dev;
1052 1.1 mw {
1053 1.14 chopps u_short stat;
1054 1.14 chopps int c, s;
1055 1.1 mw
1056 1.26 chopps s = splser();
1057 1.14 chopps /*
1058 1.14 chopps * poll
1059 1.14 chopps */
1060 1.14 chopps while (((stat = custom.serdatr & 0xffff) & SERDATRF_RBF) == 0)
1061 1.14 chopps ;
1062 1.14 chopps c = stat & 0xff;
1063 1.14 chopps /*
1064 1.14 chopps * clear interrupt
1065 1.14 chopps */
1066 1.14 chopps custom.intreq = INTF_RBF;
1067 1.14 chopps splx(s);
1068 1.14 chopps return(c);
1069 1.1 mw }
1070 1.1 mw
1071 1.1 mw /*
1072 1.1 mw * Console kernel output character routine.
1073 1.1 mw */
1074 1.31 veego void
1075 1.1 mw sercnputc(dev, c)
1076 1.14 chopps dev_t dev;
1077 1.14 chopps int c;
1078 1.1 mw {
1079 1.14 chopps register int timo;
1080 1.14 chopps int s;
1081 1.14 chopps
1082 1.14 chopps s = splhigh();
1083 1.1 mw
1084 1.14 chopps if (serconsinit == 0) {
1085 1.14 chopps (void)serinit(SERUNIT(dev), serdefaultrate);
1086 1.14 chopps serconsinit = 1;
1087 1.14 chopps }
1088 1.14 chopps
1089 1.14 chopps /*
1090 1.14 chopps * wait for any pending transmission to finish
1091 1.14 chopps */
1092 1.14 chopps timo = 50000;
1093 1.14 chopps while (!(custom.serdatr & SERDATRF_TBE) && --timo);
1094 1.14 chopps
1095 1.14 chopps /*
1096 1.14 chopps * transmit char.
1097 1.14 chopps */
1098 1.14 chopps custom.serdat = (c & 0xff) | 0x100;
1099 1.14 chopps
1100 1.14 chopps /*
1101 1.14 chopps * wait for this transmission to complete
1102 1.14 chopps */
1103 1.14 chopps timo = 1500000;
1104 1.14 chopps while (!(custom.serdatr & SERDATRF_TBE) && --timo)
1105 1.14 chopps ;
1106 1.14 chopps
1107 1.14 chopps /*
1108 1.14 chopps * Wait for the device (my vt100..) to process the data, since we
1109 1.14 chopps * don't do flow-control with cnputc
1110 1.14 chopps */
1111 1.14 chopps for (timo = 0; timo < 30000; timo++)
1112 1.14 chopps ;
1113 1.14 chopps
1114 1.14 chopps /*
1115 1.14 chopps * clear any interrupts generated by this transmission
1116 1.14 chopps */
1117 1.14 chopps custom.intreq = INTF_TBE;
1118 1.14 chopps splx(s);
1119 1.25 chopps }
1120 1.25 chopps
1121 1.25 chopps void
1122 1.25 chopps sercnpollc(dev, on)
1123 1.25 chopps dev_t dev;
1124 1.25 chopps int on;
1125 1.25 chopps {
1126 1.1 mw }
1127 1.1 mw #endif
1128