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