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