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