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