ast.c revision 1.12 1 /* $NetBSD: ast.c,v 1.12 1994/11/18 22:07:32 mycroft Exp $ */
2
3 /*
4 * Multi-port serial card interrupt demuxing support.
5 * Roland McGrath 3/20/94
6 * The author disclaims copyright and places this file in the public domain.
7 *
8 * Modified by: Charles Hannum, 3/22/94
9 */
10
11 #include <sys/param.h>
12 #include <sys/device.h>
13
14 #include <machine/pio.h>
15
16 #include <i386/isa/isavar.h>
17
18 struct ast_softc {
19 struct device sc_dev;
20 struct intrhand sc_ih;
21
22 int sc_iobase;
23 int sc_alive; /* mask of slave units attached */
24 void *sc_slaves[4]; /* com device unit numbers */
25 };
26
27 int astprobe();
28 void astattach();
29 int astintr __P((struct ast_softc *));
30
31 struct cfdriver astcd = {
32 NULL, "ast", astprobe, astattach, DV_TTY, sizeof(struct ast_softc), 1
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 int aa_slave;
53 };
54
55 int
56 astsubmatch(parent, match, aux)
57 struct device *parent;
58 void *match, *aux;
59 {
60 struct ast_softc *sc = (void *)parent;
61 struct device *self = match;
62 struct isa_attach_args *ia = aux;
63 struct ast_attach_args *aa = ia->ia_aux;
64 struct cfdata *cf = self->dv_cfdata;
65
66 if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != aa->aa_slave)
67 return (0);
68 return ((*cf->cf_driver->cd_match)(parent, match, ia));
69 }
70
71 int
72 astprint(aux, ast)
73 void *aux;
74 char *ast;
75 {
76 struct isa_attach_args *ia = aux;
77 struct ast_attach_args *aa = ia->ia_aux;
78
79 printf(" slave %d", aa->aa_slave);
80 }
81
82 void
83 astattach(parent, self, aux)
84 struct device *parent, *self;
85 void *aux;
86 {
87 struct ast_softc *sc = (void *)self;
88 struct isa_attach_args *ia = aux;
89 struct ast_attach_args aa;
90 struct isa_attach_args isa;
91
92 sc->sc_iobase = ia->ia_iobase;
93
94 /*
95 * Enable the master interrupt.
96 */
97 outb(sc->sc_iobase | 0x1f, 0x80);
98
99 printf("\n");
100
101 isa.ia_aux = &aa;
102 for (aa.aa_slave = 0; aa.aa_slave < 4; aa.aa_slave++) {
103 void *match;
104 isa.ia_iobase = sc->sc_iobase + 8 * aa.aa_slave;
105 isa.ia_iosize = 0x666;
106 isa.ia_irq = IRQUNK;
107 isa.ia_drq = DRQUNK;
108 isa.ia_msize = 0;
109 if ((match = config_search(astsubmatch, self, &isa)) != 0) {
110 sc->sc_slaves[aa.aa_slave] = match;
111 sc->sc_alive |= 1 << aa.aa_slave;
112 config_attach(self, match, &isa, astprint);
113 }
114 }
115
116 sc->sc_ih.ih_fun = astintr;
117 sc->sc_ih.ih_arg = sc;
118 sc->sc_ih.ih_level = IPL_TTY;
119 intr_establish(ia->ia_irq, &sc->sc_ih);
120 }
121
122 int
123 astintr(sc)
124 struct ast_softc *sc;
125 {
126 int iobase = sc->sc_iobase;
127 int alive = sc->sc_alive;
128 int bits;
129
130 bits = ~inb(iobase | 0x1f) & alive;
131 if (bits == 0)
132 return (0);
133
134 for (;;) {
135 #define TRY(n) \
136 if (bits & (1 << (n))) \
137 comintr(sc->sc_slaves[n]);
138 TRY(0);
139 TRY(1);
140 TRY(2);
141 TRY(3);
142 #undef TRY
143 bits = ~inb(iobase | 0x1f) & alive;
144 if (bits == 0)
145 return (1);
146 }
147 }
148