ast.c revision 1.7 1 /*
2 * Multi-port serial card interrupt demuxing support.
3 * Roland McGrath 3/20/94
4 * The author disclaims copyright and places this file in the public domain.
5 *
6 * Modified by: Charles Hannum, 3/22/94
7 *
8 * $Id: ast.c,v 1.7 1994/04/07 06:50:15 mycroft Exp $
9 */
10
11 #include <sys/param.h>
12 #include <sys/device.h>
13
14 #include <machine/pio.h>
15
16 #ifndef NEWCONFIG
17 #include <i386/isa/isa_device.h>
18 #endif
19 #include <i386/isa/isavar.h>
20
21 struct ast_softc {
22 struct device sc_dev;
23 struct intrhand sc_ih;
24
25 u_short sc_iobase;
26 int sc_alive; /* mask of slave units attached */
27 void *sc_slaves[4]; /* com device unit numbers */
28 };
29
30 int astprobe();
31 void astattach();
32 int astintr __P((struct ast_softc *));
33
34 struct cfdriver astcd = {
35 NULL, "ast", astprobe, astattach, DV_TTY, sizeof(struct ast_softc)
36 };
37
38 int
39 astprobe(parent, self, aux)
40 struct device *parent, *self;
41 void *aux;
42 {
43 struct isa_attach_args *ia = aux;
44
45 /*
46 * Do the normal com probe for the first UART and assume
47 * its presence means there is a multiport board there.
48 * XXX Needs more robustness.
49 */
50 ia->ia_iosize = 4 * 8;
51 return comprobe1(ia->ia_iobase);
52 }
53
54 struct ast_attach_args {
55 u_short aa_iobase;
56 int aa_slave;
57 };
58
59 int
60 astsubmatch(parent, self, aux)
61 struct device *parent, *self;
62 void *aux;
63 {
64 struct ast_softc *sc = (void *)parent;
65 struct ast_attach_args *aa = aux;
66 struct cfdata *cf = self->dv_cfdata;
67 int found, frobbed = 0;
68 #ifdef NEWCONFIG
69
70 #define cf_slave cf_loc[6]
71 if (cf->cf_slave != -1 && cf->cf_slave != aa->aa_slave)
72 return 0;
73 if (cf->cf_iobase == IOBASEUNK) {
74 frobbed = 1;
75 cf->cf_iobase = aa->aa_iobase;
76 }
77 #undef cf_slave
78 #else
79 struct isa_device *id = (void *)cf->cf_loc;
80
81 if (id->id_physid != -1 && id->id_physid != aa->aa_slave)
82 return 0;
83 if (id->id_iobase == 0) {
84 frobbed = 1;
85 id->id_iobase = aa->aa_iobase;
86 }
87 #endif
88 found = isasubmatch(parent, self, aux);
89 if (found) {
90 sc->sc_slaves[aa->aa_slave] = self;
91 sc->sc_alive |= 1 << aa->aa_slave;
92 }
93 /*
94 * If we changed the iobase, we have to set it back now, because it
95 * might be a clone device, and the iobase wouldn't get set properly on
96 * the next iteration.
97 */
98 #ifdef NEWCONFIG
99 if (frobbed)
100 cf->cf_iobase = IOBASEUNK;
101 #else
102 if (frobbed)
103 id->id_iobase = 0;
104 #endif
105 return found;
106 }
107
108 void
109 astattach(parent, self, aux)
110 struct device *parent, *self;
111 void *aux;
112 {
113 struct ast_softc *sc = (void *)self;
114 struct isa_attach_args *ia = aux;
115 struct ast_attach_args aa;
116
117 /*
118 * Enable the master interrupt.
119 */
120 sc->sc_iobase = ia->ia_iobase;
121 outb(sc->sc_iobase | 0x1f, 0x80);
122 printf("\n");
123
124 for (aa.aa_slave = 0, aa.aa_iobase = sc->sc_iobase;
125 aa.aa_slave < 4;
126 aa.aa_slave++, aa.aa_iobase += 8)
127 config_search(astsubmatch, self, &aa);
128
129 sc->sc_ih.ih_fun = astintr;
130 sc->sc_ih.ih_arg = sc;
131 sc->sc_ih.ih_level = IPL_TTY;
132 intr_establish(ia->ia_irq, &sc->sc_ih);
133 }
134
135 int
136 astintr(sc)
137 struct ast_softc *sc;
138 {
139 u_short iobase = sc->sc_iobase;
140 int alive = sc->sc_alive;
141 int bits;
142
143 bits = inb(iobase | 0x1f) & alive;
144 if (bits == alive)
145 return 0;
146
147 do {
148 #define TRY(n) \
149 if ((bits & (1 << (n))) == 0) \
150 comintr(sc->sc_slaves[n]);
151 TRY(0);
152 TRY(1);
153 TRY(2);
154 TRY(3);
155 #undef TRY
156 bits = inb(iobase | 0x1f) & alive;
157 } while (bits != alive);
158
159 return 1;
160 }
161