1158979Snetchild/*-
2166322Sjoel * Copyright (c) 2003 Mathew Kanner
3166322Sjoel * All rights reserved.
4166322Sjoel *
5158979Snetchild * Redistribution and use in source and binary forms, with or without
6166322Sjoel * modification, are permitted provided that the following conditions
7166322Sjoel * are met:
8166322Sjoel * 1. Redistributions of source code must retain the above copyright
9166322Sjoel *    notice, this list of conditions and the following disclaimer.
10166322Sjoel * 2. Redistributions in binary form must reproduce the above copyright
11166322Sjoel *    notice, this list of conditions and the following disclaimer in the
12166322Sjoel *    documentation and/or other materials provided with the distribution.
13166322Sjoel *
14166322Sjoel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15166322Sjoel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16166322Sjoel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17166322Sjoel * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18166322Sjoel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19166322Sjoel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20166322Sjoel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21166322Sjoel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22158979Snetchild * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23158979Snetchild * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24158979Snetchild * SUCH DAMAGE.
25158979Snetchild */
26158979Snetchild
27158979Snetchild#include <sys/cdefs.h>
28158979Snetchild__FBSDID("$FreeBSD$");
29158979Snetchild
30158979Snetchild#include <sys/param.h>
31158979Snetchild#include <sys/types.h>
32158979Snetchild#include <sys/param.h>
33158979Snetchild#include <sys/queue.h>
34158979Snetchild#include <sys/kernel.h>
35158979Snetchild#include <sys/lock.h>
36158979Snetchild#include <sys/mutex.h>
37158979Snetchild#include <sys/proc.h>
38158979Snetchild#include <sys/systm.h>
39158979Snetchild#include <sys/kobj.h>
40158979Snetchild#include <sys/malloc.h>
41166971Snetchild#include <sys/bus.h>			/* to get driver_intr_t */
42158979Snetchild
43193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS
44193640Sariff#include "opt_snd.h"
45193640Sariff#endif
46193640Sariff
47158979Snetchild#include <dev/sound/midi/mpu401.h>
48158979Snetchild#include <dev/sound/midi/midi.h>
49158979Snetchild
50158979Snetchild#include "mpu_if.h"
51158979Snetchild#include "mpufoi_if.h"
52158979Snetchild
53193979Sariff#ifndef KOBJMETHOD_END
54193979Sariff#define KOBJMETHOD_END	{ NULL, NULL }
55193979Sariff#endif
56193979Sariff
57158979Snetchild#define MPU_DATAPORT   0
58158979Snetchild#define MPU_CMDPORT    1
59158979Snetchild#define MPU_STATPORT   1
60158979Snetchild#define MPU_RESET      0xff
61158979Snetchild#define MPU_UART       0x3f
62158979Snetchild#define MPU_ACK        0xfe
63158979Snetchild#define MPU_STATMASK   0xc0
64158979Snetchild#define MPU_OUTPUTBUSY 0x40
65158979Snetchild#define MPU_INPUTBUSY  0x80
66158979Snetchild#define MPU_TRYDATA 50
67158979Snetchild#define MPU_DELAY   2500
68158979Snetchild
69158979Snetchild#define CMD(m,d)	MPUFOI_WRITE(m, m->cookie, MPU_CMDPORT,d)
70158979Snetchild#define STATUS(m)	MPUFOI_READ(m, m->cookie, MPU_STATPORT)
71158979Snetchild#define READ(m)		MPUFOI_READ(m, m->cookie, MPU_DATAPORT)
72158979Snetchild#define WRITE(m,d)	MPUFOI_WRITE(m, m->cookie, MPU_DATAPORT,d)
73158979Snetchild
74158979Snetchildstruct mpu401 {
75158979Snetchild	KOBJ_FIELDS;
76158979Snetchild	struct snd_midi *mid;
77166971Snetchild	int	flags;
78158979Snetchild	driver_intr_t *si;
79166971Snetchild	void   *cookie;
80158979Snetchild	struct callout timer;
81158979Snetchild};
82158979Snetchild
83166971Snetchildstatic void mpu401_timeout(void *m);
84158979Snetchildstatic mpu401_intr_t mpu401_intr;
85158979Snetchild
86193640Sariffstatic int mpu401_minit(struct snd_midi *, void *);
87193640Sariffstatic int mpu401_muninit(struct snd_midi *, void *);
88193640Sariffstatic int mpu401_minqsize(struct snd_midi *, void *);
89193640Sariffstatic int mpu401_moutqsize(struct snd_midi *, void *);
90193640Sariffstatic void mpu401_mcallback(struct snd_midi *, void *, int);
91193640Sariffstatic void mpu401_mcallbackp(struct snd_midi *, void *, int);
92193640Sariffstatic const char *mpu401_mdescr(struct snd_midi *, void *, int);
93193640Sariffstatic const char *mpu401_mprovider(struct snd_midi *, void *);
94158979Snetchild
95158979Snetchildstatic kobj_method_t mpu401_methods[] = {
96166971Snetchild	KOBJMETHOD(mpu_init, mpu401_minit),
97166971Snetchild	KOBJMETHOD(mpu_uninit, mpu401_muninit),
98166971Snetchild	KOBJMETHOD(mpu_inqsize, mpu401_minqsize),
99166971Snetchild	KOBJMETHOD(mpu_outqsize, mpu401_moutqsize),
100166971Snetchild	KOBJMETHOD(mpu_callback, mpu401_mcallback),
101166971Snetchild	KOBJMETHOD(mpu_callbackp, mpu401_mcallbackp),
102166971Snetchild	KOBJMETHOD(mpu_descr, mpu401_mdescr),
103166971Snetchild	KOBJMETHOD(mpu_provider, mpu401_mprovider),
104193640Sariff	KOBJMETHOD_END
105158979Snetchild};
106158979Snetchild
107158979SnetchildDEFINE_CLASS(mpu401, mpu401_methods, 0);
108158979Snetchild
109158979Snetchildvoid
110166971Snetchildmpu401_timeout(void *a)
111166971Snetchild{
112166971Snetchild	struct mpu401 *m = (struct mpu401 *)a;
113158979Snetchild
114158979Snetchild	if (m->si)
115158979Snetchild		(m->si)(m->cookie);
116158979Snetchild
117158979Snetchild}
118158979Snetchildstatic int
119158979Snetchildmpu401_intr(struct mpu401 *m)
120158979Snetchild{
121158979Snetchild#define MPU_INTR_BUF	16
122158979Snetchild	MIDI_TYPE b[MPU_INTR_BUF];
123158979Snetchild	int i;
124158979Snetchild	int s;
125166971Snetchild
126158979Snetchild/*
127158979Snetchild	printf("mpu401_intr\n");
128158979Snetchild*/
129158979Snetchild#define RXRDY(m) ( (STATUS(m) & MPU_INPUTBUSY) == 0)
130158979Snetchild#define TXRDY(m) ( (STATUS(m) & MPU_OUTPUTBUSY) == 0)
131158979Snetchild#if 0
132158979Snetchild#define D(x,l) printf("mpu401_intr %d %x %s %s\n",l, x, x&MPU_INPUTBUSY?"RX":"", x&MPU_OUTPUTBUSY?"TX":"")
133158979Snetchild#else
134158979Snetchild#define D(x,l)
135158979Snetchild#endif
136166971Snetchild	i = 0;
137158979Snetchild	s = STATUS(m);
138166971Snetchild	D(s, 1);
139166971Snetchild	while ((s & MPU_INPUTBUSY) == 0 && i < MPU_INTR_BUF) {
140166971Snetchild		b[i] = READ(m);
141158979Snetchild/*
142158979Snetchild		printf("mpu401_intr in i %d d %d\n", i, b[i]);
143158979Snetchild*/
144158979Snetchild		i++;
145166971Snetchild		s = STATUS(m);
146158979Snetchild	}
147166971Snetchild	if (i)
148166971Snetchild		midi_in(m->mid, b, i);
149166971Snetchild	i = 0;
150166971Snetchild	while (!(s & MPU_OUTPUTBUSY) && i < MPU_INTR_BUF) {
151166971Snetchild		if (midi_out(m->mid, b, 1)) {
152158979Snetchild/*
153158979Snetchild			printf("mpu401_intr out i %d d %d\n", i, b[0]);
154158979Snetchild*/
155166971Snetchild
156158979Snetchild			WRITE(m, *b);
157166971Snetchild		} else {
158158979Snetchild/*
159158979Snetchild			printf("mpu401_intr write: no output\n");
160158979Snetchild*/
161158979Snetchild			return 0;
162158979Snetchild		}
163158979Snetchild		i++;
164166971Snetchild		/* DELAY(100); */
165166971Snetchild		s = STATUS(m);
166158979Snetchild	}
167158979Snetchild
168166971Snetchild	if ((m->flags & M_TXEN) && (m->si)) {
169166971Snetchild		callout_reset(&m->timer, 1, mpu401_timeout, m);
170158979Snetchild	}
171158979Snetchild	return (m->flags & M_TXEN) == M_TXEN;
172158979Snetchild}
173158979Snetchild
174158979Snetchildstruct mpu401 *
175166971Snetchildmpu401_init(kobj_class_t cls, void *cookie, driver_intr_t softintr,
176166971Snetchild    mpu401_intr_t ** cb)
177158979Snetchild{
178158979Snetchild	struct mpu401 *m;
179158979Snetchild
180158979Snetchild	*cb = NULL;
181158979Snetchild	m = malloc(sizeof(*m), M_MIDI, M_NOWAIT | M_ZERO);
182158979Snetchild
183166971Snetchild	if (!m)
184158979Snetchild		return NULL;
185158979Snetchild
186158979Snetchild	kobj_init((kobj_t)m, cls);
187158979Snetchild
188283291Sjkim	callout_init(&m->timer, 1);
189158979Snetchild
190158979Snetchild	m->si = softintr;
191158979Snetchild	m->cookie = cookie;
192158979Snetchild	m->flags = 0;
193158979Snetchild
194166971Snetchild	m->mid = midi_init(&mpu401_class, 0, 0, m);
195158979Snetchild	if (!m->mid)
196158979Snetchild		goto err;
197158979Snetchild	*cb = mpu401_intr;
198158979Snetchild	return m;
199158979Snetchilderr:
200158979Snetchild	printf("mpu401_init error\n");
201158979Snetchild	free(m, M_MIDI);
202158979Snetchild	return NULL;
203158979Snetchild}
204158979Snetchild
205158979Snetchildint
206158979Snetchildmpu401_uninit(struct mpu401 *m)
207158979Snetchild{
208158979Snetchild	int retval;
209158979Snetchild
210158979Snetchild	CMD(m, MPU_RESET);
211158979Snetchild	retval = midi_uninit(m->mid);
212158979Snetchild	if (retval)
213158979Snetchild		return retval;
214158979Snetchild	free(m, M_MIDI);
215158979Snetchild	return 0;
216158979Snetchild}
217158979Snetchild
218158979Snetchildstatic int
219193640Sariffmpu401_minit(struct snd_midi *sm, void *arg)
220158979Snetchild{
221193640Sariff	struct mpu401 *m = arg;
222158979Snetchild	int i;
223158979Snetchild
224158979Snetchild	CMD(m, MPU_RESET);
225158979Snetchild	CMD(m, MPU_UART);
226158979Snetchild	return 0;
227166971Snetchild	i = 0;
228166971Snetchild	while (++i < 2000) {
229166971Snetchild		if (RXRDY(m))
230166971Snetchild			if (READ(m) == MPU_ACK)
231158979Snetchild				break;
232158979Snetchild	}
233158979Snetchild
234166971Snetchild	if (i < 2000) {
235158979Snetchild		CMD(m, MPU_UART);
236158979Snetchild		return 0;
237158979Snetchild	}
238158979Snetchild	printf("mpu401_minit failed active sensing\n");
239158979Snetchild	return 1;
240158979Snetchild}
241158979Snetchild
242158979Snetchild
243158979Snetchildint
244193640Sariffmpu401_muninit(struct snd_midi *sm, void *arg)
245158979Snetchild{
246193640Sariff	struct mpu401 *m = arg;
247158979Snetchild
248158979Snetchild	return MPUFOI_UNINIT(m, m->cookie);
249158979Snetchild}
250158979Snetchild
251158979Snetchildint
252193640Sariffmpu401_minqsize(struct snd_midi *sm, void *arg)
253158979Snetchild{
254158979Snetchild	return 128;
255158979Snetchild}
256158979Snetchild
257158979Snetchildint
258193640Sariffmpu401_moutqsize(struct snd_midi *sm, void *arg)
259158979Snetchild{
260158979Snetchild	return 128;
261158979Snetchild}
262158979Snetchild
263158979Snetchildstatic void
264193640Sariffmpu401_mcallback(struct snd_midi *sm, void *arg, int flags)
265158979Snetchild{
266193640Sariff	struct mpu401 *m = arg;
267158979Snetchild#if 0
268166971Snetchild	printf("mpu401_callback %s %s %s %s\n",
269166971Snetchild	    flags & M_RX ? "M_RX" : "",
270166971Snetchild	    flags & M_TX ? "M_TX" : "",
271166971Snetchild	    flags & M_RXEN ? "M_RXEN" : "",
272166971Snetchild	    flags & M_TXEN ? "M_TXEN" : "");
273158979Snetchild#endif
274158979Snetchild	if (flags & M_TXEN && m->si) {
275158979Snetchild		callout_reset(&m->timer, 1, mpu401_timeout, m);
276158979Snetchild	}
277158979Snetchild	m->flags = flags;
278158979Snetchild}
279158979Snetchild
280158979Snetchildstatic void
281193640Sariffmpu401_mcallbackp(struct snd_midi *sm, void *arg, int flags)
282158979Snetchild{
283158979Snetchild/*	printf("mpu401_callbackp\n"); */
284193640Sariff	mpu401_mcallback(sm, arg, flags);
285158979Snetchild}
286158979Snetchild
287158979Snetchildstatic const char *
288193640Sariffmpu401_mdescr(struct snd_midi *sm, void *arg, int verbosity)
289158979Snetchild{
290158979Snetchild
291158979Snetchild	return "descr mpu401";
292158979Snetchild}
293158979Snetchild
294158979Snetchildstatic const char *
295193640Sariffmpu401_mprovider(struct snd_midi *m, void *arg)
296158979Snetchild{
297158979Snetchild	return "provider mpu401";
298158979Snetchild}
299