|
|
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 <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: x_sleep((char *)(&tp->t_open), pritty, slpriSigCatch, "asyblk");
466: #else
467: v_sleep((char *)(&tp->t_open), CVTTOUT, IVTTOUT, SVTTOUT,
468: "asyblk");
469: #endif
470: if (SELF->p_ssig && nondsig()) { /* signal? */
471: u.u_error = EINTR;
472: goto bad_open;
473: }
474: }
475:
476: /*
477: * If channel not in use, mark it as such.
478: */
479: if (a1->a_in_use == 0) {
480: /*
481: * Save modes for this open attempt to avoid future conflicts.
482: * Then start asycycle() for this port.
483: */
484: if (dev & NMODC) {
485: tp->t_flags &= ~T_MODC;
486: a1->a_modc = 0;
487: } else {
488: tp->t_flags |= T_MODC;
489: a1->a_modc = 1;
490: }
491: if (dev & CPOLL)
492: a1->a_irq = 0;
493: else
494: a1->a_irq = 1;
495: if (dev & CFLOW) {
496: tp->t_flags |= T_CFLOW;
497: a1->a_flc = 1;
498: } else {
499: tp->t_flags &= ~T_CFLOW;
500: a1->a_flc = 0;
501: }
502: }
503: a1->a_in_use++;
504:
505: /*
506: * From here, error exit is bad_open_u.
507: */
508:
509: if (tp->t_open == 0) { /* not already open */
510: silo_t * in_silo = &a1->a_in;
511:
512: if (!(dev & CPOLL)) {
513: upd_irq1(a0->a_irqno);
514: a1->a_has_irq = 1;
515: }
516:
517: /*
518: * Need to start cycling to scan for CD.
519: */
520: asycycle(chan);
521:
522: s = sphi();
523: /*
524: * Raise basic modem control lines even if modem
525: * control hasn't been specified.
526: * MC_OUT2 turns on NON-open-collector IRQ line from the UART.
527: * since we can't have two UART's on same IRQ with MC_OUT2 on
528: */
529: mcr = MC_RTS | MC_DTR;
530: if (dev & CPOLL) {
531: outb(port+MCR, mcr);
532: } else {
533: outb(port+MCR, mcr | a0->a_outs);
534: outb(port+IER, IEN);
535: }
536:
537: if ((dev & NMODC) == 0) { /* want modem control? */
538: tp->t_flags |= T_HOPEN | T_STOP;
539: for (;;) { /* wait for carrier */
540: msr = inb(port+MSR);
541: /*
542: * If carrier detect present
543: * if port not already open
544: * break out of loop and finish first open
545: * else
546: * do second (or third, etc.) open
547: */
548: if (msr & MS_RLSD)
549: break;
550: /* wait for carrier */
551: #ifdef _I386
552: x_sleep((char *)(&tp->t_open), pritty,
553: slpriSigCatch, "need CD");
554: #else
555: v_sleep((char *)(&tp->t_open), CVTTOUT, IVTTOUT,
556: SVTTOUT, "need CD");
557: #endif
558: if (SELF->p_ssig && nondsig()) { /* signal? */
559: outb(port+MCR, 0);
560: outb(port+IER, 0);
561: u.u_error = EINTR;
562: tp->t_flags &= ~(T_HOPEN | T_STOP);
563: spl(s);
564: goto bad_open_u;
565: }
566: }
567:
568: /*
569: * Mark that we are no longer hanging in open.
570: * Allow output over the port unless hardware flow
571: * control says not to.
572: */
573: tp->t_flags &= ~T_HOPEN;
574: tp->t_flags &= ~T_STOP;
575: if (!(tp->t_flags & T_CFLOW) || (msr & MS_CTS))
576: a1->a_ohlt = 0;
577: else
578: a1->a_ohlt = 1;
579:
580: /*
581: * Awaken any other opens on same device.
582: */
583: wakeup((char *)(&tp->t_open));
584: }
585: ttopen(tp); /* stty inits */
586: tp->t_flags |= T_CARR;
587: if (ASY_HPCL)
588: tp->t_flags |= T_HPCL;
589:
590: asyparam(tp); /* gimmick: do this while t_open is zero */
591:
592: /*
593: * TO DO: flush UART input register(s).
594: */
595:
596: spl(s);
597:
598: /*
599: * Turn on polling for the port.
600: */
601: if (dev & CPOLL) {
602: a1->a_poll = 1;
603: asyspr();
604: }
605: } /* end of first-open case */
606:
607: tp->t_open++;
608: T_HAL(0x400, printf("ch%d open + %d\n", chan, tp->t_open));
609: ttsetgrp(tp, dev, mode);
610:
611: return;
612:
613: bad_open_u:
614: a1->a_in_use--;
615: wakeup((char *)(&tp->t_open));
616: bad_open:
617: return;
618: }
619:
620: /*
621: * asyclose()
622: */
623: static void
624: asyclose(dev, mode)
625: dev_t dev;
626: int mode;
627: {
628: int chan = channel(dev);
629: asy0_t *a0 = asy0 + chan;
630: asy1_t *a1 = asy1 + chan;
631: TTY *tp = &a1->a_tty;
632: silo_t * out_silo = &a1->a_out;
633: silo_t * in_silo = &a1->a_in;
634: int flags, maj;
635: int s;
636: short port = a0->a_port;
637: char lsr;
638:
639: if (--tp->t_open)
640: goto not_last_close;
641: T_HAL(0x400, printf("ch%d open - %d\n", chan, tp->t_open));
642: s = sphi();
643:
644: a1->a_hcls = 1; /* disallow reopen til done closing */
645: flags = tp->t_flags; /* save flags - ttclose zeroes them */
646: ttclose(tp);
647:
648: /*
649: * Wait for output silo and UART xmit buffer to empty.
650: * Allow signal to break the sleep.
651: */
652: for (;;) {
653: int chipEmpty = 0, siloEmpty = 0;
654:
655: lsr = inb(port + LSR);
656: chipEmpty = (lsr & LS_TxIDLE);
657: T_HAL(0x400, printf("ch%d chipEmpty=%d\n", chan, chipEmpty));
658: siloEmpty = (out_silo->si_ix == out_silo->si_ox);
659: T_HAL(0x400, printf("ch%d siloEmpty=%d\n", chan, siloEmpty));
660:
661: if (chipEmpty && siloEmpty)
662: break;
663: need_wake[chan] |= NW_OUTSILO;
664: #ifdef _I386
665: x_sleep((char *)out_silo, pritty, slpriSigCatch, "asyclose");
666: #else
667: v_sleep((char *)out_silo, CVTTOUT, IVTTOUT, SVTTOUT,
668: "asyclose");
669: #endif
670: if (SELF->p_ssig && nondsig()) { /* signal? */
671: RAWOUT_FLUSH(out_silo);
672: break;
673: }
674: }
675: need_wake[chan] &= ~NW_OUTSILO;
676:
677: /*
678: * If not hanging in open
679: */
680: if ((flags & T_HOPEN) == 0) {
681: /*
682: * Disable interrupts.
683: */
684: outb(port+IER, 0);
685: outb(port+MCR, inb(port+MCR) & ~MC_OUTS);
686: }
687:
688: /*
689: * If hupcls
690: */
691: if (flags & T_HPCL) {
692: T_HAL(0x400, printf("ch%d drop DTR\n", chan));
693: /*
694: * Hangup port - drop DTR and RTS.
695: */
696: outb(port+MCR, inb(port+MCR) & MC_OUTS);
697:
698: /*
699: * Hold dtr low for timeout
700: */
701: maj = major(dev);
702: drvl[maj].d_time = 1;
703: #ifdef _I386
704: x_sleep((char *)&drvl[maj].d_time, pritty, slpriNoSig,
705: "drop DTR");
706: #else
707: v_sleep((char *)&drvl[maj].d_time, CVTTOUT, IVTTOUT, SVTTOUT,
708: "drop DTR");
709: #endif
710: drvl[maj].d_time = 0;
711: }
712:
713: a1->a_poll = 0;
714: asyspr();
715: RAWIN_FLUSH(in_silo);
716: a1->a_hcls = 0; /* allow reopen - done closing */
717: wakeup((char *)(&tp->t_open));
718: spl(s);
719: a1->a_in_use--;
720:
721: if (!(dev & CPOLL))
722: upd_irq1(a0->a_irqno);
723: return;
724:
725: not_last_close:
726: T_HAL(0x400, printf("ch%d open - %d\n", chan, tp->t_open));
727: a1->a_in_use--;
728: wakeup((char *)(&tp->t_open));
729: return;
730: }
731:
732: /*
733: * asyread()
734: */
735: static void
736: asyread(dev, iop)
737: dev_t dev;
738: register IO * iop;
739: {
740: int chan = channel(dev);
741: asy1_t *a1 = asy1 + chan;
742: TTY *tp = &a1->a_tty;
743:
744: ttread(tp, iop);
745: }
746:
747: /*
748: * asytimer()
749: */
750: static void
751: asytimer(dev)
752: dev_t dev;
753: {
754: if (++drvl[major(dev)].d_time > DTRTMOUT)
755: wakeup((char *)&drvl[major(dev)].d_time);
756: }
757:
758: /*
759: * asywrite()
760: */
761: static void
762: asywrite(dev, iop)
763: dev_t dev;
764: register IO * iop;
765: {
766: int chan = channel(dev);
767: asy0_t *a0 = asy0 + chan;
768: asy1_t *a1 = asy1 + chan;
769: TTY *tp = &a1->a_tty;
770: short port = a0->a_port;
771: register int c;
772:
773: /*
774: * Treat user writes through tty driver.
775: */
776: if (iop->io_seg != IOSYS) {
777: ttwrite(tp, iop);
778: return;
779: }
780:
781: /*
782: * Treat kernel writes by blocking on transmit buffer.
783: */
784: while ((c = iogetc(iop)) >= 0) {
785: /*
786: * Wait until transmit buffer is empty.
787: * Check twice to prevent critical race with interrupt handler.
788: */
789: for (;;) {
790: if (inb(port+LSR) & LS_TxRDY)
791: if (inb(port+LSR) & LS_TxRDY)
792: break;
793: }
794:
795: /*
796: * Output the next character.
797: */
798: outb(port+DREG, c);
799: }
800: }
801:
802: /*
803: * asyioctl()
804: */
805: static void
806: asyioctl(dev, com, vec)
807: dev_t dev;
808: int com; struct sgttyb *vec;
809: {
810: int chan = channel(dev);
811: asy0_t *a0 = asy0 + chan;
812: asy1_t *a1 = asy1 + chan;
813: TTY *tp = &a1->a_tty;
814: int s;
815: int temp;
816: silo_t *out_silo = &a1->a_out;
817: silo_t *in_silo = &a1->a_in;
818: short port = a0->a_port;
819: unsigned char msr, mcr, lcr, ier;
820: char do_ttioctl = 0;
821: char do_asyparam = 0;
822:
823: s = sphi();
824: ier = inb(port+IER);
825: mcr = inb(port+MCR); /* get current MCR register status */
826: lcr = inb(port+LCR); /* get current LCR register status */
827:
828: #ifdef _I386
829: /*
830: * If command will drain output, do the drain now
831: * before calling ttioctl().
832: * Don't do this for 286 kernel: we're running out of code space.
833: */
834: switch(com) {
835: case TCSETAW:
836: case TCSETAF:
837: case TCSBRK:
838: case TIOCSETP:
839: /*
840: * Wait for output silo and UART xmit buffer to empty.
841: * Allow signal to break the sleep.
842: */
843: for (;;) {
844: if (!ttoutp(tp)
845: && (out_silo->si_ix == out_silo->si_ox)
846: && (inb(port + LSR) & LS_TxIDLE))
847: break;
848: need_wake[chan] |= NW_OUTSILO;
849: #ifdef _I386
850: x_sleep((char *)out_silo, pritty, slpriSigCatch,
851: "asydrain");
852: #else
853: v_sleep((char *)out_silo, CVTTOUT, IVTTOUT, SVTTOUT,
854: "asydrain");
855: #endif
856: if (SELF->p_ssig && nondsig()) { /* signal? */
857: break;
858: }
859: }
860: need_wake[chan] &= ~NW_OUTSILO;
861: }
862: #endif
863:
864: switch(com) {
865: case TIOCSBRK: /* set BREAK */
866: outb(port+LCR, lcr|LC_SBRK);
867: break;
868: case TIOCCBRK: /* clear BREAK */
869: outb(port+LCR, lcr & ~LC_SBRK);
870: break;
871: case TIOCSDTR: /* set DTR */
872: outb(port+MCR, mcr|MC_DTR);
873: break;
874: case TIOCCDTR: /* clear DTR */
875: outb(port+MCR, mcr & ~MC_DTR);
876: break;
877: case TIOCSRTS: /* set RTS */
878: outb(port+MCR, mcr|MC_RTS);
879: break;
880: case TIOCCRTS: /* clear RTS */
881: outb(port+MCR, mcr & ~MC_RTS);
882: break;
883: case TIOCRSPEED: /* set "raw" I/O speed divisor */
884: outb(port+LCR, lcr|LC_DLAB); /* set speed latch bit */
885: outb(port+DLL, (unsigned) vec);
886: outb(port+DLH, (unsigned) vec >> 8);
887: outb(port+LCR, lcr); /* reset latch bit */
888: break;
889: case TIOCWORDL: /* set word length and stop bits */
890: outb(port+LCR, ((lcr&~0x7) | ((unsigned) vec & 0x7)));
891: break;
892: case TIOCRMSR: /* get CTS/DSR/RI/RLSD (MSR) */
893: msr = inb(port+MSR);
894: temp = msr >> 4;
895: kucopy(&temp, (unsigned *) vec, sizeof(unsigned));
896: break;
897: case TIOCFLUSH: /* Flush silos here, queues in tty.c */
898: RAWIN_FLUSH(in_silo);
899: RAWOUT_FLUSH(out_silo);
900: do_ttioctl = 1;
901: break;
902:
903: /*
904: * If port parameters change, plan to call asyparam().
905: * Need to check now before structs are updated.
906: */
907: #ifdef _I386
908: case TCSETA:
909: case TCSETAW:
910: case TCSETAF:
911: {
912: struct termio trm;
913:
914: ukcopy(vec, &trm, sizeof(struct termio));
915: if (trm.c_cflag != tp->t_termio.c_cflag)
916: do_asyparam = 1;
917: }
918: do_ttioctl = 1;
919: break;
920: #endif
921: case TIOCSETP:
922: case TIOCSETN:
923: {
924: struct sgttyb sg;
925:
926: ukcopy(vec, &sg, sizeof(struct sgttyb));
927: if (sg.sg_ispeed != tp->t_sgttyb.sg_ispeed
928: || ((sg.sg_flags ^ tp->t_sgttyb.sg_flags) & ANYP))
929: do_asyparam = 1;
930: }
931: do_ttioctl = 1;
932: break;
933: default:
934: do_ttioctl = 1;
935: }
936: outb(port+IER, ier);
937: if (do_ttioctl)
938: ttioctl(tp, com, vec);
939: spl(s);
940: if (do_asyparam)
941: asyparam(tp);
942: #ifdef _I386
943: /*
944: * Things to be done after calling ttioctl().
945: */
946: switch(com) {
947: case TCSBRK:
948: /*
949: * Send 0.25 second break:
950: * 1. Turn on break level.
951: * 2. Set timer to turn off break level 0.25 sec later.
952: * 3. Sleep till timer expires.
953: * 4. Turn off break level.
954: */
955: outb(port+LCR, lcr|LC_SBRK);
956: a1->a_brk = 1;
957: timeout(&tp->t_sbrk, HZ/4, endbrk, chan);
958: while(a1->a_brk) {
959: #ifdef _I386
960: x_sleep(a1, pritty, slpriNoSig, "asybreak");
961: #else
962: v_sleep(a1, CVTTOUT, IVTTOUT, SVTTOUT, "asybreak");
963: #endif
964: }
965: outb(port+LCR, lcr & ~LC_SBRK);
966: }
967: #endif
968: }
969:
970: #ifdef _I386
971: /*
972: * Turn off the break level.
973: * Called from timeout after ioctl(fd, TCSBRK, 0).
974: */
975: void
976: endbrk(chan)
977: int chan;
978: {
979: asy1_t *a1 = asy1 + chan;
980:
981: a1->a_brk = 0;
982: wakeup(a1);
983: }
984: #endif
985:
986: /*
987: * asyparam()
988: */
989: static void
990: asyparam(tp)
991: TTY * tp;
992: {
993: int chan = (int)tp->t_ddp;
994: asy0_t *a0 = asy0 + chan;
995: asy1_t *a1 = asy1 + chan;
996: short port = a0->a_port;
997: int s;
998: int write_baud=1, write_lcr=1;
999: unsigned char mcr, newlcr, speed, oldSpeed;
1000:
1001: #ifdef _I386
1002: unsigned short cflag = tp->t_termio.c_cflag;
1003:
1004: T_HAL(4, printf("ch%d asyparam cflag=%x\n", chan, cflag));
1005: speed = cflag & CBAUD;
1006: switch (cflag & CSIZE) {
1007: case CS5: newlcr = LC_CS5; break;
1008: case CS6: newlcr = LC_CS6; break;
1009: case CS7: newlcr = LC_CS7; break;
1010: case CS8: newlcr = LC_CS8; break;
1011: }
1012: if (cflag & CSTOPB)
1013: newlcr |= LC_STOPB;
1014: if (cflag & PARENB) {
1015: newlcr |= LC_PARENB;
1016: if ((cflag & PARODD) == 0)
1017: newlcr |= LC_PAREVEN;
1018: }
1019: #else
1020: speed = tp->t_sgttyb.sg_ispeed;
1021: switch (tp->t_sgttyb.sg_flags & (EVENP|ODDP|RAW)) {
1022: case ODDP:
1023: newlcr = LC_CS7|LC_PARENB;
1024: break;
1025: case EVENP:
1026: newlcr = LC_CS7|LC_PARENB|LC_PAREVEN;
1027: break;
1028: default:
1029: newlcr = LC_CS8;
1030: break;
1031: }
1032: #endif
1033:
1034: /*
1035: * Don't bang on the UART needlessly.
1036: * Writing baud rate resets the port, which loses characters.
1037: * You want this on first open, NOT on later opens.
1038: */
1039: oldSpeed = a0->a_speed;
1040: if (speed == oldSpeed && tp->t_open) {
1041: write_baud = 0;
1042: if (newlcr == a1->a_lcr) {
1043: write_lcr = 0;
1044: }
1045: }
1046: a0->a_speed = speed;
1047: a1->a_lcr = newlcr;
1048:
1049: if (write_lcr) {
1050: char ier_save;
1051: s = sphi();
1052: ier_save = inb(port+IER);
1053: if (write_baud) {
1054: if (speed) {
1055: short divisor = albaud[speed];
1056:
1057: if (oldSpeed == 0) {
1058: /* if previous baud rate was zero,
1059: * need to go off hook. */
1060: mcr = inb(port+MCR) | (MC_RTS | MC_DTR);
1061: outb(port+MCR, mcr);
1062: }
1063: T_HAL(4, printf("CH%d speed=%x\n", chan, speed));
1064: outb(port+LCR, LC_DLAB);
1065: outb(port+DLL, divisor);
1066: outb(port+DLH, divisor >> 8);
1067: } else {
1068: /* Baud rate of zero means hang up. */
1069: mcr = inb(port+MCR) & ~(MC_RTS | MC_DTR);
1070: outb(port+MCR, mcr);
1071: }
1072: }
1073: T_HAL(4, printf("CH%d newlcr=%x\n", chan, newlcr));
1074: outb(port+LCR, newlcr);
1075: if (a1->a_ut == US_16550A)
1076: outb(port+FCR, FC_ENABLE | FC_Rx_RST | FC_Rx_08);
1077: outb(port+IER, ier_save);
1078: spl(s);
1079: }
1080: if (write_baud)
1081: asyspr();
1082: }
1083:
1084: /*
1085: * asystart()
1086: */
1087: static void
1088: asystart(tp)
1089: TTY * tp;
1090: {
1091: int chan = (int)tp->t_ddp;
1092: asy0_t *a0 = asy0 + chan;
1093: asy1_t *a1 = asy1 + chan;
1094: short port = a0->a_port;
1095: int s;
1096: int need_xmit = 1; /* True if should start sending data now. */
1097: silo_t *out_silo = &a1->a_out;
1098: char lsr;
1099:
1100: /*
1101: * Read line status register AFTER disabling interrupts.
1102: */
1103: s = sphi();
1104: lsr = inb(port + LSR);
1105:
1106: /*
1107: * Process break indication.
1108: * NOTE: Break indication cleared when line status register was read.
1109: */
1110: if (lsr & LS_BREAK)
1111: defer(asybreak, chan);
1112:
1113: /*
1114: * If no output data, it may be time to finish closing the port;
1115: * but won't need another xmit interrupt.
1116: */
1117: if (out_silo->si_ix == out_silo->si_ox) {
1118: if (need_wake[chan] & NW_OUTSILO) {
1119: need_wake[chan] &= ~NW_OUTSILO;
1120: wakeup((char *)out_silo);
1121: }
1122: need_xmit = 0;
1123: }
1124:
1125: /*
1126: * Do nothing if output is stopped.
1127: */
1128: if (tp->t_flags & T_STOP)
1129: need_xmit = 0;
1130: if (a1->a_ohlt)
1131: need_xmit = 0;
1132:
1133: /*
1134: * Start data transmission by writing to UART xmit reg.
1135: */
1136: if ((lsr & LS_TxRDY) && need_xmit) {
1137: int xmit_count;
1138: xmit_count = (a1->a_ut == US_16550A)?16:1;
1139: asy_send(out_silo, port+DREG, xmit_count);
1140: }
1141: spl(s);
1142: }
1143:
1144: /*
1145: * asypoll()
1146: */
1147: static int
1148: asypoll(dev, ev, msec)
1149: dev_t dev;
1150: int ev;
1151: int msec;
1152: {
1153: int chan = channel(dev);
1154: asy1_t *a1 = asy1 + chan;
1155: TTY *tp = &a1->a_tty;
1156:
1157: return ttpoll(tp, ev, msec);
1158: }
1159:
1160: /*
1161: * asycycle()
1162: *
1163: * Do a wakeup of any sleeping asy's at regular intervals.
1164: */
1165: static void
1166: asycycle(chan)
1167: int chan;
1168: {
1169: asy0_t *a0 = asy0 + chan;
1170: asy1_t *a1 = asy1 + chan;
1171: TTY *tp = &a1->a_tty;
1172: short port = a0->a_port;
1173: int s;
1174: char msr, mcr;
1175: silo_t *out_silo = &a1->a_out;
1176: silo_t *in_silo = &a1->a_in;
1177: int n, ch;
1178: int do_start = 1;
1179: unsigned char iir;
1180:
1181: /*
1182: * Check Carrier Detect (RLSD).
1183: *
1184: * Modem status interrupts were not enabled due to 8250 hardware bug.
1185: * Enabling modem status and receive interrupts may cause lockup
1186: * on older parts.
1187: */
1188: if (tp->t_flags & T_MODC) {
1189:
1190: /*
1191: * Get status
1192: */
1193: msr = inb(port+MSR);
1194:
1195: /*
1196: * Carrier changed.
1197: */
1198: if ((msr & MS_RLSD) && !(tp->t_flags & T_CARR)) {
1199: /*
1200: * Carrier is on - wakeup open.
1201: */
1202: s = sphi();
1203: tp->t_flags |= T_CARR;
1204: spl(s);
1205: wakeup((char *)(&tp->t_open));
1206: }
1207:
1208: if (!(msr & MS_RLSD) && (tp->t_flags & T_CARR)) {
1209: s = sphi();
1210: RAWIN_FLUSH(in_silo);
1211: RAWOUT_FLUSH(out_silo);
1212: tp->t_flags &= ~T_CARR;
1213: spl(s);
1214: tthup(tp);
1215: }
1216: }
1217:
1218: /*
1219: * Empty raw input buffer.
1220: *
1221: * The line discipline module (tty.c) will set T_ISTOP true when the
1222: * tt input queue is nearly full (tp->t_iq.cq_cc >= IHILIM), and make
1223: * T_ISTOP false when it's ready for more input.
1224: *
1225: * When T_ISTOP is true, ttin() simply discards the character passed.
1226: */
1227: if (!(tp->t_flags & T_ISTOP)) {
1228: while (in_silo->SILO_CHAR_COUNT > 0) {
1229: s = sphi();
1230: ttin(tp, in_silo->si_buf[in_silo->si_ox]);
1231: if (in_silo->si_ox < MAX_SILO_INDEX)
1232: in_silo->si_ox++;
1233: else
1234: in_silo->si_ox = 0;
1235: in_silo->SILO_CHAR_COUNT--;
1236: spl(s);
1237: }
1238: }
1239:
1240: /*
1241: * Hardware flow control.
1242: * Check CTS to see if we need to halt output.
1243: * (MS_INTR should have done this - repeat code here to be sure)
1244: * Check input silo to see if we need to raise RTS.
1245: */
1246: if (tp->t_flags & T_CFLOW) {
1247:
1248: /*
1249: * Get status
1250: */
1251: msr = inb(port+MSR);
1252: s = sphi();
1253: if (msr & MS_CTS)
1254: a1->a_ohlt = 0;
1255: else
1256: a1->a_ohlt = 1;
1257: spl(s);
1258: T_HAL(4, {static cts = 0; if (!cts && (msr & MS_CTS)) { cts = 1; putchar('[');\
1259: } else if (cts && !(msr & MS_CTS)) { cts = 0; putchar(']'); }});
1260:
1261: /*
1262: * If using hardware flow control, see if we need to drop RTS.
1263: */
1264: if ((tp->t_flags & T_CFLOW)
1265: && (in_silo->SILO_CHAR_COUNT > SILO_HIGH_MARK)) {
1266: s = sphi();
1267: mcr = inb(port+MCR);
1268: if (mcr & MC_RTS) {
1269: outb(port+MCR, mcr & ~MC_RTS);
1270: T_HAL(4, putchar('-'));
1271: }
1272: spl(s);
1273: }
1274:
1275: /*
1276: * If input silo below low mark, assert RTS.
1277: */
1278: if (in_silo->SILO_CHAR_COUNT <= SILO_LOW_MARK) {
1279: s = sphi();
1280: mcr = inb(port+MCR);
1281: if ((mcr & MC_RTS) == 0) {
1282: outb(port+MCR, mcr | MC_RTS);
1283: T_HAL(4, putchar('+'));
1284: }
1285: spl(s);
1286: }
1287: }
1288:
1289: /*
1290: * Calculate free output slot count.
1291: */
1292: n = sizeof(out_silo->si_buf) - 1;
1293: n += out_silo->si_ox - out_silo->si_ix;
1294: n %= sizeof(out_silo->si_buf);
1295:
1296: /*
1297: * Fill raw output buffer.
1298: */
1299: for (;;) {
1300: if (--n < 0)
1301: break;
1302: s = sphi();
1303: ch = ttout(tp);
1304: spl(s);
1305: if (ch < 0)
1306: break;
1307:
1308: s = sphi();
1309: out_silo->si_buf[out_silo->si_ix] = ch;
1310: if (out_silo->si_ix >= sizeof(out_silo->si_buf) - 1)
1311: out_silo->si_ix = 0;
1312: else
1313: out_silo->si_ix++;
1314: spl(s);
1315: }
1316:
1317: #ifdef _I386
1318: /*
1319: * if port has an interrupt pending (probably missed an irq)
1320: * the following two loops should not be merged
1321: * - need ALL port irq's inactive at once
1322: * for each port on this irq line (use irq1 for this)
1323: * disable interrupts (clear IER)
1324: * for each port on this irq line
1325: * restore interrupts
1326: */
1327: if (a1->a_has_irq && ((iir=inb(port+IIR)) & 1) == 0) {
1328: struct irqnode *ip;
1329: asy_gp_t *gp;
1330: int s;
1331: short p;
1332: char c, slot;
1333:
1334: T_HAL(4, printf("CH%d missed iir:x\n", chan, iir));
1335:
1336: do_start = 0;
1337: s = sphi();
1338: ip = irq1[a0->a_irqno];
1339: while(ip) {
1340: if (ip->func == asyintr) {
1341: p = ip->arg;
1342: outb(p + IER, 0);
1343: } else {
1344: gp = asy_gp + ip->arg;
1345: for (slot = 0; slot < MAX_SLOTS; slot++) {
1346: if ((c=gp->chan_list[slot]) < MAX_ASY){
1347: p = asy0[c].a_port;
1348: outb(p + IER, 0);
1349: }
1350: }
1351: }
1352: ip = ip->next_actv;
1353: }
1354: /*
1355: * Now, all ports on the offending irq line have irq off.
1356: */
1357: ip = irq1[a0->a_irqno];
1358: while(ip) {
1359: if (ip->func == asyintr) {
1360: p = ip->arg;
1361: outb(p + IER, IEN);
1362: } else {
1363: gp = asy_gp + ip->arg;
1364: for (slot = 0; slot < MAX_SLOTS; slot++) {
1365: if ((c=gp->chan_list[slot]) < MAX_ASY){
1366: p = asy0[c].a_port;
1367: outb(p + IER, IEN);
1368: }
1369: }
1370: }
1371: ip = ip->next_actv;
1372: }
1373: spl(s);
1374: }
1375: #endif
1376:
1377: if(do_start)
1378: ttstart(tp);
1379:
1380: /*
1381: * Schedule next cycle.
1382: */
1383: if (a1->a_in_use) {
1384: timeout(&tp->t_rawtim, HZ/10, asycycle, chan);
1385: }
1386: }
1387:
1388: /*
1389: * irqdummy()
1390: *
1391: * Suppress interrupts that may occur during chip sensing.
1392: */
1393: static void
1394: irqdummy()
1395: {
1396: /*
1397: * Try to clear all pending interrupts.
1398: */
1399: inb(dummy_port+IIR);
1400: inb(dummy_port+LSR);
1401: inb(dummy_port+MSR);
1402: inb(dummy_port+DREG);
1403: }
1404:
1405: /*
1406: * add_irq()
1407: *
1408: * Given channel number, add port info to irq0 list.
1409: */
1410: static void
1411: add_irq(irq, func, arg)
1412: int irq;
1413: void (*func)();
1414: int arg;
1415: {
1416: struct irqnode * np;
1417:
1418: /*
1419: * Sanity check.
1420: */
1421: if (irq <=0 || irq >= NUM_IRQ || itbl[irq] == 0)
1422: return;
1423:
1424: if (nextnode < MAX_ASY) {
1425: np = nodespace + nextnode++;
1426: np->func = func;
1427: np->arg = arg;
1428: np->next = irq0[irq];
1429: irq0[irq] = np;
1430: } else {
1431: printf("asy: too many irq nodes (%d)\n", nextnode);
1432: }
1433: }
1434:
1435: /*
1436: * Interrupt handlers.
1437: */
1438: static void i2() { asy_irq(irq1[2]); }
1439: static void i3() { asy_irq(irq1[3]); }
1440: static void i4() { asy_irq(irq1[4]); }
1441: static void i5() { asy_irq(irq1[5]); }
1442: static void i6() { asy_irq(irq1[6]); }
1443: static void i7() { asy_irq(irq1[7]); }
1444: static void i8() { asy_irq(irq1[8]); }
1445: static void i9() { asy_irq(irq1[9]); }
1446: static void i10() { asy_irq(irq1[10]); }
1447: static void i11() { asy_irq(irq1[11]); }
1448: static void i12() { asy_irq(irq1[12]); }
1449: static void i13() { asy_irq(irq1[13]); }
1450: static void i14() { asy_irq(irq1[14]); }
1451: static void i15() { asy_irq(irq1[15]); }
1452:
1453: /*
1454: * asy_irq()
1455: *
1456: * Given pointer to node list, service async interrupt.
1457: */
1458: static void
1459: asy_irq(ip)
1460: struct irqnode * ip;
1461: {
1462: struct irqnode *here;
1463: int doit;
1464:
1465: do {
1466: doit = 0;
1467: here = ip;
1468: while(here) {
1469: doit |= (*(here->func))(here->arg);
1470: here = here->next_actv;
1471: }
1472: } while(doit);
1473: }
1474:
1475: /*
1476: * upd_irq1()
1477: *
1478: * Given an irq number, rebuild the links for active devices.
1479: */
1480: static void
1481: upd_irq1(irq)
1482: int irq;
1483: {
1484: struct irqnode *np;
1485: asy1_t *a1;
1486: int chan;
1487: int s;
1488:
1489: /*
1490: * Sanity check.
1491: */
1492: if (irq <=0 || irq >= NUM_IRQ || itbl[irq] == 0)
1493: return;
1494:
1495: /*
1496: * For each node in the irq0 list
1497: * if node is for irq status port
1498: * for each channel using the status port
1499: * if channel in use, in irq mode
1500: * add node to irq1 list
1501: * skip rest of channels for this node
1502: * else - node is for simple UART
1503: * if channel in use, in irq mode
1504: * add node to irq1 list
1505: */
1506: s = sphi();
1507: np = irq0[irq];
1508: irq1[irq] = 0;
1509: while (np) {
1510: if (np->func != asyintr) {
1511: char ix, loop = 1;
1512: asy_gp_t *gp = asy_gp + np->arg;
1513:
1514: for (ix = 0; ix < MAX_SLOTS && loop; ix++) {
1515: if ((chan = gp->chan_list[ix]) < MAX_ASY) {
1516: a1 = asy1 + chan;
1517: if (a1->a_in_use && a1->a_irq) {
1518: np->next_actv = irq1[irq];
1519: irq1[irq] = np;
1520: loop = 0;
1521: }
1522: }
1523: }
1524: } else {
1525: a1 = asy1 + np->arg;
1526: if (a1->a_in_use && a1->a_irq) {
1527: np->next_actv = irq1[irq];
1528: irq1[irq] = np;
1529: }
1530: }
1531: np = np->next;
1532: }
1533: spl(s);
1534: }
1535:
1536: /*
1537: * asybreak()
1538: */
1539: static void
1540: asybreak(chan)
1541: int chan;
1542: {
1543: int s;
1544: asy1_t *a1 = asy1 + chan;
1545: silo_t *out_silo = &a1->a_out;
1546: silo_t *in_silo = &a1->a_in;
1547: TTY *tp = &a1->a_tty;
1548:
1549: s = sphi();
1550: RAWIN_FLUSH(in_silo);
1551: RAWOUT_FLUSH(out_silo);
1552: spl(s);
1553: ttsignal(tp, SIGINT);
1554: }
1555:
1556: /*
1557: * asyintr()
1558: *
1559: * Handle interrupt for a single channel.
1560: */
1561: static int
1562: asyintr(chan)
1563: int chan;
1564: {
1565: asy0_t *a0 = asy0 + chan;
1566: asy1_t *a1 = asy1 + chan;
1567: TTY *tp = &a1->a_tty;
1568: silo_t *out_silo = &a1->a_out;
1569: silo_t *in_silo = &a1->a_in;
1570: int c, xmit_count;
1571: int ret = 0;
1572: short port = a0->a_port;
1573: unsigned char msr, lsr;
1574:
1575: if (chan >= MAX_ASY) {
1576: printf("asy: irq on channel %d\n", chan);
1577: return 0;
1578: }
1579:
1580: rescan:
1581: switch (inb(port+IIR) & 0x07) {
1582:
1583: case LS_INTR:
1584: ret = 1;
1585: lsr = inb(port + LSR);
1586: T_HAL(0x800, printf("[%d:L%x]", chan, lsr));
1587: if (lsr & LS_BREAK)
1588: defer(asybreak, chan);
1589: goto rescan;
1590:
1591: case Rx_INTR:
1592: T_HAL(0x800, printf("[%d:R]", chan));
1593: ret = 1;
1594: c = inb(port+DREG);
1595: if (tp->t_open == 0)
1596: goto rescan;
1597: /*
1598: * Must recognize XOFF quickly to avoid transmit overrun.
1599: * Recognize XON here as well to avoid race conditions.
1600: */
1601: if (ISIXON) {
1602: /*
1603: * XON.
1604: */
1605: #if _I386
1606: if (ISSTART || (ISIXANY && ISXSTOP)) {
1607: tp->t_flags &= ~(T_STOP | T_XSTOP);
1608: goto rescan;
1609: }
1610: #else
1611: if (ISSTART) {
1612: tp->t_flags &= ~T_STOP;
1613: goto rescan;
1614: }
1615: #endif
1616:
1617: /*
1618: * XOFF.
1619: */
1620: if (ISSTOP) {
1621: tp->t_flags |= T_STOP;
1622: goto rescan;
1623: }
1624: }
1625:
1626: /*
1627: * Save char in raw input buffer.
1628: */
1629: if (in_silo->SILO_CHAR_COUNT < MAX_SILO_CHARS) {
1630: in_silo->si_buf[in_silo->si_ix] = c;
1631: if (in_silo->si_ix < MAX_SILO_INDEX)
1632: in_silo->si_ix++;
1633: else
1634: in_silo->si_ix = 0;
1635: in_silo->SILO_CHAR_COUNT++;
1636: }
1637:
1638: /*
1639: * If using hardware flow control, see if we need to drop RTS.
1640: */
1641: if ((tp->t_flags & T_CFLOW)
1642: && (in_silo->SILO_CHAR_COUNT > SILO_HIGH_MARK)) {
1643: unsigned char mcr = inb(port+MCR);
1644: if (mcr & MC_RTS) {
1645: outb(port+MCR, mcr & ~MC_RTS);
1646: }
1647: }
1648:
1649: goto rescan;
1650:
1651: case Tx_INTR:
1652: T_HAL(0x800, printf("[%d:T]", chan));
1653: ret = 1;
1654: /*
1655: * Do nothing if output is stopped.
1656: */
1657: if (tp->t_flags & T_STOP) {
1658: goto rescan;
1659: }
1660: if (a1->a_ohlt)
1661: goto rescan;
1662:
1663: /*
1664: * Transmit next char in raw output buffer.
1665: */
1666: xmit_count = (a1->a_ut == US_16550A)?16:1;
1667: asy_send(out_silo, port+DREG, xmit_count);
1668: goto rescan;
1669:
1670: case MS_INTR:
1671: ret = 1;
1672: /*
1673: * Get status (and clear interrupt).
1674: */
1675: msr = inb(port+MSR);
1676: T_HAL(0x800, printf("[%d:M%x]", chan, msr));
1677:
1678: /*
1679: * Hardware flow control.
1680: * Check CTS to see if we need to halt output.
1681: */
1682: if (tp->t_flags & T_CFLOW) {
1683: if (msr & MS_CTS)
1684: a1->a_ohlt = 0;
1685: else
1686: a1->a_ohlt = 1;
1687: }
1688:
1689: goto rescan;
1690: default:
1691: return ret;
1692: } /* endswitch */
1693: }
1694:
1695: /*
1696: * asyclk()
1697: *
1698: * Called every time T0 interrupts.- if it returns 0,
1699: * the usual system timer interrupt stuff is done.
1700: * Poll all pollable ports.
1701: */
1702: static int
1703: asyclk()
1704: {
1705: static int count;
1706: int ix;
1707:
1708: for (ix = 0; ix < ppnum; ix++)
1709: asysph(pptbl[ix]);
1710:
1711: count++;
1712: if (count >= poll_divisor)
1713: count = 0;
1714: return count;
1715: }
1716:
1717: /*
1718: * asyspr()
1719: *
1720: * asyspr is called when a port is opened or closed or changes speed
1721: * It sets the polling rate only as fast as needed, and shuts off polling
1722: * whenever possible.
1723: * It updates the links in irq1[0], which lists polled-mode ports.
1724: */
1725: static void
1726: asyspr()
1727: {
1728: asy0_t *a0;
1729: asy1_t *a1;
1730: int chan;
1731: int s;
1732: int ix, max_rate, port_rate;
1733:
1734: /*
1735: * Rebuild table of pollable ports.
1736: */
1737: s = sphi();
1738: ppnum = 0;
1739: for (chan = 0; chan < ASY_NUM; chan++) {
1740: a1 = asy1 + chan;
1741: if (a1->a_poll)
1742: pptbl[ppnum++] = chan;
1743: }
1744: spl(s);
1745:
1746: /*
1747: * If another driver has the polling clock, do nothing.
1748: */
1749: if (poll_owner & ~ POLL_ASY)
1750: return;
1751:
1752: /*
1753: * Find highest valid polling rate in units of HZ/10.
1754: * If using FIFO chip, can poll at 1/16 the usual rate.
1755: */
1756: max_rate = 0;
1757: for (ix = 0; ix < ppnum; ix++) {
1758: chan = pptbl[ix];
1759: a0 = asy0 + chan;
1760: a1 = asy1 + chan;
1761: port_rate = alp_rate[a0->a_speed];
1762: if (a1->a_ut == US_16550A) {
1763: port_rate /= 16;
1764: if (port_rate % HZ)
1765: port_rate += HZ - (port_rate % HZ);
1766: }
1767: if (max_rate < port_rate)
1768: max_rate = port_rate;
1769: }
1770:
1771: /*
1772: * if max_rate is not current rate, adjust the system clock
1773: */
1774: if (max_rate != poll_rate) {
1775: poll_rate = max_rate;
1776: poll_divisor = poll_rate/HZ; /* used in asyclk() */
1777: altclk_out(); /* stop previous polling */
1778: poll_owner &= ~ POLL_ASY;
1779: if (poll_rate) { /* resume polling at new rate if needed */
1780: poll_owner |= POLL_ASY;
1781: altclk_in(poll_rate, asyclk);
1782: }
1783: }
1784: }
1785:
1786: /*
1787: * asysph()
1788: *
1789: * Serial polling handler.
1790: */
1791: static void
1792: asysph(chan)
1793: int chan;
1794: {
1795: asy0_t *a0 = asy0 + chan;
1796: asy1_t *a1 = asy1 + chan;
1797: TTY *tp = &a1->a_tty;
1798: silo_t *out_silo = &a1->a_out;
1799: silo_t *in_silo = &a1->a_in;
1800: int c, xmit_count;
1801: short port = a0->a_port;
1802: char lsr;
1803:
1804: /*
1805: * Check for received break first.
1806: * This status is wiped out on reading the LSR.
1807: */
1808: lsr = inb(port + LSR);
1809: if (lsr & LS_BREAK)
1810: defer(asybreak, chan);
1811:
1812: /*
1813: * Handle all incoming characters.
1814: */
1815: for (;;) {
1816: lsr = inb(port + LSR);
1817: if ((lsr & LS_RxRDY) == 0)
1818: break;
1819: c = inb(port+DREG);
1820: if (tp->t_open == 0)
1821: continue;
1822: /*
1823: * Must recognize XOFF quickly to avoid transmit overrun.
1824: * Recognize XON here as well to avoid race conditions.
1825: */
1826: if (ISIXON) {
1827: /*
1828: * XOFF.
1829: */
1830: if (ISSTOP) {
1831: tp->t_flags |= T_STOP;
1832: continue;
1833: }
1834:
1835: /*
1836: * XON.
1837: */
1838: if (ISSTART) {
1839: tp->t_flags &= ~T_STOP;
1840: continue;
1841: }
1842: }
1843:
1844: /*
1845: * Save char in raw input buffer.
1846: */
1847: if (in_silo->SILO_CHAR_COUNT < MAX_SILO_CHARS) {
1848: in_silo->si_buf[in_silo->si_ix] = c;
1849: if (in_silo->si_ix < MAX_SILO_INDEX)
1850: in_silo->si_ix++;
1851: else
1852: in_silo->si_ix = 0;
1853: in_silo->SILO_CHAR_COUNT++;
1854: }
1855:
1856: /*
1857: * If using hardware flow control, see if we need to drop RTS.
1858: */
1859: if ((tp->t_flags & T_CFLOW)
1860: && (in_silo->SILO_CHAR_COUNT > SILO_HIGH_MARK)) {
1861: unsigned char mcr = inb(port+MCR);
1862: if (mcr & MC_RTS) {
1863: outb(port+MCR, mcr & ~MC_RTS);
1864: }
1865: }
1866: }
1867:
1868: /*
1869: * Handle outgoing characters.
1870: * Do nothing if output is stopped.
1871: */
1872: lsr = inb(port + LSR);
1873: if ((lsr & LS_TxRDY)
1874: && !(tp->t_flags & T_STOP)
1875: && !(a1->a_ohlt)) {
1876: /*
1877: * Transmit next char in raw output buffer.
1878: */
1879: xmit_count = (a1->a_ut == US_16550A)?16:1;
1880: asy_send(out_silo, port+DREG, xmit_count);
1881: }
1882:
1883: /*
1884: * Hardware flow control.
1885: * Check CTS to see if we need to halt output.
1886: */
1887: if (tp->t_flags & T_CFLOW) {
1888: if (inb(port+MSR) & MS_CTS)
1889: a1->a_ohlt = 0;
1890: else
1891: a1->a_ohlt = 1;
1892: }
1893: }
1894:
1895: /*
1896: * asy_send()
1897: *
1898: * Write to xmit data register of the UART.
1899: * Assume all checking about whether it's time to send has been done already.
1900: * Called by time-critical IRQ and polling routines!
1901: *
1902: * "rawout" is the output silo for the TTY struct supplying data to the port.
1903: * "dreg" is the i/o address of the UART xmit data register.
1904: * "xmit_count" is the max number of chars we can write (16 for FIFO parts).
1905: */
1906: static int
1907: asy_send(rawout, dreg, xmit_count)
1908: register silo_t * rawout;
1909: int dreg, xmit_count;
1910: {
1911: /*
1912: * Transmit next chars in raw output buffer.
1913: */
1914: for (;(rawout->si_ix != rawout->si_ox) && xmit_count; xmit_count--) {
1915: outb(dreg, rawout->si_buf[rawout->si_ox]);
1916: /*
1917: * Adjust raw output buffer output index.
1918: */
1919: if (++rawout->si_ox >= sizeof(rawout->si_buf))
1920: rawout->si_ox = 0;
1921: }
1922: return xmit_count;
1923: }
1924:
1925: /*
1926: * p1()
1927: *
1928: * Interrupt handler for Comtrol-type port groups.
1929: * Status register has 1 in bit positions for interrupting ports.
1930: */
1931: static int
1932: p1(g)
1933: int g;
1934: {
1935: asy_gp_t *gp = asy_gp + g;
1936: short port = gp->stat_port;
1937: unsigned char status, index, chan;
1938: int safety = LOOP_LIMIT;
1939: int ret = 0;
1940:
1941: #if 0 /* DEBUG */
1942: static int pxstat[2][8];
1943: int ci;
1944: int change_found=0;
1945:
1946: for (ci=0; ci<1; ci++) {
1947: index = inb(port+ci);
1948: outb(port+ci, 0);
1949: if (index != pxstat[g][ci]) {
1950: if (!change_found) {
1951: change_found = 1;
1952: printf("<%d:", g);
1953: } else
1954: putchar(' ');
1955: printf("%x:%x", port+ci, index);
1956: pxstat[g][ci] = index;
1957: }
1958: }
1959: if (change_found)
1960: putchar('>');
1961: for (ci=0; ci<8; ci++)
1962: asyintr(4+ci);
1963: putchar('.');
1964: return 0;
1965: #endif /* DEBUG */
1966:
1967: /*
1968: * while any port is active
1969: * call simple interrupt handler for active channel
1970: */
1971: while (status = inb(port)) {
1972: ret = 1;
1973: index = 0;
1974: if (status & 0xf0) {
1975: status &= 0xf0;
1976: index +=4;
1977: } else
1978: status &= 0x0f;
1979: if (status & 0xcc) {
1980: status &= 0xcc;
1981: index +=2;
1982: } else
1983: status &= 0x33;
1984: if (status & 0xaa)
1985: index++;
1986: chan = gp->chan_list[index];
1987: asyintr(chan);
1988: if (safety-- == 0) {
1989: printf("asy: p1 runaway - status %x\n", status);
1990: break;
1991: }
1992: }
1993:
1994: return ret;
1995: }
1996:
1997: /*
1998: * p2()
1999: *
2000: * Interrupt handler for Arnet-type port groups.
2001: * Status register has 0 in bit positions for interrupting ports.
2002: */
2003: static int
2004: p2(g)
2005: int g;
2006: {
2007: asy_gp_t *gp = asy_gp + g;
2008: short port = gp->stat_port;
2009: unsigned char status, index, chan;
2010: int safety = LOOP_LIMIT;
2011: int ret = 0;
2012:
2013: /*
2014: * while any port is active
2015: * call simple interrupt handler for active channel
2016: */
2017: while (status = ~inb(port)) {
2018: ret = 1;
2019: index = 0;
2020: if (status & 0xf0) {
2021: status &= 0xf0;
2022: index +=4;
2023: } else
2024: status &= 0x0f;
2025: if (status & 0xcc) {
2026: status &= 0xcc;
2027: index +=2;
2028: } else
2029: status &= 0x33;
2030: if (status & 0xaa)
2031: index++;
2032: chan = gp->chan_list[index];
2033: asyintr(chan);
2034: if (safety-- == 0) {
2035: printf("asy: p2 runaway - status %x\n", status);
2036: break;
2037: }
2038: }
2039: return ret;
2040: }
2041:
2042: /*
2043: * p3()
2044: *
2045: * Interrupt handler for GTEK-type port groups.
2046: */
2047: static int
2048: p3(g)
2049: int g;
2050: {
2051: asy_gp_t *gp = asy_gp + g;
2052: short port = gp->stat_port;
2053: unsigned char index, chan;
2054:
2055: /*
2056: * Call simple interrupt handler for active channel.
2057: */
2058: index = inb(port) & 7;
2059: chan = gp->chan_list[index];
2060: return asyintr(chan);
2061: }
2062:
2063: /*
2064: * p4()
2065: *
2066: * Interrupt handler for DigiBoard-type port groups.
2067: */
2068: static int
2069: p4(g)
2070: int g;
2071: {
2072: asy_gp_t *gp = asy_gp + g;
2073: short port = gp->stat_port;
2074: unsigned char index, chan;
2075: int ret = 0;
2076: int safety = LOOP_LIMIT;
2077:
2078: /*
2079: * Status register has slot number for active port,
2080: * or 0xFF if no port is active.
2081: */
2082:
2083: for (;;) {
2084: index = inb(port);
2085: if (index == 0xFF)
2086: break;
2087: if (safety-- == 0) {
2088: printf("asy: p4 runaway - status %x\n", index);
2089: break;
2090: }
2091: ret = 1;
2092: chan = gp->chan_list[index&0xF];
2093: asyintr(chan);
2094: }
2095: return ret;
2096: }
2097:
2098: #ifdef TRACER
2099: void
2100: asydump(chan, tag)
2101: int chan;
2102: char *tag;
2103: {
2104: asy0_t *a0 = asy0 + chan;
2105: asy1_t *a1 = asy1 + chan;
2106: TTY *tp = &a1->a_tty;
2107:
2108: printf("ch=%d %s\n", chan, tag);
2109: printf("port=%x irqno=%x speed=%d ",
2110: a0->a_port, a0->a_irqno, a0->a_speed);
2111: printf("outs=%x gp=%d xcl=%d\n",
2112: a0->a_outs, a0->a_asy_gp, a0->a_ixc);
2113: printf("in_use=%d lcr=%x irq=%d has_irq=%d ",
2114: a1->a_in_use, a1->a_lcr, a1->a_irq, a1->a_has_irq);
2115: printf("hop=%d hcl=%d ", a1->a_hopn, a1->a_hcls);
2116: printf("opn=%d ier=%x\n", tp->t_open, inb(a0->a_port+IER));
2117: }
2118: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.