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