ast.c revision 1.13 1 /* $NetBSD: ast.c,v 1.13 1995/01/02 22:27:46 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)
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 struct cfdata *cf;
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 ((cf = config_search(astsubmatch, self, &isa)) != 0) {
110 config_attach(self, cf, &isa, astprint);
111 sc->sc_slaves[aa.aa_slave] =
112 cf->cf_driver->cd_devs[cf->cf_unit];
113 sc->sc_alive |= 1 << aa.aa_slave;
114 }
115 }
116
117 sc->sc_ih.ih_fun = astintr;
118 sc->sc_ih.ih_arg = sc;
119 sc->sc_ih.ih_level = IPL_TTY;
120 intr_establish(ia->ia_irq, &sc->sc_ih);
121 }
122
123 int
124 astintr(sc)
125 struct ast_softc *sc;
126 {
127 int iobase = sc->sc_iobase;
128 int alive = sc->sc_alive;
129 int bits;
130
131 bits = ~inb(iobase | 0x1f) & alive;
132 if (bits == 0)
133 return (0);
134
135 for (;;) {
136 #define TRY(n) \
137 if (bits & (1 << (n))) \
138 comintr(sc->sc_slaves[n]);
139 TRY(0);
140 TRY(1);
141 TRY(2);
142 TRY(3);
143 #undef TRY
144 bits = ~inb(iobase | 0x1f) & alive;
145 if (bits == 0)
146 return (1);
147 }
148 }
149