FreeBSD/Linux Kernel Cross Reference
sys/dev/ic/mpu.c
1 /* $NetBSD: mpu.c,v 1.19 2012/01/21 16:49:26 chs Exp $ */
2
3 /*
4 * Copyright (c) 1998, 2008 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) and by Andrew Doran.
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.19 2012/01/21 16:49:26 chs 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 static void mpu_get_locks(void *, kmutex_t **, kmutex_t **);
85
86 const struct midi_hw_if mpu_midi_hw_if = {
87 mpu_open,
88 mpu_close,
89 mpu_output,
90 mpu_getinfo,
91 0, /* ioctl */
92 mpu_get_locks,
93 };
94
95 int
96 mpu_find(struct mpu_softc *sc)
97 {
98 if (MPU_GETSTATUS(sc->iot, sc->ioh) == 0xff) {
99 DPRINTF(("%s: No status\n", __func__));
100 goto bad;
101 }
102 sc->open = 0;
103 sc->intr = 0;
104 if (mpu_reset(sc) == 0)
105 return 1;
106 bad:
107 return 0;
108 }
109
110 void
111 mpu_attach(struct mpu_softc *sc)
112 {
113
114 if (sc->lock == NULL) {
115 panic("mpu_attach: no lock");
116 }
117
118 midi_attach_mi(&mpu_midi_hw_if, sc, sc->sc_dev);
119 }
120
121 static inline int
122 mpu_waitready(struct mpu_softc *sc)
123 {
124 int i;
125
126 KASSERT(sc->lock == NULL || mutex_owned(sc->lock));
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 static int
137 mpu_reset(struct mpu_softc *sc)
138 {
139 bus_space_tag_t iot = sc->iot;
140 bus_space_handle_t ioh = sc->ioh;
141 int i;
142
143 KASSERT(sc->lock == NULL || mutex_owned(sc->lock));
144
145 if (mpu_waitready(sc)) {
146 DPRINTF(("%s: not ready\n", __func__));
147 return EIO;
148 }
149 bus_space_write_1(iot, ioh, MPU_COMMAND, MPU_RESET);
150 for (i = 0; i < 2*MPU_MAXWAIT; i++) {
151 if (!(MPU_GETSTATUS(iot, ioh) & MPU_INPUT_EMPTY) &&
152 bus_space_read_1(iot, ioh, MPU_DATA) == MPU_ACK) {
153 return 0;
154 }
155 }
156 DPRINTF(("%s: No ACK\n", __func__));
157 return EIO;
158 }
159
160 static int
161 mpu_open(void *addr, int flags, void (*iintr)(void *, int),
162 void (*ointr)(void *), void *arg)
163 {
164 struct mpu_softc *sc = addr;
165
166 DPRINTF(("%s: sc=%p\n", __func__, sc));
167
168 KASSERT(mutex_owned(sc->lock));
169
170 if (sc->open)
171 return EBUSY;
172 #ifndef AUDIO_NO_POWER_CTL
173 if (sc->powerctl)
174 sc->powerctl(sc->powerarg, 1);
175 #endif
176 if (mpu_reset(sc) != 0) {
177 #ifndef AUDIO_NO_POWER_CTL
178 if (sc->powerctl)
179 sc->powerctl(sc->powerarg, 0);
180 #endif
181 return EIO;
182 }
183
184 bus_space_write_1(sc->iot, sc->ioh, MPU_COMMAND, MPU_UART_MODE);
185 sc->open = 1;
186 sc->intr = iintr;
187 sc->arg = arg;
188 return 0;
189 }
190
191 static void
192 mpu_close(void *addr)
193 {
194 struct mpu_softc *sc = addr;
195
196 DPRINTF(("%s: sc=%p\n", __func__, sc));
197
198 KASSERT(mutex_owned(sc->lock));
199
200 sc->open = 0;
201 sc->intr = 0;
202 mpu_reset(sc); /* exit UART mode */
203
204 #ifndef AUDIO_NO_POWER_CTL
205 if (sc->powerctl)
206 sc->powerctl(sc->powerarg, 0);
207 #endif
208 }
209
210 static void
211 mpu_readinput(struct mpu_softc *sc)
212 {
213 bus_space_tag_t iot = sc->iot;
214 bus_space_handle_t ioh = sc->ioh;
215 int data;
216
217 KASSERT(mutex_owned(sc->lock));
218
219 while(!(MPU_GETSTATUS(iot, ioh) & MPU_INPUT_EMPTY)) {
220 data = bus_space_read_1(iot, ioh, MPU_DATA);
221 DPRINTFN(3, ("%s: sc=%p 0x%02x\n", __func__, sc, data));
222 if (sc->intr)
223 sc->intr(sc->arg, data);
224 }
225 }
226
227 static int
228 mpu_output(void *addr, int d)
229 {
230 struct mpu_softc *sc = addr;
231
232 KASSERT(mutex_owned(sc->lock));
233
234 DPRINTFN(3, ("%s: sc=%p 0x%02x\n", __func__, sc, d));
235 if (!(MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_INPUT_EMPTY)) {
236 mpu_readinput(sc);
237 }
238 if (mpu_waitready(sc)) {
239 DPRINTF(("%s:: not ready\n", __func__));
240 return EIO;
241 }
242 bus_space_write_1(sc->iot, sc->ioh, MPU_DATA, d);
243 return 0;
244 }
245
246 static void
247 mpu_getinfo(void *addr, struct midi_info *mi)
248 {
249 struct mpu_softc *sc = addr;
250
251 KASSERT(mutex_owned(sc->lock));
252
253 mi->name = sc->model;
254 mi->props = 0;
255 }
256
257 static void
258 mpu_get_locks(void *addr, kmutex_t **intr, kmutex_t **proc)
259 {
260 struct mpu_softc *sc = addr;
261
262 *intr = sc->lock;
263 *proc = NULL;
264 }
265
266 int
267 mpu_intr(void *addr)
268 {
269 struct mpu_softc *sc = addr;
270
271 KASSERT(mutex_owned(sc->lock));
272
273 if (MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_INPUT_EMPTY) {
274 DPRINTF(("%s: no data\n", __func__));
275 return 0;
276 } else {
277 mpu_readinput(sc);
278 return 1;
279 }
280 }
Cache object: a59bfe0b775f517bfabde1e7b824b11f
|