xref: /netbsd-src/sys/dev/isa/ast.c (revision d9158b13b5dfe46201430699a3f7a235ecf28df3)
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