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