freebsd-skq/sys/dev/sound/midi/mpu401.c
netchild 1686236080 Commit the new (old) midi framework. It's based in parts on the NetBSD code,
but large parts are rewritten by matk and tanimura.

This is old code, it's not maintained since 2003. We also don't have a
maintainer for this! Yuriy Tsibizov took it and uses it in his emu10kx
driver. Since the emu10kx driver will enter the tree "soon" (some bugs
have to be fixed after Yuriy return from his holidays), I add it here
already.

This also contains some changes to emu10k1 and cmi, so if you're lucky,
you can now make some kind of use of midi with those soundcards.

To all those poor souls which don't have such a card: feel free to send
patches, we don't have a maintainer for this.

To those which miss a specific feature in the midi code: feel free to
submit patches, we don't have a maintainer for this.

Oh, did I already told that it would be nice if someone would take care
of it? Maintainer with midi equipment wanted! :-)

If you get LOR's, submit a PR and notify multimedia@ please. If you get
panics, submit a PR with a backtrace (compile the sound system into your
kernel instead of using modules in this case) and notify multimedia@
please.

Written by:	matk, tanimura
Submitted by:	"Yuriy Tsibizov" <Yuriy.Tsibizov@gfk.ru>
Based upon:	code from NetBSD
2006-05-27 16:32:05 +00:00

285 lines
6.4 KiB
C

