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