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$"); 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 64 struct 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 73 static void mpu401_timeout(void *m) ; 74 static mpu401_intr_t mpu401_intr; 75 76 static int mpu401_minit(kobj_t obj, struct mpu401 *m); 77 static int mpu401_muninit(kobj_t obj, struct mpu401 *m); 78 static int mpu401_minqsize(kobj_t obj, struct mpu401 *m); 79 static int mpu401_moutqsize(kobj_t obj, struct mpu401 *m); 80 static void mpu401_mcallback(kobj_t obj, struct mpu401 *m, int flags); 81 static void mpu401_mcallbackp(kobj_t obj, struct mpu401 *m, int flags); 82 static const char *mpu401_mdescr(kobj_t obj, struct mpu401 *m, int verbosity); 83 static const char *mpu401_mprovider(kobj_t obj, struct mpu401 *m); 84 85 static 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 97 DEFINE_CLASS(mpu401, mpu401_methods, 0); 98 99 void 100 mpu401_timeout(void *a) 101 { struct mpu401 *m=(struct mpu401 *)a; 102 103 if (m->si) 104 (m->si)(m->cookie); 105 106 } 107 static int 108 mpu401_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 163 struct mpu401 * 164 mpu401_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; 187 err: 188 printf("mpu401_init error\n"); 189 free(m, M_MIDI); 190 return NULL; 191 } 192 193 int 194 mpu401_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 206 static int 207 mpu401_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 230 int 231 mpu401_muninit(kobj_t obj, struct mpu401 *m) 232 { 233 234 return MPUFOI_UNINIT(m, m->cookie); 235 } 236 237 int 238 mpu401_minqsize(kobj_t obj, struct mpu401 *m) 239 { 240 return 128; 241 } 242 243 int 244 mpu401_moutqsize(kobj_t obj, struct mpu401 *m) 245 { 246 return 128; 247 } 248 249 static void 250 mpu401_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 266 static void 267 mpu401_mcallbackp(kobj_t obj, struct mpu401 *m, int flags) 268 { 269 /* printf("mpu401_callbackp\n"); */ 270 mpu401_mcallback(obj, m, flags); 271 } 272 273 static const char * 274 mpu401_mdescr(kobj_t obj, struct mpu401 *m, int verbosity) 275 { 276 277 return "descr mpu401"; 278 } 279 280 static const char * 281 mpu401_mprovider(kobj_t obj, struct mpu401 *m) 282 { 283 return "provider mpu401"; 284 } 285