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