xref: /freebsd/sys/dev/sound/midi/mpu401.c (revision 526bd1d87ec997e1c090262da6f2d9b6da0e8f89)
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
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
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 *
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
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
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
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
25090da2b28SAriff Abdullah mpu401_minqsize(struct snd_midi *sm, void *arg)
251206b17d7SAlexander Leidinger {
252206b17d7SAlexander Leidinger 	return 128;
253206b17d7SAlexander Leidinger }
254206b17d7SAlexander Leidinger 
255206b17d7SAlexander Leidinger int
25690da2b28SAriff Abdullah mpu401_moutqsize(struct snd_midi *sm, void *arg)
257206b17d7SAlexander Leidinger {
258206b17d7SAlexander Leidinger 	return 128;
259206b17d7SAlexander Leidinger }
260206b17d7SAlexander Leidinger 
261206b17d7SAlexander Leidinger static void
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
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 *
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 *
29390da2b28SAriff Abdullah mpu401_mprovider(struct snd_midi *m, void *arg)
294206b17d7SAlexander Leidinger {
295206b17d7SAlexander Leidinger 	return "provider mpu401";
296206b17d7SAlexander Leidinger }
297