mpu401.c revision 314667
11556Srgrimes/*- 21556Srgrimes * Copyright (c) 2003 Mathew Kanner 31556Srgrimes * All rights reserved. 41556Srgrimes * 51556Srgrimes * Redistribution and use in source and binary forms, with or without 61556Srgrimes * modification, are permitted provided that the following conditions 71556Srgrimes * are met: 81556Srgrimes * 1. Redistributions of source code must retain the above copyright 91556Srgrimes * notice, this list of conditions and the following disclaimer. 101556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111556Srgrimes * notice, this list of conditions and the following disclaimer in the 121556Srgrimes * documentation and/or other materials provided with the distribution. 131556Srgrimes * 141556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 151556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 161556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 171556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 181556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 191556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 201556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 211556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 221556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 231556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 241556Srgrimes * SUCH DAMAGE. 251556Srgrimes */ 261556Srgrimes 271556Srgrimes#include <sys/cdefs.h> 281556Srgrimes__FBSDID("$FreeBSD: stable/10/sys/dev/sound/midi/mpu401.c 314667 2017-03-04 13:03:31Z avg $"); 291556Srgrimes 301556Srgrimes#include <sys/param.h> 311556Srgrimes#include <sys/types.h> 321556Srgrimes#include <sys/param.h> 331556Srgrimes#include <sys/queue.h> 3436150Scharnier#include <sys/kernel.h> 3536150Scharnier#include <sys/lock.h> 3636150Scharnier#include <sys/mutex.h> 371556Srgrimes#include <sys/proc.h> 3899110Sobrien#include <sys/systm.h> 3999110Sobrien#include <sys/kobj.h> 401556Srgrimes#include <sys/malloc.h> 4117987Speter#include <sys/bus.h> /* to get driver_intr_t */ 42149017Sstefanf 4317987Speter#ifdef HAVE_KERNEL_OPTION_HEADERS 441556Srgrimes#include "opt_snd.h" 451556Srgrimes#endif 461556Srgrimes 471556Srgrimes#include <dev/sound/midi/mpu401.h> 481556Srgrimes#include <dev/sound/midi/midi.h> 491556Srgrimes 501556Srgrimes#include "mpu_if.h" 511556Srgrimes#include "mpufoi_if.h" 521556Srgrimes 531556Srgrimes#ifndef KOBJMETHOD_END 541556Srgrimes#define KOBJMETHOD_END { NULL, NULL } 551556Srgrimes#endif 561556Srgrimes 5717987Speter#define MPU_DATAPORT 0 5859436Scracauer#define MPU_CMDPORT 1 5917987Speter#define MPU_STATPORT 1 601556Srgrimes#define MPU_RESET 0xff 6117987Speter#define MPU_UART 0x3f 621556Srgrimes#define MPU_ACK 0xfe 631556Srgrimes#define MPU_STATMASK 0xc0 641556Srgrimes#define MPU_OUTPUTBUSY 0x40 651556Srgrimes#define MPU_INPUTBUSY 0x80 661556Srgrimes#define MPU_TRYDATA 50 67142845Sobrien#define MPU_DELAY 2500 68142845Sobrien 691556Srgrimes#define CMD(m,d) MPUFOI_WRITE(m, m->cookie, MPU_CMDPORT,d) 701556Srgrimes#define STATUS(m) MPUFOI_READ(m, m->cookie, MPU_STATPORT) 7117987Speter#define READ(m) MPUFOI_READ(m, m->cookie, MPU_DATAPORT) 721556Srgrimes#define WRITE(m,d) MPUFOI_WRITE(m, m->cookie, MPU_DATAPORT,d) 731556Srgrimes 741556Srgrimesstruct mpu401 { 751556Srgrimes KOBJ_FIELDS; 761556Srgrimes struct snd_midi *mid; 771556Srgrimes int flags; 781556Srgrimes driver_intr_t *si; 791556Srgrimes void *cookie; 801556Srgrimes struct callout timer; 811556Srgrimes}; 821556Srgrimes 831556Srgrimesstatic void mpu401_timeout(void *m); 84117261Sddsstatic mpu401_intr_t mpu401_intr; 85117261Sdds 86117261Sddsstatic int mpu401_minit(struct snd_midi *, void *); 87117261Sddsstatic int mpu401_muninit(struct snd_midi *, void *); 881556Srgrimesstatic int mpu401_minqsize(struct snd_midi *, void *); 89117261Sddsstatic int mpu401_moutqsize(struct snd_midi *, void *); 901556Srgrimesstatic void mpu401_mcallback(struct snd_midi *, void *, int); 91117261Sddsstatic void mpu401_mcallbackp(struct snd_midi *, void *, int); 92117261Sddsstatic const char *mpu401_mdescr(struct snd_midi *, void *, int); 93117261Sddsstatic const char *mpu401_mprovider(struct snd_midi *, void *); 94117261Sdds 95117261Sddsstatic kobj_method_t mpu401_methods[] = { 96179022Sstefanf KOBJMETHOD(mpu_init, mpu401_minit), 971556Srgrimes KOBJMETHOD(mpu_uninit, mpu401_muninit), 9818018Speter KOBJMETHOD(mpu_inqsize, mpu401_minqsize), 9918018Speter KOBJMETHOD(mpu_outqsize, mpu401_moutqsize), 1001556Srgrimes KOBJMETHOD(mpu_callback, mpu401_mcallback), 1011556Srgrimes KOBJMETHOD(mpu_callbackp, mpu401_mcallbackp), 10290111Simp KOBJMETHOD(mpu_descr, mpu401_mdescr), 10390111Simp KOBJMETHOD(mpu_provider, mpu401_mprovider), 10490111Simp KOBJMETHOD_END 10590111Simp}; 10690111Simp 10790111SimpDEFINE_CLASS(mpu401, mpu401_methods, 0); 10890111Simp 10990111Simpvoid 11090111Simpmpu401_timeout(void *a) 11190111Simp{ 11290111Simp struct mpu401 *m = (struct mpu401 *)a; 11390111Simp 11490111Simp if (m->si) 11590111Simp (m->si)(m->cookie); 116201053Sjilles 11790111Simp} 1181556Srgrimesstatic int 11917987Spetermpu401_intr(struct mpu401 *m) 1201556Srgrimes{ 1211556Srgrimes#define MPU_INTR_BUF 16 1221556Srgrimes MIDI_TYPE b[MPU_INTR_BUF]; 1231556Srgrimes int i; 1241556Srgrimes int s; 1251556Srgrimes 12690111Simp/* 12717987Speter printf("mpu401_intr\n"); 1281556Srgrimes*/ 1291556Srgrimes#define RXRDY(m) ( (STATUS(m) & MPU_INPUTBUSY) == 0) 13060593Scracauer#define TXRDY(m) ( (STATUS(m) & MPU_OUTPUTBUSY) == 0) 1311556Srgrimes#if 0 1321556Srgrimes#define D(x,l) printf("mpu401_intr %d %x %s %s\n",l, x, x&MPU_INPUTBUSY?"RX":"", x&MPU_OUTPUTBUSY?"TX":"") 1331556Srgrimes#else 1341556Srgrimes#define D(x,l) 1351556Srgrimes#endif 1361556Srgrimes i = 0; 1371556Srgrimes s = STATUS(m); 1381556Srgrimes D(s, 1); 1391556Srgrimes while ((s & MPU_INPUTBUSY) == 0 && i < MPU_INTR_BUF) { 1401556Srgrimes b[i] = READ(m); 1411556Srgrimes/* 1421556Srgrimes printf("mpu401_intr in i %d d %d\n", i, b[i]); 1431556Srgrimes*/ 1441556Srgrimes i++; 1451556Srgrimes s = STATUS(m); 1461556Srgrimes } 1471556Srgrimes if (i) 14890111Simp midi_in(m->mid, b, i); 14917987Speter i = 0; 1501556Srgrimes while (!(s & MPU_OUTPUTBUSY) && i < MPU_INTR_BUF) { 15117987Speter if (midi_out(m->mid, b, 1)) { 1521556Srgrimes/* 1531556Srgrimes printf("mpu401_intr out i %d d %d\n", i, b[0]); 1541556Srgrimes*/ 1551556Srgrimes 15617987Speter WRITE(m, *b); 1571556Srgrimes } else { 15817987Speter/* 15917987Speter printf("mpu401_intr write: no output\n"); 16017987Speter*/ 16117987Speter return 0; 16217987Speter } 16317987Speter i++; 16417987Speter /* DELAY(100); */ 16517987Speter s = STATUS(m); 16617987Speter } 16717987Speter 16817987Speter if ((m->flags & M_TXEN) && (m->si)) { 16917987Speter callout_reset(&m->timer, 1, mpu401_timeout, m); 17017987Speter } 17117987Speter return (m->flags & M_TXEN) == M_TXEN; 17217987Speter} 17317987Speter 17417987Speterstruct mpu401 * 17517987Spetermpu401_init(kobj_class_t cls, void *cookie, driver_intr_t softintr, 17617987Speter mpu401_intr_t ** cb) 17717987Speter{ 17817987Speter struct mpu401 *m; 17917987Speter 18017987Speter *cb = NULL; 18117987Speter m = malloc(sizeof(*m), M_MIDI, M_NOWAIT | M_ZERO); 18217987Speter 18317987Speter if (!m) 18413882Sjoerg return NULL; 18517987Speter 18617987Speter kobj_init((kobj_t)m, cls); 187102410Scharnier 1881556Srgrimes callout_init(&m->timer, 1); 18917987Speter 19017987Speter m->si = softintr; 19117987Speter m->cookie = cookie; 19217987Speter m->flags = 0; 19317987Speter 19417987Speter m->mid = midi_init(&mpu401_class, 0, 0, m); 19517987Speter if (!m->mid) 1961556Srgrimes goto err; 1971556Srgrimes *cb = mpu401_intr; 1981556Srgrimes return m; 1991556Srgrimeserr: 2001556Srgrimes printf("mpu401_init error\n"); 2011556Srgrimes free(m, M_MIDI); 2021556Srgrimes return NULL; 2031556Srgrimes} 2041556Srgrimes 2051556Srgrimesint 2061556Srgrimesmpu401_uninit(struct mpu401 *m) 2071556Srgrimes{ 2081556Srgrimes int retval; 2091556Srgrimes 2101556Srgrimes CMD(m, MPU_RESET); 2111556Srgrimes retval = midi_uninit(m->mid); 2121556Srgrimes if (retval) 2131556Srgrimes return retval; 2141556Srgrimes free(m, M_MIDI); 2151556Srgrimes return 0; 2161556Srgrimes} 2171556Srgrimes 21890111Simpstatic int 21990111Simpmpu401_minit(struct snd_midi *sm, void *arg) 2201556Srgrimes{ 2211556Srgrimes struct mpu401 *m = arg; 2221556Srgrimes int i; 2231556Srgrimes 2241556Srgrimes CMD(m, MPU_RESET); 2251556Srgrimes CMD(m, MPU_UART); 2261556Srgrimes return 0; 2271556Srgrimes i = 0; 2281556Srgrimes while (++i < 2000) { 2291556Srgrimes if (RXRDY(m)) 2301556Srgrimes if (READ(m) == MPU_ACK) 2311556Srgrimes break; 2321556Srgrimes } 2331556Srgrimes 2341556Srgrimes if (i < 2000) { 2351556Srgrimes CMD(m, MPU_UART); 2361556Srgrimes return 0; 2371556Srgrimes } 2381556Srgrimes printf("mpu401_minit failed active sensing\n"); 2391556Srgrimes return 1; 2401556Srgrimes} 2411556Srgrimes 2421556Srgrimes 2431556Srgrimesint 2441556Srgrimesmpu401_muninit(struct snd_midi *sm, void *arg) 24590111Simp{ 24690111Simp struct mpu401 *m = arg; 24775336Sbrian 2481556Srgrimes return MPUFOI_UNINIT(m, m->cookie); 24975336Sbrian} 2501556Srgrimes 25175336Sbrianint 252191009Sstefanfmpu401_minqsize(struct snd_midi *sm, void *arg) 2531556Srgrimes{ 25475336Sbrian return 128; 25575336Sbrian} 25675336Sbrian 2571556Srgrimesint 2581556Srgrimesmpu401_moutqsize(struct snd_midi *sm, void *arg) 2591556Srgrimes{ 2601556Srgrimes return 128; 2611556Srgrimes} 2621556Srgrimes 2631556Srgrimesstatic void 2641556Srgrimesmpu401_mcallback(struct snd_midi *sm, void *arg, int flags) 2651556Srgrimes{ 2661556Srgrimes struct mpu401 *m = arg; 2671556Srgrimes#if 0 2681556Srgrimes printf("mpu401_callback %s %s %s %s\n", 2691556Srgrimes flags & M_RX ? "M_RX" : "", 2701556Srgrimes flags & M_TX ? "M_TX" : "", 2711556Srgrimes flags & M_RXEN ? "M_RXEN" : "", 2721556Srgrimes flags & M_TXEN ? "M_TXEN" : ""); 2731556Srgrimes#endif 2741556Srgrimes if (flags & M_TXEN && m->si) { 27575336Sbrian callout_reset(&m->timer, 1, mpu401_timeout, m); 27675336Sbrian } 27775336Sbrian m->flags = flags; 27875336Sbrian} 27975336Sbrian 28075336Sbrianstatic void 28175336Sbrianmpu401_mcallbackp(struct snd_midi *sm, void *arg, int flags) 2821556Srgrimes{ 2831556Srgrimes/* printf("mpu401_callbackp\n"); */ 2841556Srgrimes mpu401_mcallback(sm, arg, flags); 2851556Srgrimes} 2861556Srgrimes 28790111Simpstatic const char * 28890111Simpmpu401_mdescr(struct snd_midi *sm, void *arg, int verbosity) 2891556Srgrimes{ 2901556Srgrimes 2911556Srgrimes return "descr mpu401"; 2921556Srgrimes} 29375160Sbrian 2941556Srgrimesstatic const char * 2951556Srgrimesmpu401_mprovider(struct snd_midi *m, void *arg) 29617987Speter{ 29717987Speter return "provider mpu401"; 2981556Srgrimes} 29920425Ssteve