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