mpu401.c revision 166322
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 166322 2007-01-28 20:38:07Z joel $");
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>
41158979Snetchild#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;
69158979Snetchild	int flags;
70158979Snetchild	driver_intr_t *si;
71158979Snetchild	void *cookie;
72158979Snetchild	struct callout timer;
73158979Snetchild};
74158979Snetchild
75158979Snetchildstatic 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[] = {
88158979Snetchild	KOBJMETHOD(mpu_init,mpu401_minit),
89158979Snetchild	KOBJMETHOD(mpu_uninit,mpu401_muninit),
90158979Snetchild	KOBJMETHOD(mpu_inqsize,mpu401_minqsize),
91158979Snetchild	KOBJMETHOD(mpu_outqsize,mpu401_moutqsize),
92158979Snetchild	KOBJMETHOD(mpu_callback,mpu401_mcallback),
93158979Snetchild	KOBJMETHOD(mpu_callbackp,mpu401_mcallbackp),
94158979Snetchild	KOBJMETHOD(mpu_descr,mpu401_mdescr),
95158979Snetchild	KOBJMETHOD(mpu_provider,mpu401_mprovider),
96158979Snetchild        { 0, 0 }
97158979Snetchild};
98158979Snetchild
99158979SnetchildDEFINE_CLASS(mpu401, mpu401_methods, 0);
100158979Snetchild
101158979Snetchildvoid
102158979Snetchildmpu401_timeout(void *a)
103158979Snetchild{	struct mpu401 *m=(struct mpu401 *)a;
104158979Snetchild
105158979Snetchild	if (m->si)
106158979Snetchild		(m->si)(m->cookie);
107158979Snetchild
108158979Snetchild}
109158979Snetchildstatic int
110158979Snetchildmpu401_intr(struct mpu401 *m)
111158979Snetchild{
112158979Snetchild#define MPU_INTR_BUF	16
113158979Snetchild	MIDI_TYPE b[MPU_INTR_BUF];
114158979Snetchild	int i;
115158979Snetchild	int s;
116158979Snetchild/*
117158979Snetchild	printf("mpu401_intr\n");
118158979Snetchild*/
119158979Snetchild#define RXRDY(m) ( (STATUS(m) & MPU_INPUTBUSY) == 0)
120158979Snetchild#define TXRDY(m) ( (STATUS(m) & MPU_OUTPUTBUSY) == 0)
121158979Snetchild#if 0
122158979Snetchild#define D(x,l) printf("mpu401_intr %d %x %s %s\n",l, x, x&MPU_INPUTBUSY?"RX":"", x&MPU_OUTPUTBUSY?"TX":"")
123158979Snetchild#else
124158979Snetchild#define D(x,l)
125158979Snetchild#endif
126158979Snetchild	i=0;
127158979Snetchild	s = STATUS(m);
128158979Snetchild	D(s,1);
129158979Snetchild	while ( (s&MPU_INPUTBUSY) == 0 && i<MPU_INTR_BUF) {
130158979Snetchild		b[i]=READ(m);
131158979Snetchild/*
132158979Snetchild		printf("mpu401_intr in i %d d %d\n", i, b[i]);
133158979Snetchild*/
134158979Snetchild		i++;
135158979Snetchild	s = STATUS(m);
136158979Snetchild	}
137158979Snetchild	if (i) midi_in(m->mid, b, i);
138158979Snetchild	i=0;
139158979Snetchild	while ( !(s&MPU_OUTPUTBUSY) && i<MPU_INTR_BUF) {
140158979Snetchild		if(midi_out(m->mid, b, 1)) {
141158979Snetchild/*
142158979Snetchild			printf("mpu401_intr out i %d d %d\n", i, b[0]);
143158979Snetchild*/
144158979Snetchild
145158979Snetchild			WRITE(m, *b);
146158979Snetchild		}
147158979Snetchild		else {
148158979Snetchild/*
149158979Snetchild			printf("mpu401_intr write: no output\n");
150158979Snetchild*/
151158979Snetchild			return 0;
152158979Snetchild		}
153158979Snetchild		i++;
154158979Snetchild	/* DELAY(100); */
155158979Snetchild	s = STATUS(m);
156158979Snetchild	}
157158979Snetchild
158158979Snetchild	if ((m->flags & M_TXEN) && (m->si) ) {
159158979Snetchild	    callout_reset(&m->timer, 1, mpu401_timeout, m);
160158979Snetchild	}
161158979Snetchild
162158979Snetchild	return (m->flags & M_TXEN) == M_TXEN;
163158979Snetchild}
164158979Snetchild
165158979Snetchildstruct mpu401 *
166158979Snetchildmpu401_init(kobj_class_t cls, void *cookie,driver_intr_t softintr, mpu401_intr_t **cb)
167158979Snetchild{
168158979Snetchild	struct mpu401 *m;
169158979Snetchild
170158979Snetchild	*cb = NULL;
171158979Snetchild	m = malloc(sizeof(*m), M_MIDI, M_NOWAIT | M_ZERO);
172158979Snetchild
173158979Snetchild	if(!m)
174158979Snetchild		return NULL;
175158979Snetchild
176158979Snetchild	kobj_init((kobj_t)m, cls);
177158979Snetchild
178158979Snetchild	callout_init(&m->timer, 1);
179158979Snetchild
180158979Snetchild	m->si = softintr;
181158979Snetchild	m->cookie = cookie;
182158979Snetchild	m->flags = 0;
183158979Snetchild
184158979Snetchild	m->mid = midi_init(&mpu401_class,0,0,m);
185158979Snetchild	if (!m->mid)
186158979Snetchild		goto err;
187158979Snetchild	*cb = mpu401_intr;
188158979Snetchild	return m;
189158979Snetchilderr:
190158979Snetchild	printf("mpu401_init error\n");
191158979Snetchild	free(m, M_MIDI);
192158979Snetchild	return NULL;
193158979Snetchild}
194158979Snetchild
195158979Snetchildint
196158979Snetchildmpu401_uninit(struct mpu401 *m)
197158979Snetchild{
198158979Snetchild	int retval;
199158979Snetchild
200158979Snetchild	CMD(m, MPU_RESET);
201158979Snetchild	retval = midi_uninit(m->mid);
202158979Snetchild	if (retval)
203158979Snetchild		return retval;
204158979Snetchild	free(m, M_MIDI);
205158979Snetchild	return 0;
206158979Snetchild}
207158979Snetchild
208158979Snetchildstatic int
209158979Snetchildmpu401_minit(kobj_t obj, struct mpu401 *m)
210158979Snetchild{
211158979Snetchild	int i;
212158979Snetchild
213158979Snetchild	CMD(m, MPU_RESET);
214158979Snetchild	CMD(m, MPU_UART);
215158979Snetchild	return 0;
216158979Snetchild	i=0;
217158979Snetchild	while(++i<2000) {
218158979Snetchild		if(RXRDY(m))
219158979Snetchild			if(READ(m) == MPU_ACK)
220158979Snetchild				break;
221158979Snetchild	}
222158979Snetchild
223158979Snetchild	if( i < 2000 ) {
224158979Snetchild		CMD(m, MPU_UART);
225158979Snetchild		return 0;
226158979Snetchild	}
227158979Snetchild	printf("mpu401_minit failed active sensing\n");
228158979Snetchild	return 1;
229158979Snetchild}
230158979Snetchild
231158979Snetchild
232158979Snetchildint
233158979Snetchildmpu401_muninit(kobj_t obj, struct mpu401 *m)
234158979Snetchild{
235158979Snetchild
236158979Snetchild	return MPUFOI_UNINIT(m, m->cookie);
237158979Snetchild}
238158979Snetchild
239158979Snetchildint
240158979Snetchildmpu401_minqsize(kobj_t obj, struct mpu401 *m)
241158979Snetchild{
242158979Snetchild	return 128;
243158979Snetchild}
244158979Snetchild
245158979Snetchildint
246158979Snetchildmpu401_moutqsize(kobj_t obj, struct mpu401 *m)
247158979Snetchild{
248158979Snetchild	return 128;
249158979Snetchild}
250158979Snetchild
251158979Snetchildstatic void
252158979Snetchildmpu401_mcallback(kobj_t obj, struct mpu401 *m, int flags)
253158979Snetchild{
254158979Snetchild#if 0
255158979Snetchild	printf("mpu401_callback %s %s %s %s\n",
256158979Snetchild		flags & M_RX ? "M_RX" : "",
257158979Snetchild		flags & M_TX ? "M_TX" : "",
258158979Snetchild		flags & M_RXEN ? "M_RXEN" : "",
259158979Snetchild		flags & M_TXEN ? "M_TXEN" : "" );
260158979Snetchild#endif
261158979Snetchild	if (flags & M_TXEN && m->si) {
262158979Snetchild		callout_reset(&m->timer, 1, mpu401_timeout, m);
263158979Snetchild	}
264158979Snetchild
265158979Snetchild	m->flags = flags;
266158979Snetchild}
267158979Snetchild
268158979Snetchildstatic void
269158979Snetchildmpu401_mcallbackp(kobj_t obj, struct mpu401 *m, int flags)
270158979Snetchild{
271158979Snetchild/*	printf("mpu401_callbackp\n"); */
272158979Snetchild	mpu401_mcallback(obj, m, flags);
273158979Snetchild}
274158979Snetchild
275158979Snetchildstatic const char *
276158979Snetchildmpu401_mdescr(kobj_t obj, struct mpu401 *m, int verbosity)
277158979Snetchild{
278158979Snetchild
279158979Snetchild	return "descr mpu401";
280158979Snetchild}
281158979Snetchild
282158979Snetchildstatic const char *
283158979Snetchildmpu401_mprovider(kobj_t obj, struct mpu401 *m)
284158979Snetchild{
285158979Snetchild	return "provider mpu401";
286158979Snetchild}
287