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