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