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