xref: /openbsd/sys/dev/isa/mpu401.c (revision 73471bf0)
1 /*	$OpenBSD: mpu401.c,v 1.16 2021/03/07 06:17:04 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 mpu_find(void *v)
82 {
83 	struct mpu_softc *sc = v;
84 
85 	if (MPU_GETSTATUS(sc->iot, sc->ioh) == 0xff) {
86 		DPRINTF(("mpu_find: No status\n"));
87 		goto bad;
88 	}
89 	sc->open = 0;
90 	sc->intr = 0;
91 	if (mpu_reset(sc) == 0)
92 		return 1;
93 bad:
94 	return 0;
95 }
96 
97 static __inline int
98 mpu_waitready(struct mpu_softc *sc)
99 {
100 	int i;
101 
102 	for(i = 0; i < MPU_MAXWAIT; i++) {
103 		if (!(MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_OUTPUT_BUSY))
104 			return 0;
105 		delay(10);
106 	}
107 	return 1;
108 }
109 
110 int
111 mpu_reset(struct mpu_softc *sc)
112 {
113 	bus_space_tag_t iot = sc->iot;
114 	bus_space_handle_t ioh = sc->ioh;
115 	int i;
116 
117 	if (mpu_waitready(sc)) {
118 		DPRINTF(("mpu_reset: not ready\n"));
119 		return EIO;
120 	}
121 	mtx_enter(&audio_lock);	/* Don't let the interrupt get our ACK. */
122 	bus_space_write_1(iot, ioh, MPU_COMMAND, MPU_RESET);
123 	for(i = 0; i < 2*MPU_MAXWAIT; i++) {
124 		if (!(MPU_GETSTATUS(iot, ioh) & MPU_INPUT_EMPTY) &&
125 		    bus_space_read_1(iot, ioh, MPU_DATA) == MPU_ACK) {
126 			mtx_leave(&audio_lock);
127 			return 0;
128 		}
129 	}
130 	mtx_leave(&audio_lock);
131 	DPRINTF(("mpu_reset: No ACK\n"));
132 	return EIO;
133 }
134 
135 int
136 mpu_open(void *v, int flags, void (*iintr)(void *, int), void (*ointr)(void *),
137     void *arg)
138 {
139 	struct mpu_softc *sc = v;
140 
141         DPRINTF(("mpu_open: sc=%p\n", sc));
142 
143 	if (sc->open)
144 		return EBUSY;
145 	if (mpu_reset(sc) != 0)
146 		return EIO;
147 
148 	bus_space_write_1(sc->iot, sc->ioh, MPU_COMMAND, MPU_UART_MODE);
149 	sc->open = 1;
150 	sc->intr = iintr;
151 	sc->arg = arg;
152 	return 0;
153 }
154 
155 void
156 mpu_close(void *v)
157 {
158 	struct mpu_softc *sc = v;
159 
160         DPRINTF(("mpu_close: sc=%p\n", sc));
161 
162 	sc->open = 0;
163 	sc->intr = 0;
164 	mpu_reset(sc); /* exit UART mode */
165 }
166 
167 void
168 mpu_readinput(struct mpu_softc *sc)
169 {
170 	bus_space_tag_t iot = sc->iot;
171 	bus_space_handle_t ioh = sc->ioh;
172 	int data;
173 
174 	while(!(MPU_GETSTATUS(iot, ioh) & MPU_INPUT_EMPTY)) {
175 		data = bus_space_read_1(iot, ioh, MPU_DATA);
176 		DPRINTFN(3, ("mpu_rea: sc=%p 0x%02x\n", sc, data));
177 		if (sc->intr)
178 			sc->intr(sc->arg, data);
179 	}
180 }
181 
182 /*
183  * called with audio_lock
184  */
185 int
186 mpu_output(void *v, int d)
187 {
188 	struct mpu_softc *sc = v;
189 
190 	DPRINTFN(3, ("mpu_output: sc=%p 0x%02x\n", sc, d));
191 	if (!(MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_INPUT_EMPTY)) {
192 		mpu_readinput(sc);
193 	}
194 	if (MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_OUTPUT_BUSY)
195 		delay(10);
196 	if (MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_OUTPUT_BUSY)
197 		return 0;
198 	bus_space_write_1(sc->iot, sc->ioh, MPU_DATA, d);
199 	return 1;
200 }
201 
202 void
203 mpu_getinfo(void *addr, struct midi_info *mi)
204 {
205 	mi->name = "MPU-401 MIDI UART";
206 	mi->props = 0;
207 }
208 
209 int
210 mpu_intr(void *v)
211 {
212 	struct mpu_softc *sc = v;
213 
214 	mtx_enter(&audio_lock);
215 	if (MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_INPUT_EMPTY) {
216 		mtx_leave(&audio_lock);
217 		DPRINTF(("mpu_intr: no data\n"));
218 		return 0;
219 	}
220 	mpu_readinput(sc);
221 	mtx_leave(&audio_lock);
222 	return 1;
223 }
224