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