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