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