ser.c revision 1.64 1 /* $NetBSD: ser.c,v 1.64 2002/09/27 15:35:41 provos 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_kgdb.h"
44
45 #include <sys/cdefs.h>
46 __KERNEL_RCSID(0, "$NetBSD: ser.c,v 1.64 2002/09/27 15:35:41 provos Exp $");
47
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/ioctl.h>
51 #include <sys/device.h>
52 #include <sys/tty.h>
53 #include <sys/proc.h>
54 #include <sys/file.h>
55 #include <sys/malloc.h>
56 #include <sys/uio.h>
57 #include <sys/kernel.h>
58 #include <sys/syslog.h>
59 #include <sys/queue.h>
60 #include <sys/conf.h>
61 #include <machine/cpu.h>
62 #include <amiga/amiga/device.h>
63 #include <amiga/dev/serreg.h>
64 #include <amiga/amiga/custom.h>
65 #include <amiga/amiga/cia.h>
66 #include <amiga/amiga/cc.h>
67
68 #include <dev/cons.h>
69
70 #include "ser.h"
71 #if NSER > 0
72
73 void serattach(struct device *, struct device *, void *);
74 int sermatch(struct device *, struct cfdata *, void *);
75
76 struct ser_softc {
77 struct device dev;
78 struct tty *ser_tty;
79 };
80
81 struct cfattach ser_ca = {
82 sizeof(struct ser_softc), sermatch, serattach
83 };
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 struct tty *tp;
577 u_char ch;
578 int c;
579
580 tp = ser_tty;
581 ch = stat & 0xff;
582 c = ch;
583
584 if ((tp->t_state & TS_ISOPEN) == 0) {
585 #ifdef KGDB
586 int maj;
587
588 /* we don't care about parity errors */
589 maj = cdevsw_lookup_major(&ser_cdevsw);
590 if (kgdb_dev == makedev(maj, 0) && c == FRAME_END)
591 kgdb_connect(0); /* trap into kgdb */
592 #endif
593 return;
594 }
595
596 /*
597 * Check for break and (if enabled) parity error.
598 */
599 if ((stat & 0x1ff) == 0)
600 c |= TTY_FE;
601 else if ((tp->t_cflag & PARENB) &&
602 (((ch >> 7) + even_parity[ch & 0x7f]
603 + !!(tp->t_cflag & PARODD)) & 1))
604 c |= TTY_PE;
605
606 if (stat & SERDATRF_OVRUN)
607 log(LOG_WARNING, "ser0: silo overflow\n");
608
609 tp->t_linesw->l_rint(c, tp);
610 }
611
612 /*
613 * This interrupt is periodically invoked in the vertical blank
614 * interrupt. It's used to keep track of the modem control lines
615 * and (new with the fast_int code) to move accumulated data
616 * up into the tty layer.
617 */
618 void
619 sermint(int unit)
620 {
621 struct tty *tp;
622 u_char stat, last, istat;
623
624 tp = ser_tty;
625 if (!tp)
626 return;
627
628 /*
629 if ((tp->t_state & TS_ISOPEN) == 0 || tp->t_wopen == 0) {
630 sbrpt = sbwpt = serbuf;
631 return;
632 }
633 */
634 /*
635 * empty buffer
636 */
637 serintr();
638
639 stat = ciab.pra;
640 last = last_ciab_pra;
641 last_ciab_pra = stat;
642
643 /*
644 * check whether any interesting signal changed state
645 */
646 istat = stat ^ last;
647
648 if (istat & serdcd) {
649 tp->t_linesw->l_modem(tp, ISDCD(stat));
650 }
651
652 if ((istat & CIAB_PRA_CTS) && (tp->t_state & TS_ISOPEN) &&
653 (tp->t_cflag & CRTSCTS)) {
654 #if 0
655 /* the line is up and we want to do rts/cts flow control */
656 if (ISCTS(stat)) {
657 tp->t_state &= ~TS_TTSTOP;
658 ttstart(tp);
659 /* cause tbe-int if we were stuck there */
660 custom.intreq = INTF_SETCLR | INTF_TBE;
661 } else
662 tp->t_state |= TS_TTSTOP;
663 #else
664 /* do this on hardware level, not with tty driver */
665 if (ISCTS(stat)) {
666 tp->t_state &= ~TS_TTSTOP;
667 /* cause TBE interrupt */
668 custom.intreq = INTF_SETCLR | INTF_TBE;
669 }
670 #endif
671 }
672 }
673
674 int
675 serioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
676 {
677 register struct tty *tp;
678 register int error;
679
680 tp = ser_tty;
681 if (!tp)
682 return ENXIO;
683
684 error = tp->t_linesw->l_ioctl(tp, cmd, data, flag, p);
685 if (error != EPASSTHROUGH)
686 return(error);
687
688 error = ttioctl(tp, cmd, data, flag, p);
689 if (error != EPASSTHROUGH)
690 return(error);
691
692 switch (cmd) {
693 case TIOCSBRK:
694 custom.adkcon = ADKCONF_SETCLR | ADKCONF_UARTBRK;
695 break;
696
697 case TIOCCBRK:
698 custom.adkcon = ADKCONF_UARTBRK;
699 break;
700
701 case TIOCSDTR:
702 (void) sermctl(dev, TIOCM_DTR, DMBIS);
703 break;
704
705 case TIOCCDTR:
706 (void) sermctl(dev, TIOCM_DTR, DMBIC);
707 break;
708
709 case TIOCMSET:
710 (void) sermctl(dev, *(int *) data, DMSET);
711 break;
712
713 case TIOCMBIS:
714 (void) sermctl(dev, *(int *) data, DMBIS);
715 break;
716
717 case TIOCMBIC:
718 (void) sermctl(dev, *(int *) data, DMBIC);
719 break;
720
721 case TIOCMGET:
722 *(int *)data = sermctl(dev, 0, DMGET);
723 break;
724 case TIOCGFLAGS:
725 *(int *)data = serswflags;
726 break;
727 case TIOCSFLAGS:
728 error = suser(p->p_ucred, &p->p_acflag);
729 if (error != 0)
730 return(EPERM);
731
732 serswflags = *(int *)data;
733 serswflags &= /* only allow valid flags */
734 (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
735 break;
736 default:
737 return(EPASSTHROUGH);
738 }
739
740 return(0);
741 }
742
743 int
744 serparam(struct tty *tp, struct termios *t)
745 {
746 int cflag, ospeed = 0;
747
748 if (t->c_ospeed > 0) {
749 if (t->c_ospeed < 110)
750 return(EINVAL);
751 ospeed = SERBRD(t->c_ospeed);
752 }
753
754 if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
755 return(EINVAL);
756
757 if (serswflags & TIOCFLAG_SOFTCAR || serconsole == 0) {
758 t->c_cflag = (t->c_cflag & ~HUPCL) | CLOCAL;
759 }
760
761 /* if no changes, dont do anything. com.c explains why. */
762 if (tp->t_ospeed == t->c_ospeed &&
763 tp->t_cflag == t->c_cflag)
764 return (0);
765
766 cflag = t->c_cflag;
767
768 if (cflag & (CLOCAL | MDMBUF))
769 serdcd = 0;
770 else
771 serdcd = CIAB_PRA_CD;
772
773 /* TODO: support multiple flow control protocols like com.c */
774
775 /*
776 * copy to tty
777 */
778 tp->t_ispeed = t->c_ispeed;
779 tp->t_ospeed = t->c_ospeed;
780 tp->t_cflag = cflag;
781 ser_open_speed = tp->t_ispeed;
782
783 /*
784 * enable interrupts
785 */
786 custom.intena = INTF_SETCLR | INTF_RBF | INTF_TBE;
787 last_ciab_pra = ciab.pra;
788
789 if (t->c_ospeed == 0)
790 (void)sermctl(tp->t_dev, 0, DMSET); /* hang up line */
791 else {
792 /*
793 * (re)enable DTR
794 * and set baud rate. (8 bit mode)
795 */
796 (void)sermctl(tp->t_dev, TIOCM_DTR, DMSET);
797 custom.serper = (0 << 15) | ospeed;
798 }
799 (void)tp->t_linesw->l_modem(tp, ISDCD(last_ciab_pra));
800
801 return(0);
802 }
803
804 int serhwiflow(struct tty *tp, int flag)
805 {
806 #if 0
807 printf ("serhwiflow %d\n", flag);
808 #endif
809 if (flag)
810 CLRRTS(ciab.pra);
811 else
812 SETRTS(ciab.pra);
813 return 1;
814 }
815
816 static void
817 ser_putchar(struct tty *tp, u_short c)
818 {
819 if ((tp->t_cflag & CSIZE) == CS7 || (tp->t_cflag & PARENB))
820 c &= 0x7f;
821
822 /*
823 * handle parity if necessary
824 */
825 if (tp->t_cflag & PARENB) {
826 if (even_parity[c])
827 c |= 0x80;
828 if (tp->t_cflag & PARODD)
829 c ^= 0x80;
830 }
831 /*
832 * add stop bit(s)
833 */
834 if (tp->t_cflag & CSTOPB)
835 c |= 0x300;
836 else
837 c |= 0x100;
838
839 custom.serdat = c;
840 }
841
842
843 static u_char ser_outbuf[SEROBUF_SIZE];
844 static u_char *sob_ptr = ser_outbuf, *sob_end = ser_outbuf;
845
846 void
847 ser_outintr(void)
848 {
849 struct tty *tp;
850 int s;
851
852 tp = ser_tty;
853 s = spltty();
854
855 if (tp == 0)
856 goto out;
857
858 if ((custom.intreqr & INTF_TBE) == 0)
859 goto out;
860
861 /*
862 * clear interrupt
863 */
864 custom.intreq = INTF_TBE;
865
866 if (sob_ptr == sob_end) {
867 tp->t_state &= ~(TS_BUSY | TS_FLUSH);
868 if (tp->t_linesw)
869 tp->t_linesw->l_start(tp);
870 else
871 serstart(tp);
872 goto out;
873 }
874
875 /*
876 * Do hardware flow control here. if the CTS line goes down, don't
877 * transmit anything. That way, we'll be restarted by the periodic
878 * interrupt when CTS comes back up.
879 */
880 if (ISCTS(ciab.pra))
881 ser_putchar(tp, *sob_ptr++);
882 else
883 CLRCTS(last_ciab_pra); /* Remember that CTS is off */
884 out:
885 splx(s);
886 }
887
888 void
889 serstart(struct tty *tp)
890 {
891 int cc, s, hiwat;
892 #ifdef DIAGNOSTIC
893 int unit;
894 #endif
895
896 hiwat = 0;
897
898 if ((tp->t_state & TS_ISOPEN) == 0)
899 return;
900
901 #ifdef DIAGNOSTIC
902 unit = SERUNIT(tp->t_dev);
903 if (unit)
904 panic("serstart: unit is %d", unit);
905 #endif
906
907 s = spltty();
908 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
909 goto out;
910
911 cc = tp->t_outq.c_cc;
912 if (cc <= tp->t_lowat) {
913 if (tp->t_state & TS_ASLEEP) {
914 tp->t_state &= ~TS_ASLEEP;
915 wakeup((caddr_t) & tp->t_outq);
916 }
917 selwakeup(&tp->t_wsel);
918 }
919 if (cc == 0 || (tp->t_state & TS_BUSY))
920 goto out;
921
922 /*
923 * We only do bulk transfers if using CTSRTS flow control, not for
924 * (probably sloooow) ixon/ixoff devices.
925 */
926 if ((tp->t_cflag & CRTSCTS) == 0)
927 cc = 1;
928
929 /*
930 * Limit the amount of output we do in one burst
931 * to prevent hogging the CPU.
932 */
933 if (cc > SEROBUF_SIZE) {
934 hiwat++;
935 cc = SEROBUF_SIZE;
936 }
937 cc = q_to_b(&tp->t_outq, ser_outbuf, cc);
938 if (cc > 0) {
939 tp->t_state |= TS_BUSY;
940
941 sob_ptr = ser_outbuf;
942 sob_end = ser_outbuf + cc;
943
944 /*
945 * Get first character out, then have TBE-interrupts blow out
946 * further characters, until buffer is empty, and TS_BUSY gets
947 * cleared.
948 */
949 ser_putchar(tp, *sob_ptr++);
950 }
951 out:
952 splx(s);
953 }
954
955 /*
956 * Stop output on a line.
957 */
958 /*ARGSUSED*/
959 void
960 serstop(struct tty *tp, int flag)
961 {
962 int s;
963
964 s = spltty();
965 if (tp->t_state & TS_BUSY) {
966 if ((tp->t_state & TS_TTSTOP) == 0)
967 tp->t_state |= TS_FLUSH;
968 }
969 splx(s);
970 }
971
972 int
973 sermctl(dev_t dev, int bits, int how)
974 {
975 int s;
976 u_char ub = 0;
977
978 /*
979 * convert TIOCM* mask into CIA mask
980 * which is active low
981 */
982 if (how != DMGET) {
983 ub = 0;
984 if (bits & TIOCM_DTR)
985 ub |= CIAB_PRA_DTR;
986 if (bits & TIOCM_RTS)
987 ub |= CIAB_PRA_RTS;
988 if (bits & TIOCM_CTS)
989 ub |= CIAB_PRA_CTS;
990 if (bits & TIOCM_CD)
991 ub |= CIAB_PRA_CD;
992 if (bits & TIOCM_RI)
993 ub |= CIAB_PRA_SEL; /* collision with /dev/par ! */
994 if (bits & TIOCM_DSR)
995 ub |= CIAB_PRA_DSR;
996 }
997 s = spltty();
998 switch (how) {
999 case DMSET:
1000 /* invert and set */
1001 ciab.pra = ~ub;
1002 break;
1003
1004 case DMBIC:
1005 ciab.pra |= ub;
1006 ub = ~ciab.pra;
1007 break;
1008
1009 case DMBIS:
1010 ciab.pra &= ~ub;
1011 ub = ~ciab.pra;
1012 break;
1013
1014 case DMGET:
1015 ub = ~ciab.pra;
1016 break;
1017 }
1018 (void)splx(s);
1019
1020 bits = 0;
1021 if (ub & CIAB_PRA_DTR)
1022 bits |= TIOCM_DTR;
1023 if (ub & CIAB_PRA_RTS)
1024 bits |= TIOCM_RTS;
1025 if (ub & CIAB_PRA_CTS)
1026 bits |= TIOCM_CTS;
1027 if (ub & CIAB_PRA_CD)
1028 bits |= TIOCM_CD;
1029 if (ub & CIAB_PRA_SEL)
1030 bits |= TIOCM_RI;
1031 if (ub & CIAB_PRA_DSR)
1032 bits |= TIOCM_DSR;
1033
1034 return(bits);
1035 }
1036
1037 /*
1038 * Following are all routines needed for SER to act as console
1039 */
1040 void
1041 sercnprobe(struct consdev *cp)
1042 {
1043 int maj, unit;
1044 #ifdef KGDB
1045 extern const struct cdevsw ctty_cdevsw;
1046 #endif
1047
1048 /* locate the major number */
1049 maj = cdevsw_lookup_major(&ser_cdevsw);
1050
1051
1052 unit = CONUNIT; /* XXX: ick */
1053
1054 /*
1055 * initialize required fields
1056 */
1057 cp->cn_dev = makedev(maj, unit);
1058 if (serconsole == unit)
1059 cp->cn_pri = CN_REMOTE;
1060 else
1061 cp->cn_pri = CN_NORMAL;
1062 #ifdef KGDB
1063 /* XXX */
1064 if (cdevsw_lookup(kgdb_dev) == &ctty_cdevsw)
1065 kgdb_dev = makedev(maj, minor(kgdb_dev));
1066 #endif
1067 }
1068
1069 void
1070 sercninit(struct consdev *cp)
1071 {
1072 int unit;
1073
1074 unit = SERUNIT(cp->cn_dev);
1075
1076 serinit(serdefaultrate);
1077 serconsole = unit;
1078 serconsinit = 1;
1079 }
1080
1081 void
1082 serinit(int rate)
1083 {
1084 int s;
1085
1086 s = splser();
1087 /*
1088 * might want to fiddle with the CIA later ???
1089 */
1090 custom.serper = (rate>=110 ? SERBRD(rate) : 0);
1091 splx(s);
1092 }
1093
1094 int
1095 sercngetc(dev_t dev)
1096 {
1097 u_short stat;
1098 int c, s;
1099
1100 s = splser();
1101 /*
1102 * poll
1103 */
1104 while (((stat = custom.serdatr & 0xffff) & SERDATRF_RBF) == 0)
1105 ;
1106 c = stat & 0xff;
1107 /*
1108 * clear interrupt
1109 */
1110 custom.intreq = INTF_RBF;
1111 splx(s);
1112 return(c);
1113 }
1114
1115 /*
1116 * Console kernel output character routine.
1117 */
1118 void
1119 sercnputc(dev_t dev, int c)
1120 {
1121 register int timo;
1122 int s;
1123
1124 s = splhigh();
1125
1126 if (serconsinit == 0) {
1127 (void)serinit(serdefaultrate);
1128 serconsinit = 1;
1129 }
1130
1131 /*
1132 * wait for any pending transmission to finish
1133 */
1134 timo = 50000;
1135 while (!(custom.serdatr & SERDATRF_TBE) && --timo);
1136
1137 /*
1138 * transmit char.
1139 */
1140 custom.serdat = (c & 0xff) | 0x100;
1141
1142 /*
1143 * wait for this transmission to complete
1144 */
1145 timo = 1500000;
1146 while (!(custom.serdatr & SERDATRF_TBE) && --timo)
1147 ;
1148
1149 /*
1150 * Wait for the device (my vt100..) to process the data, since we
1151 * don't do flow-control with cnputc
1152 */
1153 for (timo = 0; timo < 30000; timo++)
1154 ;
1155
1156 /*
1157 * We set TBE so that ser_outintr() is called right after to check
1158 * whether there still are chars to process.
1159 * We used to clear this, but it hung the tty output if the kernel
1160 * output a char while userland did on the same serial port.
1161 */
1162 custom.intreq = INTF_SETCLR | INTF_TBE;
1163 splx(s);
1164 }
1165
1166 void
1167 sercnpollc(dev_t dev, int on)
1168 {
1169 }
1170 #endif
1171