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