1206b17d7SAlexander Leidinger /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
448351eafSJoel Dahl * Copyright (c) 2003 Mathew Kanner
548351eafSJoel Dahl * All rights reserved.
6206b17d7SAlexander Leidinger *
7206b17d7SAlexander Leidinger * Redistribution and use in source and binary forms, with or without
848351eafSJoel Dahl * modification, are permitted provided that the following conditions
948351eafSJoel Dahl * are met:
1048351eafSJoel Dahl * 1. Redistributions of source code must retain the above copyright
1148351eafSJoel Dahl * notice, this list of conditions and the following disclaimer.
1248351eafSJoel Dahl * 2. Redistributions in binary form must reproduce the above copyright
1348351eafSJoel Dahl * notice, this list of conditions and the following disclaimer in the
1448351eafSJoel Dahl * documentation and/or other materials provided with the distribution.
15206b17d7SAlexander Leidinger *
1648351eafSJoel Dahl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1748351eafSJoel Dahl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1848351eafSJoel Dahl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1948351eafSJoel Dahl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2048351eafSJoel Dahl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2148351eafSJoel Dahl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2248351eafSJoel Dahl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2348351eafSJoel Dahl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24206b17d7SAlexander Leidinger * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25206b17d7SAlexander Leidinger * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26206b17d7SAlexander Leidinger * SUCH DAMAGE.
27206b17d7SAlexander Leidinger */
28206b17d7SAlexander Leidinger
29206b17d7SAlexander Leidinger #include <sys/param.h>
30206b17d7SAlexander Leidinger #include <sys/types.h>
31206b17d7SAlexander Leidinger #include <sys/param.h>
32206b17d7SAlexander Leidinger #include <sys/queue.h>
33206b17d7SAlexander Leidinger #include <sys/kernel.h>
34206b17d7SAlexander Leidinger #include <sys/lock.h>
35206b17d7SAlexander Leidinger #include <sys/mutex.h>
36206b17d7SAlexander Leidinger #include <sys/proc.h>
37206b17d7SAlexander Leidinger #include <sys/systm.h>
38206b17d7SAlexander Leidinger #include <sys/kobj.h>
39206b17d7SAlexander Leidinger #include <sys/malloc.h>
40206b17d7SAlexander Leidinger #include <sys/bus.h> /* to get driver_intr_t */
41206b17d7SAlexander Leidinger
4290da2b28SAriff Abdullah #ifdef HAVE_KERNEL_OPTION_HEADERS
4390da2b28SAriff Abdullah #include "opt_snd.h"
4490da2b28SAriff Abdullah #endif
4590da2b28SAriff Abdullah
46206b17d7SAlexander Leidinger #include <dev/sound/midi/mpu401.h>
47206b17d7SAlexander Leidinger #include <dev/sound/midi/midi.h>
48206b17d7SAlexander Leidinger
49206b17d7SAlexander Leidinger #include "mpu_if.h"
50206b17d7SAlexander Leidinger #include "mpufoi_if.h"
51206b17d7SAlexander Leidinger
525870e3c9SAriff Abdullah #ifndef KOBJMETHOD_END
535870e3c9SAriff Abdullah #define KOBJMETHOD_END { NULL, NULL }
545870e3c9SAriff Abdullah #endif
555870e3c9SAriff Abdullah
56206b17d7SAlexander Leidinger #define MPU_DATAPORT 0
57206b17d7SAlexander Leidinger #define MPU_CMDPORT 1
58206b17d7SAlexander Leidinger #define MPU_STATPORT 1
59206b17d7SAlexander Leidinger #define MPU_RESET 0xff
60206b17d7SAlexander Leidinger #define MPU_UART 0x3f
61206b17d7SAlexander Leidinger #define MPU_ACK 0xfe
62206b17d7SAlexander Leidinger #define MPU_STATMASK 0xc0
63206b17d7SAlexander Leidinger #define MPU_OUTPUTBUSY 0x40
64206b17d7SAlexander Leidinger #define MPU_INPUTBUSY 0x80
65206b17d7SAlexander Leidinger #define MPU_TRYDATA 50
66206b17d7SAlexander Leidinger #define MPU_DELAY 2500
67206b17d7SAlexander Leidinger
68206b17d7SAlexander Leidinger #define CMD(m,d) MPUFOI_WRITE(m, m->cookie, MPU_CMDPORT,d)
69206b17d7SAlexander Leidinger #define STATUS(m) MPUFOI_READ(m, m->cookie, MPU_STATPORT)
70206b17d7SAlexander Leidinger #define READ(m) MPUFOI_READ(m, m->cookie, MPU_DATAPORT)
71206b17d7SAlexander Leidinger #define WRITE(m,d) MPUFOI_WRITE(m, m->cookie, MPU_DATAPORT,d)
72206b17d7SAlexander Leidinger
73206b17d7SAlexander Leidinger struct mpu401 {
74206b17d7SAlexander Leidinger KOBJ_FIELDS;
75206b17d7SAlexander Leidinger struct snd_midi *mid;
76206b17d7SAlexander Leidinger int flags;
77206b17d7SAlexander Leidinger driver_intr_t *si;
78206b17d7SAlexander Leidinger void *cookie;
79206b17d7SAlexander Leidinger struct callout timer;
80206b17d7SAlexander Leidinger };
81206b17d7SAlexander Leidinger
82206b17d7SAlexander Leidinger static void mpu401_timeout(void *m);
83206b17d7SAlexander Leidinger static mpu401_intr_t mpu401_intr;
84206b17d7SAlexander Leidinger
8590da2b28SAriff Abdullah static int mpu401_minit(struct snd_midi *, void *);
8690da2b28SAriff Abdullah static int mpu401_muninit(struct snd_midi *, void *);
8790da2b28SAriff Abdullah static int mpu401_minqsize(struct snd_midi *, void *);
8890da2b28SAriff Abdullah static int mpu401_moutqsize(struct snd_midi *, void *);
8990da2b28SAriff Abdullah static void mpu401_mcallback(struct snd_midi *, void *, int);
9090da2b28SAriff Abdullah static void mpu401_mcallbackp(struct snd_midi *, void *, int);
9190da2b28SAriff Abdullah static const char *mpu401_mdescr(struct snd_midi *, void *, int);
9290da2b28SAriff Abdullah static const char *mpu401_mprovider(struct snd_midi *, void *);
93206b17d7SAlexander Leidinger
94206b17d7SAlexander Leidinger static kobj_method_t mpu401_methods[] = {
95206b17d7SAlexander Leidinger KOBJMETHOD(mpu_init, mpu401_minit),
96206b17d7SAlexander Leidinger KOBJMETHOD(mpu_uninit, mpu401_muninit),
97206b17d7SAlexander Leidinger KOBJMETHOD(mpu_inqsize, mpu401_minqsize),
98206b17d7SAlexander Leidinger KOBJMETHOD(mpu_outqsize, mpu401_moutqsize),
99206b17d7SAlexander Leidinger KOBJMETHOD(mpu_callback, mpu401_mcallback),
100206b17d7SAlexander Leidinger KOBJMETHOD(mpu_callbackp, mpu401_mcallbackp),
101206b17d7SAlexander Leidinger KOBJMETHOD(mpu_descr, mpu401_mdescr),
102206b17d7SAlexander Leidinger KOBJMETHOD(mpu_provider, mpu401_mprovider),
10390da2b28SAriff Abdullah KOBJMETHOD_END
104206b17d7SAlexander Leidinger };
105206b17d7SAlexander Leidinger
106206b17d7SAlexander Leidinger DEFINE_CLASS(mpu401, mpu401_methods, 0);
107206b17d7SAlexander Leidinger
108206b17d7SAlexander Leidinger void
mpu401_timeout(void * a)109206b17d7SAlexander Leidinger mpu401_timeout(void *a)
1108f981688SAlexander Leidinger {
1118f981688SAlexander Leidinger struct mpu401 *m = (struct mpu401 *)a;
112206b17d7SAlexander Leidinger
113206b17d7SAlexander Leidinger if (m->si)
114206b17d7SAlexander Leidinger (m->si)(m->cookie);
115206b17d7SAlexander Leidinger
116206b17d7SAlexander Leidinger }
117206b17d7SAlexander Leidinger static int
mpu401_intr(struct mpu401 * m)118206b17d7SAlexander Leidinger mpu401_intr(struct mpu401 *m)
119206b17d7SAlexander Leidinger {
120206b17d7SAlexander Leidinger #define MPU_INTR_BUF 16
121*526bd1d8SChristos Margiolis uint8_t b[MPU_INTR_BUF];
122206b17d7SAlexander Leidinger int i;
123206b17d7SAlexander Leidinger int s;
1248f981688SAlexander Leidinger
125206b17d7SAlexander Leidinger /*
126206b17d7SAlexander Leidinger printf("mpu401_intr\n");
127206b17d7SAlexander Leidinger */
128206b17d7SAlexander Leidinger #define RXRDY(m) ( (STATUS(m) & MPU_INPUTBUSY) == 0)
129206b17d7SAlexander Leidinger #define TXRDY(m) ( (STATUS(m) & MPU_OUTPUTBUSY) == 0)
130206b17d7SAlexander Leidinger #if 0
131206b17d7SAlexander Leidinger #define D(x,l) printf("mpu401_intr %d %x %s %s\n",l, x, x&MPU_INPUTBUSY?"RX":"", x&MPU_OUTPUTBUSY?"TX":"")
132206b17d7SAlexander Leidinger #else
133206b17d7SAlexander Leidinger #define D(x,l)
134206b17d7SAlexander Leidinger #endif
135206b17d7SAlexander Leidinger i = 0;
136206b17d7SAlexander Leidinger s = STATUS(m);
137206b17d7SAlexander Leidinger D(s, 1);
138206b17d7SAlexander Leidinger while ((s & MPU_INPUTBUSY) == 0 && i < MPU_INTR_BUF) {
139206b17d7SAlexander Leidinger b[i] = READ(m);
140206b17d7SAlexander Leidinger /*
141206b17d7SAlexander Leidinger printf("mpu401_intr in i %d d %d\n", i, b[i]);
142206b17d7SAlexander Leidinger */
143206b17d7SAlexander Leidinger i++;
144206b17d7SAlexander Leidinger s = STATUS(m);
145206b17d7SAlexander Leidinger }
1468f981688SAlexander Leidinger if (i)
1478f981688SAlexander Leidinger midi_in(m->mid, b, i);
148206b17d7SAlexander Leidinger i = 0;
149206b17d7SAlexander Leidinger while (!(s & MPU_OUTPUTBUSY) && i < MPU_INTR_BUF) {
150206b17d7SAlexander Leidinger if (midi_out(m->mid, b, 1)) {
151206b17d7SAlexander Leidinger /*
152206b17d7SAlexander Leidinger printf("mpu401_intr out i %d d %d\n", i, b[0]);
153206b17d7SAlexander Leidinger */
154206b17d7SAlexander Leidinger
155206b17d7SAlexander Leidinger WRITE(m, *b);
1568f981688SAlexander Leidinger } else {
157206b17d7SAlexander Leidinger /*
158206b17d7SAlexander Leidinger printf("mpu401_intr write: no output\n");
159206b17d7SAlexander Leidinger */
160206b17d7SAlexander Leidinger return 0;
161206b17d7SAlexander Leidinger }
162206b17d7SAlexander Leidinger i++;
163206b17d7SAlexander Leidinger /* DELAY(100); */
164206b17d7SAlexander Leidinger s = STATUS(m);
165206b17d7SAlexander Leidinger }
166206b17d7SAlexander Leidinger
167206b17d7SAlexander Leidinger if ((m->flags & M_TXEN) && (m->si)) {
168206b17d7SAlexander Leidinger callout_reset(&m->timer, 1, mpu401_timeout, m);
169206b17d7SAlexander Leidinger }
170206b17d7SAlexander Leidinger return (m->flags & M_TXEN) == M_TXEN;
171206b17d7SAlexander Leidinger }
172206b17d7SAlexander Leidinger
173206b17d7SAlexander Leidinger struct mpu401 *
mpu401_init(kobj_class_t cls,void * cookie,driver_intr_t softintr,mpu401_intr_t ** cb)1748f981688SAlexander Leidinger mpu401_init(kobj_class_t cls, void *cookie, driver_intr_t softintr,
1758f981688SAlexander Leidinger mpu401_intr_t ** cb)
176206b17d7SAlexander Leidinger {
177206b17d7SAlexander Leidinger struct mpu401 *m;
178206b17d7SAlexander Leidinger
179206b17d7SAlexander Leidinger *cb = NULL;
180206b17d7SAlexander Leidinger m = malloc(sizeof(*m), M_MIDI, M_NOWAIT | M_ZERO);
181206b17d7SAlexander Leidinger
182206b17d7SAlexander Leidinger if (!m)
183206b17d7SAlexander Leidinger return NULL;
184206b17d7SAlexander Leidinger
185206b17d7SAlexander Leidinger kobj_init((kobj_t)m, cls);
186206b17d7SAlexander Leidinger
187fd90e2edSJung-uk Kim callout_init(&m->timer, 1);
188206b17d7SAlexander Leidinger
189206b17d7SAlexander Leidinger m->si = softintr;
190206b17d7SAlexander Leidinger m->cookie = cookie;
191206b17d7SAlexander Leidinger m->flags = 0;
192206b17d7SAlexander Leidinger
193206b17d7SAlexander Leidinger m->mid = midi_init(&mpu401_class, 0, 0, m);
194206b17d7SAlexander Leidinger if (!m->mid)
195206b17d7SAlexander Leidinger goto err;
196206b17d7SAlexander Leidinger *cb = mpu401_intr;
197206b17d7SAlexander Leidinger return m;
198206b17d7SAlexander Leidinger err:
199206b17d7SAlexander Leidinger printf("mpu401_init error\n");
200206b17d7SAlexander Leidinger free(m, M_MIDI);
201206b17d7SAlexander Leidinger return NULL;
202206b17d7SAlexander Leidinger }
203206b17d7SAlexander Leidinger
204206b17d7SAlexander Leidinger int
mpu401_uninit(struct mpu401 * m)205206b17d7SAlexander Leidinger mpu401_uninit(struct mpu401 *m)
206206b17d7SAlexander Leidinger {
207206b17d7SAlexander Leidinger int retval;
208206b17d7SAlexander Leidinger
209206b17d7SAlexander Leidinger CMD(m, MPU_RESET);
210206b17d7SAlexander Leidinger retval = midi_uninit(m->mid);
211206b17d7SAlexander Leidinger if (retval)
212206b17d7SAlexander Leidinger return retval;
213206b17d7SAlexander Leidinger free(m, M_MIDI);
214206b17d7SAlexander Leidinger return 0;
215206b17d7SAlexander Leidinger }
216206b17d7SAlexander Leidinger
217206b17d7SAlexander Leidinger static int
mpu401_minit(struct snd_midi * sm,void * arg)21890da2b28SAriff Abdullah mpu401_minit(struct snd_midi *sm, void *arg)
219206b17d7SAlexander Leidinger {
22090da2b28SAriff Abdullah struct mpu401 *m = arg;
221206b17d7SAlexander Leidinger int i;
222206b17d7SAlexander Leidinger
223206b17d7SAlexander Leidinger CMD(m, MPU_RESET);
224206b17d7SAlexander Leidinger CMD(m, MPU_UART);
225206b17d7SAlexander Leidinger return 0;
226206b17d7SAlexander Leidinger i = 0;
227206b17d7SAlexander Leidinger while (++i < 2000) {
228206b17d7SAlexander Leidinger if (RXRDY(m))
229206b17d7SAlexander Leidinger if (READ(m) == MPU_ACK)
230206b17d7SAlexander Leidinger break;
231206b17d7SAlexander Leidinger }
232206b17d7SAlexander Leidinger
233206b17d7SAlexander Leidinger if (i < 2000) {
234206b17d7SAlexander Leidinger CMD(m, MPU_UART);
235206b17d7SAlexander Leidinger return 0;
236206b17d7SAlexander Leidinger }
237206b17d7SAlexander Leidinger printf("mpu401_minit failed active sensing\n");
238206b17d7SAlexander Leidinger return 1;
239206b17d7SAlexander Leidinger }
240206b17d7SAlexander Leidinger
241206b17d7SAlexander Leidinger int
mpu401_muninit(struct snd_midi * sm,void * arg)24290da2b28SAriff Abdullah mpu401_muninit(struct snd_midi *sm, void *arg)
243206b17d7SAlexander Leidinger {
24490da2b28SAriff Abdullah struct mpu401 *m = arg;
245206b17d7SAlexander Leidinger
246206b17d7SAlexander Leidinger return MPUFOI_UNINIT(m, m->cookie);
247206b17d7SAlexander Leidinger }
248206b17d7SAlexander Leidinger
249206b17d7SAlexander Leidinger int
mpu401_minqsize(struct snd_midi * sm,void * arg)25090da2b28SAriff Abdullah mpu401_minqsize(struct snd_midi *sm, void *arg)
251206b17d7SAlexander Leidinger {
252206b17d7SAlexander Leidinger return 128;
253206b17d7SAlexander Leidinger }
254206b17d7SAlexander Leidinger
255206b17d7SAlexander Leidinger int
mpu401_moutqsize(struct snd_midi * sm,void * arg)25690da2b28SAriff Abdullah mpu401_moutqsize(struct snd_midi *sm, void *arg)
257206b17d7SAlexander Leidinger {
258206b17d7SAlexander Leidinger return 128;
259206b17d7SAlexander Leidinger }
260206b17d7SAlexander Leidinger
261206b17d7SAlexander Leidinger static void
mpu401_mcallback(struct snd_midi * sm,void * arg,int flags)26290da2b28SAriff Abdullah mpu401_mcallback(struct snd_midi *sm, void *arg, int flags)
263206b17d7SAlexander Leidinger {
26490da2b28SAriff Abdullah struct mpu401 *m = arg;
265206b17d7SAlexander Leidinger #if 0
266206b17d7SAlexander Leidinger printf("mpu401_callback %s %s %s %s\n",
267206b17d7SAlexander Leidinger flags & M_RX ? "M_RX" : "",
268206b17d7SAlexander Leidinger flags & M_TX ? "M_TX" : "",
269206b17d7SAlexander Leidinger flags & M_RXEN ? "M_RXEN" : "",
270206b17d7SAlexander Leidinger flags & M_TXEN ? "M_TXEN" : "");
271206b17d7SAlexander Leidinger #endif
272206b17d7SAlexander Leidinger if (flags & M_TXEN && m->si) {
273206b17d7SAlexander Leidinger callout_reset(&m->timer, 1, mpu401_timeout, m);
274206b17d7SAlexander Leidinger }
275206b17d7SAlexander Leidinger m->flags = flags;
276206b17d7SAlexander Leidinger }
277206b17d7SAlexander Leidinger
278206b17d7SAlexander Leidinger static void
mpu401_mcallbackp(struct snd_midi * sm,void * arg,int flags)27990da2b28SAriff Abdullah mpu401_mcallbackp(struct snd_midi *sm, void *arg, int flags)
280206b17d7SAlexander Leidinger {
281206b17d7SAlexander Leidinger /* printf("mpu401_callbackp\n"); */
28290da2b28SAriff Abdullah mpu401_mcallback(sm, arg, flags);
283206b17d7SAlexander Leidinger }
284206b17d7SAlexander Leidinger
285206b17d7SAlexander Leidinger static const char *
mpu401_mdescr(struct snd_midi * sm,void * arg,int verbosity)28690da2b28SAriff Abdullah mpu401_mdescr(struct snd_midi *sm, void *arg, int verbosity)
287206b17d7SAlexander Leidinger {
288206b17d7SAlexander Leidinger
289206b17d7SAlexander Leidinger return "descr mpu401";
290206b17d7SAlexander Leidinger }
291206b17d7SAlexander Leidinger
292206b17d7SAlexander Leidinger static const char *
mpu401_mprovider(struct snd_midi * m,void * arg)29390da2b28SAriff Abdullah mpu401_mprovider(struct snd_midi *m, void *arg)
294206b17d7SAlexander Leidinger {
295206b17d7SAlexander Leidinger return "provider mpu401";
296206b17d7SAlexander Leidinger }
297