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