xref: /freebsd/sys/dev/sound/midi/mpu401.c (revision 48351eaf73558b32a2a83f13b0ccf230d84f4a46)
1 /*-
2  * Copyright (c) 2003 Mathew Kanner
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/queue.h>
34 #include <sys/kernel.h>
35 #include <sys/lock.h>
36 #include <sys/mutex.h>
37 #include <sys/proc.h>
38 #include <sys/systm.h>
39 #include <sys/kobj.h>
40 #include <sys/malloc.h>
41 #include <sys/bus.h> /* to get driver_intr_t */
42 
43 #include <dev/sound/midi/mpu401.h>
44 #include <dev/sound/midi/midi.h>
45 
46 #include "mpu_if.h"
47 #include "mpufoi_if.h"
48 
49 #define MPU_DATAPORT   0
50 #define MPU_CMDPORT    1
51 #define MPU_STATPORT   1
52 #define MPU_RESET      0xff
53 #define MPU_UART       0x3f
54 #define MPU_ACK        0xfe
55 #define MPU_STATMASK   0xc0
56 #define MPU_OUTPUTBUSY 0x40
57 #define MPU_INPUTBUSY  0x80
58 #define MPU_TRYDATA 50
59 #define MPU_DELAY   2500
60 
61 #define CMD(m,d)	MPUFOI_WRITE(m, m->cookie, MPU_CMDPORT,d)
62 #define STATUS(m)	MPUFOI_READ(m, m->cookie, MPU_STATPORT)
63 #define READ(m)		MPUFOI_READ(m, m->cookie, MPU_DATAPORT)
64 #define WRITE(m,d)	MPUFOI_WRITE(m, m->cookie, MPU_DATAPORT,d)
65 
66 struct mpu401 {
67 	KOBJ_FIELDS;
68 	struct snd_midi *mid;
69 	int flags;
70 	driver_intr_t *si;
71 	void *cookie;
72 	struct callout timer;
73 };
74 
75 static void mpu401_timeout(void *m) ;
76 static mpu401_intr_t mpu401_intr;
77 
78 static int mpu401_minit(kobj_t obj, struct mpu401 *m);
79 static int mpu401_muninit(kobj_t obj, struct mpu401 *m);
80 static int mpu401_minqsize(kobj_t obj, struct mpu401 *m);
81 static int mpu401_moutqsize(kobj_t obj, struct mpu401 *m);
82 static void mpu401_mcallback(kobj_t obj, struct mpu401 *m, int flags);
83 static void mpu401_mcallbackp(kobj_t obj, struct mpu401 *m, int flags);
84 static const char *mpu401_mdescr(kobj_t obj, struct mpu401 *m, int verbosity);
85 static const char *mpu401_mprovider(kobj_t obj, struct mpu401 *m);
86 
87 static kobj_method_t mpu401_methods[] = {
88 	KOBJMETHOD(mpu_init,mpu401_minit),
89 	KOBJMETHOD(mpu_uninit,mpu401_muninit),
90 	KOBJMETHOD(mpu_inqsize,mpu401_minqsize),
91 	KOBJMETHOD(mpu_outqsize,mpu401_moutqsize),
92 	KOBJMETHOD(mpu_callback,mpu401_mcallback),
93 	KOBJMETHOD(mpu_callbackp,mpu401_mcallbackp),
94 	KOBJMETHOD(mpu_descr,mpu401_mdescr),
95 	KOBJMETHOD(mpu_provider,mpu401_mprovider),
96         { 0, 0 }
97 };
98 
99 DEFINE_CLASS(mpu401, mpu401_methods, 0);
100 
101 void
102 mpu401_timeout(void *a)
103 {	struct mpu401 *m=(struct mpu401 *)a;
104 
105 	if (m->si)
106 		(m->si)(m->cookie);
107 
108 }
109 static int
110 mpu401_intr(struct mpu401 *m)
111 {
112 #define MPU_INTR_BUF	16
113 	MIDI_TYPE b[MPU_INTR_BUF];
114 	int i;
115 	int s;
116 /*
117 	printf("mpu401_intr\n");
118 */
119 #define RXRDY(m) ( (STATUS(m) & MPU_INPUTBUSY) == 0)
120 #define TXRDY(m) ( (STATUS(m) & MPU_OUTPUTBUSY) == 0)
121 #if 0
122 #define D(x,l) printf("mpu401_intr %d %x %s %s\n",l, x, x&MPU_INPUTBUSY?"RX":"", x&MPU_OUTPUTBUSY?"TX":"")
123 #else
124 #define D(x,l)
125 #endif
126 	i=0;
127 	s = STATUS(m);
128 	D(s,1);
129 	while ( (s&MPU_INPUTBUSY) == 0 && i<MPU_INTR_BUF) {
130 		b[i]=READ(m);
131 /*
132 		printf("mpu401_intr in i %d d %d\n", i, b[i]);
133 */
134 		i++;
135 	s = STATUS(m);
136 	}
137 	if (i) midi_in(m->mid, b, i);
138 	i=0;
139 	while ( !(s&MPU_OUTPUTBUSY) && i<MPU_INTR_BUF) {
140 		if(midi_out(m->mid, b, 1)) {
141 /*
142 			printf("mpu401_intr out i %d d %d\n", i, b[0]);
143 */
144 
145 			WRITE(m, *b);
146 		}
147 		else {
148 /*
149 			printf("mpu401_intr write: no output\n");
150 */
151 			return 0;
152 		}
153 		i++;
154 	/* DELAY(100); */
155 	s = STATUS(m);
156 	}
157 
158 	if ((m->flags & M_TXEN) && (m->si) ) {
159 	    callout_reset(&m->timer, 1, mpu401_timeout, m);
160 	}
161 
162 	return (m->flags & M_TXEN) == M_TXEN;
163 }
164 
165 struct mpu401 *
166 mpu401_init(kobj_class_t cls, void *cookie,driver_intr_t softintr, mpu401_intr_t **cb)
167 {
168 	struct mpu401 *m;
169 
170 	*cb = NULL;
171 	m = malloc(sizeof(*m), M_MIDI, M_NOWAIT | M_ZERO);
172 
173 	if(!m)
174 		return NULL;
175 
176 	kobj_init((kobj_t)m, cls);
177 
178 	callout_init(&m->timer, 1);
179 
180 	m->si = softintr;
181 	m->cookie = cookie;
182 	m->flags = 0;
183 
184 	m->mid = midi_init(&mpu401_class,0,0,m);
185 	if (!m->mid)
186 		goto err;
187 	*cb = mpu401_intr;
188 	return m;
189 err:
190 	printf("mpu401_init error\n");
191 	free(m, M_MIDI);
192 	return NULL;
193 }
194 
195 int
196 mpu401_uninit(struct mpu401 *m)
197 {
198 	int retval;
199 
200 	CMD(m, MPU_RESET);
201 	retval = midi_uninit(m->mid);
202 	if (retval)
203 		return retval;
204 	free(m, M_MIDI);
205 	return 0;
206 }
207 
208 static int
209 mpu401_minit(kobj_t obj, struct mpu401 *m)
210 {
211 	int i;
212 
213 	CMD(m, MPU_RESET);
214 	CMD(m, MPU_UART);
215 	return 0;
216 	i=0;
217 	while(++i<2000) {
218 		if(RXRDY(m))
219 			if(READ(m) == MPU_ACK)
220 				break;
221 	}
222 
223 	if( i < 2000 ) {
224 		CMD(m, MPU_UART);
225 		return 0;
226 	}
227 	printf("mpu401_minit failed active sensing\n");
228 	return 1;
229 }
230 
231 
232 int
233 mpu401_muninit(kobj_t obj, struct mpu401 *m)
234 {
235 
236 	return MPUFOI_UNINIT(m, m->cookie);
237 }
238 
239 int
240 mpu401_minqsize(kobj_t obj, struct mpu401 *m)
241 {
242 	return 128;
243 }
244 
245 int
246 mpu401_moutqsize(kobj_t obj, struct mpu401 *m)
247 {
248 	return 128;
249 }
250 
251 static void
252 mpu401_mcallback(kobj_t obj, struct mpu401 *m, int flags)
253 {
254 #if 0
255 	printf("mpu401_callback %s %s %s %s\n",
256 		flags & M_RX ? "M_RX" : "",
257 		flags & M_TX ? "M_TX" : "",
258 		flags & M_RXEN ? "M_RXEN" : "",
259 		flags & M_TXEN ? "M_TXEN" : "" );
260 #endif
261 	if (flags & M_TXEN && m->si) {
262 		callout_reset(&m->timer, 1, mpu401_timeout, m);
263 	}
264 
265 	m->flags = flags;
266 }
267 
268 static void
269 mpu401_mcallbackp(kobj_t obj, struct mpu401 *m, int flags)
270 {
271 /*	printf("mpu401_callbackp\n"); */
272 	mpu401_mcallback(obj, m, flags);
273 }
274 
275 static const char *
276 mpu401_mdescr(kobj_t obj, struct mpu401 *m, int verbosity)
277 {
278 
279 	return "descr mpu401";
280 }
281 
282 static const char *
283 mpu401_mprovider(kobj_t obj, struct mpu401 *m)
284 {
285 	return "provider mpu401";
286 }
287