ast.c revision 1.6 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.6 1994/03/29 06:58:29 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 u_short sc_iobase;
24 int sc_alive; /* mask of slave units attached */
25 int sc_slaves[8]; /* com device unit numbers */
26 };
27
28 int astprobe();
29 void astattach();
30
31 struct cfdriver astcd = {
32 NULL, "ast", astprobe, astattach, DV_TTY, sizeof(struct ast_softc)
33 };
34
35 int
36 astprobe(parent, self, aux)
37 struct device *parent, *self;
38 void *aux;
39 {
40 struct isa_attach_args *ia = aux;
41
42 /*
43 * Do the normal com probe for the first UART and assume
44 * its presence means there is a multiport board there.
45 * XXX Needs more robustness.
46 */
47 ia->ia_iosize = 4 * 8;
48 return comprobe1(ia->ia_iobase);
49 }
50
51 struct ast_attach_args {
52 u_short aa_iobase;
53 int aa_slave;
54 };
55
56 int
57 astsubmatch(parent, self, aux)
58 struct device *parent, *self;
59 void *aux;
60 {
61 struct ast_softc *sc = (void *)parent;
62 struct ast_attach_args *aa = aux;
63 struct cfdata *cf = self->dv_cfdata;
64 int found, frobbed = 0;
65 #ifdef NEWCONFIG
66
67 #define cf_slave cf_loc[6]
68 if (cf->cf_slave != -1 && cf->cf_slave != aa->aa_slave)
69 return 0;
70 if (cf->cf_iobase == IOBASEUNK) {
71 frobbed = 1;
72 cf->cf_iobase = aa->aa_iobase;
73 }
74 #undef cf_slave
75 #else
76 struct isa_device *id = (void *)cf->cf_loc;
77
78 if (id->id_physid != -1 && id->id_physid != aa->aa_slave)
79 return 0;
80 if (id->id_iobase == 0) {
81 frobbed = 1;
82 id->id_iobase = aa->aa_iobase;
83 }
84 #endif
85 found = isasubmatch(parent, self, aux);
86 if (found) {
87 sc->sc_slaves[aa->aa_slave] = cf->cf_unit;
88 sc->sc_alive |= 1 << aa->aa_slave;
89 }
90 /*
91 * If we changed the iobase, we have to set it back now, because it
92 * might be a clone device, and the iobase wouldn't get set properly on
93 * the next iteration.
94 */
95 #ifdef NEWCONFIG
96 if (frobbed)
97 cf->cf_iobase = IOBASEUNK;
98 #else
99 if (frobbed)
100 id->id_iobase = 0;
101 #endif
102 return found;
103 }
104
105 void
106 astattach(parent, self, aux)
107 struct device *parent, *self;
108 void *aux;
109 {
110 struct ast_softc *sc = (void *)self;
111 struct isa_attach_args *ia = aux;
112 struct ast_attach_args aa;
113
114 /*
115 * Enable the master interrupt.
116 */
117 sc->sc_iobase = ia->ia_iobase;
118 outb(sc->sc_iobase | 0x1f, 0x80);
119 printf("\n");
120
121 for (aa.aa_slave = 0, aa.aa_iobase = sc->sc_iobase;
122 aa.aa_slave < 4;
123 aa.aa_slave++, aa.aa_iobase += 8)
124 config_search(astsubmatch, self, &aa);
125 }
126
127 int
128 astintr(unit)
129 int unit;
130 {
131 struct ast_softc *sc = astcd.cd_devs[unit];
132 u_short iobase = sc->sc_iobase;
133 int alive = sc->sc_alive;
134 int bits;
135
136 bits = inb(iobase | 0x1f) & alive;
137 if (bits == alive)
138 return 0;
139
140 do {
141 #define TRY(n) \
142 if ((bits & (1 << (n))) == 0) \
143 comintr(sc->sc_slaves[n]);
144 TRY(0);
145 TRY(1);
146 TRY(2);
147 TRY(3);
148 #undef TRY
149 bits = inb(iobase | 0x1f) & alive;
150 } while (bits != alive);
151
152 return 1;
153 }
154