ser.c revision 1.79.4.2 1 /* $NetBSD: ser.c,v 1.79.4.2 2014/05/22 11:39:29 yamt 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.4.2 2014/05/22 11:39:29 yamt 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 .d_open = seropen,
93 .d_close = serclose,
94 .d_read = serread,
95 .d_write = serwrite,
96 .d_ioctl = serioctl,
97 .d_stop = serstop,
98 .d_tty = sertty,
99 .d_poll = serpoll,
100 .d_mmap = nommap,
101 .d_kqfilter = ttykqfilter,
102 .d_flag = D_TTY
103 };
104
105 #ifndef SEROBUF_SIZE
106 #define SEROBUF_SIZE 32
107 #endif
108 #ifndef SERIBUF_SIZE
109 #define SERIBUF_SIZE 512
110 #endif
111
112 #define splser() spl5()
113
114 void serstart(struct tty *);
115 void ser_shutdown(struct ser_softc *);
116 int serparam(struct tty *, struct termios *);
117 void serintr(void);
118 int serhwiflow(struct tty *, int);
119 int sermctl(dev_t dev, int, int);
120 void ser_fastint(void);
121 void sereint(int);
122 static void ser_putchar(struct tty *, u_short);
123 void ser_outintr(void);
124 void sercnprobe(struct consdev *);
125 void sercninit(struct consdev *);
126 void serinit(int);
127 int sercngetc(dev_t dev);
128 void sercnputc(dev_t, int);
129 void sercnpollc(dev_t, int);
130
131 int nser = NSER;
132 #ifdef SERCONSOLE
133 int serconsole = 0;
134 #else
135 int serconsole = -1;
136 #endif
137 int serconsinit;
138 int serdefaultrate = TTYDEF_SPEED;
139 int serswflags;
140
141 struct vbl_node ser_vbl_node;
142 struct tty ser_cons;
143 struct tty *ser_tty;
144
145 static u_short serbuf[SERIBUF_SIZE];
146 static u_short *sbrpt = serbuf;
147 static u_short *sbwpt = serbuf;
148 static u_short sbcnt;
149 static u_short sbovfl;
150 static u_char serdcd;
151
152 /*
153 * Since this UART is not particularly bright (to put it nicely), we'll
154 * have to do parity stuff on our own. This table contains the 8th bit
155 * in 7bit character mode, for even parity. If you want odd parity,
156 * flip the bit. (for generation of the table, see genpar.c)
157 */
158
159 u_char even_parity[] = {
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 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
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 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
166 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
167 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
168 };
169
170 /*
171 * Since we don't get interrupts for changes on the modem control line,
172 * we'll have to fake them by comparing current settings to the settings
173 * we remembered on last invocation.
174 */
175
176 u_char last_ciab_pra;
177
178 extern struct tty *constty;
179
180 extern int ser_open_speed; /* current speed of open serial device */
181
182 #ifdef KGDB
183 #include <machine/remote-sl.h>
184
185 extern dev_t kgdb_dev;
186 extern int kgdb_rate;
187 extern int kgdb_debug_init;
188 #endif
189
190 #ifdef DEBUG
191 long fifoin[17];
192 long fifoout[17];
193 long serintrcount[16];
194 long sermintcount[16];
195 #endif
196
197 void sermint(register int unit);
198
199 int
200 sermatch(device_t parent, cfdata_t cf, void *aux)
201 {
202 static int ser_matched = 0;
203 static int ser_matched_real = 0;
204
205 /* Allow only once instance. */
206 if (matchname("ser", (char *)aux) == 0)
207 return(0);
208
209 if (amiga_realconfig) {
210 if (ser_matched_real)
211 return(0);
212 ser_matched_real = 1;
213 } else {
214 if (serconsole != 0)
215 return(0);
216
217 if (ser_matched != 0)
218 return(0);
219
220 ser_matched = 1;
221 }
222 return(1);
223 }
224
225
226 void
227 serattach(device_t parent, device_t self, void *aux)
228 {
229 struct ser_softc *sc;
230 struct tty *tp;
231 u_short ir;
232
233 sc = device_private(self);
234
235 ir = custom.intenar;
236 __USE(ir);
237 if (serconsole == 0)
238 DELAY(100000);
239
240 ser_vbl_node.function = (void (*) (void *)) sermint;
241 add_vbl_function(&ser_vbl_node, SER_VBL_PRIORITY, (void *) 0);
242 #ifdef KGDB
243 if (kgdb_dev == makedev(cdevsw_lookup_major(&ser_cdevsw), 0)) {
244 if (serconsole == 0)
245 kgdb_dev = NODEV; /* can't debug over console port */
246 else {
247 (void) serinit(kgdb_rate);
248 serconsinit = 1; /* don't re-init in serputc */
249 if (kgdb_debug_init == 0)
250 printf(" kgdb enabled\n");
251 else {
252 /*
253 * Print prefix of device name,
254 * let kgdb_connect print the rest.
255 */
256 printf("ser0: ");
257 kgdb_connect(1);
258 }
259 }
260 }
261 #endif
262 /*
263 * Need to reset baud rate, etc. of next print so reset serconsinit.
264 */
265 if (0 == serconsole)
266 serconsinit = 0;
267
268 tp = tty_alloc();
269 tp->t_oproc = (void (*) (struct tty *)) serstart;
270 tp->t_param = serparam;
271 tp->t_hwiflow = serhwiflow;
272 tty_attach(tp);
273 sc->ser_tty = ser_tty = tp;
274
275 if (self)
276 printf(": input fifo %d output fifo %d\n", SERIBUF_SIZE,
277 SEROBUF_SIZE);
278 }
279
280
281 /* ARGSUSED */
282 int
283 seropen(dev_t dev, int flag, int mode, struct lwp *l)
284 {
285 struct ser_softc *sc;
286 struct tty *tp;
287 int unit, error, s, s2;
288
289 error = 0;
290 unit = SERUNIT(dev);
291
292 sc = device_lookup_private(&ser_cd, unit);
293 if (sc == NULL)
294 return (ENXIO);
295
296 /* XXX com.c: insert KGDB check here */
297
298 /* XXX ser.c had: s = spltty(); */
299
300 tp = sc->ser_tty;
301
302 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
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 lwp *l)
376 {
377 struct ser_softc *sc;
378 struct tty *tp;
379
380 sc = device_lookup_private(&ser_cd, SERUNIT(dev));
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 tty_free(tp);
431 ser_tty = (struct tty *) NULL;
432 }
433 #endif
434 ser_open_speed = tp->t_ispeed;
435 splx(s);
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 lwp *l)
457 {
458 /* ARGSUSED */
459
460 return ser_tty->t_linesw->l_poll(ser_tty, events, l);
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, void *data, int flag, struct lwp *l)
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, l);
704 if (error != EPASSTHROUGH)
705 return(error);
706
707 error = ttioctl(tp, cmd, data, flag, l);
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 = kauth_authorize_device_tty(l->l_cred,
748 KAUTH_DEVICE_TTY_PRIVSET, tp);
749 if (error != 0)
750 return(EPERM);
751
752 serswflags = *(int *)data;
753 serswflags &= /* only allow valid flags */
754 (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
755 break;
756 default:
757 return(EPASSTHROUGH);
758 }
759
760 return(0);
761 }
762
763 int
764 serparam(struct tty *tp, struct termios *t)
765 {
766 int cflag, ospeed = 0;
767
768 if (t->c_ospeed > 0) {
769 if (t->c_ospeed < 110)
770 return(EINVAL);
771 ospeed = SERBRD(t->c_ospeed);
772 }
773
774 if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
775 return(EINVAL);
776
777 if (serswflags & TIOCFLAG_SOFTCAR || serconsole == 0) {
778 t->c_cflag = (t->c_cflag & ~HUPCL) | CLOCAL;
779 }
780
781 /* if no changes, dont do anything. com.c explains why. */
782 if (tp->t_ospeed == t->c_ospeed &&
783 tp->t_cflag == t->c_cflag)
784 return (0);
785
786 cflag = t->c_cflag;
787
788 if (cflag & (CLOCAL | MDMBUF))
789 serdcd = 0;
790 else
791 serdcd = CIAB_PRA_CD;
792
793 /* TODO: support multiple flow control protocols like com.c */
794
795 /*
796 * copy to tty
797 */
798 tp->t_ispeed = t->c_ispeed;
799 tp->t_ospeed = t->c_ospeed;
800 tp->t_cflag = cflag;
801 ser_open_speed = tp->t_ispeed;
802
803 /*
804 * enable interrupts
805 */
806 custom.intena = INTF_SETCLR | INTF_RBF | INTF_TBE;
807 last_ciab_pra = ciab.pra;
808
809 if (t->c_ospeed == 0)
810 (void)sermctl(tp->t_dev, 0, DMSET); /* hang up line */
811 else {
812 /*
813 * (re)enable DTR
814 * and set baud rate. (8 bit mode)
815 */
816 (void)sermctl(tp->t_dev, TIOCM_DTR, DMSET);
817 custom.serper = (0 << 15) | ospeed;
818 }
819 (void)tp->t_linesw->l_modem(tp, ISDCD(last_ciab_pra));
820
821 return(0);
822 }
823
824 int serhwiflow(struct tty *tp, int flag)
825 {
826 #if 0
827 printf ("serhwiflow %d\n", flag);
828 #endif
829 if (flag)
830 CLRRTS(ciab.pra);
831 else
832 SETRTS(ciab.pra);
833 return 1;
834 }
835
836 static void
837 ser_putchar(struct tty *tp, u_short c)
838 {
839 if ((tp->t_cflag & CSIZE) == CS7 || (tp->t_cflag & PARENB))
840 c &= 0x7f;
841
842 /*
843 * handle parity if necessary
844 */
845 if (tp->t_cflag & PARENB) {
846 if (even_parity[c])
847 c |= 0x80;
848 if (tp->t_cflag & PARODD)
849 c ^= 0x80;
850 }
851 /*
852 * add stop bit(s)
853 */
854 if (tp->t_cflag & CSTOPB)
855 c |= 0x300;
856 else
857 c |= 0x100;
858
859 custom.serdat = c;
860 }
861
862
863 static u_char ser_outbuf[SEROBUF_SIZE];
864 static u_char *sob_ptr = ser_outbuf, *sob_end = ser_outbuf;
865
866 void
867 ser_outintr(void)
868 {
869 struct tty *tp;
870 int s;
871
872 tp = ser_tty;
873 s = spltty();
874
875 if (tp == 0)
876 goto out;
877
878 if ((custom.intreqr & INTF_TBE) == 0)
879 goto out;
880
881 /*
882 * clear interrupt
883 */
884 custom.intreq = INTF_TBE;
885
886 if (sob_ptr == sob_end) {
887 tp->t_state &= ~(TS_BUSY | TS_FLUSH);
888 if (tp->t_linesw)
889 tp->t_linesw->l_start(tp);
890 else
891 serstart(tp);
892 goto out;
893 }
894
895 /*
896 * Do hardware flow control here. if the CTS line goes down, don't
897 * transmit anything. That way, we'll be restarted by the periodic
898 * interrupt when CTS comes back up.
899 */
900 if (ISCTS(ciab.pra))
901 ser_putchar(tp, *sob_ptr++);
902 else
903 CLRCTS(last_ciab_pra); /* Remember that CTS is off */
904 out:
905 splx(s);
906 }
907
908 void
909 serstart(struct tty *tp)
910 {
911 int cc, s, hiwat;
912 #ifdef DIAGNOSTIC
913 int unit;
914 #endif
915
916 hiwat = 0;
917
918 if ((tp->t_state & TS_ISOPEN) == 0)
919 return;
920
921 #ifdef DIAGNOSTIC
922 unit = SERUNIT(tp->t_dev);
923 if (unit)
924 panic("serstart: unit is %d", unit);
925 #endif
926
927 s = spltty();
928 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
929 goto out;
930
931 cc = tp->t_outq.c_cc;
932 if (!ttypull(tp) || (tp->t_state & TS_BUSY))
933 goto out;
934
935 /*
936 * We only do bulk transfers if using CTSRTS flow control, not for
937 * (probably sloooow) ixon/ixoff devices.
938 */
939 if ((tp->t_cflag & CRTSCTS) == 0)
940 cc = 1;
941
942 /*
943 * Limit the amount of output we do in one burst
944 * to prevent hogging the CPU.
945 */
946 if (cc > SEROBUF_SIZE) {
947 hiwat++;
948 cc = SEROBUF_SIZE;
949 }
950 cc = q_to_b(&tp->t_outq, ser_outbuf, cc);
951 if (cc > 0) {
952 tp->t_state |= TS_BUSY;
953
954 sob_ptr = ser_outbuf;
955 sob_end = ser_outbuf + cc;
956
957 /*
958 * Get first character out, then have TBE-interrupts blow out
959 * further characters, until buffer is empty, and TS_BUSY gets
960 * cleared.
961 */
962 ser_putchar(tp, *sob_ptr++);
963 }
964 out:
965 splx(s);
966 }
967
968 /*
969 * Stop output on a line.
970 */
971 /*ARGSUSED*/
972 void
973 serstop(struct tty *tp, int flag)
974 {
975 int s;
976
977 s = spltty();
978 if (tp->t_state & TS_BUSY) {
979 if ((tp->t_state & TS_TTSTOP) == 0)
980 tp->t_state |= TS_FLUSH;
981 }
982 splx(s);
983 }
984
985 int
986 sermctl(dev_t dev, int bits, int how)
987 {
988 int s;
989 u_char ub = 0;
990
991 /*
992 * convert TIOCM* mask into CIA mask
993 * which is active low
994 */
995 if (how != DMGET) {
996 ub = 0;
997 if (bits & TIOCM_DTR)
998 ub |= CIAB_PRA_DTR;
999 if (bits & TIOCM_RTS)
1000 ub |= CIAB_PRA_RTS;
1001 if (bits & TIOCM_CTS)
1002 ub |= CIAB_PRA_CTS;
1003 if (bits & TIOCM_CD)
1004 ub |= CIAB_PRA_CD;
1005 if (bits & TIOCM_RI)
1006 ub |= CIAB_PRA_SEL; /* collision with /dev/par ! */
1007 if (bits & TIOCM_DSR)
1008 ub |= CIAB_PRA_DSR;
1009 }
1010 s = spltty();
1011 switch (how) {
1012 case DMSET:
1013 /* invert and set */
1014 ciab.pra = ~ub;
1015 break;
1016
1017 case DMBIC:
1018 ciab.pra |= ub;
1019 ub = ~ciab.pra;
1020 break;
1021
1022 case DMBIS:
1023 ciab.pra &= ~ub;
1024 ub = ~ciab.pra;
1025 break;
1026
1027 case DMGET:
1028 ub = ~ciab.pra;
1029 break;
1030 }
1031 (void)splx(s);
1032
1033 bits = 0;
1034 if (ub & CIAB_PRA_DTR)
1035 bits |= TIOCM_DTR;
1036 if (ub & CIAB_PRA_RTS)
1037 bits |= TIOCM_RTS;
1038 if (ub & CIAB_PRA_CTS)
1039 bits |= TIOCM_CTS;
1040 if (ub & CIAB_PRA_CD)
1041 bits |= TIOCM_CD;
1042 if (ub & CIAB_PRA_SEL)
1043 bits |= TIOCM_RI;
1044 if (ub & CIAB_PRA_DSR)
1045 bits |= TIOCM_DSR;
1046
1047 return(bits);
1048 }
1049
1050 /*
1051 * Following are all routines needed for SER to act as console
1052 */
1053 void
1054 sercnprobe(struct consdev *cp)
1055 {
1056 int maj, unit;
1057 #ifdef KGDB
1058 extern const struct cdevsw ctty_cdevsw;
1059 #endif
1060
1061 /* locate the major number */
1062 maj = cdevsw_lookup_major(&ser_cdevsw);
1063
1064
1065 unit = CONUNIT; /* XXX: ick */
1066
1067 /*
1068 * initialize required fields
1069 */
1070 cp->cn_dev = makedev(maj, unit);
1071 if (serconsole == unit)
1072 cp->cn_pri = CN_REMOTE;
1073 else
1074 cp->cn_pri = CN_NORMAL;
1075 #ifdef KGDB
1076 /* XXX */
1077 if (cdevsw_lookup(kgdb_dev) == &ctty_cdevsw)
1078 kgdb_dev = makedev(maj, minor(kgdb_dev));
1079 #endif
1080 }
1081
1082 void
1083 sercninit(struct consdev *cp)
1084 {
1085 int unit;
1086
1087 unit = SERUNIT(cp->cn_dev);
1088
1089 serinit(serdefaultrate);
1090 serconsole = unit;
1091 serconsinit = 1;
1092 }
1093
1094 void
1095 serinit(int rate)
1096 {
1097 int s;
1098
1099 s = splser();
1100 /*
1101 * might want to fiddle with the CIA later ???
1102 */
1103 custom.serper = (rate>=110 ? SERBRD(rate) : 0);
1104 splx(s);
1105 }
1106
1107 int
1108 sercngetc(dev_t dev)
1109 {
1110 u_short stat;
1111 int c, s;
1112
1113 s = splser();
1114 /*
1115 * poll
1116 */
1117 while (((stat = custom.serdatr & 0xffff) & SERDATRF_RBF) == 0)
1118 ;
1119
1120 c = stat & 0xff;
1121 /*
1122 * clear interrupt
1123 */
1124 custom.intreq = INTF_RBF;
1125 splx(s);
1126
1127 return(c);
1128 }
1129
1130 /*
1131 * Console kernel output character routine.
1132 */
1133 void
1134 sercnputc(dev_t dev, int c)
1135 {
1136 register int timo;
1137 int s;
1138
1139 s = splhigh();
1140
1141 if (serconsinit == 0) {
1142 (void)serinit(serdefaultrate);
1143 serconsinit = 1;
1144 }
1145
1146 /*
1147 * wait for any pending transmission to finish
1148 */
1149 timo = 50000;
1150 while (!(custom.serdatr & SERDATRF_TBE) && --timo);
1151
1152 /*
1153 * transmit char.
1154 */
1155 custom.serdat = (c & 0xff) | 0x100;
1156
1157 /*
1158 * wait for this transmission to complete
1159 */
1160 timo = 1500000;
1161 while (!(custom.serdatr & SERDATRF_TBE) && --timo)
1162 ;
1163
1164 /*
1165 * Wait for the device (my vt100..) to process the data, since we
1166 * don't do flow-control with cnputc
1167 */
1168 for (timo = 0; timo < 30000; timo++)
1169 ;
1170
1171 /*
1172 * We set TBE so that ser_outintr() is called right after to check
1173 * whether there still are chars to process.
1174 * We used to clear this, but it hung the tty output if the kernel
1175 * output a char while userland did on the same serial port.
1176 */
1177 custom.intreq = INTF_SETCLR | INTF_TBE;
1178 splx(s);
1179 }
1180
1181 void
1182 sercnpollc(dev_t dev, int on)
1183 {
1184 }
1185 #endif
1186