1 /* $NetBSD: mpu.c,v 1.4 2000/06/28 17:13:02 mrg Exp $ */ 2 3 /* 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Lennart Augustsson (augustss@netbsd.org). 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/errno.h> 42 #include <sys/ioctl.h> 43 #include <sys/syslog.h> 44 #include <sys/device.h> 45 #include <sys/proc.h> 46 #include <sys/buf.h> 47 48 #include <machine/cpu.h> 49 #include <machine/intr.h> 50 #include <machine/bus.h> 51 52 #include <dev/midi_if.h> 53 54 #include <dev/ic/mpuvar.h> 55 56 #ifdef AUDIO_DEBUG 57 #define DPRINTF(x) if (mpudebug) printf x 58 #define DPRINTFN(n,x) if (mpudebug >= (n)) printf x 59 int mpudebug = 0; 60 #else 61 #define DPRINTF(x) 62 #define DPRINTFN(n,x) 63 #endif 64 65 #define MPU_DATA 0 66 #define MPU_COMMAND 1 67 #define MPU_RESET 0xff 68 #define MPU_UART_MODE 0x3f 69 #define MPU_ACK 0xfe 70 #define MPU_STATUS 1 71 #define MPU_OUTPUT_BUSY 0x40 72 #define MPU_INPUT_EMPTY 0x80 73 74 #define MPU_MAXWAIT 10000 /* usec/10 to wait */ 75 76 #define MPU_GETSTATUS(iot, ioh) (bus_space_read_1(iot, ioh, MPU_STATUS)) 77 78 int mpu_reset(struct mpu_softc *); 79 static __inline int mpu_waitready(struct mpu_softc *); 80 void mpu_readinput(struct mpu_softc *); 81 82 int mpu_open __P((void *, int, 83 void (*iintr)__P((void *, int)), 84 void (*ointr)__P((void *)), void *arg)); 85 void mpu_close __P((void *)); 86 int mpu_output __P((void *, int)); 87 void mpu_getinfo __P((void *, struct midi_info *)); 88 89 struct midi_hw_if mpu_midi_hw_if = { 90 mpu_open, 91 mpu_close, 92 mpu_output, 93 mpu_getinfo, 94 0, /* ioctl */ 95 }; 96 97 int 98 mpu_find(sc) 99 struct mpu_softc *sc; 100 { 101 if (MPU_GETSTATUS(sc->iot, sc->ioh) == 0xff) { 102 DPRINTF(("mpu_find: No status\n")); 103 goto bad; 104 } 105 sc->open = 0; 106 sc->intr = 0; 107 if (mpu_reset(sc) == 0) 108 return 1; 109 bad: 110 return 0; 111 } 112 113 void 114 mpu_attach(sc) 115 struct mpu_softc *sc; 116 { 117 printf("\n"); 118 119 midi_attach_mi(&mpu_midi_hw_if, sc, &sc->sc_dev); 120 } 121 122 static __inline int 123 mpu_waitready(sc) 124 struct mpu_softc *sc; 125 { 126 int i; 127 128 for(i = 0; i < MPU_MAXWAIT; i++) { 129 if (!(MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_OUTPUT_BUSY)) 130 return 0; 131 delay(10); 132 } 133 return 1; 134 } 135 136 int 137 mpu_reset(sc) 138 struct mpu_softc *sc; 139 { 140 bus_space_tag_t iot = sc->iot; 141 bus_space_handle_t ioh = sc->ioh; 142 int i; 143 int s; 144 145 if (mpu_waitready(sc)) { 146 DPRINTF(("mpu_reset: not ready\n")); 147 return EIO; 148 } 149 s = splaudio(); /* Don't let the interrupt get our ACK. */ 150 bus_space_write_1(iot, ioh, MPU_COMMAND, MPU_RESET); 151 for(i = 0; i < 2*MPU_MAXWAIT; i++) { 152 if (!(MPU_GETSTATUS(iot, ioh) & MPU_INPUT_EMPTY) && 153 bus_space_read_1(iot, ioh, MPU_DATA) == MPU_ACK) { 154 splx(s); 155 return 0; 156 } 157 } 158 splx(s); 159 DPRINTF(("mpu_reset: No ACK\n")); 160 return EIO; 161 } 162 163 int 164 mpu_open(addr, flags, iintr, ointr, arg) 165 void *addr; 166 int flags; 167 void (*iintr)__P((void *, int)); 168 void (*ointr)__P((void *)); 169 void *arg; 170 { 171 struct mpu_softc *sc = addr; 172 173 DPRINTF(("mpu_open: sc=%p\n", sc)); 174 175 if (sc->open) 176 return EBUSY; 177 #ifndef AUDIO_NO_POWER_CTL 178 if (sc->powerctl) 179 sc->powerctl(sc->powerarg, 1); 180 #endif 181 if (mpu_reset(sc) != 0) { 182 #ifndef AUDIO_NO_POWER_CTL 183 if (sc->powerctl) 184 sc->powerctl(sc->powerarg, 0); 185 #endif 186 return EIO; 187 } 188 189 bus_space_write_1(sc->iot, sc->ioh, MPU_COMMAND, MPU_UART_MODE); 190 sc->open = 1; 191 sc->intr = iintr; 192 sc->arg = arg; 193 return 0; 194 } 195 196 void 197 mpu_close(addr) 198 void *addr; 199 { 200 struct mpu_softc *sc = addr; 201 202 DPRINTF(("mpu_close: sc=%p\n", sc)); 203 204 sc->open = 0; 205 sc->intr = 0; 206 mpu_reset(sc); /* exit UART mode */ 207 208 #ifndef AUDIO_NO_POWER_CTL 209 if (sc->powerctl) 210 sc->powerctl(sc->powerarg, 0); 211 #endif 212 } 213 214 void 215 mpu_readinput(sc) 216 struct mpu_softc *sc; 217 { 218 bus_space_tag_t iot = sc->iot; 219 bus_space_handle_t ioh = sc->ioh; 220 int data; 221 222 while(!(MPU_GETSTATUS(iot, ioh) & MPU_INPUT_EMPTY)) { 223 data = bus_space_read_1(iot, ioh, MPU_DATA); 224 DPRINTFN(3, ("mpu_rea: sc=%p 0x%02x\n", sc, data)); 225 if (sc->intr) 226 sc->intr(sc->arg, data); 227 } 228 } 229 230 int 231 mpu_output(addr, d) 232 void *addr; 233 int d; 234 { 235 struct mpu_softc *sc = addr; 236 int s; 237 238 DPRINTFN(3, ("mpu_output: sc=%p 0x%02x\n", sc, d)); 239 if (!(MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_INPUT_EMPTY)) { 240 s = splaudio(); 241 mpu_readinput(sc); 242 splx(s); 243 } 244 if (mpu_waitready(sc)) { 245 DPRINTF(("mpu_output: not ready\n")); 246 return EIO; 247 } 248 bus_space_write_1(sc->iot, sc->ioh, MPU_DATA, d); 249 return 0; 250 } 251 252 void 253 mpu_getinfo(addr, mi) 254 void *addr; 255 struct midi_info *mi; 256 { 257 struct mpu_softc *sc = addr; 258 259 mi->name = sc->model; 260 mi->props = 0; 261 } 262 263 int 264 mpu_intr(addr) 265 void *addr; 266 { 267 struct mpu_softc *sc = addr; 268 269 if (MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_INPUT_EMPTY) { 270 DPRINTF(("mpu_intr: no data\n")); 271 return (0); 272 } else { 273 mpu_readinput(sc); 274 return (1); 275 } 276 } 277