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: releng/10.2/sys/dev/sound/midi/mpu401.c 193979 2009-06-11 09:06:09Z ariff $"); 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 43193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS 44193640Sariff#include "opt_snd.h" 45193640Sariff#endif 46193640Sariff 47158979Snetchild#include <dev/sound/midi/mpu401.h> 48158979Snetchild#include <dev/sound/midi/midi.h> 49158979Snetchild 50158979Snetchild#include "mpu_if.h" 51158979Snetchild#include "mpufoi_if.h" 52158979Snetchild 53193979Sariff#ifndef KOBJMETHOD_END 54193979Sariff#define KOBJMETHOD_END { NULL, NULL } 55193979Sariff#endif 56193979Sariff 57158979Snetchild#define MPU_DATAPORT 0 58158979Snetchild#define MPU_CMDPORT 1 59158979Snetchild#define MPU_STATPORT 1 60158979Snetchild#define MPU_RESET 0xff 61158979Snetchild#define MPU_UART 0x3f 62158979Snetchild#define MPU_ACK 0xfe 63158979Snetchild#define MPU_STATMASK 0xc0 64158979Snetchild#define MPU_OUTPUTBUSY 0x40 65158979Snetchild#define MPU_INPUTBUSY 0x80 66158979Snetchild#define MPU_TRYDATA 50 67158979Snetchild#define MPU_DELAY 2500 68158979Snetchild 69158979Snetchild#define CMD(m,d) MPUFOI_WRITE(m, m->cookie, MPU_CMDPORT,d) 70158979Snetchild#define STATUS(m) MPUFOI_READ(m, m->cookie, MPU_STATPORT) 71158979Snetchild#define READ(m) MPUFOI_READ(m, m->cookie, MPU_DATAPORT) 72158979Snetchild#define WRITE(m,d) MPUFOI_WRITE(m, m->cookie, MPU_DATAPORT,d) 73158979Snetchild 74158979Snetchildstruct mpu401 { 75158979Snetchild KOBJ_FIELDS; 76158979Snetchild struct snd_midi *mid; 77166971Snetchild int flags; 78158979Snetchild driver_intr_t *si; 79166971Snetchild void *cookie; 80158979Snetchild struct callout timer; 81158979Snetchild}; 82158979Snetchild 83166971Snetchildstatic void mpu401_timeout(void *m); 84158979Snetchildstatic mpu401_intr_t mpu401_intr; 85158979Snetchild 86193640Sariffstatic int mpu401_minit(struct snd_midi *, void *); 87193640Sariffstatic int mpu401_muninit(struct snd_midi *, void *); 88193640Sariffstatic int mpu401_minqsize(struct snd_midi *, void *); 89193640Sariffstatic int mpu401_moutqsize(struct snd_midi *, void *); 90193640Sariffstatic void mpu401_mcallback(struct snd_midi *, void *, int); 91193640Sariffstatic void mpu401_mcallbackp(struct snd_midi *, void *, int); 92193640Sariffstatic const char *mpu401_mdescr(struct snd_midi *, void *, int); 93193640Sariffstatic const char *mpu401_mprovider(struct snd_midi *, void *); 94158979Snetchild 95158979Snetchildstatic kobj_method_t mpu401_methods[] = { 96166971Snetchild KOBJMETHOD(mpu_init, mpu401_minit), 97166971Snetchild KOBJMETHOD(mpu_uninit, mpu401_muninit), 98166971Snetchild KOBJMETHOD(mpu_inqsize, mpu401_minqsize), 99166971Snetchild KOBJMETHOD(mpu_outqsize, mpu401_moutqsize), 100166971Snetchild KOBJMETHOD(mpu_callback, mpu401_mcallback), 101166971Snetchild KOBJMETHOD(mpu_callbackp, mpu401_mcallbackp), 102166971Snetchild KOBJMETHOD(mpu_descr, mpu401_mdescr), 103166971Snetchild KOBJMETHOD(mpu_provider, mpu401_mprovider), 104193640Sariff KOBJMETHOD_END 105158979Snetchild}; 106158979Snetchild 107158979SnetchildDEFINE_CLASS(mpu401, mpu401_methods, 0); 108158979Snetchild 109158979Snetchildvoid 110166971Snetchildmpu401_timeout(void *a) 111166971Snetchild{ 112166971Snetchild struct mpu401 *m = (struct mpu401 *)a; 113158979Snetchild 114158979Snetchild if (m->si) 115158979Snetchild (m->si)(m->cookie); 116158979Snetchild 117158979Snetchild} 118158979Snetchildstatic int 119158979Snetchildmpu401_intr(struct mpu401 *m) 120158979Snetchild{ 121158979Snetchild#define MPU_INTR_BUF 16 122158979Snetchild MIDI_TYPE b[MPU_INTR_BUF]; 123158979Snetchild int i; 124158979Snetchild int s; 125166971Snetchild 126158979Snetchild/* 127158979Snetchild printf("mpu401_intr\n"); 128158979Snetchild*/ 129158979Snetchild#define RXRDY(m) ( (STATUS(m) & MPU_INPUTBUSY) == 0) 130158979Snetchild#define TXRDY(m) ( (STATUS(m) & MPU_OUTPUTBUSY) == 0) 131158979Snetchild#if 0 132158979Snetchild#define D(x,l) printf("mpu401_intr %d %x %s %s\n",l, x, x&MPU_INPUTBUSY?"RX":"", x&MPU_OUTPUTBUSY?"TX":"") 133158979Snetchild#else 134158979Snetchild#define D(x,l) 135158979Snetchild#endif 136166971Snetchild i = 0; 137158979Snetchild s = STATUS(m); 138166971Snetchild D(s, 1); 139166971Snetchild while ((s & MPU_INPUTBUSY) == 0 && i < MPU_INTR_BUF) { 140166971Snetchild b[i] = READ(m); 141158979Snetchild/* 142158979Snetchild printf("mpu401_intr in i %d d %d\n", i, b[i]); 143158979Snetchild*/ 144158979Snetchild i++; 145166971Snetchild s = STATUS(m); 146158979Snetchild } 147166971Snetchild if (i) 148166971Snetchild midi_in(m->mid, b, i); 149166971Snetchild i = 0; 150166971Snetchild while (!(s & MPU_OUTPUTBUSY) && i < MPU_INTR_BUF) { 151166971Snetchild if (midi_out(m->mid, b, 1)) { 152158979Snetchild/* 153158979Snetchild printf("mpu401_intr out i %d d %d\n", i, b[0]); 154158979Snetchild*/ 155166971Snetchild 156158979Snetchild WRITE(m, *b); 157166971Snetchild } else { 158158979Snetchild/* 159158979Snetchild printf("mpu401_intr write: no output\n"); 160158979Snetchild*/ 161158979Snetchild return 0; 162158979Snetchild } 163158979Snetchild i++; 164166971Snetchild /* DELAY(100); */ 165166971Snetchild s = STATUS(m); 166158979Snetchild } 167158979Snetchild 168166971Snetchild if ((m->flags & M_TXEN) && (m->si)) { 169166971Snetchild callout_reset(&m->timer, 1, mpu401_timeout, m); 170158979Snetchild } 171158979Snetchild return (m->flags & M_TXEN) == M_TXEN; 172158979Snetchild} 173158979Snetchild 174158979Snetchildstruct mpu401 * 175166971Snetchildmpu401_init(kobj_class_t cls, void *cookie, driver_intr_t softintr, 176166971Snetchild mpu401_intr_t ** cb) 177158979Snetchild{ 178158979Snetchild struct mpu401 *m; 179158979Snetchild 180158979Snetchild *cb = NULL; 181158979Snetchild m = malloc(sizeof(*m), M_MIDI, M_NOWAIT | M_ZERO); 182158979Snetchild 183166971Snetchild if (!m) 184158979Snetchild return NULL; 185158979Snetchild 186158979Snetchild kobj_init((kobj_t)m, cls); 187158979Snetchild 188178250Skris callout_init(&m->timer, CALLOUT_MPSAFE); 189158979Snetchild 190158979Snetchild m->si = softintr; 191158979Snetchild m->cookie = cookie; 192158979Snetchild m->flags = 0; 193158979Snetchild 194166971Snetchild m->mid = midi_init(&mpu401_class, 0, 0, m); 195158979Snetchild if (!m->mid) 196158979Snetchild goto err; 197158979Snetchild *cb = mpu401_intr; 198158979Snetchild return m; 199158979Snetchilderr: 200158979Snetchild printf("mpu401_init error\n"); 201158979Snetchild free(m, M_MIDI); 202158979Snetchild return NULL; 203158979Snetchild} 204158979Snetchild 205158979Snetchildint 206158979Snetchildmpu401_uninit(struct mpu401 *m) 207158979Snetchild{ 208158979Snetchild int retval; 209158979Snetchild 210158979Snetchild CMD(m, MPU_RESET); 211158979Snetchild retval = midi_uninit(m->mid); 212158979Snetchild if (retval) 213158979Snetchild return retval; 214158979Snetchild free(m, M_MIDI); 215158979Snetchild return 0; 216158979Snetchild} 217158979Snetchild 218158979Snetchildstatic int 219193640Sariffmpu401_minit(struct snd_midi *sm, void *arg) 220158979Snetchild{ 221193640Sariff struct mpu401 *m = arg; 222158979Snetchild int i; 223158979Snetchild 224158979Snetchild CMD(m, MPU_RESET); 225158979Snetchild CMD(m, MPU_UART); 226158979Snetchild return 0; 227166971Snetchild i = 0; 228166971Snetchild while (++i < 2000) { 229166971Snetchild if (RXRDY(m)) 230166971Snetchild if (READ(m) == MPU_ACK) 231158979Snetchild break; 232158979Snetchild } 233158979Snetchild 234166971Snetchild if (i < 2000) { 235158979Snetchild CMD(m, MPU_UART); 236158979Snetchild return 0; 237158979Snetchild } 238158979Snetchild printf("mpu401_minit failed active sensing\n"); 239158979Snetchild return 1; 240158979Snetchild} 241158979Snetchild 242158979Snetchild 243158979Snetchildint 244193640Sariffmpu401_muninit(struct snd_midi *sm, void *arg) 245158979Snetchild{ 246193640Sariff struct mpu401 *m = arg; 247158979Snetchild 248158979Snetchild return MPUFOI_UNINIT(m, m->cookie); 249158979Snetchild} 250158979Snetchild 251158979Snetchildint 252193640Sariffmpu401_minqsize(struct snd_midi *sm, void *arg) 253158979Snetchild{ 254158979Snetchild return 128; 255158979Snetchild} 256158979Snetchild 257158979Snetchildint 258193640Sariffmpu401_moutqsize(struct snd_midi *sm, void *arg) 259158979Snetchild{ 260158979Snetchild return 128; 261158979Snetchild} 262158979Snetchild 263158979Snetchildstatic void 264193640Sariffmpu401_mcallback(struct snd_midi *sm, void *arg, int flags) 265158979Snetchild{ 266193640Sariff struct mpu401 *m = arg; 267158979Snetchild#if 0 268166971Snetchild printf("mpu401_callback %s %s %s %s\n", 269166971Snetchild flags & M_RX ? "M_RX" : "", 270166971Snetchild flags & M_TX ? "M_TX" : "", 271166971Snetchild flags & M_RXEN ? "M_RXEN" : "", 272166971Snetchild flags & M_TXEN ? "M_TXEN" : ""); 273158979Snetchild#endif 274158979Snetchild if (flags & M_TXEN && m->si) { 275158979Snetchild callout_reset(&m->timer, 1, mpu401_timeout, m); 276158979Snetchild } 277158979Snetchild m->flags = flags; 278158979Snetchild} 279158979Snetchild 280158979Snetchildstatic void 281193640Sariffmpu401_mcallbackp(struct snd_midi *sm, void *arg, int flags) 282158979Snetchild{ 283158979Snetchild/* printf("mpu401_callbackp\n"); */ 284193640Sariff mpu401_mcallback(sm, arg, flags); 285158979Snetchild} 286158979Snetchild 287158979Snetchildstatic const char * 288193640Sariffmpu401_mdescr(struct snd_midi *sm, void *arg, int verbosity) 289158979Snetchild{ 290158979Snetchild 291158979Snetchild return "descr mpu401"; 292158979Snetchild} 293158979Snetchild 294158979Snetchildstatic const char * 295193640Sariffmpu401_mprovider(struct snd_midi *m, void *arg) 296158979Snetchild{ 297158979Snetchild return "provider mpu401"; 298158979Snetchild} 299