ser.c revision 1.7 1 /*
2 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)ser.c 7.12 (Berkeley) 6/27/91
34 */
35
36 #include "ser.h"
37
38 #if NSER > 0
39 #include "sys/param.h"
40 #include "sys/systm.h"
41 #include "sys/ioctl.h"
42 #include "sys/tty.h"
43 #include "sys/proc.h"
44 #include "sys/conf.h"
45 #include "sys/file.h"
46 #include "sys/malloc.h"
47 #include "sys/uio.h"
48 #include "sys/kernel.h"
49 #include "sys/syslog.h"
50
51 #include "device.h"
52 #include "serreg.h"
53 #include "machine/cpu.h"
54
55 #include "../amiga/custom.h"
56 #include "../amiga/cia.h"
57 #include "../amiga/cc.h"
58
59 int serprobe();
60 struct driver serdriver = {
61 serprobe, "ser",
62 };
63
64 int serstart(), serparam(), serintr();
65 int ser_active;
66 int ser_hasfifo;
67 int nser = NSER;
68 #ifdef SERCONSOLE
69 int serconsole = SERCONSOLE;
70 #else
71 int serconsole = -1;
72 #endif
73 int serconsinit;
74 int serdefaultrate = TTYDEF_SPEED;
75 int sermajor;
76 struct serdevice *ser_addr[NSER];
77 struct vbl_node ser_vbl_node[NSER];
78 struct tty ser_cons;
79 struct tty *ser_tty[NSER];
80
81 struct speedtab serspeedtab[] = {
82 0, 0,
83 50, SERBRD(50),
84 75, SERBRD(75),
85 110, SERBRD(110),
86 134, SERBRD(134),
87 150, SERBRD(150),
88 200, SERBRD(200),
89 300, SERBRD(300),
90 600, SERBRD(600),
91 1200, SERBRD(1200),
92 1800, SERBRD(1800),
93 2400, SERBRD(2400),
94 4800, SERBRD(4800),
95 9600, SERBRD(9600),
96 19200, SERBRD(19200),
97 38400, SERBRD(38400),
98 -1, -1
99 };
100
101
102 /* since this UART is not particularly bright (nice put), we'll have to do
103 parity stuff on our own. this table contains the 8th bit in 7bit character
104 mode, for even parity. If you want odd parity, flip the bit. (for
105 generation of the table, see genpar.c) */
106
107 u_char even_parity[] = {
108 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
109 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
110 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
111 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
112 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
113 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
114 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
115 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
116 };
117
118
119 /* since we don't get interrupts for changes on the modem control line,
120 well have to fake them by comparing current settings to the settings
121 we remembered on last invocation. */
122 u_char last_ciab_pra;
123
124 extern struct tty *constty;
125 #ifdef KGDB
126 #include "machine/remote-sl.h"
127
128 extern dev_t kgdb_dev;
129 extern int kgdb_rate;
130 extern int kgdb_debug_init;
131 #endif
132
133 #ifdef DEBUG
134 long fifoin[17];
135 long fifoout[17];
136 long serintrcount[16];
137 long sermintcount[16];
138 #endif
139
140 void sermint (register int unit);
141
142 int
143 serprobe(ad)
144 register struct amiga_device *ad;
145 {
146 register struct serdevice *ser;
147 register int unit;
148 unsigned short ir = custom.intenar;
149
150 ser = (struct serdevice *) ad->amiga_addr;
151 unit = ad->amiga_unit;
152 if (unit == serconsole)
153 DELAY(100000);
154
155 ad->amiga_ipl = 2;
156 ser_addr[unit] = ser;
157 ser_active |= 1 << unit;
158 ser_vbl_node[unit].function = (void (*)(void *))sermint;
159 add_vbl_function (&ser_vbl_node[unit], SER_VBL_PRIORITY, (void *)unit);
160 #ifdef KGDB
161 if (kgdb_dev == makedev(sermajor, unit)) {
162 if (serconsole == unit)
163 kgdb_dev = NODEV; /* can't debug over console port */
164 else {
165 (void) serinit(unit, kgdb_rate);
166 serconsinit = 1; /* don't re-init in serputc */
167 if (kgdb_debug_init) {
168 /*
169 * Print prefix of device name,
170 * let kgdb_connect print the rest.
171 */
172 printf("ser%d: ", unit);
173 kgdb_connect(1);
174 } else
175 printf("ser%d: kgdb enabled\n", unit);
176 }
177 }
178 #endif
179 /*
180 * Need to reset baud rate, etc. of next print so reset serconsinit.
181 */
182 if (unit == serconsole)
183 serconsinit = 0;
184
185 return (1);
186 }
187
188 /* ARGSUSED */
189 int
190 #ifdef __STDC__
191 seropen(dev_t dev, int flag, int mode, struct proc *p)
192 #else
193 seropen(dev, flag, mode, p)
194 dev_t dev;
195 int flag, mode;
196 struct proc *p;
197 #endif
198 {
199 register struct tty *tp;
200 register int unit;
201 int error = 0;
202 int s;
203
204 unit = SERUNIT(dev);
205
206 if (unit >= NSER || (ser_active & (1 << unit)) == 0)
207 return (ENXIO);
208 if(!ser_tty[unit])
209 {
210 tp = ser_tty[unit] = ttymalloc();
211 /* default values are not optimal for this device, increase
212 buffers */
213 clfree(&tp->t_rawq);
214 clfree(&tp->t_canq);
215 clfree(&tp->t_outq);
216 clalloc(&tp->t_rawq, 8192, 1);
217 clalloc(&tp->t_canq, 8192, 1);
218 clalloc(&tp->t_outq, 8192, 0);
219 }
220 else
221 tp = ser_tty[unit];
222
223 tp->t_oproc = (void (*)(struct tty *)) serstart;
224 tp->t_param = serparam;
225 tp->t_dev = dev;
226
227 if ((tp->t_state & TS_ISOPEN) == 0)
228 {
229 tp->t_state |= TS_WOPEN;
230 ttychars(tp);
231 if (tp->t_ispeed == 0)
232 {
233 tp->t_iflag = TTYDEF_IFLAG | IXOFF; /* XXXXX */
234 tp->t_oflag = TTYDEF_OFLAG;
235 #if 0
236 tp->t_cflag = TTYDEF_CFLAG;
237 #else
238 tp->t_cflag = (CREAD | CS8 | CLOCAL); /* XXXXX */
239 #endif
240 tp->t_lflag = TTYDEF_LFLAG;
241 tp->t_ispeed = tp->t_ospeed = serdefaultrate;
242 }
243 serparam(tp, &tp->t_termios);
244 ttsetwater(tp);
245 }
246 else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
247 return (EBUSY);
248
249 (void) sermctl (dev, TIOCM_DTR | TIOCM_RTS, DMSET);
250
251 if (DIALOUT(dev) || (sermctl (dev, 0, DMGET) & TIOCM_CD))
252 tp->t_state |= TS_CARR_ON;
253
254 s = spltty();
255 while ((flag & O_NONBLOCK) == 0
256 && (tp->t_cflag & CLOCAL) == 0
257 && (tp->t_state & TS_CARR_ON) == 0)
258 {
259 tp->t_state |= TS_WOPEN;
260 if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
261 ttopen, 0))
262 break;
263 }
264 splx (s);
265 if (error == 0)
266 {
267 /* reset the tty pointer, as there could have been a dialout
268 use of the tty with a dialin open waiting. */
269 tp->t_dev = dev;
270 error = (*linesw[tp->t_line].l_open)(dev, tp);
271 }
272 return (error);
273 }
274
275 /*ARGSUSED*/
276 int
277 serclose(dev, flag, mode, p)
278 dev_t dev;
279 int flag, mode;
280 struct proc *p;
281 {
282 register struct tty *tp;
283 register struct serdevice *ser;
284 register int unit;
285
286 unit = SERUNIT(dev);
287
288 ser = ser_addr[unit];
289 tp = ser_tty[unit];
290 (*linesw[tp->t_line].l_close)(tp, flag);
291 custom.adkcon = ADKCONF_UARTBRK; /* clear break */
292 #ifdef KGDB
293 /* do not disable interrupts if debugging */
294 if (dev != kgdb_dev)
295 #endif
296 custom.intena = INTF_RBF|INTF_TBE; /* clear interrupt enable */
297 custom.intreq = INTF_RBF|INTF_TBE; /* and interrupt request */
298 #if 0
299 /* if the device is closed, it's close, no matter whether we deal with modem
300 control signals nor not. */
301 if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
302 (tp->t_state&TS_ISOPEN) == 0)
303 #endif
304 (void) sermctl(dev, 0, DMSET);
305 ttyclose(tp);
306 #if 0
307 if (tp != &ser_cons)
308 {
309 remove_vbl_function (&ser_vbl_node[unit]);
310 ttyfree (tp);
311 ser_tty[unit] = (struct tty *)NULL;
312 }
313 #endif
314 return (0);
315 }
316
317 int
318 serread(dev, uio, flag)
319 dev_t dev;
320 struct uio *uio;
321 {
322 register struct tty *tp = ser_tty[SERUNIT(dev)];
323 int error;
324
325 if (! tp)
326 return ENXIO;
327
328 error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
329
330 return error;
331 }
332
333 int
334 serwrite(dev, uio, flag)
335 dev_t dev;
336 struct uio *uio;
337 {
338 int unit = SERUNIT(dev);
339 register struct tty *tp = ser_tty[unit];
340
341 if (! tp)
342 return ENXIO;
343
344 /*
345 * (XXX) We disallow virtual consoles if the physical console is
346 * a serial port. This is in case there is a display attached that
347 * is not the console. In that situation we don't need/want the X
348 * server taking over the console.
349 */
350 if (constty && unit == serconsole)
351 constty = NULL;
352 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
353 }
354
355
356 /* don't do any processing of data here, so we store the raw code
357 obtained from the uart register. In theory, 110kBaud gives you
358 11kcps, so 16k buffer should be more than enough, interrupt
359 latency of 1s should never happen, or something is seriously
360 wrong.. */
361 #define SERIBUF_SIZE 16384
362 static u_short serbuf[SERIBUF_SIZE];
363 static u_short *sbrpt = serbuf;
364 static u_short *sbwpt = serbuf;
365
366
367 /* this is a replacement for the lack of a hardware fifo. 32k should be
368 enough (there's only one unit anyway, so this is not going to
369 accumulate). */
370 void
371 ser_fastint ()
372 {
373 /* we're at RBE-level, which is higher than VBL-level which is used
374 to periodically transmit contents of this buffer up one layer,
375 so no spl-raising is necessary. */
376
377 register u_short ints, code;
378
379 ints = custom.intreqr & INTF_RBF;
380 if (! ints)
381 return;
382
383 /* clear interrupt */
384 custom.intreq = ints;
385 /* this register contains both data and status bits! */
386 code = custom.serdatr;
387
388 /* should really not happen, but you never know.. buffer
389 overflow. */
390 if (sbwpt + 1 == sbrpt
391 || (sbwpt == serbuf + SERIBUF_SIZE - 1 && sbrpt == serbuf))
392 {
393 log (LOG_WARNING, "ser_fastint: buffer overflow!");
394 return;
395 }
396
397 *sbwpt++ = code;
398 if (sbwpt == serbuf + SERIBUF_SIZE)
399 sbwpt = serbuf;
400 }
401
402
403 int
404 serintr (unit)
405 register int unit;
406 {
407 register struct serdevice *ser;
408 int s1, s2;
409
410 ser = ser_addr[unit];
411
412 /* make sure we're not interrupted by another
413 vbl, but allow level5 ints */
414 s1 = spltty();
415
416 /* ok, pass along any acumulated information .. */
417 while (sbrpt != sbwpt)
418 {
419 /* no collision with ser_fastint() */
420 sereint (unit, *sbrpt, ser);
421 /* lock against ser_fastint() */
422 s2 = spl5();
423 {
424 sbrpt++;
425 if (sbrpt == serbuf + SERIBUF_SIZE)
426 sbrpt = serbuf;
427 }
428 splx (s2);
429 }
430
431 splx (s1);
432
433 #if 0
434 /* add the code below if you really need it */
435 {
436 /*
437 * Process a received byte. Inline for speed...
438 */
439 #ifdef KGDB
440 #define RCVBYTE() \
441 ch = code & 0xff; \
442 if ((tp->t_state & TS_ISOPEN) == 0) { \
443 if (ch == FRAME_END && \
444 kgdb_dev == makedev(sermajor, unit)) \
445 kgdb_connect(0); /* trap into kgdb */ \
446 }
447 #else
448 #define RCVBYTE()
449 #endif
450 RCVBYTE();
451 /* sereint does the receive-processing */
452 sereint (unit, code, ser);
453 }
454 #endif
455 }
456
457 int
458 sereint(unit, stat, ser)
459 register int unit, stat;
460 register struct serdevice *ser;
461 {
462 register struct tty *tp;
463 register int c;
464 register u_char ch;
465
466 tp = ser_tty[unit];
467 if ((tp->t_state & TS_ISOPEN) == 0)
468 {
469 #ifdef KGDB
470 /* we don't care about parity errors */
471 if (kgdb_dev == makedev(sermajor, unit) && c == FRAME_END)
472 kgdb_connect(0); /* trap into kgdb */
473 #endif
474 return;
475 }
476
477 ch = stat & 0xff;
478 c = ch;
479 /* all databits 0 including stop indicate break condition */
480 if (!(stat & 0x1ff))
481 c |= TTY_FE;
482
483 /* if parity checking enabled, check parity */
484 else if ((tp->t_cflag & PARENB) &&
485 (((ch >> 7) + even_parity[ch & 0x7f] + !!(tp->t_cflag & PARODD)) & 1))
486 c |= TTY_PE;
487
488 if (stat & SERDATRF_OVRUN)
489 log(LOG_WARNING, "ser%d: silo overflow\n", unit);
490
491 (*linesw[tp->t_line].l_rint)(c, tp);
492 }
493
494 /* this interrupt is periodically invoked in the vertical blank
495 interrupt. It's used to keep track of the modem control lines
496 and (new with the fast_int code) to move accumulated data
497 up into the tty layer. */
498 void
499 sermint (register int unit)
500 {
501 register struct tty *tp;
502 register u_char stat, last, istat;
503 register struct serdevice *ser;
504
505 tp = ser_tty[unit];
506 if (!tp)
507 return;
508
509 if ((tp->t_state & (TS_ISOPEN|TS_WOPEN)) == 0)
510 {
511 sbrpt = sbwpt = serbuf;
512 return;
513 }
514
515 /* first empty buffer */
516 serintr (unit);
517
518 stat = ciab.pra;
519 last = last_ciab_pra;
520 last_ciab_pra = stat;
521
522 /* check whether any interesting signal changed state */
523 istat = stat ^ last;
524
525 if ((istat & CIAB_PRA_CD) && DIALIN(tp->t_dev))
526 {
527 if (ISDCD (stat))
528 (*linesw[tp->t_line].l_modem)(tp, 1);
529 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
530 {
531 CLRDTR (stat);
532 CLRRTS (stat);
533 ciab.pra = stat;
534 last_ciab_pra = stat;
535 }
536 }
537 if ((istat & CIAB_PRA_CTS) && (tp->t_state & TS_ISOPEN) &&
538 (tp->t_cflag & CRTSCTS))
539 {
540 #if 0
541 /* the line is up and we want to do rts/cts flow control */
542 if (ISCTS (stat))
543 {
544 tp->t_state &=~ TS_TTSTOP;
545 ttstart(tp);
546 /* cause tbe-int if we were stuck there */
547 custom.intreq = INTF_SETCLR | INTF_TBE;
548 }
549 else
550 tp->t_state |= TS_TTSTOP;
551 #else
552 /* do this on hardware level, not with tty driver */
553 if (ISCTS (stat))
554 {
555 tp->t_state &= ~TS_TTSTOP;
556 /* cause TBE interrupt */
557 custom.intreq = INTF_SETCLR | INTF_TBE;
558 }
559 #endif
560 }
561 }
562
563 int
564 serioctl(dev, cmd, data, flag)
565 dev_t dev;
566 caddr_t data;
567 {
568 register struct tty *tp;
569 register int unit = SERUNIT(dev);
570 register struct serdevice *ser;
571 register int error;
572
573 tp = ser_tty[unit];
574 if (! tp)
575 return ENXIO;
576
577 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
578 if (error >= 0)
579 return (error);
580
581 error = ttioctl(tp, cmd, data, flag);
582 if (error >= 0)
583 return (error);
584
585 ser = ser_addr[unit];
586 switch (cmd)
587 {
588 case TIOCSBRK:
589 custom.adkcon = ADKCONF_SETCLR | ADKCONF_UARTBRK;
590 break;
591
592 case TIOCCBRK:
593 custom.adkcon = ADKCONF_UARTBRK;
594 break;
595
596 case TIOCSDTR:
597 (void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
598 break;
599
600 case TIOCCDTR:
601 (void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
602 break;
603
604 case TIOCMSET:
605 (void) sermctl(dev, *(int *)data, DMSET);
606 break;
607
608 case TIOCMBIS:
609 (void) sermctl(dev, *(int *)data, DMBIS);
610 break;
611
612 case TIOCMBIC:
613 (void) sermctl(dev, *(int *)data, DMBIC);
614 break;
615
616 case TIOCMGET:
617 *(int *)data = sermctl(dev, 0, DMGET);
618 break;
619
620 default:
621 return (ENOTTY);
622 }
623
624 return (0);
625 }
626
627 int
628 serparam(tp, t)
629 register struct tty *tp;
630 register struct termios *t;
631 {
632 register struct serdevice *ser;
633 register int cfcr, cflag = t->c_cflag;
634 int unit = SERUNIT(tp->t_dev);
635 int ospeed = ttspeedtab(t->c_ospeed, serspeedtab);
636
637 /* check requested parameters */
638 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
639 return (EINVAL);
640
641 /* and copy to tty */
642 tp->t_ispeed = t->c_ispeed;
643 tp->t_ospeed = t->c_ospeed;
644 tp->t_cflag = cflag;
645
646 custom.intena = INTF_SETCLR | INTF_RBF | INTF_TBE;
647 last_ciab_pra = ciab.pra;
648
649 if (ospeed == 0)
650 {
651 (void) sermctl(tp->t_dev, 0, DMSET); /* hang up line */
652 return (0);
653 }
654 else
655 {
656 /* make sure any previous hangup is undone, ie.
657 reenable DTR. */
658 (void) sermctl (tp->t_dev, TIOCM_DTR | TIOCM_RTS, DMSET);
659 }
660 /* set the baud rate */
661 custom.serper = (0<<15) | ospeed; /* select 8 bit mode (instead of 9 bit) */
662
663 return (0);
664 }
665
666
667 static void
668 ser_putchar (tp, c)
669 struct tty *tp;
670 unsigned short c;
671 {
672 /* handle truncation of character if necessary */
673 if ((tp->t_cflag & CSIZE) == CS7)
674 c &= 0x7f;
675
676 /* handle parity if necessary (forces CS7) */
677 if (tp->t_cflag & PARENB)
678 {
679 c &= 0x7f;
680 if (even_parity[c])
681 c |= 0x80;
682 if (tp->t_cflag & PARODD)
683 c ^= 0x80;
684 }
685
686 /* add stop bit(s) */
687 if (tp->t_cflag & CSTOPB)
688 c |= 0x300;
689 else
690 c |= 0x100;
691
692 custom.serdat = c;
693 }
694
695
696 #define SEROBUF_SIZE 32
697 static u_char ser_outbuf[SEROBUF_SIZE];
698 static u_char *sob_ptr=ser_outbuf, *sob_end=ser_outbuf;
699 void
700 ser_outintr ()
701 {
702 struct tty *tp = ser_tty[0]; /* hmmmmm */
703 unsigned short c;
704 int s = spltty ();
705
706 if (! tp)
707 goto out;
708
709 if (! (custom.intreqr & INTF_TBE))
710 goto out;
711
712 /* clear interrupt */
713 custom.intreq = INTF_TBE;
714
715 if (sob_ptr == sob_end)
716 {
717 tp->t_state &= ~(TS_BUSY|TS_FLUSH);
718 if (tp->t_line)
719 (*linesw[tp->t_line].l_start)(tp);
720 else
721 serstart (tp);
722
723 goto out;
724 }
725
726 /* do hardware flow control here. if the CTS line goes down, don't
727 transmit anything. That way, we'll be restarted by the periodic
728 interrupt when CTS comes back up. */
729 if (ISCTS (ciab.pra))
730 ser_putchar (tp, *sob_ptr++);
731 out:
732 splx (s);
733 }
734
735 int
736 serstart(tp)
737 register struct tty *tp;
738 {
739 register int cc, s;
740 int unit;
741 register struct serdevice *ser;
742 int hiwat = 0;
743
744 if (! (tp->t_state & TS_ISOPEN))
745 return;
746
747 unit = SERUNIT(tp->t_dev);
748 ser = ser_addr[unit];
749
750 s = spltty();
751 if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
752 goto out;
753
754 cc = tp->t_outq.c_cc;
755 if (cc <= tp->t_lowat)
756 {
757 if (tp->t_state & TS_ASLEEP)
758 {
759 tp->t_state &= ~TS_ASLEEP;
760 wakeup((caddr_t)&tp->t_outq);
761 }
762 selwakeup(&tp->t_wsel);
763 }
764
765 if (! cc || (tp->t_state & TS_BUSY))
766 goto out;
767
768 /* we only do bulk transfers if using CTSRTS flow control,
769 not for (probably sloooow) ixon/ixoff devices. */
770 if (! (tp->t_cflag & CRTSCTS))
771 cc = 1;
772
773 /*
774 * Limit the amount of output we do in one burst
775 * to prevent hogging the CPU.
776 */
777 if (cc > SEROBUF_SIZE)
778 {
779 hiwat++;
780 cc = SEROBUF_SIZE;
781 }
782 cc = q_to_b (&tp->t_outq, ser_outbuf, cc);
783 if (cc > 0)
784 {
785 tp->t_state |= TS_BUSY;
786
787 sob_ptr = ser_outbuf;
788 sob_end = ser_outbuf + cc;
789 /* get first character out, then have tbe-interrupts blow out
790 further characters, until buffer is empty, and TS_BUSY
791 gets cleared. */
792 ser_putchar (tp, *sob_ptr++);
793 }
794
795 out:
796 splx(s);
797 }
798
799 /*
800 * Stop output on a line.
801 */
802 /*ARGSUSED*/
803 int
804 serstop(tp, flag)
805 register struct tty *tp;
806 {
807 register int s;
808
809 s = spltty();
810 if (tp->t_state & TS_BUSY)
811 {
812 if ((tp->t_state & TS_TTSTOP) == 0)
813 tp->t_state |= TS_FLUSH;
814 }
815 splx(s);
816 }
817
818 int
819 sermctl(dev, bits, how)
820 dev_t dev;
821 int bits, how;
822 {
823 register struct serdevice *ser;
824 register int unit;
825 u_char ub;
826 int s;
827
828 unit = SERUNIT(dev);
829 ser = ser_addr[unit];
830
831 /* convert TIOCM* mask into CIA mask (which is really low-active!!) */
832 if (how != DMGET)
833 {
834 ub = 0;
835 if (bits & TIOCM_DTR) ub |= CIAB_PRA_DTR;
836 if (bits & TIOCM_RTS) ub |= CIAB_PRA_RTS;
837 if (bits & TIOCM_CTS) ub |= CIAB_PRA_CTS;
838 if (bits & TIOCM_CD) ub |= CIAB_PRA_CD;
839 if (bits & TIOCM_RI) ub |= CIAB_PRA_SEL; /* collision with /dev/par ! */
840 if (bits & TIOCM_DSR) ub |= CIAB_PRA_DSR;
841 }
842
843
844 s = spltty();
845 switch (how)
846 {
847 case DMSET:
848 /* invert and set */
849 ciab.pra = ~ub;
850 break;
851
852 case DMBIC:
853 ciab.pra |= ub;
854 ub = ~ciab.pra;
855 break;
856
857 case DMBIS:
858 ciab.pra &= ~ub;
859 ub = ~ciab.pra;
860 break;
861
862 case DMGET:
863 ub = ~ciab.pra;
864 break;
865 }
866 (void) splx(s);
867
868 bits = 0;
869 if (ub & CIAB_PRA_DTR) bits |= TIOCM_DTR;
870 if (ub & CIAB_PRA_RTS) bits |= TIOCM_RTS;
871 if (ub & CIAB_PRA_CTS) bits |= TIOCM_CTS;
872 if (ub & CIAB_PRA_CD) bits |= TIOCM_CD;
873 if (ub & CIAB_PRA_SEL) bits |= TIOCM_RI;
874 if (ub & CIAB_PRA_DSR) bits |= TIOCM_DSR;
875
876 return bits;
877 }
878
879 /*
880 * Following are all routines needed for SER to act as console
881 */
882 #include "../amiga/cons.h"
883
884 sercnprobe(cp)
885 struct consdev *cp;
886 {
887 int unit = CONUNIT;
888 /* locate the major number */
889 for (sermajor = 0; sermajor < nchrdev; sermajor++)
890 if (cdevsw[sermajor].d_open == seropen)
891 break;
892
893 /* XXX: ick */
894 unit = CONUNIT;
895
896 /* initialize required fields */
897 cp->cn_dev = makedev(sermajor, unit);
898 #if 0
899 /* on ser it really doesn't matter whether we're later
900 using the tty interface or single-character io thru
901 cnputc, so don't reach out to later on remember that
902 our console is here (see ite.c) */
903 cp->cn_tp = ser_tty[unit];
904 #endif
905 cp->cn_pri = CN_NORMAL;
906
907 /*
908 * If serconsole is initialized, raise our priority.
909 */
910 if (serconsole == unit)
911 cp->cn_pri = CN_REMOTE;
912 #ifdef KGDB
913 if (major(kgdb_dev) == 1) /* XXX */
914 kgdb_dev = makedev(sermajor, minor(kgdb_dev));
915 #endif
916 }
917
918 sercninit(cp)
919 struct consdev *cp;
920 {
921 int unit = SERUNIT(cp->cn_dev);
922
923 serinit(unit, serdefaultrate);
924 serconsole = unit;
925 serconsinit = 1;
926 }
927
928 serinit(unit, rate)
929 int unit, rate;
930 {
931 int s;
932
933 #ifdef lint
934 stat = unit; if (stat) return;
935 #endif
936 s = splhigh();
937 /* might want to fiddle with the CIA later ??? */
938 custom.serper = ttspeedtab(rate, serspeedtab);
939 splx(s);
940 }
941
942 sercngetc(dev)
943 {
944 u_short stat;
945 int c, s;
946
947 #ifdef lint
948 stat = dev; if (stat) return (0);
949 #endif
950 s = splhigh();
951 while (!((stat = custom.serdatr & 0xffff) & SERDATRF_RBF))
952 ;
953 c = stat & 0xff;
954 /* clear interrupt */
955 custom.intreq = INTF_RBF;
956 splx(s);
957 return (c);
958 }
959
960 /*
961 * Console kernel output character routine.
962 */
963 sercnputc(dev, c)
964 dev_t dev;
965 register int c;
966 {
967 register int timo;
968 short stat;
969 int s = splhigh();
970
971 #ifdef lint
972 stat = dev; if (stat) return;
973 #endif
974 if (serconsinit == 0)
975 {
976 (void) serinit(SERUNIT(dev), serdefaultrate);
977 serconsinit = 1;
978 }
979
980 /* wait for any pending transmission to finish */
981 timo = 50000;
982 while (! (custom.serdatr & SERDATRF_TBE) && --timo)
983 ;
984
985 custom.serdat = (c&0xff) | 0x100;
986 /* wait for this transmission to complete */
987 timo = 1500000;
988 while (! (custom.serdatr & SERDATRF_TBE) && --timo)
989 ;
990
991 /* wait for the device (my vt100..) to process the data, since
992 we don't do flow-control with cnputc */
993 for (timo = 0; timo < 30000; timo++) ;
994
995 /* clear any interrupts generated by this transmission */
996 custom.intreq = INTF_TBE;
997 splx(s);
998 }
999
1000
1001 serspit(c)
1002 int c;
1003 {
1004 register struct Custom *cu asm("a2") = (struct Custom *)CUSTOMbase;
1005 register int timo asm("d2");
1006 extern int cold;
1007 int s;
1008
1009 if (c == 10)
1010 serspit (13);
1011
1012 s = splhigh();
1013
1014 /* wait for any pending transmission to finish */
1015 timo = 500000;
1016 while (! (cu->serdatr & (SERDATRF_TBE|SERDATRF_TSRE)) && --timo)
1017 ;
1018 cu->serdat = (c&0xff) | 0x100;
1019 /* wait for this transmission to complete */
1020 timo = 15000000;
1021 while (! (cu->serdatr & SERDATRF_TBE) && --timo)
1022 ;
1023 /* clear any interrupts generated by this transmission */
1024 cu->intreq = INTF_TBE;
1025
1026 for (timo = 0; timo < 30000; timo++) ;
1027
1028 splx (s);
1029 }
1030
1031 serspits(cp)
1032 char *cp;
1033 {
1034 while (*cp)
1035 serspit(*cp++);
1036 }
1037
1038 int
1039 serselect(dev, rw, p)
1040 dev_t dev;
1041 int rw;
1042 struct proc *p;
1043 {
1044 register struct tty *tp = ser_tty[SERUNIT(dev)];
1045 int nread;
1046 int s = spltty();
1047 struct proc *selp;
1048
1049 switch (rw)
1050 {
1051 case FREAD:
1052 nread = ttnread(tp);
1053 if (nread > 0 || ((tp->t_cflag&CLOCAL) == 0
1054 && (tp->t_state&TS_CARR_ON) == 0))
1055 goto win;
1056 selrecord(p, &tp->t_rsel);
1057 break;
1058
1059 case FWRITE:
1060 if (tp->t_outq.c_cc <= tp->t_lowat)
1061 goto win;
1062 selrecord(p, &tp->t_wsel);
1063 break;
1064 }
1065 splx(s);
1066 return (0);
1067
1068 win:
1069 splx(s);
1070 return (1);
1071 }
1072
1073 #endif
1074