1206b17d7SAlexander Leidinger /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3718cf2ccSPedro F. Giffuni * 448351eafSJoel Dahl * Copyright (c) 2003 Mathew Kanner 548351eafSJoel Dahl * All rights reserved. 6206b17d7SAlexander Leidinger * 7206b17d7SAlexander Leidinger * Redistribution and use in source and binary forms, with or without 848351eafSJoel Dahl * modification, are permitted provided that the following conditions 948351eafSJoel Dahl * are met: 1048351eafSJoel Dahl * 1. Redistributions of source code must retain the above copyright 1148351eafSJoel Dahl * notice, this list of conditions and the following disclaimer. 1248351eafSJoel Dahl * 2. Redistributions in binary form must reproduce the above copyright 1348351eafSJoel Dahl * notice, this list of conditions and the following disclaimer in the 1448351eafSJoel Dahl * documentation and/or other materials provided with the distribution. 15206b17d7SAlexander Leidinger * 1648351eafSJoel Dahl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1748351eafSJoel Dahl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1848351eafSJoel Dahl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1948351eafSJoel Dahl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2048351eafSJoel Dahl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2148351eafSJoel Dahl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2248351eafSJoel Dahl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2348351eafSJoel Dahl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24206b17d7SAlexander Leidinger * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25206b17d7SAlexander Leidinger * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26206b17d7SAlexander Leidinger * SUCH DAMAGE. 27206b17d7SAlexander Leidinger */ 28206b17d7SAlexander Leidinger 29206b17d7SAlexander Leidinger #include <sys/param.h> 30206b17d7SAlexander Leidinger #include <sys/types.h> 31206b17d7SAlexander Leidinger #include <sys/param.h> 32206b17d7SAlexander Leidinger #include <sys/queue.h> 33206b17d7SAlexander Leidinger #include <sys/kernel.h> 34206b17d7SAlexander Leidinger #include <sys/lock.h> 35206b17d7SAlexander Leidinger #include <sys/mutex.h> 36206b17d7SAlexander Leidinger #include <sys/proc.h> 37206b17d7SAlexander Leidinger #include <sys/systm.h> 38206b17d7SAlexander Leidinger #include <sys/kobj.h> 39206b17d7SAlexander Leidinger #include <sys/malloc.h> 40206b17d7SAlexander Leidinger #include <sys/bus.h> /* to get driver_intr_t */ 41206b17d7SAlexander Leidinger 4290da2b28SAriff Abdullah #ifdef HAVE_KERNEL_OPTION_HEADERS 4390da2b28SAriff Abdullah #include "opt_snd.h" 4490da2b28SAriff Abdullah #endif 4590da2b28SAriff Abdullah 46206b17d7SAlexander Leidinger #include <dev/sound/midi/mpu401.h> 47206b17d7SAlexander Leidinger #include <dev/sound/midi/midi.h> 48206b17d7SAlexander Leidinger 49206b17d7SAlexander Leidinger #include "mpu_if.h" 50206b17d7SAlexander Leidinger #include "mpufoi_if.h" 51206b17d7SAlexander Leidinger 525870e3c9SAriff Abdullah #ifndef KOBJMETHOD_END 535870e3c9SAriff Abdullah #define KOBJMETHOD_END { NULL, NULL } 545870e3c9SAriff Abdullah #endif 555870e3c9SAriff Abdullah 56206b17d7SAlexander Leidinger #define MPU_DATAPORT 0 57206b17d7SAlexander Leidinger #define MPU_CMDPORT 1 58206b17d7SAlexander Leidinger #define MPU_STATPORT 1 59206b17d7SAlexander Leidinger #define MPU_RESET 0xff 60206b17d7SAlexander Leidinger #define MPU_UART 0x3f 61206b17d7SAlexander Leidinger #define MPU_ACK 0xfe 62206b17d7SAlexander Leidinger #define MPU_STATMASK 0xc0 63206b17d7SAlexander Leidinger #define MPU_OUTPUTBUSY 0x40 64206b17d7SAlexander Leidinger #define MPU_INPUTBUSY 0x80 65206b17d7SAlexander Leidinger #define MPU_TRYDATA 50 66206b17d7SAlexander Leidinger #define MPU_DELAY 2500 67206b17d7SAlexander Leidinger 68206b17d7SAlexander Leidinger #define CMD(m,d) MPUFOI_WRITE(m, m->cookie, MPU_CMDPORT,d) 69206b17d7SAlexander Leidinger #define STATUS(m) MPUFOI_READ(m, m->cookie, MPU_STATPORT) 70206b17d7SAlexander Leidinger #define READ(m) MPUFOI_READ(m, m->cookie, MPU_DATAPORT) 71206b17d7SAlexander Leidinger #define WRITE(m,d) MPUFOI_WRITE(m, m->cookie, MPU_DATAPORT,d) 72206b17d7SAlexander Leidinger 73206b17d7SAlexander Leidinger struct mpu401 { 74206b17d7SAlexander Leidinger KOBJ_FIELDS; 75206b17d7SAlexander Leidinger struct snd_midi *mid; 76206b17d7SAlexander Leidinger int flags; 77206b17d7SAlexander Leidinger driver_intr_t *si; 78206b17d7SAlexander Leidinger void *cookie; 79206b17d7SAlexander Leidinger struct callout timer; 80206b17d7SAlexander Leidinger }; 81206b17d7SAlexander Leidinger 82206b17d7SAlexander Leidinger static void mpu401_timeout(void *m); 83206b17d7SAlexander Leidinger static mpu401_intr_t mpu401_intr; 84206b17d7SAlexander Leidinger 8590da2b28SAriff Abdullah static int mpu401_minit(struct snd_midi *, void *); 8690da2b28SAriff Abdullah static int mpu401_muninit(struct snd_midi *, void *); 8790da2b28SAriff Abdullah static int mpu401_minqsize(struct snd_midi *, void *); 8890da2b28SAriff Abdullah static int mpu401_moutqsize(struct snd_midi *, void *); 8990da2b28SAriff Abdullah static void mpu401_mcallback(struct snd_midi *, void *, int); 9090da2b28SAriff Abdullah static void mpu401_mcallbackp(struct snd_midi *, void *, int); 9190da2b28SAriff Abdullah static const char *mpu401_mdescr(struct snd_midi *, void *, int); 9290da2b28SAriff Abdullah static const char *mpu401_mprovider(struct snd_midi *, void *); 93206b17d7SAlexander Leidinger 94206b17d7SAlexander Leidinger static kobj_method_t mpu401_methods[] = { 95206b17d7SAlexander Leidinger KOBJMETHOD(mpu_init, mpu401_minit), 96206b17d7SAlexander Leidinger KOBJMETHOD(mpu_uninit, mpu401_muninit), 97206b17d7SAlexander Leidinger KOBJMETHOD(mpu_inqsize, mpu401_minqsize), 98206b17d7SAlexander Leidinger KOBJMETHOD(mpu_outqsize, mpu401_moutqsize), 99206b17d7SAlexander Leidinger KOBJMETHOD(mpu_callback, mpu401_mcallback), 100206b17d7SAlexander Leidinger KOBJMETHOD(mpu_callbackp, mpu401_mcallbackp), 101206b17d7SAlexander Leidinger KOBJMETHOD(mpu_descr, mpu401_mdescr), 102206b17d7SAlexander Leidinger KOBJMETHOD(mpu_provider, mpu401_mprovider), 10390da2b28SAriff Abdullah KOBJMETHOD_END 104206b17d7SAlexander Leidinger }; 105206b17d7SAlexander Leidinger 106206b17d7SAlexander Leidinger DEFINE_CLASS(mpu401, mpu401_methods, 0); 107206b17d7SAlexander Leidinger 108206b17d7SAlexander Leidinger void 109206b17d7SAlexander Leidinger mpu401_timeout(void *a) 1108f981688SAlexander Leidinger { 1118f981688SAlexander Leidinger struct mpu401 *m = (struct mpu401 *)a; 112206b17d7SAlexander Leidinger 113206b17d7SAlexander Leidinger if (m->si) 114206b17d7SAlexander Leidinger (m->si)(m->cookie); 115206b17d7SAlexander Leidinger 116206b17d7SAlexander Leidinger } 117206b17d7SAlexander Leidinger static int 118206b17d7SAlexander Leidinger mpu401_intr(struct mpu401 *m) 119206b17d7SAlexander Leidinger { 120206b17d7SAlexander Leidinger #define MPU_INTR_BUF 16 121*526bd1d8SChristos Margiolis uint8_t b[MPU_INTR_BUF]; 122206b17d7SAlexander Leidinger int i; 123206b17d7SAlexander Leidinger int s; 1248f981688SAlexander Leidinger 125206b17d7SAlexander Leidinger /* 126206b17d7SAlexander Leidinger printf("mpu401_intr\n"); 127206b17d7SAlexander Leidinger */ 128206b17d7SAlexander Leidinger #define RXRDY(m) ( (STATUS(m) & MPU_INPUTBUSY) == 0) 129206b17d7SAlexander Leidinger #define TXRDY(m) ( (STATUS(m) & MPU_OUTPUTBUSY) == 0) 130206b17d7SAlexander Leidinger #if 0 131206b17d7SAlexander Leidinger #define D(x,l) printf("mpu401_intr %d %x %s %s\n",l, x, x&MPU_INPUTBUSY?"RX":"", x&MPU_OUTPUTBUSY?"TX":"") 132206b17d7SAlexander Leidinger #else 133206b17d7SAlexander Leidinger #define D(x,l) 134206b17d7SAlexander Leidinger #endif 135206b17d7SAlexander Leidinger i = 0; 136206b17d7SAlexander Leidinger s = STATUS(m); 137206b17d7SAlexander Leidinger D(s, 1); 138206b17d7SAlexander Leidinger while ((s & MPU_INPUTBUSY) == 0 && i < MPU_INTR_BUF) { 139206b17d7SAlexander Leidinger b[i] = READ(m); 140206b17d7SAlexander Leidinger /* 141206b17d7SAlexander Leidinger printf("mpu401_intr in i %d d %d\n", i, b[i]); 142206b17d7SAlexander Leidinger */ 143206b17d7SAlexander Leidinger i++; 144206b17d7SAlexander Leidinger s = STATUS(m); 145206b17d7SAlexander Leidinger } 1468f981688SAlexander Leidinger if (i) 1478f981688SAlexander Leidinger midi_in(m->mid, b, i); 148206b17d7SAlexander Leidinger i = 0; 149206b17d7SAlexander Leidinger while (!(s & MPU_OUTPUTBUSY) && i < MPU_INTR_BUF) { 150206b17d7SAlexander Leidinger if (midi_out(m->mid, b, 1)) { 151206b17d7SAlexander Leidinger /* 152206b17d7SAlexander Leidinger printf("mpu401_intr out i %d d %d\n", i, b[0]); 153206b17d7SAlexander Leidinger */ 154206b17d7SAlexander Leidinger 155206b17d7SAlexander Leidinger WRITE(m, *b); 1568f981688SAlexander Leidinger } else { 157206b17d7SAlexander Leidinger /* 158206b17d7SAlexander Leidinger printf("mpu401_intr write: no output\n"); 159206b17d7SAlexander Leidinger */ 160206b17d7SAlexander Leidinger return 0; 161206b17d7SAlexander Leidinger } 162206b17d7SAlexander Leidinger i++; 163206b17d7SAlexander Leidinger /* DELAY(100); */ 164206b17d7SAlexander Leidinger s = STATUS(m); 165206b17d7SAlexander Leidinger } 166206b17d7SAlexander Leidinger 167206b17d7SAlexander Leidinger if ((m->flags & M_TXEN) && (m->si)) { 168206b17d7SAlexander Leidinger callout_reset(&m->timer, 1, mpu401_timeout, m); 169206b17d7SAlexander Leidinger } 170206b17d7SAlexander Leidinger return (m->flags & M_TXEN) == M_TXEN; 171206b17d7SAlexander Leidinger } 172206b17d7SAlexander Leidinger 173206b17d7SAlexander Leidinger struct mpu401 * 1748f981688SAlexander Leidinger mpu401_init(kobj_class_t cls, void *cookie, driver_intr_t softintr, 1758f981688SAlexander Leidinger mpu401_intr_t ** cb) 176206b17d7SAlexander Leidinger { 177206b17d7SAlexander Leidinger struct mpu401 *m; 178206b17d7SAlexander Leidinger 179206b17d7SAlexander Leidinger *cb = NULL; 180206b17d7SAlexander Leidinger m = malloc(sizeof(*m), M_MIDI, M_NOWAIT | M_ZERO); 181206b17d7SAlexander Leidinger 182206b17d7SAlexander Leidinger if (!m) 183206b17d7SAlexander Leidinger return NULL; 184206b17d7SAlexander Leidinger 185206b17d7SAlexander Leidinger kobj_init((kobj_t)m, cls); 186206b17d7SAlexander Leidinger 187fd90e2edSJung-uk Kim callout_init(&m->timer, 1); 188206b17d7SAlexander Leidinger 189206b17d7SAlexander Leidinger m->si = softintr; 190206b17d7SAlexander Leidinger m->cookie = cookie; 191206b17d7SAlexander Leidinger m->flags = 0; 192206b17d7SAlexander Leidinger 193206b17d7SAlexander Leidinger m->mid = midi_init(&mpu401_class, 0, 0, m); 194206b17d7SAlexander Leidinger if (!m->mid) 195206b17d7SAlexander Leidinger goto err; 196206b17d7SAlexander Leidinger *cb = mpu401_intr; 197206b17d7SAlexander Leidinger return m; 198206b17d7SAlexander Leidinger err: 199206b17d7SAlexander Leidinger printf("mpu401_init error\n"); 200206b17d7SAlexander Leidinger free(m, M_MIDI); 201206b17d7SAlexander Leidinger return NULL; 202206b17d7SAlexander Leidinger } 203206b17d7SAlexander Leidinger 204206b17d7SAlexander Leidinger int 205206b17d7SAlexander Leidinger mpu401_uninit(struct mpu401 *m) 206206b17d7SAlexander Leidinger { 207206b17d7SAlexander Leidinger int retval; 208206b17d7SAlexander Leidinger 209206b17d7SAlexander Leidinger CMD(m, MPU_RESET); 210206b17d7SAlexander Leidinger retval = midi_uninit(m->mid); 211206b17d7SAlexander Leidinger if (retval) 212206b17d7SAlexander Leidinger return retval; 213206b17d7SAlexander Leidinger free(m, M_MIDI); 214206b17d7SAlexander Leidinger return 0; 215206b17d7SAlexander Leidinger } 216206b17d7SAlexander Leidinger 217206b17d7SAlexander Leidinger static int 21890da2b28SAriff Abdullah mpu401_minit(struct snd_midi *sm, void *arg) 219206b17d7SAlexander Leidinger { 22090da2b28SAriff Abdullah struct mpu401 *m = arg; 221206b17d7SAlexander Leidinger int i; 222206b17d7SAlexander Leidinger 223206b17d7SAlexander Leidinger CMD(m, MPU_RESET); 224206b17d7SAlexander Leidinger CMD(m, MPU_UART); 225206b17d7SAlexander Leidinger return 0; 226206b17d7SAlexander Leidinger i = 0; 227206b17d7SAlexander Leidinger while (++i < 2000) { 228206b17d7SAlexander Leidinger if (RXRDY(m)) 229206b17d7SAlexander Leidinger if (READ(m) == MPU_ACK) 230206b17d7SAlexander Leidinger break; 231206b17d7SAlexander Leidinger } 232206b17d7SAlexander Leidinger 233206b17d7SAlexander Leidinger if (i < 2000) { 234206b17d7SAlexander Leidinger CMD(m, MPU_UART); 235206b17d7SAlexander Leidinger return 0; 236206b17d7SAlexander Leidinger } 237206b17d7SAlexander Leidinger printf("mpu401_minit failed active sensing\n"); 238206b17d7SAlexander Leidinger return 1; 239206b17d7SAlexander Leidinger } 240206b17d7SAlexander Leidinger 241206b17d7SAlexander Leidinger int 24290da2b28SAriff Abdullah mpu401_muninit(struct snd_midi *sm, void *arg) 243206b17d7SAlexander Leidinger { 24490da2b28SAriff Abdullah struct mpu401 *m = arg; 245206b17d7SAlexander Leidinger 246206b17d7SAlexander Leidinger return MPUFOI_UNINIT(m, m->cookie); 247206b17d7SAlexander Leidinger } 248206b17d7SAlexander Leidinger 249206b17d7SAlexander Leidinger int 25090da2b28SAriff Abdullah mpu401_minqsize(struct snd_midi *sm, void *arg) 251206b17d7SAlexander Leidinger { 252206b17d7SAlexander Leidinger return 128; 253206b17d7SAlexander Leidinger } 254206b17d7SAlexander Leidinger 255206b17d7SAlexander Leidinger int 25690da2b28SAriff Abdullah mpu401_moutqsize(struct snd_midi *sm, void *arg) 257206b17d7SAlexander Leidinger { 258206b17d7SAlexander Leidinger return 128; 259206b17d7SAlexander Leidinger } 260206b17d7SAlexander Leidinger 261206b17d7SAlexander Leidinger static void 26290da2b28SAriff Abdullah mpu401_mcallback(struct snd_midi *sm, void *arg, int flags) 263206b17d7SAlexander Leidinger { 26490da2b28SAriff Abdullah struct mpu401 *m = arg; 265206b17d7SAlexander Leidinger #if 0 266206b17d7SAlexander Leidinger printf("mpu401_callback %s %s %s %s\n", 267206b17d7SAlexander Leidinger flags & M_RX ? "M_RX" : "", 268206b17d7SAlexander Leidinger flags & M_TX ? "M_TX" : "", 269206b17d7SAlexander Leidinger flags & M_RXEN ? "M_RXEN" : "", 270206b17d7SAlexander Leidinger flags & M_TXEN ? "M_TXEN" : ""); 271206b17d7SAlexander Leidinger #endif 272206b17d7SAlexander Leidinger if (flags & M_TXEN && m->si) { 273206b17d7SAlexander Leidinger callout_reset(&m->timer, 1, mpu401_timeout, m); 274206b17d7SAlexander Leidinger } 275206b17d7SAlexander Leidinger m->flags = flags; 276206b17d7SAlexander Leidinger } 277206b17d7SAlexander Leidinger 278206b17d7SAlexander Leidinger static void 27990da2b28SAriff Abdullah mpu401_mcallbackp(struct snd_midi *sm, void *arg, int flags) 280206b17d7SAlexander Leidinger { 281206b17d7SAlexander Leidinger /* printf("mpu401_callbackp\n"); */ 28290da2b28SAriff Abdullah mpu401_mcallback(sm, arg, flags); 283206b17d7SAlexander Leidinger } 284206b17d7SAlexander Leidinger 285206b17d7SAlexander Leidinger static const char * 28690da2b28SAriff Abdullah mpu401_mdescr(struct snd_midi *sm, void *arg, int verbosity) 287206b17d7SAlexander Leidinger { 288206b17d7SAlexander Leidinger 289206b17d7SAlexander Leidinger return "descr mpu401"; 290206b17d7SAlexander Leidinger } 291206b17d7SAlexander Leidinger 292206b17d7SAlexander Leidinger static const char * 29390da2b28SAriff Abdullah mpu401_mprovider(struct snd_midi *m, void *arg) 294206b17d7SAlexander Leidinger { 295206b17d7SAlexander Leidinger return "provider mpu401"; 296206b17d7SAlexander Leidinger } 297