xref: /netbsd-src/sys/dev/ic/mpu.c (revision 481fca6e59249d8ffcf24fef7cfbe7b131bfb080)
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