mpu401.c revision 166971
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 166971 2007-02-25 13:51:52Z netchild $"); 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> 41166971Snetchild#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; 69166971Snetchild int flags; 70158979Snetchild driver_intr_t *si; 71166971Snetchild void *cookie; 72158979Snetchild struct callout timer; 73158979Snetchild}; 74158979Snetchild 75166971Snetchildstatic 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[] = { 88166971Snetchild KOBJMETHOD(mpu_init, mpu401_minit), 89166971Snetchild KOBJMETHOD(mpu_uninit, mpu401_muninit), 90166971Snetchild KOBJMETHOD(mpu_inqsize, mpu401_minqsize), 91166971Snetchild KOBJMETHOD(mpu_outqsize, mpu401_moutqsize), 92166971Snetchild KOBJMETHOD(mpu_callback, mpu401_mcallback), 93166971Snetchild KOBJMETHOD(mpu_callbackp, mpu401_mcallbackp), 94166971Snetchild KOBJMETHOD(mpu_descr, mpu401_mdescr), 95166971Snetchild KOBJMETHOD(mpu_provider, mpu401_mprovider), 96166971Snetchild {0, 0} 97158979Snetchild}; 98158979Snetchild 99158979SnetchildDEFINE_CLASS(mpu401, mpu401_methods, 0); 100158979Snetchild 101158979Snetchildvoid 102166971Snetchildmpu401_timeout(void *a) 103166971Snetchild{ 104166971Snetchild struct mpu401 *m = (struct mpu401 *)a; 105158979Snetchild 106158979Snetchild if (m->si) 107158979Snetchild (m->si)(m->cookie); 108158979Snetchild 109158979Snetchild} 110158979Snetchildstatic int 111158979Snetchildmpu401_intr(struct mpu401 *m) 112158979Snetchild{ 113158979Snetchild#define MPU_INTR_BUF 16 114158979Snetchild MIDI_TYPE b[MPU_INTR_BUF]; 115158979Snetchild int i; 116158979Snetchild int s; 117166971Snetchild 118158979Snetchild/* 119158979Snetchild printf("mpu401_intr\n"); 120158979Snetchild*/ 121158979Snetchild#define RXRDY(m) ( (STATUS(m) & MPU_INPUTBUSY) == 0) 122158979Snetchild#define TXRDY(m) ( (STATUS(m) & MPU_OUTPUTBUSY) == 0) 123158979Snetchild#if 0 124158979Snetchild#define D(x,l) printf("mpu401_intr %d %x %s %s\n",l, x, x&MPU_INPUTBUSY?"RX":"", x&MPU_OUTPUTBUSY?"TX":"") 125158979Snetchild#else 126158979Snetchild#define D(x,l) 127158979Snetchild#endif 128166971Snetchild i = 0; 129158979Snetchild s = STATUS(m); 130166971Snetchild D(s, 1); 131166971Snetchild while ((s & MPU_INPUTBUSY) == 0 && i < MPU_INTR_BUF) { 132166971Snetchild b[i] = READ(m); 133158979Snetchild/* 134158979Snetchild printf("mpu401_intr in i %d d %d\n", i, b[i]); 135158979Snetchild*/ 136158979Snetchild i++; 137166971Snetchild s = STATUS(m); 138158979Snetchild } 139166971Snetchild if (i) 140166971Snetchild midi_in(m->mid, b, i); 141166971Snetchild i = 0; 142166971Snetchild while (!(s & MPU_OUTPUTBUSY) && i < MPU_INTR_BUF) { 143166971Snetchild if (midi_out(m->mid, b, 1)) { 144158979Snetchild/* 145158979Snetchild printf("mpu401_intr out i %d d %d\n", i, b[0]); 146158979Snetchild*/ 147166971Snetchild 148158979Snetchild WRITE(m, *b); 149166971Snetchild } else { 150158979Snetchild/* 151158979Snetchild printf("mpu401_intr write: no output\n"); 152158979Snetchild*/ 153158979Snetchild return 0; 154158979Snetchild } 155158979Snetchild i++; 156166971Snetchild /* DELAY(100); */ 157166971Snetchild s = STATUS(m); 158158979Snetchild } 159158979Snetchild 160166971Snetchild if ((m->flags & M_TXEN) && (m->si)) { 161166971Snetchild callout_reset(&m->timer, 1, mpu401_timeout, m); 162158979Snetchild } 163158979Snetchild return (m->flags & M_TXEN) == M_TXEN; 164158979Snetchild} 165158979Snetchild 166158979Snetchildstruct mpu401 * 167166971Snetchildmpu401_init(kobj_class_t cls, void *cookie, driver_intr_t softintr, 168166971Snetchild mpu401_intr_t ** cb) 169158979Snetchild{ 170158979Snetchild struct mpu401 *m; 171158979Snetchild 172158979Snetchild *cb = NULL; 173158979Snetchild m = malloc(sizeof(*m), M_MIDI, M_NOWAIT | M_ZERO); 174158979Snetchild 175166971Snetchild if (!m) 176158979Snetchild return NULL; 177158979Snetchild 178158979Snetchild kobj_init((kobj_t)m, cls); 179158979Snetchild 180158979Snetchild callout_init(&m->timer, 1); 181158979Snetchild 182158979Snetchild m->si = softintr; 183158979Snetchild m->cookie = cookie; 184158979Snetchild m->flags = 0; 185158979Snetchild 186166971Snetchild m->mid = midi_init(&mpu401_class, 0, 0, m); 187158979Snetchild if (!m->mid) 188158979Snetchild goto err; 189158979Snetchild *cb = mpu401_intr; 190158979Snetchild return m; 191158979Snetchilderr: 192158979Snetchild printf("mpu401_init error\n"); 193158979Snetchild free(m, M_MIDI); 194158979Snetchild return NULL; 195158979Snetchild} 196158979Snetchild 197158979Snetchildint 198158979Snetchildmpu401_uninit(struct mpu401 *m) 199158979Snetchild{ 200158979Snetchild int retval; 201158979Snetchild 202158979Snetchild CMD(m, MPU_RESET); 203158979Snetchild retval = midi_uninit(m->mid); 204158979Snetchild if (retval) 205158979Snetchild return retval; 206158979Snetchild free(m, M_MIDI); 207158979Snetchild return 0; 208158979Snetchild} 209158979Snetchild 210158979Snetchildstatic int 211158979Snetchildmpu401_minit(kobj_t obj, struct mpu401 *m) 212158979Snetchild{ 213158979Snetchild int i; 214158979Snetchild 215158979Snetchild CMD(m, MPU_RESET); 216158979Snetchild CMD(m, MPU_UART); 217158979Snetchild return 0; 218166971Snetchild i = 0; 219166971Snetchild while (++i < 2000) { 220166971Snetchild if (RXRDY(m)) 221166971Snetchild if (READ(m) == MPU_ACK) 222158979Snetchild break; 223158979Snetchild } 224158979Snetchild 225166971Snetchild if (i < 2000) { 226158979Snetchild CMD(m, MPU_UART); 227158979Snetchild return 0; 228158979Snetchild } 229158979Snetchild printf("mpu401_minit failed active sensing\n"); 230158979Snetchild return 1; 231158979Snetchild} 232158979Snetchild 233158979Snetchild 234158979Snetchildint 235158979Snetchildmpu401_muninit(kobj_t obj, struct mpu401 *m) 236158979Snetchild{ 237158979Snetchild 238158979Snetchild return MPUFOI_UNINIT(m, m->cookie); 239158979Snetchild} 240158979Snetchild 241158979Snetchildint 242158979Snetchildmpu401_minqsize(kobj_t obj, struct mpu401 *m) 243158979Snetchild{ 244158979Snetchild return 128; 245158979Snetchild} 246158979Snetchild 247158979Snetchildint 248158979Snetchildmpu401_moutqsize(kobj_t obj, struct mpu401 *m) 249158979Snetchild{ 250158979Snetchild return 128; 251158979Snetchild} 252158979Snetchild 253158979Snetchildstatic void 254158979Snetchildmpu401_mcallback(kobj_t obj, struct mpu401 *m, int flags) 255158979Snetchild{ 256158979Snetchild#if 0 257166971Snetchild printf("mpu401_callback %s %s %s %s\n", 258166971Snetchild flags & M_RX ? "M_RX" : "", 259166971Snetchild flags & M_TX ? "M_TX" : "", 260166971Snetchild flags & M_RXEN ? "M_RXEN" : "", 261166971Snetchild flags & M_TXEN ? "M_TXEN" : ""); 262158979Snetchild#endif 263158979Snetchild if (flags & M_TXEN && m->si) { 264158979Snetchild callout_reset(&m->timer, 1, mpu401_timeout, m); 265158979Snetchild } 266158979Snetchild m->flags = flags; 267158979Snetchild} 268158979Snetchild 269158979Snetchildstatic void 270158979Snetchildmpu401_mcallbackp(kobj_t obj, struct mpu401 *m, int flags) 271158979Snetchild{ 272158979Snetchild/* printf("mpu401_callbackp\n"); */ 273158979Snetchild mpu401_mcallback(obj, m, flags); 274158979Snetchild} 275158979Snetchild 276158979Snetchildstatic const char * 277158979Snetchildmpu401_mdescr(kobj_t obj, struct mpu401 *m, int verbosity) 278158979Snetchild{ 279158979Snetchild 280158979Snetchild return "descr mpu401"; 281158979Snetchild} 282158979Snetchild 283158979Snetchildstatic const char * 284158979Snetchildmpu401_mprovider(kobj_t obj, struct mpu401 *m) 285158979Snetchild{ 286158979Snetchild return "provider mpu401"; 287158979Snetchild} 288