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