1 /* $OpenBSD: beep.c,v 1.5 2010/07/31 16:04:50 miod 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/types.h> 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/kernel.h> 37 #include <sys/device.h> 38 #include <sys/conf.h> 39 #include <sys/timeout.h> 40 41 #include <machine/bus.h> 42 #include <machine/autoconf.h> 43 #include <machine/openfirm.h> 44 45 #include <sparc64/dev/ebusreg.h> 46 #include <sparc64/dev/ebusvar.h> 47 48 #include "hidkbd.h" 49 #if NHIDKBD > 0 50 #include <dev/usb/hidkbdvar.h> 51 #endif 52 53 #define BEEP_CTRL 0 54 #define BEEP_CNT_0 2 55 #define BEEP_CNT_1 3 56 #define BEEP_CNT_2 4 57 #define BEEP_CNT_3 5 58 59 #define BEEP_CTRL_ON 0x01 60 #define BEEP_CTRL_OFF 0x00 61 62 struct beep_freq { 63 int freq; 64 u_int32_t reg; 65 }; 66 67 struct beep_softc { 68 struct device sc_dev; 69 bus_space_tag_t sc_iot; 70 bus_space_handle_t sc_ioh; 71 int sc_clk; 72 struct beep_freq sc_freqs[9]; 73 struct timeout sc_to; 74 int sc_belltimeout; 75 int sc_bellactive; 76 }; 77 78 int beep_match(struct device *, void *, void *); 79 void beep_attach(struct device *, struct device *, void *); 80 void beep_setfreq(struct beep_softc *, int); 81 82 struct cfattach beep_ca = { 83 sizeof(struct beep_softc), beep_match, beep_attach 84 }; 85 86 struct cfdriver beep_cd = { 87 NULL, "beep", DV_DULL 88 }; 89 90 #if NHIDKBD > 0 91 void beep_stop(void *); 92 void beep_bell(void *, u_int, u_int, u_int, int); 93 #endif 94 95 int 96 beep_match(struct device *parent, void *match, void *aux) 97 { 98 struct ebus_attach_args *ea = aux; 99 100 if (strcmp(ea->ea_name, "beep") == 0) 101 return (1); 102 return (0); 103 } 104 105 void 106 beep_attach(parent, self, aux) 107 struct device *parent, *self; 108 void *aux; 109 { 110 struct beep_softc *sc = (void *)self; 111 struct ebus_attach_args *ea = aux; 112 int i; 113 114 sc->sc_iot = ea->ea_memtag; 115 116 /* Use prom address if available, otherwise map it. */ 117 if (ea->ea_nvaddrs) { 118 if (bus_space_map(sc->sc_iot, ea->ea_vaddrs[0], 0, 119 BUS_SPACE_MAP_PROMADDRESS, &sc->sc_ioh)) { 120 printf(": can't map PROM register space\n"); 121 return; 122 } 123 } else if (ebus_bus_map(sc->sc_iot, 0, 124 EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), ea->ea_regs[0].size, 0, 0, 125 &sc->sc_ioh) != 0) { 126 printf(": can't map register space\n"); 127 return; 128 } 129 130 /* The bbc,beep is clocked at half the BBC frequency */ 131 sc->sc_clk = getpropint(findroot(), "clock-frequency", 0); 132 sc->sc_clk /= 2; 133 134 /* 135 * Compute the frequence table based on the scalar and base 136 * board clock speed. 137 */ 138 for (i = 0; i < 9; i++) { 139 sc->sc_freqs[i].reg = 1 << (18 - i); 140 sc->sc_freqs[i].freq = sc->sc_clk / sc->sc_freqs[i].reg; 141 } 142 143 /* set beep at around 1200hz */ 144 beep_setfreq(sc, 1200); 145 146 #if 0 147 bus_space_write_1(sc->sc_iot, sc->sc_ioh, BEEP_CTRL, 148 BEEP_CTRL_ON); 149 for (i = 0; i < 1000; i++) 150 DELAY(1000); 151 bus_space_write_1(sc->sc_iot, sc->sc_ioh, BEEP_CTRL, 152 BEEP_CTRL_OFF); 153 #endif 154 155 printf(": clock %sMHz\n", clockfreq(sc->sc_clk)); 156 157 #if NHIDKBD > 0 158 timeout_set(&sc->sc_to, beep_stop, sc); 159 hidkbd_hookup_bell(beep_bell, sc); 160 #endif 161 } 162 163 void 164 beep_setfreq(struct beep_softc *sc, int freq) 165 { 166 int i, n, selected = -1; 167 168 n = sizeof(sc->sc_freqs)/sizeof(sc->sc_freqs[0]); 169 170 if (freq < sc->sc_freqs[0].freq) 171 selected = 0; 172 if (freq > sc->sc_freqs[n - 1].freq) 173 selected = n - 1; 174 175 for (i = 1; selected == -1 && i < n; i++) { 176 if (sc->sc_freqs[i].freq == freq) 177 selected = i; 178 else if (sc->sc_freqs[i].freq > freq) { 179 int diff1, diff2; 180 181 diff1 = freq - sc->sc_freqs[i - 1].freq; 182 diff2 = sc->sc_freqs[i].freq - freq; 183 if (diff1 < diff2) 184 selected = i - 1; 185 else 186 selected = i; 187 } 188 } 189 190 if (selected == -1) 191 selected = 0; 192 193 bus_space_write_1(sc->sc_iot, sc->sc_ioh, BEEP_CNT_0, 194 (sc->sc_freqs[i].reg >> 24) & 0xff); 195 bus_space_write_1(sc->sc_iot, sc->sc_ioh, BEEP_CNT_1, 196 (sc->sc_freqs[i].reg >> 16) & 0xff); 197 bus_space_write_1(sc->sc_iot, sc->sc_ioh, BEEP_CNT_2, 198 (sc->sc_freqs[i].reg >> 8) & 0xff); 199 bus_space_write_1(sc->sc_iot, sc->sc_ioh, BEEP_CNT_3, 200 (sc->sc_freqs[i].reg >> 0) & 0xff); 201 } 202 203 #if NHIDKBD > 0 204 void 205 beep_stop(void *vsc) 206 { 207 struct beep_softc *sc = vsc; 208 int s; 209 210 s = spltty(); 211 bus_space_write_1(sc->sc_iot, sc->sc_ioh, BEEP_CTRL, 212 BEEP_CTRL_OFF); 213 sc->sc_bellactive = 0; 214 sc->sc_belltimeout = 0; 215 splx(s); 216 } 217 218 void 219 beep_bell(void *vsc, u_int pitch, u_int period, u_int volume, int poll) 220 { 221 struct beep_softc *sc = vsc; 222 int s, ticks; 223 224 ticks = (period * hz) / 1000; 225 if (ticks <= 0) 226 ticks = 1; 227 228 s = spltty(); 229 if (sc->sc_bellactive) { 230 if (sc->sc_belltimeout == 0) 231 timeout_del(&sc->sc_to); 232 } 233 if (pitch == 0 || period == 0 || volume == 0) { 234 beep_stop(sc); 235 splx(s); 236 return; 237 } 238 if (!sc->sc_bellactive) { 239 sc->sc_bellactive = 1; 240 sc->sc_belltimeout = 1; 241 bus_space_write_1(sc->sc_iot, sc->sc_ioh, BEEP_CTRL, 242 BEEP_CTRL_ON); 243 timeout_add(&sc->sc_to, ticks); 244 } 245 splx(s); 246 } 247 #endif /* NHIDKBD > 0 */ 248