Line data Source code
1 : /* $OpenBSD: mpu401.c,v 1.15 2015/03/14 03:38:47 jsg 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 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 : * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 : * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 : * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 : * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 : * POSSIBILITY OF SUCH DAMAGE.
31 : */
32 :
33 : #include <sys/param.h>
34 : #include <sys/systm.h>
35 : #include <sys/errno.h>
36 : #include <sys/ioctl.h>
37 : #include <sys/syslog.h>
38 : #include <sys/device.h>
39 : #include <sys/buf.h>
40 :
41 : #include <machine/cpu.h>
42 : #include <machine/intr.h>
43 : #include <machine/bus.h>
44 :
45 : #include <dev/audio_if.h>
46 : #include <dev/midi_if.h>
47 :
48 : #include <dev/isa/isavar.h>
49 :
50 : #include <dev/ic/mpuvar.h>
51 :
52 : #ifdef AUDIO_DEBUG
53 : #define DPRINTF(x) if (mpu401debug) printf x
54 : #define DPRINTFN(n,x) if (mpu401debug >= (n)) printf x
55 : int mpu401debug = 0;
56 : #else
57 : #define DPRINTF(x)
58 : #define DPRINTFN(n,x)
59 : #endif
60 :
61 : #define MPU_GETSTATUS(iot, ioh) (bus_space_read_1(iot, ioh, MPU_STATUS))
62 :
63 : int mpu_reset(struct mpu_softc *);
64 : static __inline int mpu_waitready(struct mpu_softc *);
65 : void mpu_readinput(struct mpu_softc *);
66 :
67 : struct cfdriver mpu_cd = {
68 : NULL, "mpu", DV_DULL
69 : };
70 :
71 : struct midi_hw_if mpu_midi_hw_if = {
72 : mpu_open,
73 : mpu_close,
74 : mpu_output,
75 : 0, /* flush */
76 : mpu_getinfo,
77 : 0, /* ioctl */
78 : };
79 :
80 : int
81 0 : mpu_find(v)
82 : void *v;
83 : {
84 0 : struct mpu_softc *sc = v;
85 :
86 0 : if (MPU_GETSTATUS(sc->iot, sc->ioh) == 0xff) {
87 : DPRINTF(("mpu_find: No status\n"));
88 : goto bad;
89 : }
90 0 : sc->open = 0;
91 0 : sc->intr = 0;
92 0 : if (mpu_reset(sc) == 0)
93 0 : return 1;
94 : bad:
95 0 : return 0;
96 0 : }
97 :
98 : static __inline int
99 0 : mpu_waitready(sc)
100 : struct mpu_softc *sc;
101 : {
102 : int i;
103 :
104 0 : for(i = 0; i < MPU_MAXWAIT; i++) {
105 0 : if (!(MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_OUTPUT_BUSY))
106 0 : return 0;
107 0 : delay(10);
108 : }
109 0 : return 1;
110 0 : }
111 :
112 : int
113 0 : mpu_reset(sc)
114 : struct mpu_softc *sc;
115 : {
116 0 : bus_space_tag_t iot = sc->iot;
117 0 : bus_space_handle_t ioh = sc->ioh;
118 : int i;
119 :
120 0 : if (mpu_waitready(sc)) {
121 : DPRINTF(("mpu_reset: not ready\n"));
122 0 : return EIO;
123 : }
124 0 : mtx_enter(&audio_lock); /* Don't let the interrupt get our ACK. */
125 0 : bus_space_write_1(iot, ioh, MPU_COMMAND, MPU_RESET);
126 0 : for(i = 0; i < 2*MPU_MAXWAIT; i++) {
127 0 : if (!(MPU_GETSTATUS(iot, ioh) & MPU_INPUT_EMPTY) &&
128 0 : bus_space_read_1(iot, ioh, MPU_DATA) == MPU_ACK) {
129 0 : mtx_leave(&audio_lock);
130 0 : return 0;
131 : }
132 : }
133 0 : mtx_leave(&audio_lock);
134 : DPRINTF(("mpu_reset: No ACK\n"));
135 0 : return EIO;
136 0 : }
137 :
138 : int
139 0 : mpu_open(v, flags, iintr, ointr, arg)
140 : void *v;
141 : int flags;
142 : void (*iintr)(void *, int);
143 : void (*ointr)(void *);
144 : void *arg;
145 : {
146 0 : struct mpu_softc *sc = v;
147 :
148 : DPRINTF(("mpu_open: sc=%p\n", sc));
149 :
150 0 : if (sc->open)
151 0 : return EBUSY;
152 0 : if (mpu_reset(sc) != 0)
153 0 : return EIO;
154 :
155 0 : bus_space_write_1(sc->iot, sc->ioh, MPU_COMMAND, MPU_UART_MODE);
156 0 : sc->open = 1;
157 0 : sc->intr = iintr;
158 0 : sc->arg = arg;
159 0 : return 0;
160 0 : }
161 :
162 : void
163 0 : mpu_close(v)
164 : void *v;
165 : {
166 0 : struct mpu_softc *sc = v;
167 :
168 : DPRINTF(("mpu_close: sc=%p\n", sc));
169 :
170 0 : sc->open = 0;
171 0 : sc->intr = 0;
172 0 : mpu_reset(sc); /* exit UART mode */
173 0 : }
174 :
175 : void
176 0 : mpu_readinput(sc)
177 : struct mpu_softc *sc;
178 : {
179 0 : bus_space_tag_t iot = sc->iot;
180 0 : bus_space_handle_t ioh = sc->ioh;
181 : int data;
182 :
183 0 : while(!(MPU_GETSTATUS(iot, ioh) & MPU_INPUT_EMPTY)) {
184 0 : data = bus_space_read_1(iot, ioh, MPU_DATA);
185 : DPRINTFN(3, ("mpu_rea: sc=%p 0x%02x\n", sc, data));
186 0 : if (sc->intr)
187 0 : sc->intr(sc->arg, data);
188 : }
189 0 : }
190 :
191 : /*
192 : * called with audio_lock
193 : */
194 : int
195 0 : mpu_output(v, d)
196 : void *v;
197 : int d;
198 : {
199 0 : struct mpu_softc *sc = v;
200 :
201 : DPRINTFN(3, ("mpu_output: sc=%p 0x%02x\n", sc, d));
202 0 : if (!(MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_INPUT_EMPTY)) {
203 0 : mpu_readinput(sc);
204 0 : }
205 0 : if (MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_OUTPUT_BUSY)
206 0 : delay(10);
207 0 : if (MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_OUTPUT_BUSY)
208 0 : return 0;
209 0 : bus_space_write_1(sc->iot, sc->ioh, MPU_DATA, d);
210 0 : return 1;
211 0 : }
212 :
213 : void
214 0 : mpu_getinfo(addr, mi)
215 : void *addr;
216 : struct midi_info *mi;
217 : {
218 0 : mi->name = "MPU-401 MIDI UART";
219 0 : mi->props = 0;
220 0 : }
221 :
222 : int
223 0 : mpu_intr(v)
224 : void *v;
225 : {
226 0 : struct mpu_softc *sc = v;
227 :
228 0 : mtx_enter(&audio_lock);
229 0 : if (MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_INPUT_EMPTY) {
230 0 : mtx_leave(&audio_lock);
231 : DPRINTF(("mpu_intr: no data\n"));
232 0 : return 0;
233 : }
234 0 : mpu_readinput(sc);
235 0 : mtx_leave(&audio_lock);
236 0 : return 1;
237 0 : }
|