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