1 /* $NetBSD: pcppi.c,v 1.1 1998/04/15 20:26:18 drochner Exp $ */ 2 3 /* 4 * Copyright (c) 1996 Carnegie-Mellon University. 5 * All rights reserved. 6 * 7 * Author: Chris G. Demetriou 8 * 9 * Permission to use, copy, modify and distribute this software and 10 * its documentation is hereby granted, provided that both the copyright 11 * notice and this permission notice appear in all copies of the 12 * software, derivative works or modified versions, and any portions 13 * thereof, and that both notices appear in supporting documentation. 14 * 15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 17 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 18 * 19 * Carnegie Mellon requests users of this software to return to 20 * 21 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 22 * School of Computer Science 23 * Carnegie Mellon University 24 * Pittsburgh PA 15213-3890 25 * 26 * any improvements or extensions that they make and grant Carnegie the 27 * rights to redistribute these changes. 28 */ 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/kernel.h> 33 #include <sys/proc.h> 34 #include <sys/device.h> 35 #include <sys/errno.h> 36 37 #include <machine/bus.h> 38 39 #include <dev/isa/isareg.h> 40 #include <dev/isa/isavar.h> 41 #include <dev/isa/pcppireg.h> 42 #include <dev/isa/pcppivar.h> 43 44 #include <dev/ic/i8253reg.h> 45 46 struct pcppi_softc { 47 struct device sc_dv; 48 49 bus_space_tag_t sc_iot; 50 bus_space_handle_t sc_ppi_ioh, sc_pit1_ioh; 51 52 int sc_bellactive, sc_bellpitch; 53 int sc_slp; 54 }; 55 56 int pcppi_match __P((struct device *, struct cfdata *, void *)); 57 void pcppi_attach __P((struct device *, struct device *, void *)); 58 59 struct cfattach pcppi_ca = { 60 sizeof(struct pcppi_softc), pcppi_match, pcppi_attach, 61 }; 62 63 static void pcppi_bell_stop __P((void*)); 64 65 #define PCPPIPRI (PZERO - 1) 66 67 int 68 pcppi_match(parent, match, aux) 69 struct device *parent; 70 struct cfdata *match; 71 void *aux; 72 { 73 struct isa_attach_args *ia = aux; 74 bus_space_handle_t ppi_ioh, pit1_ioh; 75 int have_pit1, have_ppi, rv; 76 u_int8_t v, nv; 77 78 /* If values are hardwired to something that they can't be, punt. */ 79 if ((ia->ia_iobase != IOBASEUNK && ia->ia_iobase != IO_PPI) || 80 ia->ia_maddr != MADDRUNK || ia->ia_msize != 0 || 81 ia->ia_irq != IRQUNK || ia->ia_drq != DRQUNK) 82 return (0); 83 84 rv = 0; 85 have_pit1 = have_ppi = 0; 86 87 if (bus_space_map(ia->ia_iot, IO_TIMER1, 4, 0, &pit1_ioh)) 88 goto lose; 89 have_pit1 = 1; 90 if (bus_space_map(ia->ia_iot, IO_PPI, 1, 0, &ppi_ioh)) 91 goto lose; 92 have_ppi = 1; 93 94 /* 95 * Check for existence of PPI. Realistically, this is either going to 96 * be here or nothing is going to be here. 97 * 98 * We don't want to have any chance of changing speaker output (which 99 * this test might, if it crashes in the middle, or something; 100 * normally it's be to quick to produce anthing audible), but 101 * many "combo chip" mock-PPI's don't seem to support the top bit 102 * of Port B as a settable bit. The bottom bit has to be settable, 103 * since the speaker driver hardware still uses it. 104 */ 105 v = bus_space_read_1(ia->ia_iot, ppi_ioh, 0); /* XXX */ 106 bus_space_write_1(ia->ia_iot, ppi_ioh, 0, v ^ 0x01); /* XXX */ 107 nv = bus_space_read_1(ia->ia_iot, ppi_ioh, 0); /* XXX */ 108 if (((nv ^ v) & 0x01) == 0x01) 109 rv = 1; 110 bus_space_write_1(ia->ia_iot, ppi_ioh, 0, v); /* XXX */ 111 nv = bus_space_read_1(ia->ia_iot, ppi_ioh, 0); /* XXX */ 112 if (((nv ^ v) & 0x01) != 0x00) { 113 rv = 0; 114 goto lose; 115 } 116 117 /* 118 * We assume that the programmable interval timer is there. 119 */ 120 121 lose: 122 if (have_pit1) 123 bus_space_unmap(ia->ia_iot, pit1_ioh, 4); 124 if (have_ppi) 125 bus_space_unmap(ia->ia_iot, ppi_ioh, 1); 126 if (rv) { 127 ia->ia_iobase = IO_PPI; 128 ia->ia_iosize = 0x1; 129 ia->ia_msize = 0x0; 130 } 131 return (rv); 132 } 133 134 void 135 pcppi_attach(parent, self, aux) 136 struct device *parent, *self; 137 void *aux; 138 { 139 struct pcppi_softc *sc = (struct pcppi_softc *)self; 140 struct isa_attach_args *ia = aux; 141 bus_space_tag_t iot; 142 struct pcppi_attach_args pa; 143 144 sc->sc_iot = iot = ia->ia_iot; 145 146 if (bus_space_map(iot, IO_TIMER1, 4, 0, &sc->sc_pit1_ioh) || 147 bus_space_map(iot, IO_PPI, 1, 0, &sc->sc_ppi_ioh)) 148 panic("pcppi_attach: couldn't map"); 149 150 printf("\n"); 151 152 sc->sc_bellactive = sc->sc_bellpitch = sc->sc_slp = 0; 153 154 pa.pa_cookie = sc; 155 while (config_found(self, &pa, 0)); 156 } 157 158 void 159 pcppi_bell(self, pitch, period, slp) 160 pcppi_tag_t self; 161 int pitch, period; 162 int slp; 163 { 164 struct pcppi_softc *sc = self; 165 int s1, s2; 166 167 s1 = spltty(); /* ??? */ 168 if (sc->sc_bellactive) { 169 untimeout(pcppi_bell_stop, sc); 170 if (sc->sc_slp) 171 wakeup(pcppi_bell_stop); 172 } 173 if (pitch == 0 || period == 0) { 174 pcppi_bell_stop(sc); 175 sc->sc_bellpitch = 0; 176 splx(s1); 177 return; 178 } 179 if (!sc->sc_bellactive || sc->sc_bellpitch != pitch) { 180 s2 = splhigh(); 181 bus_space_write_1(sc->sc_iot, sc->sc_pit1_ioh, TIMER_MODE, 182 TIMER_SEL2 | TIMER_16BIT | TIMER_SQWAVE); 183 bus_space_write_1(sc->sc_iot, sc->sc_pit1_ioh, TIMER_CNTR2, 184 TIMER_DIV(pitch) % 256); 185 bus_space_write_1(sc->sc_iot, sc->sc_pit1_ioh, TIMER_CNTR2, 186 TIMER_DIV(pitch) / 256); 187 splx(s2); 188 /* enable speaker */ 189 bus_space_write_1(sc->sc_iot, sc->sc_ppi_ioh, 0, 190 bus_space_read_1(sc->sc_iot, sc->sc_ppi_ioh, 0) 191 | PIT_SPKR); 192 } 193 sc->sc_bellpitch = pitch; 194 195 sc->sc_bellactive = 1; 196 timeout(pcppi_bell_stop, sc, period); 197 if (slp) { 198 sc->sc_slp = 1; 199 tsleep(pcppi_bell_stop, PCPPIPRI | PCATCH, "bell", 0); 200 sc->sc_slp = 0; 201 } 202 splx(s1); 203 } 204 205 static void 206 pcppi_bell_stop(arg) 207 void *arg; 208 { 209 struct pcppi_softc *sc = arg; 210 int s; 211 212 s = spltty(); /* ??? */ 213 /* disable bell */ 214 bus_space_write_1(sc->sc_iot, sc->sc_ppi_ioh, 0, 215 bus_space_read_1(sc->sc_iot, sc->sc_ppi_ioh, 0) 216 & ~PIT_SPKR); 217 sc->sc_bellactive = 0; 218 if (sc->sc_slp) 219 wakeup(pcppi_bell_stop); 220 splx(s); 221 } 222