1 /* $OpenBSD: beep.c,v 1.9 2019/06/22 20:30:42 kn Exp $ */ 2 3 /* 4 * Copyright (c) 2006 Jason L. Wright (jason@thought.net) 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * Driver for beeper device on BBC machines (Blade 1k, 2k, etc) 31 */ 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/kernel.h> 36 #include <sys/device.h> 37 #include <sys/conf.h> 38 #include <sys/timeout.h> 39 40 #include <machine/bus.h> 41 #include <machine/autoconf.h> 42 #include <machine/openfirm.h> 43 44 #include <sparc64/dev/ebusreg.h> 45 #include <sparc64/dev/ebusvar.h> 46 47 #include "hidkbd.h" 48 #if NHIDKBD > 0 49 #include <dev/hid/hidkbdvar.h> 50 #endif 51 52 #define BEEP_CTRL 0 53 #define BEEP_CNT_0 2 54 #define BEEP_CNT_1 3 55 #define BEEP_CNT_2 4 56 #define BEEP_CNT_3 5 57 58 #define BEEP_CTRL_ON 0x01 59 #define BEEP_CTRL_OFF 0x00 60 61 struct beep_freq { 62 int freq; 63 u_int32_t reg; 64 }; 65 66 struct beep_softc { 67 struct device sc_dev; 68 bus_space_tag_t sc_iot; 69 bus_space_handle_t sc_ioh; 70 int sc_clk; 71 struct beep_freq sc_freqs[9]; 72 struct timeout sc_to; 73 int sc_belltimeout; 74 int sc_bellactive; 75 }; 76 77 int beep_match(struct device *, void *, void *); 78 void beep_attach(struct device *, struct device *, void *); 79 void beep_setfreq(struct beep_softc *, int); 80 81 struct cfattach beep_ca = { 82 sizeof(struct beep_softc), beep_match, beep_attach 83 }; 84 85 struct cfdriver beep_cd = { 86 NULL, "beep", DV_DULL 87 }; 88 89 #if NHIDKBD > 0 90 void beep_stop(void *); 91 void beep_bell(void *, u_int, u_int, u_int, int); 92 #endif 93 94 int 95 beep_match(struct device *parent, void *match, void *aux) 96 { 97 struct ebus_attach_args *ea = aux; 98 99 if (strcmp(ea->ea_name, "beep") == 0) 100 return (1); 101 return (0); 102 } 103 104 void 105 beep_attach(parent, self, aux) 106 struct device *parent, *self; 107 void *aux; 108 { 109 struct beep_softc *sc = (void *)self; 110 struct ebus_attach_args *ea = aux; 111 int i; 112 113 sc->sc_iot = ea->ea_memtag; 114 115 /* Use prom address if available, otherwise map it. */ 116 if (ea->ea_nvaddrs) { 117 if (bus_space_map(sc->sc_iot, ea->ea_vaddrs[0], 0, 118 BUS_SPACE_MAP_PROMADDRESS, &sc->sc_ioh)) { 119 printf(": can't map PROM register space\n"); 120 return; 121 } 122 } else if (ebus_bus_map(sc->sc_iot, 0, 123 EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), ea->ea_regs[0].size, 0, 0, 124 &sc->sc_ioh) != 0) { 125 printf(": can't map register space\n"); 126 return; 127 } 128 129 /* The bbc,beep is clocked at half the BBC frequency */ 130 sc->sc_clk = getpropint(findroot(), "clock-frequency", 0); 131 sc->sc_clk /= 2; 132 133 /* 134 * Compute the frequence table based on the scalar and base 135 * board clock speed. 136 */ 137 for (i = 0; i < 9; i++) { 138 sc->sc_freqs[i].reg = 1 << (18 - i); 139 sc->sc_freqs[i].freq = sc->sc_clk / sc->sc_freqs[i].reg; 140 } 141 142 /* set beep at around 1200hz */ 143 beep_setfreq(sc, 1200); 144 145 #if 0 146 bus_space_write_1(sc->sc_iot, sc->sc_ioh, BEEP_CTRL, 147 BEEP_CTRL_ON); 148 for (i = 0; i < 1000; i++) 149 DELAY(1000); 150 bus_space_write_1(sc->sc_iot, sc->sc_ioh, BEEP_CTRL, 151 BEEP_CTRL_OFF); 152 #endif 153 154 printf(": clock %sMHz\n", clockfreq(sc->sc_clk)); 155 156 #if NHIDKBD > 0 157 timeout_set(&sc->sc_to, beep_stop, sc); 158 hidkbd_hookup_bell(beep_bell, sc); 159 #endif 160 } 161 162 void 163 beep_setfreq(struct beep_softc *sc, int freq) 164 { 165 int i, n, selected = -1; 166 167 n = sizeof(sc->sc_freqs)/sizeof(sc->sc_freqs[0]); 168 169 if (freq < sc->sc_freqs[0].freq) 170 selected = 0; 171 if (freq > sc->sc_freqs[n - 1].freq) 172 selected = n - 1; 173 174 for (i = 1; selected == -1 && i < n; i++) { 175 if (sc->sc_freqs[i].freq == freq) 176 selected = i; 177 else if (sc->sc_freqs[i].freq > freq) { 178 int diff1, diff2; 179 180 diff1 = freq - sc->sc_freqs[i - 1].freq; 181 diff2 = sc->sc_freqs[i].freq - freq; 182 if (diff1 < diff2) 183 selected = i - 1; 184 else 185 selected = i; 186 } 187 } 188 189 if (selected == -1) 190 selected = 0; 191 192 bus_space_write_1(sc->sc_iot, sc->sc_ioh, BEEP_CNT_0, 193 (sc->sc_freqs[i].reg >> 24) & 0xff); 194 bus_space_write_1(sc->sc_iot, sc->sc_ioh, BEEP_CNT_1, 195 (sc->sc_freqs[i].reg >> 16) & 0xff); 196 bus_space_write_1(sc->sc_iot, sc->sc_ioh, BEEP_CNT_2, 197 (sc->sc_freqs[i].reg >> 8) & 0xff); 198 bus_space_write_1(sc->sc_iot, sc->sc_ioh, BEEP_CNT_3, 199 (sc->sc_freqs[i].reg >> 0) & 0xff); 200 } 201 202 #if NHIDKBD > 0 203 void 204 beep_stop(void *vsc) 205 { 206 struct beep_softc *sc = vsc; 207 int s; 208 209 s = spltty(); 210 bus_space_write_1(sc->sc_iot, sc->sc_ioh, BEEP_CTRL, 211 BEEP_CTRL_OFF); 212 sc->sc_bellactive = 0; 213 sc->sc_belltimeout = 0; 214 splx(s); 215 } 216 217 void 218 beep_bell(void *vsc, u_int pitch, u_int period, u_int volume, int poll) 219 { 220 struct beep_softc *sc = vsc; 221 int s; 222 223 s = spltty(); 224 if (sc->sc_bellactive) { 225 if (sc->sc_belltimeout == 0) 226 timeout_del(&sc->sc_to); 227 } 228 if (pitch == 0 || period == 0 || volume == 0) { 229 beep_stop(sc); 230 splx(s); 231 return; 232 } 233 if (!sc->sc_bellactive) { 234 sc->sc_bellactive = 1; 235 sc->sc_belltimeout = 1; 236 bus_space_write_1(sc->sc_iot, sc->sc_ioh, BEEP_CTRL, 237 BEEP_CTRL_ON); 238 timeout_add_msec(&sc->sc_to, period); 239 } 240 splx(s); 241 } 242 #endif /* NHIDKBD > 0 */ 243