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