|
|
1.1 root 1: /*
2: * File: asy.c
3: *
4: * Purpose: 8250-family async port device driver
5: *
6: * Devices are named /dev/asy[00..31]{fpl}
7: * Minor number bit assignments:
8: * x... .... 1 for NO modem control, "l"
9: * .x.. .... 1 for polled operation (no irq service), "p"
10: * ..x. .... 1 for RTS/CTS flow control, "f"
11: * ...x xxxx channel number - 0..31
12: *
13: * $Log: asy.c,v $
14: * Revision 1.7 92/07/16 16:34:44 hal
15: * Kernel #58
16: *
17: * Revision 1.6 92/07/07 09:04:30 root
18: * Allow up to 16 slots per group.
19: * Support Digiboard as fourth group type.
20: *
21: * Revision 1.5 92/06/11 17:28:05 root
22: * Temporary fling with condev & asy_putchar.
23: *
24: * Revision 1.4 92/06/10 17:26:59 hal
25: * Conditional logging to screen of opens and closes. Ker #55.
26: *
27: * Revision 1.3 92/06/06 12:39:33 hal
28: * Last before adding termio field to tty struct.
29: *
30: */
31:
32: /*
33: * -----------------------------------------------------------------
34: * Includes.
35: */
36: #include <sys/coherent.h>
37: #include <sys/stat.h>
38: #include <sys/proc.h>
39: #include <sys/tty.h>
40: #include <sys/con.h>
41: #include <sys/devices.h>
42: #include <errno.h>
43: #include <poll.h>
44: #include <sys/sched.h> /* CVTTOUT, IVTTOUT, SVTTOUT */
45: #include <sys/asy.h>
46: #include <sys/ins8250.h>
47: #include <sys/poll_clk.h>
48: #ifdef _I386
49: #include <termio.h>
50: #endif
51:
52: /*
53: * -----------------------------------------------------------------
54: * Definitions.
55: * Constants.
56: * Macros with argument lists.
57: * Typedefs.
58: * Enums.
59: */
60: #define IEN_USE_MSI (IE_RxI | IE_TxI | IE_LSI | IE_MSI)
61: #define IEN_NO_MSI (IE_RxI | IE_TxI | IE_LSI)
62:
63: #define CTLQ 0021
64: #define CTLS 0023
65:
66: #define NUM_IRQ 16 /* PC allows irq numbers 0..15 */
67: #define BPB 8 /* 8 bits per byte */
68: #define DTRTMOUT 3 /* DTR seconds for close */
69: #define LOOP_LIMIT 100 /* safety valve on irq loops */
70:
71: /*
72: * For rawin silo (see poll_clk.h), use last element of si_buf to count
73: * the number of characters in the silo.
74: */
75: #define SILO_CHAR_COUNT si_buf[SI_BUFSIZ-1]
76: #define SILO_HIGH_MARK (SI_BUFSIZ-SI_BUFSIZ/4)
77: #define SILO_LOW_MARK (SI_BUFSIZ/4)
78: #define MAX_SILO_INDEX (SI_BUFSIZ-2)
79: #define MAX_SILO_CHARS (SI_BUFSIZ-1)
80:
81: #define RAWIN_FLUSH(in_silo) { \
82: in_silo->si_ox = in_silo->si_ix; \
83: in_silo->SILO_CHAR_COUNT = 0; }
84: #define RAWOUT_FLUSH(out_silo) { out_silo->si_ox = out_silo->si_ix; }
85: #define channel(dev) (dev & 0x1F)
86:
87: #define IEN ((a0->a_nms)?IEN_NO_MSI:IEN_USE_MSI)
88: #ifdef _I386
89: #define EEBUSY EBUSY
90: #else
91: #define EEBUSY EDBUSY
92: #endif
93:
94: #define NW_OUTSILO 1 /* bits in need_wake[] entries */
95:
96: typedef void (* VPTR)(); /* pointer to function returning void */
97: typedef void (* FPTR)(); /* pointer to function returning int */
98:
99: /*
100: * -----------------------------------------------------------------
101: * Functions.
102: * Import Functions.
103: * Export Functions.
104: * Local Functions.
105: */
106: int nulldev();
107:
108: void asy_putchar();
109:
110: /*
111: * Configuration functions (local).
112: */
113: static void asyclose();
114: static void asyioctl();
115: static void asyioctl0();
116: static void asyload();
117: static void asyopen();
118: static void asyread();
119: static void asytimer();
120: static void asyunload();
121: static void asywrite();
122: static int asypoll();
123: static void cinit();
124:
125: /*
126: * Support functions (local).
127: */
128: static void add_irq();
129: static void asy_irq();
130: static int asy_send();
131: static void asybreak();
132: static void asyclock();
133: static void asycycle();
134: static void asydump();
135: static int asyintr();
136: static void asyparam();
137: static void asysph();
138: static void asyspr();
139: static void asystart();
140: static void irqdummy();
141: static void upd_irq1();
142:
143: static void i2(),i3(),i4(),i5(),i6(),i7(),i8(),i9();
144: static void i10(),i11(),i12(),i13(),i14(),i15();
145: static int p1(),p2(),p3(),p4();
146:
147: /*
148: * -----------------------------------------------------------------
149: * Global Data.
150: * Import Variables.
151: * Export Variables.
152: * Local Variables.
153: */
154: extern int albaud[], alp_rate[];
155:
156: /*
157: * When asypatch runs, it checks whether its internal value for
158: * ASY_VERSION matches this driver's value, so as to prevent the patch
159: * utility and the driver from getting out of phase.
160: */
161: int ASY_VER = ASY_VERSION;
162: int ASY_HPCL = 1;
163: int ASY_NUM = 0;
164: int ASYGP_NUM = 0;
165: asy0_t asy0[MAX_ASY] = {
166: { 0 }
167: };
168: asy_gp_t asy_gp[MAX_ASYGP] = {
169: { 0 }
170: };
171:
172: static asy1_t * asy1; /* unused entries have type US_NONE */
173: static short dummy_port; /* used only during driver startup */
174: static int poll_divisor; /* set by asyspr(), read by asyclk() */
175: static char pptbl[MAX_ASY]; /* channel numbers of polled ports */
176: static int ppnum; /* number of channels in pptbl */
177:
178: /*
179: * itbl keeps function pointers for irq service routines, for ease of setting
180: * and clearing vectors.
181: *
182: * irq0[x] and irq1[x] are lists for irq number x.
183: * irq0 has nodes that may possibly cause an irq.
184: * irq1 contains nodes for active devices.
185: * Whenever a device becomes active or inactive, irq1 is rebuilt from irq0.
186: *
187: * nodespace is an array of available nodes used in making the lists.
188: * nextnode points to the next free node.
189: * Nodes are taken from nodespace only during driver load.
190: */
191: static VPTR itbl[NUM_IRQ] = {
192: 0,0,i2,i3,i4,i5,i6,i7,i8,i9,i10,i11,i12,i13,i14,i15 };
193: static FPTR ptbl[PT_MAX] = { asyintr,p1,p2,p3,p4 };
194: static struct irqnode *irq0[NUM_IRQ], *irq1[NUM_IRQ];
195: static struct irqnode nodespace[MAX_ASY];
196: static char need_wake[MAX_ASY];
197: static char nextnode;
198: static int initialized; /* for asy_putchar() */
199:
200: /*
201: * Configuration table (export data).
202: */
203: CON asycon ={
204: DFCHR|DFPOL, /* Flags */
205: ASY_MAJOR, /* Major index */
206: asyopen, /* Open */
207: asyclose, /* Close */
208: nulldev, /* Block */
209: asyread, /* Read */
210: asywrite, /* Write */
211: #ifdef _I386
212: asyioctl0, /* Ioctl */
213: #else
214: asyioctl, /* Ioctl */
215: #endif
216: nulldev, /* Powerfail */
217: asytimer, /* Timeout */
218: asyload, /* Load */
219: asyunload, /* Unload */
220: asypoll /* Poll */
221: };
222:
223: /*
224: * -----------------------------------------------------------------
225: * Code.
226: */
227:
228: /*
229: * asyload()
230: */
231: static void
232: asyload()
233: {
234: int s, chan;
235: asy0_t *a0;
236: asy1_t *a1;
237: TTY *tp;
238: short port;
239: char irq;
240: char speed;
241: char g;
242: char sense_ct = 0;
243:
244: /*
245: * Allocate space for asy structs. Possible error return.
246: */
247: asy1 = (asy1_t *)kalloc(ASY_NUM * sizeof(asy1_t));
248: if (asy1 == 0) {
249: printf("asyload: can't allocate space for %d async devices\n",
250: ASY_NUM);
251: return;
252: }
253: kclear(asy1, ASY_NUM*sizeof(asy1_t));
254:
255: /*
256: * For each non-null port:
257: * if port is uses irq
258: * set dummy routine in case uart_sense causes bogus irpts
259: * sense chip type
260: * write baud rate to sgtty/termio structs
261: * disable port interrupts
262: * hang up port
263: * set default baud rate (also resets UART)
264: * hook "start" function into line discipline module
265: * hook "param" function into line discipline module
266: * hook CS into line discipline module
267: * if port is uses irq
268: * release dummy routine
269: * if not in a port group
270: * add to irq list
271: */
272: for (chan = 0; chan < ASY_NUM; chan++) {
273: a0 = asy0 + chan;
274: a1 = asy1 + chan;
275: tp = &a1->a_tty;
276: speed = a0->a_speed;
277: tp->t_sgttyb.sg_ispeed = tp->t_sgttyb.sg_ospeed = speed;
278: tp->t_dispeed = tp->t_dospeed = speed;
279: port = a0->a_port;
280:
281: /*
282: * A port address of zero means a skipped entry in the table.
283: * In this case a1->a_ut keeps its initial value of US_NONE.
284: */
285: if (port) {
286: dummy_port = port;
287: if (a0->a_irqno)
288: setivec(a0->a_irqno, irqdummy);
289: /*
290: * uart_sense() prints port info.
291: * Do this four times per line.
292: */
293: a1->a_ut = uart_sense(port);
294: sense_ct++;
295: if ((sense_ct & 1) == 0)
296: putchar('\n');
297: else
298: putchar('\t');
299: s = sphi();
300: outb(port+MCR, 0);
301: outb(port+LCR, LC_DLAB);
302: outb(port+DLL, albaud[speed]);
303: outb(port+DLH, albaud[speed] >> 8);
304: outb(port+LCR, LC_CS8);
305: tp->t_start = asystart;
306: /* leave tp->t_param at 0 */
307: tp->t_cs_sel = cs_sel();
308: tp->t_ddp = (int *)chan;
309: spl(s);
310: if (a0->a_irqno) {
311: clrivec(a0->a_irqno);
312: if (a0->a_asy_gp == NO_ASYGP)
313: add_irq(a0->a_irqno, asyintr, chan);
314: }
315: }
316: }
317: if (sense_ct & 1)
318: putchar('\n');
319:
320: /*
321: * for each port group
322: * add group to irq list
323: */
324: for (g = 0; g < ASYGP_NUM; g++) {
325: add_irq(asy_gp[g].irq, ptbl[asy_gp[g].gp_type], g);
326: }
327:
328: /*
329: * Attach irq routines.
330: */
331: for (irq = 0; irq < NUM_IRQ; irq++)
332: if (irq0[irq]) {
333: setivec(irq, itbl[irq]);
334: }
335: }
336:
337: /*
338: * asyunload()
339: */
340: static void
341: asyunload()
342: {
343: char chan, irq;
344:
345: /*
346: * for each channel
347: * disable UART interrupts
348: * hangup port
349: * cancel timer
350: */
351: for (chan = 0; chan < ASY_NUM; chan++) {
352: asy0_t * a0 = asy0 + chan;
353: asy1_t * a1 = asy1 + chan;
354: short port = a0->a_port;
355: TTY *tp = &a1->a_tty;
356:
357: outb(port+IER, 0);
358: outb(port+MCR, 0);
359: timeout(tp->t_rawtim, 0, NULL, 0);
360: }
361:
362: /*
363: * for each irq
364: * if irq routine was attached
365: * detach it
366: */
367: for (irq = 0; irq < NUM_IRQ; irq++)
368: if (irq0[irq])
369: clrivec(irq);
370:
371: /*
372: * Deallocate dynamic asy storage.
373: */
374: if (asy1)
375: kfree(asy1);
376: }
377:
378: /*
379: * asyopen()
380: */
381: static void
382: asyopen(dev, mode)
383: dev_t dev;
384: int mode;
385: {
386: int s;
387: char msr, mcr;
388: char chan = channel(dev);
389: asy0_t *a0 = asy0 + chan;
390: asy1_t *a1 = asy1 + chan;
391: TTY *tp = &a1->a_tty;
392: short port = a0->a_port;
393:
394: if (a1->a_ut == US_NONE) { /* chip not found */
395: T_HAL(4, devmsg(dev, "no UART"));
396: u.u_error = ENXIO;
397: goto bad_open;
398: }
399:
400: if ((tp->t_flags & T_EXCL) && !super()) {
401: T_HAL(4, devmsg(dev, "exclusive use"));
402: u.u_error = ENODEV;
403: goto bad_open;
404: }
405:
406: #if 0
407: if (drvl[major(dev)].d_time != 0) { /* Modem settling */
408: T_HAL(4, devmsg(dev, "modem settling"));
409: u.u_error = EEBUSY;
410: goto bad_open;
411: }
412: #endif
413:
414: /*
415: * Can't open for hardware flow control if modem status
416: * interrupts are disallowed.
417: */
418: if (a0->a_nms && (dev & CFLOW)) {
419: T_HAL(4, devmsg(dev, "no modem status irq's"));
420: u.u_error = ENXIO;
421: goto bad_open;
422: }
423:
424: /*
425: * Can't open a polled port if another driver is using polling.
426: */
427: if (dev & CPOLL && poll_owner & ~ POLL_ASY) {
428: T_HAL(4, devmsg(dev, "polling unavailable"));
429: u.u_error = EEBUSY;
430: goto bad_open;
431: }
432:
433: /*
434: * Can't have both com[13] or both com[24] IRQ at once.
435: */
436: if (!(dev & CPOLL) && a0->a_ixc) {
437: struct irqnode *np = irq1[a0->a_irqno];
438: while (np) {
439: if (np->func != ptbl[0] || np->arg != chan) {
440: T_HAL(4, devmsg(dev, "irq conflict"));
441: u.u_error = EEBUSY;
442: goto bad_open;
443: }
444: np = np->next_actv;
445: }
446: }
447:
448: /*
449: * If port already in use, are new and old open modes compatible?
450: */
451: if (a1->a_in_use) {
452: int oldmode = 0, newmode = 0; /* mctl:1 irq:2 flow:4 */
453:
454: if (a1->a_modc)
455: oldmode += 1;
456: if (a1->a_irq)
457: oldmode += 2;
458: if (a1->a_flc)
459: oldmode += 4;
460: if ((dev & NMODC) == 0)
461: newmode += 1;
462: if ((dev & CPOLL) == 0)
463: newmode += 2;
464: if (dev & CFLOW)
465: newmode += 4;
466: if (oldmode != newmode) {
467: T_HAL(4, devmsg(dev, "conflicting open modes"));
468: u.u_error = EEBUSY;
469: goto bad_open;
470: }
471: }
472:
473: /*
474: * Sleep here if another process is opening or closing the port.
475: * This can happen if:
476: * another process is trying a first open and awaiting CD;
477: * another process is closing the port after losing CD;
478: * a remote process opened the port, spawned a daemon,
479: * and disconnected, and the daemon ignored SIGHUP and is
480: * improperly keeping the port open.
481: * Don't try to set tp->t_flags before this sleep! During
482: * the sleep, ttclose() may be called and clear the flags.
483: */
484: while (a1->a_in_use && (a1->a_hcls ||
485: ((dev & NMODC) == 0 && (inb(port+MSR) & MS_RLSD) == 0))) {
486: v_sleep((char *)(&tp->t_open), CVTTOUT, IVTTOUT, SVTTOUT,
487: "asyblk");
488: if (SELF->p_ssig && nondsig()) { /* signal? */
489: u.u_error = EINTR;
490: goto bad_open;
491: }
492: }
493:
494: /*
495: * If channel not in use, mark it as such.
496: */
497: if (a1->a_in_use == 0) {
498: /*
499: * Save modes for this open attempt to avoid future conflicts.
500: * Then start asycycle() for this port.
501: */
502: if (dev & NMODC) {
503: tp->t_flags &= ~T_MODC;
504: a1->a_modc = 0;
505: } else {
506: tp->t_flags |= T_MODC;
507: a1->a_modc = 1;
508: }
509: if (dev & CPOLL)
510: a1->a_irq = 0;
511: else
512: a1->a_irq = 1;
513: if (dev & CFLOW) {
514: tp->t_flags |= T_CFLOW;
515: a1->a_flc = 1;
516: } else {
517: tp->t_flags &= ~T_CFLOW;
518: a1->a_flc = 0;
519: }
520: }
521: a1->a_in_use++;
522:
523: /*
524: * From here, error exit is bad_open_u.
525: */
526:
527: if (tp->t_open == 0) { /* not already open */
528: silo_t * in_silo = &a1->a_in;
529:
530: if (!(dev & CPOLL)) {
531: upd_irq1(a0->a_irqno);
532: a1->a_has_irq = 1;
533: }
534:
535: /*
536: * Need to start cycling to scan for CD.
537: */
538: asycycle(chan);
539:
540: s = sphi();
541: /*
542: * Raise basic modem control lines even if modem
543: * control hasn't been specified.
544: * MC_OUT2 turns on NON-open-collector IRQ line from the UART.
545: * since we can't have two UART's on same IRQ with MC_OUT2 on
546: */
547: mcr = MC_RTS | MC_DTR;
548: if (dev & CPOLL) {
549: outb(port+MCR, mcr);
550: } else {
551: outb(port+MCR, mcr | a0->a_outs);
552: outb(port+IER, IEN);
553: }
554:
555: if ((dev & NMODC) == 0) { /* want modem control? */
556: tp->t_flags |= T_HOPEN | T_STOP;
557: for (;;) { /* wait for carrier */
558: msr = inb(port+MSR);
559: /*
560: * If carrier detect present
561: * if port not already open
562: * break out of loop and finish first open
563: * else
564: * do second (or third, etc.) open
565: */
566: if (msr & MS_RLSD)
567: break;
568: sleep((char *)(&tp->t_open), CVTTOUT, IVTTOUT,
569: SVTTOUT, "need CD"); /* wait for carrier */
570: if (SELF->p_ssig && nondsig()) { /* signal? */
571: outb(port+MCR, 0);
572: outb(port+IER, 0);
573: u.u_error = EINTR;
574: tp->t_flags &= ~(T_HOPEN | T_STOP);
575: spl(s);
576: goto bad_open_u;
577: }
578: }
579:
580: /*
581: * Mark that we are no longer hanging in open.
582: * Allow output over the port unless hardware flow
583: * control says not to.
584: */
585: tp->t_flags &= ~T_HOPEN;
586: tp->t_flags &= ~T_STOP;
587: if (!(tp->t_flags & T_CFLOW) || (msr & MS_CTS))
588: a1->a_ohlt = 0;
589: else
590: a1->a_ohlt = 1;
591:
592: /*
593: * Awaken any other opens on same device.
594: */
595: wakeup((char *)(&tp->t_open));
596: }
597: ttopen(tp); /* stty inits */
598: tp->t_flags |= T_CARR;
599: if (ASY_HPCL)
600: tp->t_flags |= T_HPCL;
601:
602: asyparam(tp); /* gimmick: do this while t_open is zero */
603:
604: /*
605: * TO DO: flush UART input register(s).
606: */
607:
608: spl(s);
609:
610: /*
611: * Turn on polling for the port.
612: */
613: if (dev & CPOLL) {
614: a1->a_poll = 1;
615: asyspr();
616: }
617: } /* end of first-open case */
618:
619: tp->t_open++;
620: T_HAL(0x400, printf("ch%d open + %d\n", chan, tp->t_open));
621: ttsetgrp(tp, dev, mode);
622:
623: return;
624:
625: bad_open_u:
626: a1->a_in_use--;
627: wakeup((char *)(&tp->t_open));
628: bad_open:
629: return;
630: }
631:
632: /*
633: * asyclose()
634: */
635: static void
636: asyclose(dev, mode)
637: dev_t dev;
638: int mode;
639: {
640: int chan = channel(dev);
641: asy0_t *a0 = asy0 + chan;
642: asy1_t *a1 = asy1 + chan;
643: TTY *tp = &a1->a_tty;
644: silo_t * out_silo = &a1->a_out;
645: silo_t * in_silo = &a1->a_in;
646: int flags, maj;
647: int s;
648: short port = a0->a_port;
649: char lsr;
650:
651: if (--tp->t_open)
652: goto not_last_close;
653: T_HAL(0x400, printf("ch%d open - %d\n", chan, tp->t_open));
654: s = sphi();
655:
656: a1->a_hcls = 1; /* disallow reopen til done closing */
657: flags = tp->t_flags; /* save flags - ttclose zeroes them */
658: #if 1
659: ttclose(tp);
660: #endif
661:
662: /*
663: * Wait for output silo and UART xmit buffer to empty.
664: * Allow signal to break the sleep.
665: */
666: for (;;) {
667: lsr = inb(port + LSR);
668: if ((lsr & LS_TxIDLE)
669: && (out_silo->si_ix == out_silo->si_ox))
670: break;
671: need_wake[chan] |= NW_OUTSILO;
672: v_sleep((char *)out_silo, CVTTOUT, IVTTOUT, SVTTOUT,
673: "asyclose");
674: if (SELF->p_ssig && nondsig()) { /* signal? */
675: RAWOUT_FLUSH(out_silo);
676: break;
677: }
678: }
679: need_wake[chan] &= ~NW_OUTSILO;
680:
681: /*
682: * If not hanging in open
683: */
684: if ((flags & T_HOPEN) == 0) {
685: /*
686: * Disable interrupts.
687: */
688: outb(port+IER, 0);
689: outb(port+MCR, inb(port+MCR) & ~MC_OUTS);
690: }
691:
692: /*
693: * If hupcls
694: */
695: if (flags & T_HPCL) {
696: T_HAL(0x400, printf("ch%d drop DTR\n", chan));
697: /*
698: * Hangup port - drop DTR and RTS.
699: */
700: outb(port+MCR, inb(port+MCR) & MC_OUTS);
701:
702: /*
703: * Hold dtr low for timeout
704: */
705: maj = major(dev);
706: drvl[maj].d_time = 1;
707: v_sleep((char *)&drvl[maj].d_time, CVTTOUT, IVTTOUT, SVTTOUT,
708: "drop DTR");
709: drvl[maj].d_time = 0;
710: }
711:
712: a1->a_poll = 0;
713: asyspr();
714: RAWIN_FLUSH(in_silo);
715: a1->a_hcls = 0; /* allow reopen - done closing */
716: wakeup((char *)(&tp->t_open));
717: spl(s);
718: a1->a_in_use--;
719:
720: if (!(dev & CPOLL))
721: upd_irq1(a0->a_irqno);
722: return;
723:
724: not_last_close:
725: T_HAL(0x400, printf("ch%d open - %d\n", chan, tp->t_open));
726: a1->a_in_use--;
727: wakeup((char *)(&tp->t_open));
728: return;
729: }
730:
731: /*
732: * asyread()
733: */
734: static void
735: asyread(dev, iop)
736: dev_t dev;
737: register IO * iop;
738: {
739: int chan = channel(dev);
740: asy1_t *a1 = asy1 + chan;
741: TTY *tp = &a1->a_tty;
742:
743: ttread(tp, iop);
744: }
745:
746: /*
747: * asytimer()
748: */
749: static void
750: asytimer(dev)
751: dev_t dev;
752: {
753: if (++drvl[major(dev)].d_time > DTRTMOUT)
754: wakeup((char *)&drvl[major(dev)].d_time);
755: }
756:
757: /*
758: * asywrite()
759: */
760: static void
761: asywrite(dev, iop)
762: dev_t dev;
763: register IO * iop;
764: {
765: int chan = channel(dev);
766: asy0_t *a0 = asy0 + chan;
767: asy1_t *a1 = asy1 + chan;
768: TTY *tp = &a1->a_tty;
769: short port = a0->a_port;
770: register int c;
771:
772: /*
773: * Treat user writes through tty driver.
774: */
775: if (iop->io_seg != IOSYS) {
776: ttwrite(tp, iop);
777: return;
778: }
779:
780: /*
781: * Treat kernel writes by blocking on transmit buffer.
782: */
783: while ((c = iogetc(iop)) >= 0) {
784: /*
785: * Wait until transmit buffer is empty.
786: * Check twice to prevent critical race with interrupt handler.
787: */
788: for (;;) {
789: if (inb(port+LSR) & LS_TxRDY)
790: if (inb(port+LSR) & LS_TxRDY)
791: break;
792: }
793:
794: /*
795: * Output the next character.
796: */
797: outb(port+DREG, c);
798: }
799: }
800:
801: /*
802: * asyioctl()
803: */
804: #ifdef _I386
805: static void
806: asyioctl0(dev, com, vec)
807: dev_t dev;
808: int com;
809: struct sgttyb *vec;
810: {
811: tioc286(dev, com, vec, asyioctl);
812: }
813: #endif
814:
815: static void
816: asyioctl(dev, com, vec)
817: dev_t dev;
818: int com; struct sgttyb *vec;
819: {
820: int chan = channel(dev);
821: asy0_t *a0 = asy0 + chan;
822: asy1_t *a1 = asy1 + chan;
823: TTY *tp = &a1->a_tty;
824: int s;
825: int stat1, stat2;
826: silo_t *out_silo = &a1->a_out;
827: silo_t *in_silo = &a1->a_in;
828: short port = a0->a_port;
829: char msr;
830: char ier_save;
831: char do_ttioctl = 0;
832: char do_asyparam = 0;
833:
834: s = sphi();
835: ier_save = inb(port+IER);
836: stat1 = inb(port+MCR); /* get current MCR register status */
837: stat2 = inb(port+LCR); /* get current LCR register status */
838:
839: #if 0
840: /*
841: * If command will drain input, do the drain now
842: * before calling ttioctl().
843: */
844: switch(com) {
845: case TCSETAW:
846: case TCSETAF:
847: case TIOCSETP:
848: /*
849: * Wait for output silo and UART xmit buffer to empty.
850: * Allow signal to break the sleep.
851: */
852: for (;;) {
853: if (!ttoutp(tp)
854: && (out_silo->si_ix == out_silo->si_ox)
855: && (inb(port + LSR) & LS_TxIDLE))
856: break;
857: need_wake[chan] |= NW_OUTSILO;
858: v_sleep((char *)out_silo, CVTTOUT, IVTTOUT, SVTTOUT,
859: "asydrain");
860: if (SELF->p_ssig && nondsig()) { /* signal? */
861: break;
862: }
863: }
864: need_wake[chan] &= ~NW_OUTSILO;
865: }
866: #endif
867:
868: switch(com) {
869: case TIOCSBRK: /* set BREAK */
870: outb(port+LCR, stat2|LC_SBRK);
871: break;
872: case TIOCCBRK: /* clear BREAK */
873: outb(port+LCR, stat2 & ~LC_SBRK);
874: break;
875: case TIOCSDTR: /* set DTR */
876: outb(port+MCR, stat1|MC_DTR);
877: break;
878: case TIOCCDTR: /* clear DTR */
879: outb(port+MCR, stat1 & ~MC_DTR);
880: break;
881: case TIOCSRTS: /* set RTS */
882: outb(port+MCR, stat1|MC_RTS);
883: break;
884: case TIOCCRTS: /* clear RTS */
885: outb(port+MCR, stat1 & ~MC_RTS);
886: break;
887: case TIOCRSPEED: /* set "raw" I/O speed divisor */
888: outb(port+LCR, stat2|LC_DLAB); /* set speed latch bit */
889: outb(port+DLL, (unsigned) vec);
890: outb(port+DLH, (unsigned) vec >> 8);
891: outb(port+LCR, stat2); /* reset latch bit */
892: break;
893: case TIOCWORDL: /* set word length and stop bits */
894: outb(port+LCR, ((stat2&~0x7) | ((unsigned) vec & 0x7)));
895: break;
896: case TIOCRMSR: /* get CTS/DSR/RI/RLSD (MSR) */
897: msr = inb(port+MSR);
898: stat1 = msr >> 4;
899: kucopy(&stat1, (unsigned *) vec, sizeof(unsigned));
900: break;
901: case TIOCFLUSH: /* Flush silos here, queues in tty.c */
902: RAWIN_FLUSH(in_silo);
903: RAWOUT_FLUSH(out_silo);
904: do_ttioctl = 1;
905: break;
906:
907: /*
908: * If port parameters change, plan to call asyparam().
909: * Need to check now before structs are updated.
910: */
911: #ifdef _I386
912: case TCSETA:
913: case TCSETAW:
914: case TCSETAF:
915: {
916: struct termio trm;
917:
918: ukcopy(vec, &trm, sizeof(struct termio));
919: if (trm.c_cflag != tp->t_termio.c_cflag)
920: do_asyparam = 1;
921: }
922: do_ttioctl = 1;
923: break;
924: #endif
925: case TIOCSETP:
926: case TIOCSETN:
927: {
928: struct sgttyb sg;
929:
930: ukcopy(vec, &sg, sizeof(struct sgttyb));
931: if (sg.sg_ispeed != tp->t_sgttyb.sg_ispeed
932: || ((sg.sg_flags ^ tp->t_sgttyb.sg_flags) & ANYP))
933: do_asyparam = 1;
934: }
935: do_ttioctl = 1;
936: break;
937: default:
938: do_ttioctl = 1;
939: }
940: outb(port+IER, ier_save);
941: if (do_ttioctl)
942: ttioctl(tp, com, vec);
943: spl(s);
944: if (do_asyparam)
945: asyparam(tp);
946: }
947:
948: /*
949: * asyparam()
950: */
951: static void
952: asyparam(tp)
953: TTY * tp;
954: {
955: int chan = (int)tp->t_ddp;
956: asy0_t *a0 = asy0 + chan;
957: asy1_t *a1 = asy1 + chan;
958: short port = a0->a_port;
959: int s;
960: int write_baud=1, write_lcr=1;
961: char newlcr, speed;
962:
963: #ifdef _I386
964: unsigned short cflag = tp->t_termio.c_cflag;
965:
966: T_HAL(4, printf("ch%d asyparam cflag=%x\n", chan, cflag));
967: speed = cflag & CBAUD;
968: switch (cflag & CSIZE) {
969: case CS5: newlcr = LC_CS5; break;
970: case CS6: newlcr = LC_CS6; break;
971: case CS7: newlcr = LC_CS7; break;
972: case CS8: newlcr = LC_CS8; break;
973: }
974: if (cflag & CSTOPB)
975: newlcr |= LC_STOPB;
976: if (cflag & PARENB) {
977: newlcr |= LC_PARENB;
978: if ((cflag & PARODD) == 0)
979: newlcr |= LC_PAREVEN;
980: }
981: #else
982: speed = tp->t_sgttyb.sg_ispeed;
983: switch (tp->t_sgttyb.sg_flags & (EVENP|ODDP|RAW)) {
984: case ODDP:
985: newlcr = LC_CS7|LC_PARENB;
986: break;
987: case EVENP:
988: newlcr = LC_CS7|LC_PARENB|LC_PAREVEN;
989: break;
990: default:
991: newlcr = LC_CS8;
992: break;
993: }
994: #endif
995:
996: /*
997: * Don't bang on the UART needlessly.
998: * Writing baud rate resets the port, which loses characters.
999: * You want this on first open, NOT on later opens.
1000: */
1001: if (speed == a0->a_speed && tp->t_open) {
1002: write_baud = 0;
1003: if (newlcr == a1->a_lcr) {
1004: write_lcr = 0;
1005: }
1006: }
1007: a0->a_speed = speed;
1008: a1->a_lcr = newlcr;
1009:
1010: if (write_lcr) {
1011: char ier_save;
1012: s = sphi();
1013: ier_save = inb(port+IER);
1014: if (write_baud) {
1015: short divisor = albaud[speed];
1016:
1017: T_HAL(4, printf("CH%d speed=%x\n", chan, speed));
1018: outb(port+LCR, LC_DLAB);
1019: outb(port+DLL, divisor);
1020: outb(port+DLH, divisor >> 8);
1021: }
1022: T_HAL(4, printf("CH%d newlcr=%x\n", chan, newlcr));
1023: outb(port+LCR, newlcr);
1024: if (a1->a_ut == US_16550A)
1025: outb(port+FCR, FC_ENABLE | FC_Rx_RST | FC_Rx_08);
1026: outb(port+IER, ier_save);
1027: spl(s);
1028: }
1029: if (write_baud)
1030: asyspr();
1031: }
1032:
1033: /*
1034: * asystart()
1035: */
1036: static void
1037: asystart(tp)
1038: TTY * tp;
1039: {
1040: int chan = (int)tp->t_ddp;
1041: asy0_t *a0 = asy0 + chan;
1042: asy1_t *a1 = asy1 + chan;
1043: short port = a0->a_port;
1044: int s;
1045: int need_xmit = 1; /* True if should start sending data now. */
1046: silo_t *out_silo = &a1->a_out;
1047: char lsr;
1048:
1049: /*
1050: * Read line status register AFTER disabling interrupts.
1051: */
1052: s = sphi();
1053: lsr = inb(port + LSR);
1054:
1055: /*
1056: * Process break indication.
1057: * NOTE: Break indication cleared when line status register was read.
1058: */
1059: if (lsr & LS_BREAK)
1060: defer(asybreak, chan);
1061:
1062: /*
1063: * If no output data, it may be time to finish closing the port;
1064: * but won't need another xmit interrupt.
1065: */
1066: if (out_silo->si_ix == out_silo->si_ox) {
1067: if (need_wake[chan] & NW_OUTSILO) {
1068: need_wake[chan] &= ~NW_OUTSILO;
1069: wakeup((char *)out_silo);
1070: }
1071: need_xmit = 0;
1072: }
1073:
1074: /*
1075: * Do nothing if output is stopped.
1076: */
1077: if (tp->t_flags & T_STOP)
1078: need_xmit = 0;
1079: if (a1->a_ohlt)
1080: need_xmit = 0;
1081:
1082: /*
1083: * Start data transmission by writing to UART xmit reg.
1084: */
1085: if ((lsr & LS_TxRDY) && need_xmit) {
1086: int xmit_count;
1087: xmit_count = (a1->a_ut == US_16550A)?16:1;
1088: asy_send(out_silo, port+DREG, xmit_count);
1089: }
1090: spl(s);
1091: }
1092:
1093: /*
1094: * asypoll()
1095: */
1096: static int
1097: asypoll(dev, ev, msec)
1098: dev_t dev;
1099: int ev;
1100: int msec;
1101: {
1102: int chan = channel(dev);
1103: asy1_t *a1 = asy1 + chan;
1104: TTY *tp = &a1->a_tty;
1105:
1106: return ttpoll(tp, ev, msec);
1107: }
1108:
1109: /*
1110: * asycycle()
1111: *
1112: * Do a wakeup of any sleeping asy's at regular intervals.
1113: */
1114: static void
1115: asycycle(chan)
1116: int chan;
1117: {
1118: asy0_t *a0 = asy0 + chan;
1119: asy1_t *a1 = asy1 + chan;
1120: TTY *tp = &a1->a_tty;
1121: short port = a0->a_port;
1122: int s;
1123: char msr, mcr;
1124: silo_t *out_silo = &a1->a_out;
1125: silo_t *in_silo = &a1->a_in;
1126: int n, ch;
1127: int do_start = 1;
1128: unsigned char iir;
1129:
1130: /*
1131: * Check Carrier Detect (RLSD).
1132: *
1133: * Modem status interrupts were not enabled due to 8250 hardware bug.
1134: * Enabling modem status and receive interrupts may cause lockup
1135: * on older parts.
1136: */
1137: if (tp->t_flags & T_MODC) {
1138:
1139: /*
1140: * Get status
1141: */
1142: msr = inb(port+MSR);
1143:
1144: /*
1145: * Carrier changed.
1146: */
1147: if ((msr & MS_RLSD) && !(tp->t_flags & T_CARR)) {
1148: /*
1149: * Carrier is on - wakeup open.
1150: */
1151: s = sphi();
1152: tp->t_flags |= T_CARR;
1153: spl(s);
1154: wakeup((char *)(&tp->t_open));
1155: }
1156:
1157: if (!(msr & MS_RLSD) && (tp->t_flags & T_CARR)) {
1158: s = sphi();
1159: RAWIN_FLUSH(in_silo);
1160: RAWOUT_FLUSH(out_silo);
1161: tp->t_flags &= ~T_CARR;
1162: spl(s);
1163: tthup(tp);
1164: }
1165: }
1166:
1167: /*
1168: * Empty raw input buffer.
1169: *
1170: * The line discipline module (tty.c) will set T_ISTOP true when the
1171: * tt input queue is nearly full (tp->t_iq.cq_cc >= IHILIM), and make
1172: * T_ISTOP false when it's ready for more input.
1173: *
1174: * When T_ISTOP is true, ttin() simply discards the character passed.
1175: */
1176: if (!(tp->t_flags & T_ISTOP)) {
1177: while (in_silo->SILO_CHAR_COUNT > 0) {
1178: s = sphi();
1179: ttin(tp, in_silo->si_buf[in_silo->si_ox]);
1180: if (in_silo->si_ox < MAX_SILO_INDEX)
1181: in_silo->si_ox++;
1182: else
1183: in_silo->si_ox = 0;
1184: in_silo->SILO_CHAR_COUNT--;
1185: spl(s);
1186: }
1187: }
1188:
1189: /*
1190: * Hardware flow control.
1191: * Check CTS to see if we need to halt output.
1192: * (MS_INTR should have done this - repeat code here to be sure)
1193: * Check input silo to see if we need to raise RTS.
1194: */
1195: if (tp->t_flags & T_CFLOW) {
1196:
1197: /*
1198: * Get status
1199: */
1200: msr = inb(port+MSR);
1201: s = sphi();
1202: if (msr & MS_CTS)
1203: a1->a_ohlt = 0;
1204: else
1205: a1->a_ohlt = 1;
1206: spl(s);
1207: T_HAL(4, {static cts = 0; if (!cts && (msr & MS_CTS)) { cts = 1; putchar('[');\
1208: } else if (cts && !(msr & MS_CTS)) { cts = 0; putchar(']'); }});
1209:
1210: /*
1211: * If using hardware flow control, see if we need to drop RTS.
1212: */
1213: if ((tp->t_flags & T_CFLOW)
1214: && (in_silo->SILO_CHAR_COUNT > SILO_HIGH_MARK)) {
1215: s = sphi();
1216: mcr = inb(port+MCR);
1217: if (mcr & MC_RTS) {
1218: outb(port+MCR, mcr & ~MC_RTS);
1219: T_HAL(4, putchar('-'));
1220: }
1221: spl(s);
1222: }
1223:
1224: /*
1225: * If input silo below low mark, assert RTS.
1226: */
1227: if (in_silo->SILO_CHAR_COUNT <= SILO_LOW_MARK) {
1228: s = sphi();
1229: mcr = inb(port+MCR);
1230: if ((mcr & MC_RTS) == 0) {
1231: outb(port+MCR, mcr | MC_RTS);
1232: T_HAL(4, putchar('+'));
1233: }
1234: spl(s);
1235: }
1236: }
1237:
1238: /*
1239: * Calculate free output slot count.
1240: */
1241: n = sizeof(out_silo->si_buf) - 1;
1242: n += out_silo->si_ox - out_silo->si_ix;
1243: n %= sizeof(out_silo->si_buf);
1244:
1245: /*
1246: * Fill raw output buffer.
1247: */
1248: for (;;) {
1249: if (--n < 0)
1250: break;
1251: s = sphi();
1252: ch = ttout(tp);
1253: spl(s);
1254: if (ch < 0)
1255: break;
1256:
1257: s = sphi();
1258: out_silo->si_buf[out_silo->si_ix] = ch;
1259: if (out_silo->si_ix >= sizeof(out_silo->si_buf) - 1)
1260: out_silo->si_ix = 0;
1261: else
1262: out_silo->si_ix++;
1263: spl(s);
1264: }
1265:
1266: #ifdef _I386
1267: /*
1268: * if port has an interrupt pending (probably missed an irq)
1269: * the following two loops should not be merged
1270: * - need ALL port irq's inactive at once
1271: * for each port on this irq line (use irq1 for this)
1272: * disable interrupts (clear IER)
1273: * for each port on this irq line
1274: * restore interrupts
1275: */
1276: if (a1->a_has_irq && ((iir=inb(port+IIR)) & 1) == 0) {
1277: struct irqnode *ip;
1278: asy_gp_t *gp;
1279: int s;
1280: short p;
1281: char c, slot;
1282:
1283: T_HAL(4, printf("CH%d missed iir:x\n", chan, iir));
1284:
1285: do_start = 0;
1286: s = sphi();
1287: ip = irq1[a0->a_irqno];
1288: while(ip) {
1289: if (ip->func == asyintr) {
1290: p = ip->arg;
1291: outb(p + IER, 0);
1292: } else {
1293: gp = asy_gp + ip->arg;
1294: for (slot = 0; slot < MAX_SLOTS; slot++) {
1295: if ((c=gp->chan_list[slot]) < MAX_ASY){
1296: p = asy0[c].a_port;
1297: outb(p + IER, 0);
1298: }
1299: }
1300: }
1301: ip = ip->next_actv;
1302: }
1303: /*
1304: * Now, all ports on the offending irq line have irq off.
1305: */
1306: ip = irq1[a0->a_irqno];
1307: while(ip) {
1308: if (ip->func == asyintr) {
1309: p = ip->arg;
1310: outb(p + IER, IEN);
1311: } else {
1312: gp = asy_gp + ip->arg;
1313: for (slot = 0; slot < MAX_SLOTS; slot++) {
1314: if ((c=gp->chan_list[slot]) < MAX_ASY){
1315: p = asy0[c].a_port;
1316: outb(p + IER, IEN);
1317: }
1318: }
1319: }
1320: ip = ip->next_actv;
1321: }
1322: spl(s);
1323: }
1324: #endif
1325:
1326: if(do_start)
1327: ttstart(tp);
1328:
1329: /*
1330: * Schedule next cycle.
1331: */
1332: if (a1->a_in_use) {
1333: timeout(&tp->t_rawtim, HZ/10, asycycle, chan);
1334: }
1335: }
1336:
1337: /*
1338: * irqdummy()
1339: *
1340: * Suppress interrupts that may occur during chip sensing.
1341: */
1342: static void
1343: irqdummy()
1344: {
1345: /*
1346: * Try to clear all pending interrupts.
1347: */
1348: inb(dummy_port+IIR);
1349: inb(dummy_port+LSR);
1350: inb(dummy_port+MSR);
1351: inb(dummy_port+DREG);
1352: }
1353:
1354: /*
1355: * add_irq()
1356: *
1357: * Given channel number, add port info to irq0 list.
1358: */
1359: static void
1360: add_irq(irq, func, arg)
1361: int irq;
1362: void (*func)();
1363: int arg;
1364: {
1365: struct irqnode * np;
1366:
1367: /*
1368: * Sanity check.
1369: */
1370: if (irq <=0 || irq >= NUM_IRQ || itbl[irq] == 0)
1371: return;
1372:
1373: if (nextnode < MAX_ASY) {
1374: np = nodespace + nextnode++;
1375: np->func = func;
1376: np->arg = arg;
1377: np->next = irq0[irq];
1378: irq0[irq] = np;
1379: } else {
1380: printf("asy: too many irq nodes (%d)\n", nextnode);
1381: }
1382: }
1383:
1384: /*
1385: * Interrupt handlers.
1386: */
1387: static void i2() { asy_irq(irq1[2]); }
1388: static void i3() { asy_irq(irq1[3]); }
1389: static void i4() { asy_irq(irq1[4]); }
1390: static void i5() { asy_irq(irq1[5]); }
1391: static void i6() { asy_irq(irq1[6]); }
1392: static void i7() { asy_irq(irq1[7]); }
1393: static void i8() { asy_irq(irq1[8]); }
1394: static void i9() { asy_irq(irq1[9]); }
1395: static void i10() { asy_irq(irq1[10]); }
1396: static void i11() { asy_irq(irq1[11]); }
1397: static void i12() { asy_irq(irq1[12]); }
1398: static void i13() { asy_irq(irq1[13]); }
1399: static void i14() { asy_irq(irq1[14]); }
1400: static void i15() { asy_irq(irq1[15]); }
1401:
1402: /*
1403: * asy_irq()
1404: *
1405: * Given pointer to node list, service async interrupt.
1406: */
1407: static void
1408: asy_irq(ip)
1409: struct irqnode * ip;
1410: {
1411: struct irqnode *here;
1412: int doit;
1413:
1414: do {
1415: doit = 0;
1416: here = ip;
1417: while(here) {
1418: doit |= (*(here->func))(here->arg);
1419: here = here->next_actv;
1420: }
1421: } while(doit);
1422: }
1423:
1424: /*
1425: * upd_irq1()
1426: *
1427: * Given an irq number, rebuild the links for active devices.
1428: */
1429: static void
1430: upd_irq1(irq)
1431: int irq;
1432: {
1433: struct irqnode *np;
1434: asy1_t *a1;
1435: int chan;
1436: int s;
1437:
1438: /*
1439: * Sanity check.
1440: */
1441: if (irq <=0 || irq >= NUM_IRQ || itbl[irq] == 0)
1442: return;
1443:
1444: /*
1445: * For each node in the irq0 list
1446: * if node is for irq status port
1447: * for each channel using the status port
1448: * if channel in use, in irq mode
1449: * add node to irq1 list
1450: * skip rest of channels for this node
1451: * else - node is for simple UART
1452: * if channel in use, in irq mode
1453: * add node to irq1 list
1454: */
1455: s = sphi();
1456: np = irq0[irq];
1457: irq1[irq] = 0;
1458: while (np) {
1459: if (np->func != asyintr) {
1460: char ix, loop = 1;
1461: asy_gp_t *gp = asy_gp + np->arg;
1462:
1463: for (ix = 0; ix < MAX_SLOTS && loop; ix++) {
1464: if ((chan = gp->chan_list[ix]) < MAX_ASY) {
1465: a1 = asy1 + chan;
1466: if (a1->a_in_use && a1->a_irq) {
1467: np->next_actv = irq1[irq];
1468: irq1[irq] = np;
1469: loop = 0;
1470: }
1471: }
1472: }
1473: } else {
1474: a1 = asy1 + np->arg;
1475: if (a1->a_in_use && a1->a_irq) {
1476: np->next_actv = irq1[irq];
1477: irq1[irq] = np;
1478: }
1479: }
1480: np = np->next;
1481: }
1482: spl(s);
1483: }
1484:
1485: /*
1486: * asybreak()
1487: */
1488: static void
1489: asybreak(chan)
1490: int chan;
1491: {
1492: int s;
1493: asy1_t *a1 = asy1 + chan;
1494: silo_t *out_silo = &a1->a_out;
1495: silo_t *in_silo = &a1->a_in;
1496: TTY *tp = &a1->a_tty;
1497:
1498: s = sphi();
1499: RAWIN_FLUSH(in_silo);
1500: RAWOUT_FLUSH(out_silo);
1501: spl(s);
1502: ttsignal(tp, SIGINT);
1503: }
1504:
1505: /*
1506: * asyintr()
1507: *
1508: * Handle interrupt for a single channel.
1509: */
1510: static int
1511: asyintr(chan)
1512: int chan;
1513: {
1514: asy0_t *a0 = asy0 + chan;
1515: asy1_t *a1 = asy1 + chan;
1516: TTY *tp = &a1->a_tty;
1517: silo_t *out_silo = &a1->a_out;
1518: silo_t *in_silo = &a1->a_in;
1519: int c, xmit_count;
1520: int ret = 0;
1521: short port = a0->a_port;
1522: unsigned char msr, lsr;
1523:
1524: if (chan >= MAX_ASY) {
1525: printf("asy: irq on channel %d\n", chan);
1526: return 0;
1527: }
1528:
1529: rescan:
1530: switch (inb(port+IIR) & 0x07) {
1531:
1532: case LS_INTR:
1533: ret = 1;
1534: lsr = inb(port + LSR);
1535: T_HAL(0x800, printf("[%d:L%x]", chan, lsr));
1536: if (lsr & LS_BREAK)
1537: defer(asybreak, chan);
1538: goto rescan;
1539:
1540: case Rx_INTR:
1541: T_HAL(0x800, printf("[%d:R]", chan));
1542: ret = 1;
1543: c = inb(port+DREG);
1544: if (tp->t_open == 0)
1545: goto rescan;
1546: /*
1547: * Must recognize XOFF quickly to avoid transmit overrun.
1548: * Recognize XON here as well to avoid race conditions.
1549: */
1550: if (!ISRIN) {
1551: /*
1552: * XOFF.
1553: */
1554: if (ISSTOP) {
1555: tp->t_flags |= T_STOP;
1556: goto rescan;
1557: }
1558:
1559: /*
1560: * XON.
1561: */
1562: if (ISSTART) {
1563: tp->t_flags &= ~T_STOP;
1564: goto rescan;
1565: }
1566: }
1567:
1568: /*
1569: * Save char in raw input buffer.
1570: */
1571: if (in_silo->SILO_CHAR_COUNT < MAX_SILO_CHARS) {
1572: in_silo->si_buf[in_silo->si_ix] = c;
1573: if (in_silo->si_ix < MAX_SILO_INDEX)
1574: in_silo->si_ix++;
1575: else
1576: in_silo->si_ix = 0;
1577: in_silo->SILO_CHAR_COUNT++;
1578: }
1579:
1580: /*
1581: * If using hardware flow control, see if we need to drop RTS.
1582: */
1583: if ((tp->t_flags & T_CFLOW)
1584: && (in_silo->SILO_CHAR_COUNT > SILO_HIGH_MARK)) {
1585: unsigned char mcr = inb(port+MCR);
1586: if (mcr & MC_RTS) {
1587: outb(port+MCR, mcr & ~MC_RTS);
1588: }
1589: }
1590:
1591: goto rescan;
1592:
1593: case Tx_INTR:
1594: T_HAL(0x800, printf("[%d:T]", chan));
1595: ret = 1;
1596: /*
1597: * Do nothing if output is stopped.
1598: */
1599: if (tp->t_flags & T_STOP) {
1600: goto rescan;
1601: }
1602: if (a1->a_ohlt)
1603: goto rescan;
1604:
1605: /*
1606: * Transmit next char in raw output buffer.
1607: */
1608: xmit_count = (a1->a_ut == US_16550A)?16:1;
1609: asy_send(out_silo, port+DREG, xmit_count);
1610: goto rescan;
1611:
1612: case MS_INTR:
1613: ret = 1;
1614: /*
1615: * Get status (and clear interrupt).
1616: */
1617: msr = inb(port+MSR);
1618: T_HAL(0x800, printf("[%d:M%x]", chan, msr));
1619:
1620: /*
1621: * Hardware flow control.
1622: * Check CTS to see if we need to halt output.
1623: */
1624: if (tp->t_flags & T_CFLOW) {
1625: if (msr & MS_CTS)
1626: a1->a_ohlt = 0;
1627: else
1628: a1->a_ohlt = 1;
1629: }
1630:
1631: goto rescan;
1632: default:
1633: return ret;
1634: } /* endswitch */
1635: }
1636:
1637: /*
1638: * asyclk()
1639: *
1640: * Called every time T0 interrupts.- if it returns 0,
1641: * the usual system timer interrupt stuff is done.
1642: * Poll all pollable ports.
1643: */
1644: static int
1645: asyclk()
1646: {
1647: static int count;
1648: int ix;
1649:
1650: for (ix = 0; ix < ppnum; ix++)
1651: asysph(pptbl[ix]);
1652:
1653: count++;
1654: if (count >= poll_divisor)
1655: count = 0;
1656: return count;
1657: }
1658:
1659: /*
1660: * asyspr()
1661: *
1662: * asyspr is called when a port is opened or closed or changes speed
1663: * It sets the polling rate only as fast as needed, and shuts off polling
1664: * whenever possible.
1665: * It updates the links in irq1[0], which lists polled-mode ports.
1666: */
1667: static void
1668: asyspr()
1669: {
1670: asy0_t *a0;
1671: asy1_t *a1;
1672: int chan;
1673: int s;
1674: int ix, max_rate, port_rate;
1675:
1676: /*
1677: * Rebuild table of pollable ports.
1678: */
1679: s = sphi();
1680: ppnum = 0;
1681: for (chan = 0; chan < ASY_NUM; chan++) {
1682: a1 = asy1 + chan;
1683: if (a1->a_poll)
1684: pptbl[ppnum++] = chan;
1685: }
1686: spl(s);
1687:
1688: /*
1689: * If another driver has the polling clock, do nothing.
1690: */
1691: if (poll_owner & ~ POLL_ASY)
1692: return;
1693:
1694: /*
1695: * Find highest valid polling rate in units of HZ/10.
1696: * If using FIFO chip, can poll at 1/16 the usual rate.
1697: */
1698: max_rate = 0;
1699: for (ix = 0; ix < ppnum; ix++) {
1700: chan = pptbl[ix];
1701: a0 = asy0 + chan;
1702: a1 = asy1 + chan;
1703: port_rate = alp_rate[a0->a_speed];
1704: if (a1->a_ut == US_16550A) {
1705: port_rate /= 16;
1706: if (port_rate % HZ)
1707: port_rate += HZ - (port_rate % HZ);
1708: }
1709: if (max_rate < port_rate)
1710: max_rate = port_rate;
1711: }
1712:
1713: /*
1714: * if max_rate is not current rate, adjust the system clock
1715: */
1716: if (max_rate != poll_rate) {
1717: poll_rate = max_rate;
1718: poll_divisor = poll_rate/HZ; /* used in asyclk() */
1719: altclk_out(); /* stop previous polling */
1720: poll_owner &= ~ POLL_ASY;
1721: if (poll_rate) { /* resume polling at new rate if needed */
1722: poll_owner |= POLL_ASY;
1723: altclk_in(poll_rate, asyclk);
1724: }
1725: }
1726: }
1727:
1728: /*
1729: * asysph()
1730: *
1731: * Serial polling handler.
1732: */
1733: static void
1734: asysph(chan)
1735: int chan;
1736: {
1737: asy0_t *a0 = asy0 + chan;
1738: asy1_t *a1 = asy1 + chan;
1739: TTY *tp = &a1->a_tty;
1740: silo_t *out_silo = &a1->a_out;
1741: silo_t *in_silo = &a1->a_in;
1742: int c, xmit_count;
1743: short port = a0->a_port;
1744: char lsr;
1745:
1746: /*
1747: * Check for received break first.
1748: * This status is wiped out on reading the LSR.
1749: */
1750: lsr = inb(port + LSR);
1751: if (lsr & LS_BREAK)
1752: defer(asybreak, chan);
1753:
1754: /*
1755: * Handle all incoming characters.
1756: */
1757: for (;;) {
1758: lsr = inb(port + LSR);
1759: if ((lsr & LS_RxRDY) == 0)
1760: break;
1761: c = inb(port+DREG);
1762: if (tp->t_open == 0)
1763: continue;
1764: /*
1765: * Must recognize XOFF quickly to avoid transmit overrun.
1766: * Recognize XON here as well to avoid race conditions.
1767: */
1768: if (!ISRIN) {
1769: /*
1770: * XOFF.
1771: */
1772: if (ISSTOP) {
1773: tp->t_flags |= T_STOP;
1774: continue;
1775: }
1776:
1777: /*
1778: * XON.
1779: */
1780: if (ISSTART) {
1781: tp->t_flags &= ~T_STOP;
1782: continue;
1783: }
1784: }
1785:
1786: /*
1787: * Save char in raw input buffer.
1788: */
1789: if (in_silo->SILO_CHAR_COUNT < MAX_SILO_CHARS) {
1790: in_silo->si_buf[in_silo->si_ix] = c;
1791: if (in_silo->si_ix < MAX_SILO_INDEX)
1792: in_silo->si_ix++;
1793: else
1794: in_silo->si_ix = 0;
1795: in_silo->SILO_CHAR_COUNT++;
1796: }
1797:
1798: /*
1799: * If using hardware flow control, see if we need to drop RTS.
1800: */
1801: if ((tp->t_flags & T_CFLOW)
1802: && (in_silo->SILO_CHAR_COUNT > SILO_HIGH_MARK)) {
1803: unsigned char mcr = inb(port+MCR);
1804: if (mcr & MC_RTS) {
1805: outb(port+MCR, mcr & ~MC_RTS);
1806: }
1807: }
1808: }
1809:
1810: /*
1811: * Handle outgoing characters.
1812: * Do nothing if output is stopped.
1813: */
1814: lsr = inb(port + LSR);
1815: if ((lsr & LS_TxRDY)
1816: && !(tp->t_flags & T_STOP)
1817: && !(a1->a_ohlt)) {
1818: /*
1819: * Transmit next char in raw output buffer.
1820: */
1821: xmit_count = (a1->a_ut == US_16550A)?16:1;
1822: asy_send(out_silo, port+DREG, xmit_count);
1823: }
1824:
1825: /*
1826: * Hardware flow control.
1827: * Check CTS to see if we need to halt output.
1828: */
1829: if (tp->t_flags & T_CFLOW) {
1830: if (inb(port+MSR) & MS_CTS)
1831: a1->a_ohlt = 0;
1832: else
1833: a1->a_ohlt = 1;
1834: }
1835: }
1836:
1837: /*
1838: * asy_send()
1839: *
1840: * Write to xmit data register of the UART.
1841: * Assume all checking about whether it's time to send has been done already.
1842: * Called by time-critical IRQ and polling routines!
1843: *
1844: * "rawout" is the output silo for the TTY struct supplying data to the port.
1845: * "dreg" is the i/o address of the UART xmit data register.
1846: * "xmit_count" is the max number of chars we can write (16 for FIFO parts).
1847: */
1848: static int
1849: asy_send(rawout, dreg, xmit_count)
1850: register silo_t * rawout;
1851: int dreg, xmit_count;
1852: {
1853: /*
1854: * Transmit next chars in raw output buffer.
1855: */
1856: for (;(rawout->si_ix != rawout->si_ox) && xmit_count; xmit_count--) {
1857: outb(dreg, rawout->si_buf[rawout->si_ox]);
1858: /*
1859: * Adjust raw output buffer output index.
1860: */
1861: if (++rawout->si_ox >= sizeof(rawout->si_buf))
1862: rawout->si_ox = 0;
1863: }
1864: return xmit_count;
1865: }
1866:
1867: /*
1868: * p1()
1869: *
1870: * Interrupt handler for Comtrol-type port groups.
1871: * Status register has 1 in bit positions for interrupting ports.
1872: */
1873: static int
1874: p1(g)
1875: int g;
1876: {
1877: asy_gp_t *gp = asy_gp + g;
1878: short port = gp->stat_port;
1879: unsigned char status, index, chan;
1880: int safety = LOOP_LIMIT;
1881: int ret = 0;
1882:
1883: #if 0 /* DEBUG */
1884: static int pxstat[2][8];
1885: int ci;
1886: int change_found=0;
1887:
1888: for (ci=0; ci<1; ci++) {
1889: index = inb(port+ci);
1890: outb(port+ci, 0);
1891: if (index != pxstat[g][ci]) {
1892: if (!change_found) {
1893: change_found = 1;
1894: printf("<%d:", g);
1895: } else
1896: putchar(' ');
1897: printf("%x:%x", port+ci, index);
1898: pxstat[g][ci] = index;
1899: }
1900: }
1901: if (change_found)
1902: putchar('>');
1903: for (ci=0; ci<8; ci++)
1904: asyintr(4+ci);
1905: putchar('.');
1906: return 0;
1907: #endif /* DEBUG */
1908:
1909: /*
1910: * while any port is active
1911: * call simple interrupt handler for active channel
1912: */
1913: while (status = inb(port)) {
1914: ret = 1;
1915: index = 0;
1916: if (status & 0xf0) {
1917: status &= 0xf0;
1918: index +=4;
1919: } else
1920: status &= 0x0f;
1921: if (status & 0xcc) {
1922: status &= 0xcc;
1923: index +=2;
1924: } else
1925: status &= 0x33;
1926: if (status & 0xaa)
1927: index++;
1928: chan = gp->chan_list[index];
1929: asyintr(chan);
1930: if (safety-- == 0) {
1931: printf("asy: p1 runaway - status %x\n", status);
1932: break;
1933: }
1934: }
1935:
1936: return ret;
1937: }
1938:
1939: /*
1940: * p2()
1941: *
1942: * Interrupt handler for Arnet-type port groups.
1943: * Status register has 0 in bit positions for interrupting ports.
1944: */
1945: static int
1946: p2(g)
1947: int g;
1948: {
1949: asy_gp_t *gp = asy_gp + g;
1950: short port = gp->stat_port;
1951: unsigned char status, index, chan;
1952: int safety = LOOP_LIMIT;
1953: int ret = 0;
1954:
1955: /*
1956: * while any port is active
1957: * call simple interrupt handler for active channel
1958: */
1959: while (status = ~inb(port)) {
1960: ret = 1;
1961: index = 0;
1962: if (status & 0xf0) {
1963: status &= 0xf0;
1964: index +=4;
1965: } else
1966: status &= 0x0f;
1967: if (status & 0xcc) {
1968: status &= 0xcc;
1969: index +=2;
1970: } else
1971: status &= 0x33;
1972: if (status & 0xaa)
1973: index++;
1974: chan = gp->chan_list[index];
1975: asyintr(chan);
1976: if (safety-- == 0) {
1977: printf("asy: p2 runaway - status %x\n", status);
1978: break;
1979: }
1980: }
1981: return ret;
1982: }
1983:
1984: /*
1985: * p3()
1986: *
1987: * Interrupt handler for GTEK-type port groups.
1988: */
1989: static int
1990: p3(g)
1991: int g;
1992: {
1993: asy_gp_t *gp = asy_gp + g;
1994: short port = gp->stat_port;
1995: unsigned char index, chan;
1996:
1997: /*
1998: * Call simple interrupt handler for active channel.
1999: */
2000: index = inb(port) & 7;
2001: chan = gp->chan_list[index];
2002: return asyintr(chan);
2003: }
2004:
2005: /*
2006: * p4()
2007: *
2008: * Interrupt handler for DigiBoard-type port groups.
2009: */
2010: static int
2011: p4(g)
2012: int g;
2013: {
2014: asy_gp_t *gp = asy_gp + g;
2015: short port = gp->stat_port;
2016: unsigned char index, chan;
2017: int ret = 0;
2018: int safety = LOOP_LIMIT;
2019:
2020: /*
2021: * Status register has slot number for active port,
2022: * or 0xFF if no port is active.
2023: */
2024:
2025: for (;;) {
2026: index = inb(port);
2027: if (index == 0xFF)
2028: break;
2029: if (safety-- == 0) {
2030: printf("asy: p4 runaway - status %x\n", index);
2031: break;
2032: }
2033: ret = 1;
2034: chan = gp->chan_list[index&0xF];
2035: asyintr(chan);
2036: }
2037: return ret;
2038: }
2039:
2040: #ifdef TRACER
2041: void
2042: asydump(chan, tag)
2043: int chan;
2044: char *tag;
2045: {
2046: asy0_t *a0 = asy0 + chan;
2047: asy1_t *a1 = asy1 + chan;
2048: TTY *tp = &a1->a_tty;
2049:
2050: printf("ch=%d %s\n", chan, tag);
2051: printf("port=%x irqno=%x speed=%d ",
2052: a0->a_port, a0->a_irqno, a0->a_speed);
2053: printf("outs=%x gp=%d xcl=%d\n",
2054: a0->a_outs, a0->a_asy_gp, a0->a_ixc);
2055: printf("in_use=%d lcr=%x irq=%d has_irq=%d ",
2056: a1->a_in_use, a1->a_lcr, a1->a_irq, a1->a_has_irq);
2057: printf("hop=%d hcl=%d ", a1->a_hopn, a1->a_hcls);
2058: printf("opn=%d ier=%x\n", tp->t_open, inb(a0->a_port+IER));
2059: }
2060: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.