mpu401.c revision 166971
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: head/sys/dev/sound/midi/mpu401.c 166971 2007-02-25 13:51:52Z netchild $");
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
43158979Snetchild#include <dev/sound/midi/mpu401.h>
44158979Snetchild#include <dev/sound/midi/midi.h>
45158979Snetchild
46158979Snetchild#include "mpu_if.h"
47158979Snetchild#include "mpufoi_if.h"
48158979Snetchild
49158979Snetchild#define MPU_DATAPORT   0
50158979Snetchild#define MPU_CMDPORT    1
51158979Snetchild#define MPU_STATPORT   1
52158979Snetchild#define MPU_RESET      0xff
53158979Snetchild#define MPU_UART       0x3f
54158979Snetchild#define MPU_ACK        0xfe
55158979Snetchild#define MPU_STATMASK   0xc0
56158979Snetchild#define MPU_OUTPUTBUSY 0x40
57158979Snetchild#define MPU_INPUTBUSY  0x80
58158979Snetchild#define MPU_TRYDATA 50
59158979Snetchild#define MPU_DELAY   2500
60158979Snetchild
61158979Snetchild#define CMD(m,d)	MPUFOI_WRITE(m, m->cookie, MPU_CMDPORT,d)
62158979Snetchild#define STATUS(m)	MPUFOI_READ(m, m->cookie, MPU_STATPORT)
63158979Snetchild#define READ(m)		MPUFOI_READ(m, m->cookie, MPU_DATAPORT)
64158979Snetchild#define WRITE(m,d)	MPUFOI_WRITE(m, m->cookie, MPU_DATAPORT,d)
65158979Snetchild
66158979Snetchildstruct mpu401 {
67158979Snetchild	KOBJ_FIELDS;
68158979Snetchild	struct snd_midi *mid;
69166971Snetchild	int	flags;
70158979Snetchild	driver_intr_t *si;
71166971Snetchild	void   *cookie;
72158979Snetchild	struct callout timer;
73158979Snetchild};
74158979Snetchild
75166971Snetchildstatic void mpu401_timeout(void *m);
76158979Snetchildstatic mpu401_intr_t mpu401_intr;
77158979Snetchild
78158979Snetchildstatic int mpu401_minit(kobj_t obj, struct mpu401 *m);
79158979Snetchildstatic int mpu401_muninit(kobj_t obj, struct mpu401 *m);
80158979Snetchildstatic int mpu401_minqsize(kobj_t obj, struct mpu401 *m);
81158979Snetchildstatic int mpu401_moutqsize(kobj_t obj, struct mpu401 *m);
82158979Snetchildstatic void mpu401_mcallback(kobj_t obj, struct mpu401 *m, int flags);
83158979Snetchildstatic void mpu401_mcallbackp(kobj_t obj, struct mpu401 *m, int flags);
84158979Snetchildstatic const char *mpu401_mdescr(kobj_t obj, struct mpu401 *m, int verbosity);
85158979Snetchildstatic const char *mpu401_mprovider(kobj_t obj, struct mpu401 *m);
86158979Snetchild
87158979Snetchildstatic kobj_method_t mpu401_methods[] = {
88166971Snetchild	KOBJMETHOD(mpu_init, mpu401_minit),
89166971Snetchild	KOBJMETHOD(mpu_uninit, mpu401_muninit),
90166971Snetchild	KOBJMETHOD(mpu_inqsize, mpu401_minqsize),
91166971Snetchild	KOBJMETHOD(mpu_outqsize, mpu401_moutqsize),
92166971Snetchild	KOBJMETHOD(mpu_callback, mpu401_mcallback),
93166971Snetchild	KOBJMETHOD(mpu_callbackp, mpu401_mcallbackp),
94166971Snetchild	KOBJMETHOD(mpu_descr, mpu401_mdescr),
95166971Snetchild	KOBJMETHOD(mpu_provider, mpu401_mprovider),
96166971Snetchild	{0, 0}
97158979Snetchild};
98158979Snetchild
99158979SnetchildDEFINE_CLASS(mpu401, mpu401_methods, 0);
100158979Snetchild
101158979Snetchildvoid
102166971Snetchildmpu401_timeout(void *a)
103166971Snetchild{
104166971Snetchild	struct mpu401 *m = (struct mpu401 *)a;
105158979Snetchild
106158979Snetchild	if (m->si)
107158979Snetchild		(m->si)(m->cookie);
108158979Snetchild
109158979Snetchild}
110158979Snetchildstatic int
111158979Snetchildmpu401_intr(struct mpu401 *m)
112158979Snetchild{
113158979Snetchild#define MPU_INTR_BUF	16
114158979Snetchild	MIDI_TYPE b[MPU_INTR_BUF];
115158979Snetchild	int i;
116158979Snetchild	int s;
117166971Snetchild
118158979Snetchild/*
119158979Snetchild	printf("mpu401_intr\n");
120158979Snetchild*/
121158979Snetchild#define RXRDY(m) ( (STATUS(m) & MPU_INPUTBUSY) == 0)
122158979Snetchild#define TXRDY(m) ( (STATUS(m) & MPU_OUTPUTBUSY) == 0)
123158979Snetchild#if 0
124158979Snetchild#define D(x,l) printf("mpu401_intr %d %x %s %s\n",l, x, x&MPU_INPUTBUSY?"RX":"", x&MPU_OUTPUTBUSY?"TX":"")
125158979Snetchild#else
126158979Snetchild#define D(x,l)
127158979Snetchild#endif
128166971Snetchild	i = 0;
129158979Snetchild	s = STATUS(m);
130166971Snetchild	D(s, 1);
131166971Snetchild	while ((s & MPU_INPUTBUSY) == 0 && i < MPU_INTR_BUF) {
132166971Snetchild		b[i] = READ(m);
133158979Snetchild/*
134158979Snetchild		printf("mpu401_intr in i %d d %d\n", i, b[i]);
135158979Snetchild*/
136158979Snetchild		i++;
137166971Snetchild		s = STATUS(m);
138158979Snetchild	}
139166971Snetchild	if (i)
140166971Snetchild		midi_in(m->mid, b, i);
141166971Snetchild	i = 0;
142166971Snetchild	while (!(s & MPU_OUTPUTBUSY) && i < MPU_INTR_BUF) {
143166971Snetchild		if (midi_out(m->mid, b, 1)) {
144158979Snetchild/*
145158979Snetchild			printf("mpu401_intr out i %d d %d\n", i, b[0]);
146158979Snetchild*/
147166971Snetchild
148158979Snetchild			WRITE(m, *b);
149166971Snetchild		} else {
150158979Snetchild/*
151158979Snetchild			printf("mpu401_intr write: no output\n");
152158979Snetchild*/
153158979Snetchild			return 0;
154158979Snetchild		}
155158979Snetchild		i++;
156166971Snetchild		/* DELAY(100); */
157166971Snetchild		s = STATUS(m);
158158979Snetchild	}
159158979Snetchild
160166971Snetchild	if ((m->flags & M_TXEN) && (m->si)) {
161166971Snetchild		callout_reset(&m->timer, 1, mpu401_timeout, m);
162158979Snetchild	}
163158979Snetchild	return (m->flags & M_TXEN) == M_TXEN;
164158979Snetchild}
165158979Snetchild
166158979Snetchildstruct mpu401 *
167166971Snetchildmpu401_init(kobj_class_t cls, void *cookie, driver_intr_t softintr,
168166971Snetchild    mpu401_intr_t ** cb)
169158979Snetchild{
170158979Snetchild	struct mpu401 *m;
171158979Snetchild
172158979Snetchild	*cb = NULL;
173158979Snetchild	m = malloc(sizeof(*m), M_MIDI, M_NOWAIT | M_ZERO);
174158979Snetchild
175166971Snetchild	if (!m)
176158979Snetchild		return NULL;
177158979Snetchild
178158979Snetchild	kobj_init((kobj_t)m, cls);
179158979Snetchild
180158979Snetchild	callout_init(&m->timer, 1);
181158979Snetchild
182158979Snetchild	m->si = softintr;
183158979Snetchild	m->cookie = cookie;
184158979Snetchild	m->flags = 0;
185158979Snetchild
186166971Snetchild	m->mid = midi_init(&mpu401_class, 0, 0, m);
187158979Snetchild	if (!m->mid)
188158979Snetchild		goto err;
189158979Snetchild	*cb = mpu401_intr;
190158979Snetchild	return m;
191158979Snetchilderr:
192158979Snetchild	printf("mpu401_init error\n");
193158979Snetchild	free(m, M_MIDI);
194158979Snetchild	return NULL;
195158979Snetchild}
196158979Snetchild
197158979Snetchildint
198158979Snetchildmpu401_uninit(struct mpu401 *m)
199158979Snetchild{
200158979Snetchild	int retval;
201158979Snetchild
202158979Snetchild	CMD(m, MPU_RESET);
203158979Snetchild	retval = midi_uninit(m->mid);
204158979Snetchild	if (retval)
205158979Snetchild		return retval;
206158979Snetchild	free(m, M_MIDI);
207158979Snetchild	return 0;
208158979Snetchild}
209158979Snetchild
210158979Snetchildstatic int
211158979Snetchildmpu401_minit(kobj_t obj, struct mpu401 *m)
212158979Snetchild{
213158979Snetchild	int i;
214158979Snetchild
215158979Snetchild	CMD(m, MPU_RESET);
216158979Snetchild	CMD(m, MPU_UART);
217158979Snetchild	return 0;
218166971Snetchild	i = 0;
219166971Snetchild	while (++i < 2000) {
220166971Snetchild		if (RXRDY(m))
221166971Snetchild			if (READ(m) == MPU_ACK)
222158979Snetchild				break;
223158979Snetchild	}
224158979Snetchild
225166971Snetchild	if (i < 2000) {
226158979Snetchild		CMD(m, MPU_UART);
227158979Snetchild		return 0;
228158979Snetchild	}
229158979Snetchild	printf("mpu401_minit failed active sensing\n");
230158979Snetchild	return 1;
231158979Snetchild}
232158979Snetchild
233158979Snetchild
234158979Snetchildint
235158979Snetchildmpu401_muninit(kobj_t obj, struct mpu401 *m)
236158979Snetchild{
237158979Snetchild
238158979Snetchild	return MPUFOI_UNINIT(m, m->cookie);
239158979Snetchild}
240158979Snetchild
241158979Snetchildint
242158979Snetchildmpu401_minqsize(kobj_t obj, struct mpu401 *m)
243158979Snetchild{
244158979Snetchild	return 128;
245158979Snetchild}
246158979Snetchild
247158979Snetchildint
248158979Snetchildmpu401_moutqsize(kobj_t obj, struct mpu401 *m)
249158979Snetchild{
250158979Snetchild	return 128;
251158979Snetchild}
252158979Snetchild
253158979Snetchildstatic void
254158979Snetchildmpu401_mcallback(kobj_t obj, struct mpu401 *m, int flags)
255158979Snetchild{
256158979Snetchild#if 0
257166971Snetchild	printf("mpu401_callback %s %s %s %s\n",
258166971Snetchild	    flags & M_RX ? "M_RX" : "",
259166971Snetchild	    flags & M_TX ? "M_TX" : "",
260166971Snetchild	    flags & M_RXEN ? "M_RXEN" : "",
261166971Snetchild	    flags & M_TXEN ? "M_TXEN" : "");
262158979Snetchild#endif
263158979Snetchild	if (flags & M_TXEN && m->si) {
264158979Snetchild		callout_reset(&m->timer, 1, mpu401_timeout, m);
265158979Snetchild	}
266158979Snetchild	m->flags = flags;
267158979Snetchild}
268158979Snetchild
269158979Snetchildstatic void
270158979Snetchildmpu401_mcallbackp(kobj_t obj, struct mpu401 *m, int flags)
271158979Snetchild{
272158979Snetchild/*	printf("mpu401_callbackp\n"); */
273158979Snetchild	mpu401_mcallback(obj, m, flags);
274158979Snetchild}
275158979Snetchild
276158979Snetchildstatic const char *
277158979Snetchildmpu401_mdescr(kobj_t obj, struct mpu401 *m, int verbosity)
278158979Snetchild{
279158979Snetchild
280158979Snetchild	return "descr mpu401";
281158979Snetchild}
282158979Snetchild
283158979Snetchildstatic const char *
284158979Snetchildmpu401_mprovider(kobj_t obj, struct mpu401 *m)
285158979Snetchild{
286158979Snetchild	return "provider mpu401";
287158979Snetchild}
288