/*-
* (c) 2003 Mathew Kanner
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. 2.
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/kobj.h>
#include <sys/malloc.h>
#include <sys/bus.h> /* to get driver_intr_t */
#include <dev/sound/midi/mpu401.h>
#include <dev/sound/midi/midi.h>
#include "mpu_if.h"
#include "mpufoi_if.h"
#define MPU_DATAPORT 0
#define MPU_CMDPORT 1
#define MPU_STATPORT 1
#define MPU_RESET 0xff
#define MPU_UART 0x3f
#define MPU_ACK 0xfe
#define MPU_STATMASK 0xc0
#define MPU_OUTPUTBUSY 0x40
#define MPU_INPUTBUSY 0x80
#define MPU_TRYDATA 50
#define MPU_DELAY 2500
#define CMD(m,d) MPUFOI_WRITE(m, m->cookie, MPU_CMDPORT,d)
#define STATUS(m) MPUFOI_READ(m, m->cookie, MPU_STATPORT)
#define READ(m) MPUFOI_READ(m, m->cookie, MPU_DATAPORT)
#define WRITE(m,d) MPUFOI_WRITE(m, m->cookie, MPU_DATAPORT,d)
struct mpu401 {
KOBJ_FIELDS;
struct snd_midi *mid;
int flags;
driver_intr_t *si;
void *cookie;
struct callout timer;
};
static void mpu401_timeout(void *m) ;
static mpu401_intr_t mpu401_intr;
static int mpu401_minit(kobj_t obj, struct mpu401 *m);
static int mpu401_muninit(kobj_t obj, struct mpu401 *m);
static int mpu401_minqsize(kobj_t obj, struct mpu401 *m);
static int mpu401_moutqsize(kobj_t obj, struct mpu401 *m);
static void mpu401_mcallback(kobj_t obj, struct mpu401 *m, int flags);
static void mpu401_mcallbackp(kobj_t obj, struct mpu401 *m, int flags);
static const char *mpu401_mdescr(kobj_t obj, struct mpu401 *m, int verbosity);
static const char *mpu401_mprovider(kobj_t obj, struct mpu401 *m);
static kobj_method_t mpu401_methods[] = {
KOBJMETHOD(mpu_init,mpu401_minit),
KOBJMETHOD(mpu_uninit,mpu401_muninit),
KOBJMETHOD(mpu_inqsize,mpu401_minqsize),
KOBJMETHOD(mpu_outqsize,mpu401_moutqsize),
KOBJMETHOD(mpu_callback,mpu401_mcallback),
KOBJMETHOD(mpu_callbackp,mpu401_mcallbackp),
KOBJMETHOD(mpu_descr,mpu401_mdescr),
KOBJMETHOD(mpu_provider,mpu401_mprovider),
{ 0, 0 }
};
DEFINE_CLASS(mpu401, mpu401_methods, 0);
void
mpu401_timeout(void *a)
{ struct mpu401 *m=(struct mpu401 *)a;
if (m->si)
(m->si)(m->cookie);
}
static int
mpu401_intr(struct mpu401 *m)
{
#define MPU_INTR_BUF 16
MIDI_TYPE b[MPU_INTR_BUF];
int i;
int s;
/*
printf("mpu401_intr\n");
*/
#define RXRDY(m) ( (STATUS(m) & MPU_INPUTBUSY) == 0)
#define TXRDY(m) ( (STATUS(m) & MPU_OUTPUTBUSY) == 0)
#if 0
#define D(x,l) printf("mpu401_intr %d %x %s %s\n",l, x, x&MPU_INPUTBUSY?"RX":"", x&MPU_OUTPUTBUSY?"TX":"")
#else
#define D(x,l)
#endif
i=0;
s = STATUS(m);
D(s,1);
while ( (s&MPU_INPUTBUSY) == 0 && i<MPU_INTR_BUF) {
b[i]=READ(m);
/*
printf("mpu401_intr in i %d d %d\n", i, b[i]);
*/
i++;
s = STATUS(m);
}
if (i) midi_in(m->mid, b, i);
i=0;
while ( !(s&MPU_OUTPUTBUSY) && i<MPU_INTR_BUF) {
if(midi_out(m->mid, b, 1)) {
/*
printf("mpu401_intr out i %d d %d\n", i, b[0]);
*/
WRITE(m, *b);
}
else {
/*
printf("mpu401_intr write: no output\n");
*/
return 0;
}
i++;
/* DELAY(100); */
s = STATUS(m);
}
if ((m->flags & M_TXEN) && (m->si) ) {
callout_reset(&m->timer, 1, mpu401_timeout, m);
}
return (m->flags & M_TXEN) == M_TXEN;
}
struct mpu401 *
mpu401_init(kobj_class_t cls, void *cookie,driver_intr_t softintr, mpu401_intr_t **cb)
{
struct mpu401 *m;
*cb = NULL;
m = malloc(sizeof(*m), M_MIDI, M_NOWAIT | M_ZERO);
if(!m)
return NULL;
kobj_init((kobj_t)m, cls);
callout_init(&m->timer, 1);
m->si = softintr;
m->cookie = cookie;
m->flags = 0;
m->mid = midi_init(&mpu401_class,0,0,m);
if (!m->mid)
goto err;
*cb = mpu401_intr;
return m;
err:
printf("mpu401_init error\n");
free(m, M_MIDI);
return NULL;
}
int
mpu401_uninit(struct mpu401 *m)
{
int retval;
CMD(m, MPU_RESET);
retval = midi_uninit(m->mid);
if (retval)
return retval;
free(m, M_MIDI);
return 0;
}
static int
mpu401_minit(kobj_t obj, struct mpu401 *m)
{
int i;
CMD(m, MPU_RESET);
CMD(m, MPU_UART);
return 0;
i=0;
while(++i<2000) {
if(RXRDY(m))
if(READ(m) == MPU_ACK)
break;
}
if( i < 2000 ) {
CMD(m, MPU_UART);
return 0;
}
printf("mpu401_minit failed active sensing\n");
return 1;
}
int
mpu401_muninit(kobj_t obj, struct mpu401 *m)
{
return MPUFOI_UNINIT(m, m->cookie);
}
int
mpu401_minqsize(kobj_t obj, struct mpu401 *m)
{
return 128;
}
int
mpu401_moutqsize(kobj_t obj, struct mpu401 *m)
{
return 128;
}
static void
mpu401_mcallback(kobj_t obj, struct mpu401 *m, int flags)
{
#if 0
printf("mpu401_callback %s %s %s %s\n",
flags & M_RX ? "M_RX" : "",
flags & M_TX ? "M_TX" : "",
flags & M_RXEN ? "M_RXEN" : "",
flags & M_TXEN ? "M_TXEN" : "" );
#endif
if (flags & M_TXEN && m->si) {
callout_reset(&m->timer, 1, mpu401_timeout, m);
}
m->flags = flags;
}
static void
mpu401_mcallbackp(kobj_t obj, struct mpu401 *m, int flags)
{
/* printf("mpu401_callbackp\n"); */
mpu401_mcallback(obj, m, flags);
}
static const char *
mpu401_mdescr(kobj_t obj, struct mpu401 *m, int verbosity)
{
return "descr mpu401";
}
static const char *
mpu401_mprovider(kobj_t obj, struct mpu401 *m)
{
return "provider mpu401";
}