Finally merge newmidi.

(I had been busy for my own research activity until the last weekend)

Supported devices:

SB Midi Port			(sbc + midi)
SB OPL3				(sbc + midi)
16550 UART			(midi, needs a trick in your hint)
CS461x Midi Port		(csa + midi)

OSS-compatible sequencer	(seq)

Supported playing software:

playmidi			(We definitely need more)

Notes:

/dev/midistat now reports installed midi drivers. /dev/sndstat reports
only pcm drivers. We need the new name(pcmstat?).

EMU8000(SB AWE) does not sound yet but does get probed so that the OPL3
synth on an AWE card works.

TODO:

MSS/PCI bridge drivers
Midi-tty interface to support general serial devices
Modules
This commit is contained in:
Seigo Tanimura 2000-07-11 11:49:33 +00:00
parent a611641f01
commit fb0ef52838
30 changed files with 11069 additions and 90 deletions

@ -1344,7 +1344,9 @@ snd*)
# minor number 7 is unused
mknod music$unit c $chr `expr $unit '*' 16 + 8`
mknod pss$unit c $chr `expr $unit '*' 16 + 9`
# minor numbers 10-15 are unused
# minor number 10 is unused
mknod midistat c $chr 11
# minor numbers 12-15 are unused
umask 77
;;

@ -588,7 +588,8 @@ pnpbios_identify(driver_t *driver, device_t parent)
isa_set_logicalid(dev, pd->devid);
ISA_SET_CONFIG_CALLBACK(parent, dev, pnpbios_set_config, 0);
pnp_parse_resources(dev, &pd->devdata[0],
pd->size - sizeof(struct pnp_sysdev));
pd->size - sizeof(struct pnp_sysdev),
isa_get_vendorid(dev), isa_get_logicalid(dev), 0);
if (!device_get_desc(dev))
device_set_desc_copy(dev, pnp_eisaformat(pd->devid));

@ -1649,8 +1649,32 @@ hint.pcm.0.flags="0x0"
# For PnP/PCI sound cards, no hints are required.
#
# midi: MIDI interfaces and synthesizers
#
device midi
# For non-pnp sound cards with no bridge drivers:
hint.midi.0.at="isa"
hint.midi.0.irq="5"
hint.midi.0.flags="0x0"
# For serial ports (this example configures port 2):
# TODO: implement generic tty-midi interface so that we can use
# other uarts.
hint.midi.0.at="isa"
hint.midi.0.port="0x2F8"
hint.midi.0.irq="3"
#
# seq: MIDI sequencer
#
device seq
# The bridge drivers for sound cards. These can be seperately configured
# for providing services to the likes of new-midi (not in the tree yet).
# for providing services to the likes of new-midi.
# When used with 'device pcm' they also provide pcm sound services.
#
# sbc: Creative SoundBlaster ISA PnP/non-PnP

@ -248,17 +248,27 @@ dev/sn/if_sn.c optional sn
dev/sn/if_sn_isa.c optional sn isa
dev/sn/if_sn_pccard.c optional sn card
dev/sound/isa/ad1816.c optional pcm isa
dev/sound/isa/emu8000.c optional midi isa
dev/sound/isa/es1888.c optional pcm isa
dev/sound/isa/ess.c optional pcm isa
dev/sound/isa/gusc.c optional gusc isa
dev/sound/isa/gusc.c optional pcm isa
dev/sound/isa/gusmidi.c optional midi isa
dev/sound/isa/mpu.c optional midi isa
dev/sound/isa/mss.c optional pcm isa
dev/sound/isa/opl.c optional midi isa
dev/sound/isa/sb.c optional pcm isa
dev/sound/isa/sbc.c optional pcm isa
dev/sound/isa/sbc.c optional sbc isa
dev/sound/isa/uartsio.c optional midi isa
dev/sound/midi/midi.c optional midi
dev/sound/midi/midibuf.c optional midi
dev/sound/midi/midisynth.c optional midi
dev/sound/midi/sequencer.c optional seq midi
#dev/sound/pci/aureal.c optional pcm pci
dev/sound/pci/csa.c optional csa pci
dev/sound/pci/csa.c optional pcm pci
dev/sound/pci/csamidi.c optional midi csa
dev/sound/pci/csapcm.c optional pcm pci
dev/sound/pci/ds1.c optional pcm pci
dev/sound/pci/emu10k1.c optional pcm pci

2037
sys/dev/sound/isa/emu8000.c Normal file

File diff suppressed because it is too large Load Diff

@ -53,6 +53,13 @@
#define LOGICALID_OPL 0x0300561e
#define LOGICALID_MIDI 0x0400561e
/* PnP IDs */
static struct isa_pnp_id gusc_ids[] = {
{LOGICALID_PCM, "GRV0000 Gravis UltraSound PnP PCM"}, /* GRV0000 */
{LOGICALID_OPL, "GRV0003 Gravis UltraSound PnP OPL"}, /* GRV0003 */
{LOGICALID_MIDI, "GRV0004 Gravis UltraSound PnP MIDI"}, /* GRV0004 */
};
/* Interrupt handler. */
struct gusc_ihandler {
void (*intr)(void *);
@ -88,9 +95,7 @@ static struct resource *gusc_alloc_resource(device_t bus, device_t child, int ty
static int gusc_release_resource(device_t bus, device_t child, int type, int rid,
struct resource *r);
#if notyet
static device_t find_masterdev(sc_p scp);
#endif /* notyet */
static int alloc_resource(sc_p scp);
static int release_resource(sc_p scp);
@ -100,52 +105,53 @@ static int
gusc_probe(device_t dev)
{
device_t child;
u_int32_t vend_id, logical_id;
u_int32_t logical_id;
char *s;
struct sndcard_func *func;
vend_id = isa_get_vendorid(dev);
if (vend_id == 0)
return gusisa_probe(dev);
int ret;
logical_id = isa_get_logicalid(dev);
s = NULL;
if (vend_id == 0x0100561e) { /* Gravis */
switch (logical_id) {
case LOGICALID_PCM:
s = "Gravis UltraSound Plug & Play PCM";
func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT);
if (func == NULL)
return (ENOMEM);
bzero(func, sizeof(*func));
func->func = SCF_PCM;
child = device_add_child(dev, "pcm", -1);
device_set_ivars(child, func);
break;
#if notyet
case LOGICALID_OPL:
s = "Gravis UltraSound Plug & Play OPL";
func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT);
if (func == NULL)
return (ENOMEM);
bzero(func, sizeof(*func));
func->func = SCF_SYNTH;
child = device_add_child(dev, "midi", -1);
device_set_ivars(child, func);
break;
case LOGICALID_MIDI:
s = "Gravis UltraSound Plug & Play MIDI";
func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT);
if (func == NULL)
return (ENOMEM);
bzero(func, sizeof(*func));
func->func = SCF_MIDI;
child = device_add_child(dev, "midi", -1);
device_set_ivars(child, func);
break;
#endif /* notyet */
}
/* Check isapnp ids */
if (logical_id != 0 && (ret = ISA_PNP_PROBE(device_get_parent(dev), dev, gusc_ids)) != 0)
return (ret);
else {
if (logical_id == 0)
return gusisa_probe(dev);
}
switch (logical_id) {
case LOGICALID_PCM:
s = "Gravis UltraSound Plug & Play PCM";
func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT);
if (func == NULL)
return (ENOMEM);
bzero(func, sizeof(*func));
func->func = SCF_PCM;
child = device_add_child(dev, "pcm", -1);
device_set_ivars(child, func);
break;
case LOGICALID_OPL:
s = "Gravis UltraSound Plug & Play OPL";
func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT);
if (func == NULL)
return (ENOMEM);
bzero(func, sizeof(*func));
func->func = SCF_SYNTH;
child = device_add_child(dev, "midi", -1);
device_set_ivars(child, func);
break;
case LOGICALID_MIDI:
s = "Gravis UltraSound Plug & Play MIDI";
func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT);
if (func == NULL)
return (ENOMEM);
bzero(func, sizeof(*func));
func->func = SCF_MIDI;
child = device_add_child(dev, "midi", -1);
device_set_ivars(child, func);
break;
}
if (s != NULL) {
@ -265,7 +271,6 @@ gusisa_probe(device_t dev)
bus_set_resource(dev, SYS_RES_DRQ, 1,
flags & DV_F_DRQ_MASK, 1);
#if notyet
/* We can support the CS4231 and MIDI devices. */
func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT);
@ -275,7 +280,6 @@ gusisa_probe(device_t dev)
func->func = SCF_MIDI;
child = device_add_child(dev, "midi", -1);
device_set_ivars(child, func);
#endif /* notyet */
func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT);
if (func == NULL)
@ -342,13 +346,11 @@ gusc_intr(void *arg)
(*scp->pcm_intr.intr)(scp->pcm_intr.arg);
did_something = 1;
}
#if notyet
if (scp->midi_intr.intr != NULL &&
(port_rd(scp->io[1], 0) & 0x80)) {
(*scp->midi_intr.intr)(scp->midi_intr.arg);
did_something = 1;
}
#endif /* notyet */
} while (did_something != 0);
}
@ -444,7 +446,6 @@ gusc_setup_intr(device_t dev, device_t child, struct resource *irq,
arg, cookiep);
}
#if notyet
static device_t
find_masterdev(sc_p scp)
{
@ -467,7 +468,6 @@ find_masterdev(sc_p scp)
return (dev);
}
#endif /* notyet */
static int io_range[3] = {0x10, 0x8 , 0x4 };
static int io_offset[3] = {0x0 , 0x100, 0x10c};
@ -475,9 +475,7 @@ static int
alloc_resource(sc_p scp)
{
int i, base, lid, flags;
#if notyet
device_t dev;
#endif /* notyet */
flags = 0;
if (isa_get_vendorid(scp->dev))
@ -534,7 +532,6 @@ alloc_resource(sc_p scp)
}
}
break;
#if notyet
case LOGICALID_OPL:
if (scp->io[0] == NULL) {
scp->io_rid[0] = 0;
@ -567,7 +564,6 @@ alloc_resource(sc_p scp)
scp->irq_alloced = 0;
}
break;
#endif /* notyet */
}
return (0);
}
@ -576,9 +572,7 @@ static int
release_resource(sc_p scp)
{
int i, lid, flags;
#if notyet
device_t dev;
#endif /* notyet */
flags = 0;
if (isa_get_vendorid(scp->dev))
@ -607,7 +601,6 @@ release_resource(sc_p scp)
}
}
break;
#if notyet
case LOGICALID_OPL:
if (scp->io[0] != NULL) {
bus_release_resource(scp->dev, SYS_RES_IOPORT, scp->io_rid[0], scp->io[0]);
@ -628,7 +621,6 @@ release_resource(sc_p scp)
scp->irq = NULL;
}
break;
#endif /* notyet */
}
return (0);
}

523
sys/dev/sound/isa/gusmidi.c Normal file

@ -0,0 +1,523 @@
/*
* GUS midi interface driver.
* Based on the newmidi MPU401 driver.
*
* Copyright (c) 1999 Ville-Pertti Keinonen
* Copyright by Hannu Savolainen 1993
*
* 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.
*
* Modified: Riccardo Facchetti 24 Mar 1995 - Added the Audio Excel DSP 16
* initialization routine.
*
* Ported to the new Audio Driver by Luigi Rizzo:
* (C) 1999 Seigo Tanimura <tanimura@r.dl.itc.u-tokyo.ac.jp>
*
* $FreeBSD$
*
*/
#include <dev/sound/midi/midi.h>
#include <dev/sound/chip.h>
#include <machine/cpufunc.h>
static devclass_t midi_devclass;
extern synthdev_info midisynth_op_desc;
/* These are the synthesizer and the midi interface information. */
static struct synth_info gusmidi_synthinfo = {
"GUS MIDI",
0,
SYNTH_TYPE_MIDI,
0,
0,
128,
128,
128,
SYNTH_CAP_INPUT,
};
static struct midi_info gusmidi_midiinfo = {
"GUS MIDI",
0,
0,
0,
};
#define MIDICTL_MASTER_RESET 0x03
#define MIDICTL_TX_IRQ_EN 0x20
#define MIDICTL_RX_IRQ_EN 0x80
#define MIDIST_RXFULL 0x01
#define MIDIST_TXDONE 0x02
#define MIDIST_ERR_FR 0x10
#define MIDIST_ERR_OVR 0x20
#define MIDIST_INTR_PEND 0x80
#define PORT_CTL 0
#define PORT_ST 0
#define PORT_TX 1
#define PORT_RX 1
/*
* These functions goes into gusmidi_op_desc to get called
* from sound.c.
*/
static int gusmidi_probe(device_t dev);
static int gusmidi_attach(device_t dev);
static d_open_t gusmidi_open;
static d_ioctl_t gusmidi_ioctl;
driver_intr_t gusmidi_intr;
static midi_callback_t gusmidi_callback;
/* Here is the parameter structure per a device. */
struct gusmidi_softc {
device_t dev; /* device information */
mididev_info *devinfo; /* midi device information */
struct resource *io; /* Base of io port */
int io_rid; /* Io resource ID */
struct resource *irq; /* Irq */
int irq_rid; /* Irq resource ID */
void *ih; /* Interrupt cookie */
struct callout_handle dh; /* Callout handler for delay */
int ctl; /* Control bits. */
};
typedef struct gusmidi_softc *sc_p;
/* These functions are local. */
static int gusmidi_init(device_t dev);
static int gusmidi_allocres(sc_p scp, device_t dev);
static void gusmidi_releaseres(sc_p scp, device_t dev);
static void gusmidi_startplay(sc_p scp);
static void gusmidi_xmit(sc_p scp);
static u_int gusmidi_readport(sc_p scp, int off);
static void gusmidi_writeport(sc_p scp, int off, u_int8_t value);
/*
* This is the device descriptor for the midi device.
*/
static mididev_info gusmidi_op_desc = {
"GUS midi",
SNDCARD_GUS,
gusmidi_open,
NULL,
NULL,
NULL,
gusmidi_ioctl,
NULL,
gusmidi_callback,
MIDI_BUFFSIZE, /* Queue Length */
0, /* XXX This is not an *audio* device! */
};
static int
gusmidi_probe(device_t dev)
{
char *s;
sc_p scp;
struct sndcard_func *func;
/* The parent device has already been probed. */
func = device_get_ivars(dev);
if (func == NULL || func->func != SCF_MIDI)
return (ENXIO);
s = "GUS Midi Interface";
scp = device_get_softc(dev);
bzero(scp, sizeof(*scp));
scp->io_rid = 1;
scp->irq_rid = 0;
#if notdef
ret = mpu_probe2(dev);
if (ret != 0)
return (ret);
#endif /* notdef */
device_set_desc(dev, s);
return (0);
}
static int
gusmidi_attach(device_t dev)
{
sc_p scp;
scp = device_get_softc(dev);
/* Allocate the resources, switch to uart mode. */
if (gusmidi_allocres(scp, dev)) {
gusmidi_releaseres(scp, dev);
return (ENXIO);
}
gusmidi_init(dev);
return (0);
}
static int
gusmidi_init(device_t dev)
{
sc_p scp;
mididev_info *devinfo;
int unit;
scp = device_get_softc(dev);
unit = device_get_unit(dev);
/* Fill the softc. */
scp->dev = dev;
scp->devinfo = devinfo = &midi_info[unit];
/* Fill the midi info. */
bcopy(&gusmidi_op_desc, devinfo, sizeof(gusmidi_op_desc));
midiinit(devinfo, dev);
devinfo->flags = 0;
bcopy(&midisynth_op_desc, &devinfo->synth, sizeof(midisynth_op_desc));
if (scp->irq != NULL)
snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at 0x%x irq %d",
(u_int)rman_get_start(scp->io), (int)rman_get_start(scp->irq));
else
snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at 0x%x",
(u_int)rman_get_start(scp->io));
/* Init the queue. */
devinfo->midi_dbuf_in.unit_size = devinfo->midi_dbuf_out.unit_size = 1;
midibuf_init(&devinfo->midi_dbuf_in);
midibuf_init(&devinfo->midi_dbuf_out);
bus_setup_intr(dev, scp->irq, INTR_TYPE_TTY, gusmidi_intr, scp,
&scp->ih);
/* Increase the number of midi devices. */
nmidi++;
return (0);
}
static int
gusmidi_open(dev_t i_dev, int flags, int mode, struct proc *p)
{
sc_p scp;
mididev_info *devinfo;
int unit;
unit = MIDIUNIT(i_dev);
if (unit >= nmidi + nsynth) {
DEB(printf("gusmidi_open: unit %d does not exist.\n", unit));
return (ENXIO);
}
devinfo = get_mididev_info(i_dev, &unit);
if (devinfo == NULL) {
DEB(printf("gusmidi_open: unit %d is not configured.\n", unit));
return (ENXIO);
}
scp = devinfo->softc;
gusmidi_writeport(scp, PORT_CTL, MIDICTL_MASTER_RESET);
DELAY(100);
gusmidi_writeport(scp, PORT_CTL, scp->ctl);
return (0);
}
static int
gusmidi_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc *p)
{
sc_p scp;
mididev_info *devinfo;
int unit;
struct synth_info *synthinfo;
struct midi_info *midiinfo;
unit = MIDIUNIT(i_dev);
if (unit >= nmidi + nsynth) {
DEB(printf("gusmidi_ioctl: unit %d does not exist.\n", unit));
return (ENXIO);
}
devinfo = get_mididev_info(i_dev, &unit);
if (devinfo == NULL) {
DEB(printf("gusmidi_ioctl: unit %d is not configured.\n", unit));
return (ENXIO);
}
scp = devinfo->softc;
switch (cmd) {
case SNDCTL_SYNTH_INFO:
synthinfo = (struct synth_info *)arg;
if (synthinfo->device > nmidi + nsynth || synthinfo->device != unit)
return (ENXIO);
bcopy(&gusmidi_synthinfo, synthinfo, sizeof(gusmidi_synthinfo));
synthinfo->device = unit;
return (0);
break;
case SNDCTL_MIDI_INFO:
midiinfo = (struct midi_info *)arg;
if (midiinfo->device > nmidi + nsynth || midiinfo->device != unit)
return (ENXIO);
bcopy(&gusmidi_midiinfo, midiinfo, sizeof(gusmidi_midiinfo));
midiinfo->device = unit;
return (0);
break;
default:
return (ENOSYS);
}
/* NOTREACHED */
return (EINVAL);
}
void
gusmidi_intr(void *arg)
{
sc_p scp;
int s;
u_char c;
mididev_info *devinfo;
int stat, did_something;
scp = (sc_p)arg;
devinfo = scp->devinfo;
s = splclock();
/* XXX No framing/overrun checks... */
do {
stat = gusmidi_readport(scp, PORT_ST);
did_something = 0;
if (stat & MIDIST_RXFULL) {
c = gusmidi_readport(scp, PORT_RX);
if ((devinfo->flags & MIDI_F_PASSTHRU) &&
(!(devinfo->flags & MIDI_F_BUSY) ||
!(devinfo->fflags & FWRITE))) {
midibuf_input_intr(&devinfo->midi_dbuf_passthru,
&c, sizeof c);
devinfo->callback(devinfo,
MIDI_CB_START | MIDI_CB_WR);
}
if ((devinfo->flags & MIDI_F_READING) && c != 0xfe)
midibuf_input_intr(&devinfo->midi_dbuf_in,
&c, sizeof c);
did_something = 1;
}
if (stat & MIDIST_TXDONE) {
if (devinfo->flags & MIDI_F_WRITING) {
gusmidi_xmit(scp);
did_something = 1;
} else if (scp->ctl & MIDICTL_TX_IRQ_EN) {
/* This shouldn't happen. */
scp->ctl &= ~MIDICTL_TX_IRQ_EN;
gusmidi_writeport(scp, PORT_CTL, scp->ctl);
}
}
} while (did_something != 0);
/* Invoke the upper layer. */
midi_intr(devinfo);
splx(s);
}
static int
gusmidi_callback(mididev_info *d, int reason)
{
int unit;
sc_p scp;
if (d == NULL) {
DEB(printf("gusmidi_callback: device not configured.\n"));
return (ENXIO);
}
unit = d->unit;
scp = d->softc;
switch (reason & MIDI_CB_REASON_MASK) {
case MIDI_CB_START:
if ((reason & MIDI_CB_RD) != 0 && (d->flags & MIDI_F_READING) == 0) {
/* Begin recording. */
d->flags |= MIDI_F_READING;
scp->ctl |= MIDICTL_RX_IRQ_EN;
}
if ((reason & MIDI_CB_WR) != 0 && (d->flags & MIDI_F_WRITING) == 0)
/* Start playing. */
gusmidi_startplay(scp);
break;
case MIDI_CB_STOP:
case MIDI_CB_ABORT:
if ((reason & MIDI_CB_RD) != 0 && (d->flags & MIDI_F_READING) != 0) {
/* Stop recording. */
d->flags &= ~MIDI_F_READING;
scp->ctl &= ~MIDICTL_RX_IRQ_EN;
}
if ((reason & MIDI_CB_WR) != 0 && (d->flags & MIDI_F_WRITING) != 0) {
/* Stop Playing. */
d->flags &= ~MIDI_F_WRITING;
scp->ctl &= ~MIDICTL_TX_IRQ_EN;
}
break;
}
gusmidi_writeport(scp, PORT_CTL, scp->ctl);
return (0);
}
/*
* The functions below here are the libraries for the above ones.
*/
/*
* Starts to play the data in the output queue.
* Call this at >=splclock.
*/
static void
gusmidi_startplay(sc_p scp)
{
mididev_info *devinfo;
devinfo = scp->devinfo;
/* Can we play now? */
if (devinfo->midi_dbuf_out.rl == 0)
return;
devinfo->flags |= MIDI_F_WRITING;
scp->ctl |= MIDICTL_TX_IRQ_EN;
}
static void
gusmidi_xmit(sc_p scp)
{
register mididev_info *devinfo;
register midi_dbuf *dbuf;
u_char c;
devinfo = scp->devinfo;
/* See which source to use. */
if ((devinfo->flags & MIDI_F_PASSTHRU) == 0 || ((devinfo->flags & MIDI_F_BUSY) != 0 && (devinfo->fflags & FWRITE) != 0))
dbuf = &devinfo->midi_dbuf_out;
else
dbuf = &devinfo->midi_dbuf_passthru;
/* Transmit the data in the queue. */
while ((devinfo->flags & MIDI_F_WRITING) &&
(gusmidi_readport(scp, PORT_ST) & MIDIST_TXDONE)) {
/* Do we have the data to transmit? */
if (dbuf->rl == 0) {
/* Stop playing. */
devinfo->flags &= ~MIDI_F_WRITING;
scp->ctl &= ~MIDICTL_TX_IRQ_EN;
gusmidi_writeport(scp, PORT_CTL, scp->ctl);
break;
} else {
/* Send the data. */
midibuf_output_intr(dbuf, &c, sizeof(c));
gusmidi_writeport(scp, PORT_TX, c);
/* We are playing now. */
}
}
}
/* Reads from a port. */
static u_int
gusmidi_readport(sc_p scp, int off)
{
return bus_space_read_1(rman_get_bustag(scp->io), rman_get_bushandle(scp->io), off) & 0xff;
}
/* Writes to a port. */
static void
gusmidi_writeport(sc_p scp, int off, u_int8_t value)
{
bus_space_write_1(rman_get_bustag(scp->io), rman_get_bushandle(scp->io), off, value);
}
/* Allocates resources. */
static int
gusmidi_allocres(sc_p scp, device_t dev)
{
if (scp->io == NULL) {
scp->io = bus_alloc_resource(dev, SYS_RES_IOPORT, &scp->io_rid, 0, ~0, 2, RF_ACTIVE);
if (scp->io == NULL)
return (1);
}
#if notdef
if (scp->irq == NULL && !(device_get_flags(dev) & MPU_DF_NO_IRQ)) {
#else
if (scp->irq == NULL) {
#endif /* notdef */
scp->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &scp->irq_rid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
if (scp->irq == NULL)
return (1);
}
return (0);
}
/* Releases resources. */
static void
gusmidi_releaseres(sc_p scp, device_t dev)
{
if (scp->irq != NULL) {
bus_release_resource(dev, SYS_RES_IRQ, scp->irq_rid, scp->irq);
scp->irq = NULL;
}
if (scp->io != NULL) {
bus_release_resource(dev, SYS_RES_IOPORT, scp->io_rid, scp->io);
scp->io = NULL;
}
}
static device_method_t gusmidi_methods[] = {
/* Device interface */
DEVMETHOD(device_probe , gusmidi_probe ),
DEVMETHOD(device_attach, gusmidi_attach),
{ 0, 0 },
};
driver_t gusmidi_driver = {
"midi",
gusmidi_methods,
sizeof(struct gusmidi_softc),
};
DRIVER_MODULE(gusmidi, gusc, gusmidi_driver, midi_devclass, 0, 0);

835
sys/dev/sound/isa/mpu.c Normal file

@ -0,0 +1,835 @@
/*
* The low level driver for Roland MPU-401 compatible Midi interfaces.
*
* Copyright by Hannu Savolainen 1993
*
* 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.
*
* Modified: Riccardo Facchetti 24 Mar 1995 - Added the Audio Excel DSP 16
* initialization routine.
*
* Ported to the new Audio Driver by Luigi Rizzo:
* (C) 1999 Seigo Tanimura
*
* This is the MPU401 midi interface driver for FreeBSD, based on the Luigi Sound Driver.
* This handles io against /dev/midi, the midi {in, out}put event queues
* and the event/message transmittion to/from an MPU401 interface.
*
* $FreeBSD$
*
*/
#include "opt_devfs.h"
#include <dev/sound/midi/midi.h>
#include <dev/sound/chip.h>
#include <machine/cpufunc.h>
#include <isa/isavar.h>
#include <isa/sioreg.h>
#include <isa/ic/ns16550.h>
#define MPU_USEMICROTIMER 0
static devclass_t midi_devclass;
#ifndef DDB
#undef DDB
#define DDB(x)
#endif /* DDB */
#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 25000
/* Device flag. */
#define MPU_DF_NO_IRQ 1
extern synthdev_info midisynth_op_desc;
/* PnP IDs */
static struct isa_pnp_id mpu_ids[] = {
{0x01200001, "@H@2001 Midi Interface"}, /* @H@2001 */
{0x01100001, "@H@1001 Midi Interface"}, /* @H@1001 */
#if notdef
/* TODO: write bridge driver for these devices */
{0x0000630e, "CSC0000 Midi Interface"}, /* CSC0000 */
{0x2100a865, "YMH0021 Midi Interface"}, /* YMH0021 */
{0x80719304, "ADS7180 Midi Interface"}, /* ADS7180 */
{0x0300561e, "GRV0003 Midi Interface"}, /* GRV0003 */
#endif
};
/* These are the synthesizer and the midi interface information. */
static struct synth_info mpu_synthinfo = {
"MPU401 MIDI",
0,
SYNTH_TYPE_MIDI,
0,
0,
128,
128,
128,
SYNTH_CAP_INPUT,
};
static struct midi_info mpu_midiinfo = {
"MPU401 MIDI",
0,
0,
0,
};
/*
* These functions goes into mpu_op_desc to get called
* from sound.c.
*/
static int mpu_probe(device_t dev);
static int mpu_probe1(device_t dev);
static int mpu_probe2(device_t dev);
static int mpu_attach(device_t dev);
static int mpusbc_probe(device_t dev);
static int mpusbc_attach(device_t dev);
static d_ioctl_t mpu_ioctl;
static driver_intr_t mpu_intr;
static midi_callback_t mpu_callback;
/* Here is the parameter structure per a device. */
struct mpu_softc {
device_t dev; /* device information */
mididev_info *devinfo; /* midi device information */
struct resource *io; /* Base of io port */
int io_rid; /* Io resource ID */
u_long irq_val; /* Irq value */
struct resource *irq; /* Irq */
int irq_rid; /* Irq resource ID */
void *ih; /* Interrupt cookie */
struct callout_handle dh; /* Callout handler for delay */
int fflags; /* File flags */
};
typedef struct mpu_softc *sc_p;
/* These functions are local. */
static void mpu_startplay(sc_p scp);
static void mpu_xmit(sc_p scp);
#if MPU_USEMICROTIMER
static void mpu_timeout(sc_p scp);
static timeout_t mpu_timer;
#endif /* MPU_USEMICROTIMER */
static int mpu_resetmode(sc_p scp);
static int mpu_uartmode(sc_p scp);
static int mpu_waitack(sc_p scp);
static int mpu_status(sc_p scp);
static int mpu_command(sc_p scp, u_int8_t value);
static int mpu_readdata(sc_p scp);
static int mpu_writedata(sc_p scp, u_int8_t value);
static u_int mpu_readport(sc_p scp, int off);
static void mpu_writeport(sc_p scp, int off, u_int8_t value);
static int mpu_allocres(sc_p scp, device_t dev);
static void mpu_releaseres(sc_p scp, device_t dev);
/*
* This is the device descriptor for the midi device.
*/
static mididev_info mpu_op_desc = {
"MPU401 midi",
SNDCARD_MPU401,
NULL,
NULL,
NULL,
NULL,
mpu_ioctl,
NULL,
mpu_callback,
MIDI_BUFFSIZE, /* Queue Length */
0, /* XXX This is not an *audio* device! */
};
/*
* Here are the main functions to interact to the user process.
*/
static int
mpu_probe(device_t dev)
{
sc_p scp;
int ret;
/* Check isapnp ids */
if (isa_get_logicalid(dev) != 0)
return (ISA_PNP_PROBE(device_get_parent(dev), dev, mpu_ids));
scp = device_get_softc(dev);
device_set_desc(dev, mpu_op_desc.name);
bzero(scp, sizeof(*scp));
scp->io_rid = 0;
ret = mpu_probe1(dev);
if (ret != 0)
return (ret);
ret = mpu_probe2(dev);
if (ret != 0)
return (ret);
return (0);
}
/*
* Make sure this is an MPU401, not an 16550 uart.
* Called only for non-pnp devices.
*/
static int
mpu_probe1(device_t dev)
{
sc_p scp;
int iir;
struct resource *io;
scp = device_get_softc(dev);
/*
* If an MPU401 is ready to both input and output,
* the status register value is zero, which may
* confuse an 16550 uart to probe as an MPU401.
* We read the IIR (base + 2), which is not used
* by an MPU401.
*/
io = bus_alloc_resource(dev, SYS_RES_IOPORT, &scp->io_rid, 0, ~0, 3, RF_ACTIVE);
iir = bus_space_read_1(rman_get_bustag(io), rman_get_bushandle(io), com_iir) & 0xff;
bus_release_resource(dev, SYS_RES_IOPORT, scp->io_rid, io);
if ((iir & ~(IIR_IMASK | IIR_FIFO_MASK)) == 0)
/* Likely to be an 16550. */
return (ENXIO);
return (0);
}
/* Look up the irq. */
static int
mpu_probe2(device_t dev)
{
sc_p scp;
int unit, i;
intrmask_t irqp0, irqp1;
scp = device_get_softc(dev);
unit = device_get_unit(dev);
scp->io = bus_alloc_resource(dev, SYS_RES_IOPORT, &scp->io_rid, 0, ~0, 2, RF_ACTIVE);
if (scp->io == NULL)
return (ENXIO);
DEB(printf("mpu%d: probing.\n", unit));
/* Reset the interface. */
if (mpu_resetmode(scp) != 0 || mpu_waitack(scp) != 0) {
printf("mpu%d: reset failed.\n", unit);
mpu_releaseres(scp, dev);
return (ENXIO);
}
/*
* At this point, we are likely to have an interface.
*
* Switching the interface to uart mode gives us an interrupt.
* We can make use of it to determine the irq.
* Idea-stolen-from: sys/isa/sio.c:sioprobe()
*/
disable_intr();
/*
* See the initial irq. We have to do this now,
* otherwise a midi module/instrument might send
* an active sensing, to mess up the irq.
*/
irqp0 = isa_irq_pending();
irqp1 = 0;
/* Switch to uart mode. */
if (mpu_uartmode(scp) != 0) {
enable_intr();
printf("mpu%d: mode switching failed.\n", unit);
mpu_releaseres(scp, dev);
return (ENXIO);
}
if (device_get_flags(dev) & MPU_DF_NO_IRQ) {
irqp0 = irqp1 = 0;
goto no_irq;
}
/* See which irq we have now. */
for (i = 0 ; i < MPU_TRYDATA ; i++) {
DELAY(MPU_DELAY);
irqp1 = isa_irq_pending();
if (irqp1 != irqp0)
break;
}
if (irqp1 == irqp0) {
enable_intr();
printf("mpu%d: switching the mode gave no interrupt.\n", unit);
mpu_releaseres(scp, dev);
return (ENXIO);
}
no_irq:
/* Wait to see an ACK. */
if (mpu_waitack(scp) != 0) {
enable_intr();
printf("mpu%d: not acked.\n", unit);
mpu_releaseres(scp, dev);
return (ENXIO);
}
enable_intr();
if (device_get_flags(dev) & MPU_DF_NO_IRQ)
scp->irq_val = 0;
else
/* We have found the irq. */
scp->irq_val = ffs(~irqp0 & irqp1) - 1;
DEB(printf("mpu%d: probed.\n", unit));
return (0);
}
static int
mpusbc_probe(device_t dev)
{
char *s;
sc_p scp;
struct sndcard_func *func;
/* The parent device has already been probed. */
func = device_get_ivars(dev);
if (func == NULL || func->func != SCF_MIDI)
return (ENXIO);
s = "SB Midi Interface";
scp = device_get_softc(dev);
bzero(scp, sizeof(*scp));
scp->io_rid = 1;
scp->irq_rid = 0;
device_set_desc(dev, s);
return (0);
}
static int
mpu_attach(device_t dev)
{
sc_p scp;
mididev_info *devinfo;
int unit;
scp = device_get_softc(dev);
unit = device_get_unit(dev);
DEB(printf("mpu%d: attaching.\n", unit));
/* Allocate the resources, switch to uart mode. */
if (mpu_allocres(scp, dev) || mpu_uartmode(scp)) {
mpu_releaseres(scp, dev);
return (ENXIO);
}
/* mpu_probe() has put the interface to uart mode. */
/* Fill the softc. */
scp->dev = dev;
scp->devinfo = devinfo = &midi_info[unit];
callout_handle_init(&scp->dh);
/* Fill the midi info. */
bcopy(&mpu_op_desc, devinfo, sizeof(mpu_op_desc));
midiinit(devinfo, dev);
devinfo->flags = 0;
bcopy(&midisynth_op_desc, &devinfo->synth, sizeof(midisynth_op_desc));
if (scp->irq != NULL)
snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at 0x%x irq %d",
(u_int)rman_get_start(scp->io), (int)rman_get_start(scp->irq));
else
snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at 0x%x",
(u_int)rman_get_start(scp->io));
/* Init the queue. */
devinfo->midi_dbuf_in.unit_size = devinfo->midi_dbuf_out.unit_size = 1;
midibuf_init(&devinfo->midi_dbuf_in);
midibuf_init(&devinfo->midi_dbuf_out);
/* Increase the number of midi devices. */
nmidi++;
/* Now we can handle the interrupts. */
if (scp->irq != NULL)
bus_setup_intr(dev, scp->irq, INTR_TYPE_TTY, mpu_intr, scp,
&scp->ih);
DEB(printf("mpu%d: attached.\n", unit));
return (0);
}
static int
mpusbc_attach(device_t dev)
{
sc_p scp;
int unit;
scp = device_get_softc(dev);
unit = device_get_unit(dev);
mpu_attach(dev);
return (0);
}
static int
mpu_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc *p)
{
sc_p scp;
mididev_info *devinfo;
int unit;
struct synth_info *synthinfo;
struct midi_info *midiinfo;
unit = MIDIUNIT(i_dev);
if (unit >= nmidi + nsynth) {
DEB(printf("mpu_ioctl: unit %d does not exist.\n", unit));
return (ENXIO);
}
devinfo = get_mididev_info(i_dev, &unit);
if (devinfo == NULL) {
DEB(printf("mpu_ioctl: unit %d is not configured.\n", unit));
return (ENXIO);
}
scp = devinfo->softc;
switch (cmd) {
case SNDCTL_SYNTH_INFO:
synthinfo = (struct synth_info *)arg;
if (synthinfo->device > nmidi + nsynth || synthinfo->device != unit)
return (ENXIO);
bcopy(&mpu_synthinfo, synthinfo, sizeof(mpu_synthinfo));
synthinfo->device = unit;
return (0);
break;
case SNDCTL_MIDI_INFO:
midiinfo = (struct midi_info *)arg;
if (midiinfo->device > nmidi + nsynth || midiinfo->device != unit)
return (ENXIO);
bcopy(&mpu_midiinfo, midiinfo, sizeof(mpu_midiinfo));
midiinfo->device = unit;
return (0);
break;
default:
return (ENOSYS);
}
/* NOTREACHED */
return (EINVAL);
}
static void
mpu_intr(void *arg)
{
sc_p scp;
u_char c;
mididev_info *devinfo;
scp = (sc_p)arg;
devinfo = scp->devinfo;
/* Read the received data. */
while ((mpu_status(scp) & MPU_INPUTBUSY) == 0) {
/* Receive the data. */
c = mpu_readdata(scp);
/* Queue into the passthru buffer and start transmitting if we can. */
if ((devinfo->flags & MIDI_F_PASSTHRU) != 0 && ((devinfo->flags & MIDI_F_BUSY) == 0 || (devinfo->fflags & FWRITE) == 0)) {
midibuf_input_intr(&devinfo->midi_dbuf_passthru, &c, sizeof(c));
devinfo->callback(devinfo, MIDI_CB_START | MIDI_CB_WR);
}
/* Queue if we are reading. Discard an active sensing. */
if ((devinfo->flags & MIDI_F_READING) != 0 && c != 0xfe)
midibuf_input_intr(&devinfo->midi_dbuf_in, &c, sizeof(c));
}
/* Invoke the upper layer. */
midi_intr(devinfo);
}
static int
mpu_callback(mididev_info *d, int reason)
{
int unit;
sc_p scp;
if (d == NULL) {
DEB(printf("mpu_callback: device not configured.\n"));
return (ENXIO);
}
unit = d->unit;
scp = d->softc;
switch (reason & MIDI_CB_REASON_MASK) {
case MIDI_CB_START:
if ((reason & MIDI_CB_RD) != 0 && (d->flags & MIDI_F_READING) == 0)
/* Begin recording. */
d->flags |= MIDI_F_READING;
if ((reason & MIDI_CB_WR) != 0 && (d->flags & MIDI_F_WRITING) == 0)
/* Start playing. */
mpu_startplay(scp);
break;
case MIDI_CB_STOP:
case MIDI_CB_ABORT:
if ((reason & MIDI_CB_RD) != 0 && (d->flags & MIDI_F_READING) != 0)
/* Stop recording. */
d->flags &= ~MIDI_F_READING;
if ((reason & MIDI_CB_WR) != 0 && (d->flags & MIDI_F_WRITING) != 0)
/* Stop Playing. */
d->flags &= ~MIDI_F_WRITING;
break;
}
return (0);
}
/*
* The functions below here are the libraries for the above ones.
*/
/*
* Starts to play the data in the output queue.
* Call this at >=splclock.
*/
static void
mpu_startplay(sc_p scp)
{
mididev_info *devinfo;
devinfo = scp->devinfo;
/* Can we play now? */
if (devinfo->midi_dbuf_out.rl == 0)
return;
devinfo->flags |= MIDI_F_WRITING;
#if MPU_USEMICROTIMER
mpu_timeout(scp);
#else
mpu_xmit(scp);
#endif /* MPU_USEMICROTIMER */
}
static void
mpu_xmit(sc_p scp)
{
register mididev_info *devinfo;
register midi_dbuf *dbuf;
u_char c;
devinfo = scp->devinfo;
/* See which source to use. */
if ((devinfo->flags & MIDI_F_PASSTHRU) == 0 || ((devinfo->flags & MIDI_F_BUSY) != 0 && (devinfo->fflags & FWRITE) != 0))
dbuf = &devinfo->midi_dbuf_out;
else
dbuf = &devinfo->midi_dbuf_passthru;
/* Transmit the data in the queue. */
#if MPU_USEMICROTIMER
while ((devinfo->flags & MIDI_F_WRITING) != 0 && (mpu_status(scp) & MPU_OUTPUTBUSY) == 0) {
/* Do we have the data to transmit? */
if (dbuf->rl == 0) {
/* Stop playing. */
devinfo->flags &= ~MIDI_F_WRITING;
break;
} else {
/* Send the data. */
midibuf_output_intr(dbuf, &c, sizeof(c));
mpu_writedata(scp, c);
/* We are playing now. */
devinfo->flags |= MIDI_F_WRITING;
}
}
/* De we have still more? */
if ((devinfo->flags & MIDI_F_WRITING) != 0)
/* Handle them on the next interrupt. */
mpu_timeout(scp);
#else
while ((devinfo->flags & MIDI_F_WRITING) != 0 && dbuf->rl > 0) {
/* XXX Wait until we can write the data. */
while ((mpu_status(scp) & MPU_OUTPUTBUSY) != 0);
/* Send the data. */
midibuf_output_intr(dbuf, &c, sizeof(c));
mpu_writedata(scp, c);
/* We are playing now. */
devinfo->flags |= MIDI_F_WRITING;
}
/* Stop playing. */
devinfo->flags &= ~MIDI_F_WRITING;
#endif /* MPU_USEMICROTIMER */
}
#if MPU_USEMICROTIMER
/* Arm a timer. */
static void
mpu_timeout(sc_p scp)
{
microtimeout(mpu_timer, scp, hz * hzmul / 3125);
}
/* Called when a timer has beeped. */
static void
mpu_timer(void *arg)
{
sc_p scp;
scp = arg;
mpu_xmit(scp);
}
#endif /* MPU_USEMICROTIMER */
/* Reset mpu. */
static int
mpu_resetmode(sc_p scp)
{
int i, resp;
/* Reset the mpu. */
resp = 0;
for (i = 0 ; i < MPU_TRYDATA ; i++) {
resp = mpu_command(scp, MPU_RESET);
if (resp == 0)
break;
}
if (resp != 0)
return (1);
DELAY(MPU_DELAY);
return (0);
}
/* Switch to uart mode. */
static int
mpu_uartmode(sc_p scp)
{
int i, resp;
/* Switch to uart mode. */
resp = 0;
for (i = 0 ; i < MPU_TRYDATA ; i++) {
resp = mpu_command(scp, MPU_UART);
if (resp == 0)
break;
}
if (resp != 0)
return (1);
DELAY(MPU_DELAY);
return (0);
}
/* Wait to see an ACK. */
static int
mpu_waitack(sc_p scp)
{
int i, resp;
resp = 0;
for (i = 0 ; i < MPU_TRYDATA ; i++) {
resp = mpu_readdata(scp);
if (resp >= 0)
break;
}
if (resp != MPU_ACK)
return (1);
DELAY(MPU_DELAY);
return (0);
}
/* Reads the status. */
static int
mpu_status(sc_p scp)
{
return mpu_readport(scp, MPU_STATPORT);
}
/* Writes a command. */
static int
mpu_command(sc_p scp, u_int8_t value)
{
u_int status;
/* Is the interface ready to write? */
status = mpu_status(scp);
if ((status & MPU_OUTPUTBUSY) != 0)
/* The interface is busy. */
return (EAGAIN);
mpu_writeport(scp, MPU_CMDPORT, value);
return (0);
}
/* Reads a byte of data. */
static int
mpu_readdata(sc_p scp)
{
u_int status;
/* Is the interface ready to write? */
status = mpu_status(scp);
if ((status & MPU_INPUTBUSY) != 0)
/* The interface is busy. */
return (-EAGAIN);
return (int)mpu_readport(scp, MPU_DATAPORT) & 0xff;
}
/* Writes a byte of data. */
static int
mpu_writedata(sc_p scp, u_int8_t value)
{
u_int status;
/* Is the interface ready to write? */
status = mpu_status(scp);
if ((status & MPU_OUTPUTBUSY) != 0)
/* The interface is busy. */
return (EAGAIN);
mpu_writeport(scp, MPU_DATAPORT, value);
return (0);
}
/* Reads from a port. */
static u_int
mpu_readport(sc_p scp, int off)
{
return bus_space_read_1(rman_get_bustag(scp->io), rman_get_bushandle(scp->io), off) & 0xff;
}
/* Writes to a port. */
static void
mpu_writeport(sc_p scp, int off, u_int8_t value)
{
bus_space_write_1(rman_get_bustag(scp->io), rman_get_bushandle(scp->io), off, value);
}
/* Allocates resources. */
static int
mpu_allocres(sc_p scp, device_t dev)
{
if (scp->io == NULL) {
scp->io = bus_alloc_resource(dev, SYS_RES_IOPORT, &scp->io_rid, 0, ~0, 2, RF_ACTIVE);
if (scp->io == NULL)
return (1);
}
if (scp->irq == NULL && !(device_get_flags(dev) & MPU_DF_NO_IRQ)) {
if (scp->irq_val == 0)
scp->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &scp->irq_rid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
else
scp->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &scp->irq_rid, scp->irq_val, scp->irq_val, 1, RF_ACTIVE | RF_SHAREABLE);
if (scp->irq == NULL)
return (1);
}
return (0);
}
/* Releases resources. */
static void
mpu_releaseres(sc_p scp, device_t dev)
{
if (scp->irq != NULL) {
bus_release_resource(dev, SYS_RES_IRQ, scp->irq_rid, scp->irq);
scp->irq = NULL;
}
if (scp->io != NULL) {
bus_release_resource(dev, SYS_RES_IOPORT, scp->io_rid, scp->io);
scp->io = NULL;
}
}
static device_method_t mpu_methods[] = {
/* Device interface */
DEVMETHOD(device_probe , mpu_probe ),
DEVMETHOD(device_attach, mpu_attach),
{ 0, 0 },
};
static driver_t mpu_driver = {
"midi",
mpu_methods,
sizeof(struct mpu_softc),
};
DRIVER_MODULE(mpu, isa, mpu_driver, midi_devclass, 0, 0);
static device_method_t mpusbc_methods[] = {
/* Device interface */
DEVMETHOD(device_probe , mpusbc_probe ),
DEVMETHOD(device_attach, mpusbc_attach),
{ 0, 0 },
};
static driver_t mpusbc_driver = {
"midi",
mpusbc_methods,
sizeof(struct mpu_softc),
};
DRIVER_MODULE(mpusbc, sbc, mpusbc_driver, midi_devclass, 0, 0);

@ -34,10 +34,6 @@
#include <dev/sound/isa/mss.h>
#include <dev/sound/chip.h>
#if notyet
#include "midi.h"
#endif /* notyet */
#define MSS_BUFFSIZE (65536 - 256)
#define abs(x) (((x) < 0) ? -(x) : (x))
@ -352,12 +348,8 @@ gusmax_setup(struct mss_info *mss, device_t dev, struct resource *alt)
port_wr(alt, 0x0f, 0x00);
irqctl = irq_bits[isa_get_irq(parent)];
#if notyet
#if NMIDI > 0
/* Share the IRQ with the MIDI driver. */
irqctl |= 0x40;
#endif /* NMIDI > 0 */
#endif /* notyet */
dmactl = dma_bits[isa_get_drq(parent)];
if (device_get_flags(parent) & DV_F_DUAL_DMA)
dmactl |= dma_bits[device_get_flags(parent) & DV_F_DRQ_MASK]
@ -495,7 +487,7 @@ mss_probe(device_t dev)
int flags, irq, drq, result = ENXIO, setres = 0;
struct mss_info *mss;
if (isa_get_vendorid(dev)) return ENXIO; /* not yet */
if (isa_get_logicalid(dev)) return ENXIO; /* not yet */
mss = (struct mss_info *)malloc(sizeof *mss, M_DEVBUF, M_NOWAIT);
if (!mss) return ENXIO;
@ -1556,7 +1548,7 @@ guspcm_attach(device_t dev)
mss->drq1_rid = 1;
mss->drq2_rid = -1;
if (isa_get_vendorid(parent) == 0)
if (isa_get_logicalid(parent) == 0)
mss->bd_id = MD_GUSMAX;
else {
mss->bd_id = MD_GUSPNP;

1904
sys/dev/sound/isa/opl.c Normal file

File diff suppressed because it is too large Load Diff

@ -400,7 +400,6 @@ sbc_attach(device_t dev)
child = device_add_child(dev, "pcm", -1);
device_set_ivars(child, func);
#if notyet
/* Midi Interface */
func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT);
if (func == NULL) goto bad;
@ -416,7 +415,6 @@ sbc_attach(device_t dev)
func->func = SCF_SYNTH;
child = device_add_child(dev, "midi", -1);
device_set_ivars(child, func);
#endif /* notyet */
/* probe/attach kids */
bus_generic_attach(dev);

524
sys/dev/sound/isa/uartsio.c Normal file

@ -0,0 +1,524 @@
/*
* Copyright by George Hansper 1996
*
* Tue Jan 23 22:32:10 EST 1996 ghansper@daemon.apana.org.au
* added 16450/16550 support for standard serial-port UARTs
*
* 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.
*
*
* Wed Apl 1 02:25:30 JST 1998 zinnia@jan.ne.jp
* ported to FreeBSD 2.2.5R-RELEASE
*
* Fri Apl 1 21:16:20 JST 1999 zinnia@jan.ne.jp
* ported to FreeBSD 3.1-STABLE
*
*
* Ported to the new Audio Driver by Luigi Rizzo:
* (C) 1999 Seigo Tanimura
*
* This is the 16550 midi uart driver for FreeBSD, based on the Luigi Sound Driver.
* This handles io against /dev/midi, the midi {in, out}put event queues
* and the event/message transmittion to/from a serial port interface.
*
* $FreeBSD$
*
*/
#include "opt_devfs.h"
#include <isa/sioreg.h>
#include <isa/ic/ns16550.h>
#include <dev/sound/midi/midi.h>
/* XXX What about a PCI uart? */
#include <isa/isavar.h>
static devclass_t midi_devclass;
#ifndef DDB
#undef DDB
#define DDB(x)
#endif /* DDB */
#define TX_FIFO_SIZE 16
extern synthdev_info midisynth_op_desc;
/* These are the synthesizer and the midi interface information. */
static struct synth_info uartsio_synthinfo = {
"uart16550A MIDI",
0,
SYNTH_TYPE_MIDI,
0,
0,
128,
128,
128,
SYNTH_CAP_INPUT,
};
static struct midi_info uartsio_midiinfo = {
"uart16550A MIDI",
0,
0,
0,
};
/*
* These functions goes into uartsio_op_desc to get called
* from sound.c.
*/
static int uartsio_probe(device_t dev);
static int uartsio_attach(device_t dev);
static d_ioctl_t uartsio_ioctl;
static driver_intr_t uartsio_intr;
static midi_callback_t uartsio_callback;
/* Here is the parameter structure per a device. */
struct uartsio_softc {
device_t dev; /* device information */
mididev_info *devinfo; /* midi device information */
struct resource *io; /* Base of io port */
int io_rid; /* Io resource ID */
struct resource *irq; /* Irq */
int irq_rid; /* Irq resource ID */
void *ih; /* Interrupt cookie */
int fflags; /* File flags */
int has_fifo; /* TX/RX fifo in the uart */
int tx_size; /* Size of TX on a transmission */
};
typedef struct uartsio_softc *sc_p;
/* These functions are local. */
static void uartsio_startplay(sc_p scp);
static int uartsio_xmit(sc_p scp);
static int uartsio_readport(sc_p scp, int off);
static void uartsio_writeport(sc_p scp, int off, u_int8_t value);
static int uartsio_allocres(sc_p scp, device_t dev);
static void uartsio_releaseres(sc_p scp, device_t dev);
/*
* This is the device descriptor for the midi device.
*/
static mididev_info uartsio_op_desc = {
"16550 uart midi",
SNDCARD_UART16550,
NULL,
NULL,
NULL,
NULL,
uartsio_ioctl,
NULL,
uartsio_callback,
MIDI_BUFFSIZE, /* Queue Length */
0, /* XXX This is not an *audio* device! */
};
/*
* Here are the main functions to interact to the user process.
* These are called from snd* functions in sys/i386/isa/snd/sound.c.
*/
static int
uartsio_probe(device_t dev)
{
sc_p scp;
int unit;
u_char c;
if (isa_get_logicalid(dev) != 0)
/* This is NOT a PnP device! */
return (ENXIO);
scp = device_get_softc(dev);
unit = device_get_unit(dev);
device_set_desc(dev, uartsio_op_desc.name);
bzero(scp, sizeof(*scp));
scp->io_rid = 0;
scp->io = bus_alloc_resource(dev, SYS_RES_IOPORT, &scp->io_rid, 0, ~0, 8, RF_ACTIVE);
if (scp->io == NULL)
return (ENXIO);
DEB(printf("uartsio%d: probing.\n", unit));
/* Read the IER. The upper four bits should all be zero. */
c = uartsio_readport(scp, com_ier);
if ((c & 0xf0) != 0) {
uartsio_releaseres(scp, dev);
return (ENXIO);
}
/* Read the MSR. The upper three bits should all be zero. */
c = uartsio_readport(scp, com_mcr);
if ((c & 0xe0) != 0) {
uartsio_releaseres(scp, dev);
return (ENXIO);
}
/* XXX Do we need a loopback test? */
DEB(printf("uartsio%d: probed.\n", unit));
return (0);
}
static int
uartsio_attach(device_t dev)
{
sc_p scp;
mididev_info *devinfo;
int unit;
scp = device_get_softc(dev);
unit = device_get_unit(dev);
DEB(printf("uartsio%d: attaching.\n", unit));
/* Allocate resources. */
if (uartsio_allocres(scp, dev)) {
uartsio_releaseres(scp, dev);
return (ENXIO);
}
/* See the size of the tx fifo. */
uartsio_writeport(scp, com_fifo, FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_RX_HIGH);
if ((uartsio_readport(scp, com_iir) & IIR_FIFO_MASK) == FIFO_RX_HIGH) {
scp->has_fifo = 1;
scp->tx_size = TX_FIFO_SIZE;
DEB(printf("uartsio%d: uart is 16550A, tx size is %d bytes.\n", unit, scp->tx_size));
} else {
scp->has_fifo = 0;
scp->tx_size = 1;
DEB(printf("uartsio%d: uart is not 16550A.\n", unit));
}
/* Fill the softc. */
scp->dev = dev;
scp->devinfo = devinfo = &midi_info[unit];
/* Fill the midi info. */
bcopy(&uartsio_op_desc, devinfo, sizeof(uartsio_op_desc));
midiinit(devinfo, dev);
devinfo->flags = 0;
bcopy(&midisynth_op_desc, &devinfo->synth, sizeof(midisynth_op_desc));
snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at 0x%x irq %d",
(u_int)rman_get_start(scp->io), (int)rman_get_start(scp->irq));
/* Init the queue. */
devinfo->midi_dbuf_in.unit_size = devinfo->midi_dbuf_out.unit_size = 1;
midibuf_init(&devinfo->midi_dbuf_in);
midibuf_init(&devinfo->midi_dbuf_out);
midibuf_init(&devinfo->midi_dbuf_passthru);
/* Configure the uart. */
uartsio_writeport(scp, com_cfcr, CFCR_DLAB); /* Latch the divisor. */
uartsio_writeport(scp, com_dlbl, 0x03);
uartsio_writeport(scp, com_dlbh, 0x00); /* We want a bitrate of 38.4kbps. */
uartsio_writeport(scp, com_cfcr, CFCR_8BITS); /* We want 8bits, 1 stop bit, no parity. */
uartsio_writeport(scp, com_mcr, MCR_IENABLE | MCR_RTS | MCR_DTR); /* Enable interrupt, set RTS and DTR. */
uartsio_writeport(scp, com_ier, IER_ERXRDY | IER_ETXRDY | IER_EMSC | IER_ERLS); /* Give us an interrupt on RXRDY, TXRDY, MSC and RLS. */
if (scp->has_fifo)
uartsio_writeport(scp, com_fifo, FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_RX_LOW); /* We use the fifo. */
else
uartsio_writeport(scp, com_fifo, FIFO_RCV_RST | FIFO_XMT_RST | FIFO_RX_LOW); /* We do not use the fifo. */
/* Clear the gabage. */
uartsio_readport(scp, com_lsr);
uartsio_readport(scp, com_lsr);
uartsio_readport(scp, com_iir);
uartsio_readport(scp, com_data);
/* Increase the number of midi devices. */
nmidi++;
/* Now we can handle the interrupts. */
bus_setup_intr(dev, scp->irq, INTR_TYPE_TTY, uartsio_intr, scp, &scp->ih);
DEB(printf("uartsio%d: attached.\n", unit));
return (0);
}
static int
uartsio_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc *p)
{
sc_p scp;
mididev_info *devinfo;
int unit;
struct synth_info *synthinfo;
struct midi_info *midiinfo;
unit = MIDIUNIT(i_dev);
if (unit >= nmidi + nsynth) {
DEB(printf("uartsio_ioctl: unit %d does not exist.\n", unit));
return (ENXIO);
}
devinfo = get_mididev_info(i_dev, &unit);
if (devinfo == NULL) {
DEB(printf("uartsio_ioctl: unit %d is not configured.\n", unit));
return (ENXIO);
}
scp = devinfo->softc;
switch (cmd) {
case SNDCTL_SYNTH_INFO:
synthinfo = (struct synth_info *)arg;
if (synthinfo->device > nmidi + nsynth || synthinfo->device != unit)
return (ENXIO);
bcopy(&uartsio_synthinfo, synthinfo, sizeof(uartsio_synthinfo));
synthinfo->device = unit;
return (0);
break;
case SNDCTL_MIDI_INFO:
midiinfo = (struct midi_info *)arg;
if (midiinfo->device > nmidi + nsynth || midiinfo->device != unit)
return (ENXIO);
bcopy(&uartsio_midiinfo, midiinfo, sizeof(uartsio_midiinfo));
midiinfo->device = unit;
return (0);
break;
default:
return (ENOSYS);
}
/* NOTREACHED */
return (EINVAL);
}
static void
uartsio_intr(void *arg)
{
sc_p scp;
mididev_info *devinfo;
scp = (sc_p)arg;
devinfo = scp->devinfo;
uartsio_xmit(scp);
/* Invoke the upper layer. */
midi_intr(devinfo);
}
static int
uartsio_callback(mididev_info *d, int reason)
{
int unit;
sc_p scp;
if (d == NULL) {
DEB(printf("uartsio_callback: device not configured.\n"));
return (ENXIO);
}
unit = d->unit;
scp = d->softc;
switch (reason & MIDI_CB_REASON_MASK) {
case MIDI_CB_START:
if ((reason & MIDI_CB_RD) != 0 && (d->flags & MIDI_F_READING) == 0)
/* Begin recording. */
d->flags |= MIDI_F_READING;
if ((reason & MIDI_CB_WR) != 0 && (d->flags & MIDI_F_WRITING) == 0)
/* Start playing. */
uartsio_startplay(scp);
break;
case MIDI_CB_STOP:
case MIDI_CB_ABORT:
if ((reason & MIDI_CB_RD) != 0 && (d->flags & MIDI_F_READING) != 0)
/* Stop recording. */
d->flags &= ~MIDI_F_READING;
if ((reason & MIDI_CB_WR) != 0 && (d->flags & MIDI_F_WRITING) != 0)
/* Stop Playing. */
d->flags &= ~MIDI_F_WRITING;
break;
}
return (0);
}
/*
* The functions below here are the libraries for the above ones.
*/
/*
* Starts to play the data in the output queue.
* Call this at >=splmidi.
*/
static void
uartsio_startplay(sc_p scp)
{
mididev_info *devinfo;
devinfo = scp->devinfo;
/* Can we play now? */
if (devinfo->midi_dbuf_out.rl == 0)
return;
devinfo->flags |= MIDI_F_WRITING;
uartsio_xmit(scp);
}
static int
uartsio_xmit(sc_p scp)
{
mididev_info *devinfo;
midi_dbuf *dbuf;
int lsr, msr, iir, i, txsize;
u_char c[TX_FIFO_SIZE];
devinfo = scp->devinfo;
do {
/* Read the received data. */
while (((lsr = uartsio_readport(scp, com_lsr)) & LSR_RCV_MASK) != 0) {
/* Is this a data or an error/break? */
if ((lsr & LSR_RXRDY) == 0)
printf("uartsio_xmit: receive error or break in unit %d.\n", devinfo->unit);
else {
/* Receive the data. */
c[0] = uartsio_readport(scp, com_data);
/* Queue into the passthru buffer and start transmitting if we can. */
if ((devinfo->flags & MIDI_F_PASSTHRU) != 0 && ((devinfo->flags & MIDI_F_BUSY) == 0 || (devinfo->fflags & FWRITE) == 0)) {
midibuf_input_intr(&devinfo->midi_dbuf_passthru, &c[0], sizeof(c[0]));
devinfo->flags |= MIDI_F_WRITING;
}
/* Queue if we are reading. Discard an active sensing. */
if ((devinfo->flags & MIDI_F_READING) != 0 && c[0] != 0xfe)
midibuf_input_intr(&devinfo->midi_dbuf_in, &c[0], sizeof(c[0]));
}
}
/* Read MSR. */
msr = uartsio_readport(scp, com_msr);
/* See which source to use. */
if ((devinfo->flags & MIDI_F_PASSTHRU) == 0 || ((devinfo->flags & MIDI_F_BUSY) != 0 && (devinfo->fflags & FWRITE) != 0))
dbuf = &devinfo->midi_dbuf_out;
else
dbuf = &devinfo->midi_dbuf_passthru;
/* Transmit the data in the queue. */
if ((devinfo->flags & MIDI_F_WRITING) != 0 && (lsr & LSR_TXRDY) != 0 && (msr & MSR_CTS) != 0) {
/* Do we have the data to transmit? */
if (dbuf->rl == 0) {
/* Stop playing. */
devinfo->flags &= ~MIDI_F_WRITING;
} else {
/* send the data. */
txsize = scp->tx_size;
if (dbuf->rl < txsize)
txsize = dbuf->rl;
midibuf_output_intr(dbuf, c, txsize);
for (i = 0 ; i < txsize ; i++)
uartsio_writeport(scp, com_data, c[i]);
/* We are playing now. */
devinfo->flags |= MIDI_F_WRITING;
}
} else {
/* Do we have the data to transmit? */
if (dbuf->rl > 0)
/* Wait for the next interrupt. */
devinfo->flags |= MIDI_F_WRITING;
}
} while (((iir = uartsio_readport(scp, com_iir)) & IIR_IMASK) != IIR_NOPEND);
return (0);
}
/* Reads from a port. */
static int
uartsio_readport(sc_p scp, int off)
{
return bus_space_read_1(rman_get_bustag(scp->io), rman_get_bushandle(scp->io), off);
}
/* Writes to a port. */
static void
uartsio_writeport(sc_p scp, int off, u_int8_t value)
{
return bus_space_write_1(rman_get_bustag(scp->io), rman_get_bushandle(scp->io), off, value);
}
/* Allocates resources other than IO ports. */
static int
uartsio_allocres(sc_p scp, device_t dev)
{
if (scp->irq == NULL) {
scp->irq_rid = 0;
scp->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &scp->irq_rid, 0, ~0, 1, RF_ACTIVE);
}
if (scp->irq == NULL)
return (1);
return (0);
}
/* Releases resources. */
static void
uartsio_releaseres(sc_p scp, device_t dev)
{
if (scp->irq != NULL) {
bus_release_resource(dev, SYS_RES_IRQ, scp->irq_rid, scp->irq);
scp->irq = NULL;
}
if (scp->io != NULL) {
bus_release_resource(dev, SYS_RES_IOPORT, scp->io_rid, scp->io);
scp->io = NULL;
}
}
static device_method_t uartsio_methods[] = {
/* Device interface */
DEVMETHOD(device_probe , uartsio_probe ),
DEVMETHOD(device_attach, uartsio_attach),
{ 0, 0 },
};
static driver_t uartsio_driver = {
"midi",
uartsio_methods,
sizeof(struct uartsio_softc),
};
DRIVER_MODULE(uartsio, isa, uartsio_driver, midi_devclass, 0, 0);

702
sys/dev/sound/midi/midi.c Normal file

@ -0,0 +1,702 @@
/*
* Main midi driver for FreeBSD. This file provides the main
* entry points for probe/attach and all i/o demultiplexing, including
* default routines for generic devices.
*
* (C) 1999 Seigo Tanimura
*
* 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.
*
*
* For each card type a template "mididev_info" structure contains
* all the relevant parameters, both for configuration and runtime.
*
* In this file we build tables of pointers to the descriptors for
* the various supported cards. The generic probe routine scans
* the table(s) looking for a matching entry, then invokes the
* board-specific probe routine. If successful, a pointer to the
* correct mididev_info is stored in mididev_last_probed, for subsequent
* use in the attach routine. The generic attach routine copies
* the template to a permanent descriptor (midi_info[unit] and
* friends), initializes all generic parameters, and calls the
* board-specific attach routine.
*
* On device calls, the generic routines do the checks on unit and
* device parameters, then call the board-specific routines if
* available, or try to perform the task using the default code.
*
* $FreeBSD$
*
*/
#include "opt_devfs.h"
#include <dev/sound/midi/midi.h>
static devclass_t midi_devclass;
static d_open_t midiopen;
static d_close_t midiclose;
static d_ioctl_t midiioctl;
static d_read_t midiread;
static d_write_t midiwrite;
static d_poll_t midipoll;
/* These functions are local. */
static d_open_t midistat_open;
static d_close_t midistat_close;
static d_read_t midistat_read;
static int midi_initstatus(char *buf, int size);
static int midi_readstatus(char *buf, int *ptr, struct uio *uio);
#define CDEV_MAJOR MIDI_CDEV_MAJOR
static struct cdevsw midi_cdevsw = {
/* open */ midiopen,
/* close */ midiclose,
/* read */ midiread,
/* write */ midiwrite,
/* ioctl */ midiioctl,
/* poll */ midipoll,
/* mmap */ nommap,
/* strategy */ nostrategy,
/* name */ "midi",
/* maj */ CDEV_MAJOR,
/* dump */ nodump,
/* psize */ nopsize,
/* flags */ 0,
/* bmaj */ -1
};
/*
* descriptors for active devices. also used as the public softc
* of a device.
*/
mididev_info midi_info[NMIDI_MAX];
u_long nmidi; /* total number of midi devices, filled in by the driver */
u_long nsynth; /* total number of synthesizers, filled in by the driver */
/* These make the buffer for /dev/midistat */
static int midistatbusy;
static char midistatbuf[4096];
static int midistatptr;
/*
* This is the generic init routine
*/
int
midiinit(mididev_info *d, device_t dev)
{
int unit;
if (midi_devclass == NULL) {
midi_devclass = device_get_devclass(dev);
make_dev(&midi_cdevsw, MIDIMKMINOR(0, MIDI_DEV_STATUS),
UID_ROOT, GID_WHEEL, 0444, "midistat");
}
unit = device_get_unit(dev);
make_dev(&midi_cdevsw, MIDIMKMINOR(unit, MIDI_DEV_MIDIN),
UID_ROOT, GID_WHEEL, 0666, "midi%d", unit);
/*
* initialize standard parameters for the device. This can be
* overridden by device-specific configurations but better do
* here the generic things.
*/
d->unit = device_get_unit(dev);
d->softc = device_get_softc(dev);
d->dev = dev;
d->magic = MAGIC(d->unit); /* debugging... */
return 0 ;
}
/*
* a small utility function which, given a device number, returns
* a pointer to the associated mididev_info struct, and sets the unit
* number.
*/
mididev_info *
get_mididev_info(dev_t i_dev, int *unit)
{
int u;
mididev_info *d = NULL;
if (MIDIDEV(i_dev) != MIDI_DEV_MIDIN)
return NULL;
u = MIDIUNIT(i_dev);
if (unit)
*unit = u;
if (u >= nmidi + nsynth) {
DEB(printf("get_mididev_info: unit %d is not configured.\n", u));
return NULL;
}
d = &midi_info[u];
return d;
}
/*
* here are the switches for the main functions. The switches do
* all necessary checks on the device number to make sure
* that the device is configured. They also provide some default
* functionalities so that device-specific drivers have to deal
* only with special cases.
*/
static int
midiopen(dev_t i_dev, int flags, int mode, struct proc * p)
{
switch (MIDIDEV(i_dev)) {
case MIDI_DEV_MIDIN:
return midi_open(i_dev, flags, mode, p);
case MIDI_DEV_STATUS:
return midistat_open(i_dev, flags, mode, p);
}
return (ENXIO);
}
static int
midiclose(dev_t i_dev, int flags, int mode, struct proc * p)
{
switch (MIDIDEV(i_dev)) {
case MIDI_DEV_MIDIN:
return midi_close(i_dev, flags, mode, p);
case MIDI_DEV_STATUS:
return midistat_close(i_dev, flags, mode, p);
}
return (ENXIO);
}
static int
midiread(dev_t i_dev, struct uio * buf, int flag)
{
switch (MIDIDEV(i_dev)) {
case MIDI_DEV_MIDIN:
return midi_read(i_dev, buf, flag);
case MIDI_DEV_STATUS:
return midistat_read(i_dev, buf, flag);
}
return (ENXIO);
}
static int
midiwrite(dev_t i_dev, struct uio * buf, int flag)
{
switch (MIDIDEV(i_dev)) {
case MIDI_DEV_MIDIN:
return midi_write(i_dev, buf, flag);
}
return (ENXIO);
}
static int
midiioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p)
{
switch (MIDIDEV(i_dev)) {
case MIDI_DEV_MIDIN:
return midi_ioctl(i_dev, cmd, arg, mode, p);
}
return (ENXIO);
}
static int
midipoll(dev_t i_dev, int events, struct proc * p)
{
switch (MIDIDEV(i_dev)) {
case MIDI_DEV_MIDIN:
return midi_poll(i_dev, events, p);
}
return (ENXIO);
}
/*
* Followings are the generic methods in midi drivers.
*/
int
midi_open(dev_t i_dev, int flags, int mode, struct proc * p)
{
int dev, unit, s, ret;
mididev_info *d;
dev = minor(i_dev);
d = get_mididev_info(i_dev, &unit);
DEB(printf("open midi%d subdev %d flags 0x%08x mode 0x%08x\n",
unit, dev & 0xf, flags, mode));
if (d == NULL)
return (ENXIO);
s = splmidi();
/* Mark this device busy. */
device_busy(d->dev);
if ((d->flags & MIDI_F_BUSY) != 0) {
splx(s);
DEB(printf("opl_open: unit %d is busy.\n", unit));
return (EBUSY);
}
d->flags |= MIDI_F_BUSY;
d->flags &= ~(MIDI_F_READING | MIDI_F_WRITING);
d->fflags = flags;
/* Init the queue. */
if ((d->fflags & FREAD) != 0)
midibuf_init(&d->midi_dbuf_in);
if ((d->fflags & FWRITE) != 0) {
midibuf_init(&d->midi_dbuf_out);
midibuf_init(&d->midi_dbuf_passthru);
}
if (d->open == NULL)
ret = 0;
else
ret = d->open(i_dev, flags, mode, p);
splx(s);
return (ret);
}
int
midi_close(dev_t i_dev, int flags, int mode, struct proc * p)
{
int dev, unit, s, ret;
mididev_info *d;
dev = minor(i_dev);
d = get_mididev_info(i_dev, &unit);
DEB(printf("close midi%d subdev %d\n", unit, dev & 0xf));
if (d == NULL)
return (ENXIO);
s = splmidi();
/* Clear the queues. */
if ((d->fflags & FREAD) != 0)
midibuf_init(&d->midi_dbuf_in);
if ((d->fflags & FWRITE) != 0) {
midibuf_init(&d->midi_dbuf_out);
midibuf_init(&d->midi_dbuf_passthru);
}
/* Stop playing and unmark this device busy. */
d->flags &= ~MIDI_F_BUSY;
d->fflags = 0;
device_unbusy(d->dev);
if (d->close == NULL)
ret = 0;
else
ret = d->close(i_dev, flags, mode, p);
splx(s);
return (ret);
}
int
midi_read(dev_t i_dev, struct uio * buf, int flag)
{
int dev, unit, s, len, ret;
mididev_info *d ;
dev = minor(i_dev);
d = get_mididev_info(i_dev, &unit);
DEB(printf("read midi%d subdev %d flag 0x%08x\n", unit, dev & 0xf, flag));
if (d == NULL)
return (ENXIO);
ret = 0;
s = splmidi();
/* Begin recording. */
d->callback(d, MIDI_CB_START | MIDI_CB_RD);
/* Have we got the data to read? */
if ((d->flags & MIDI_F_NBIO) != 0 && d->midi_dbuf_in.rl == 0)
ret = EAGAIN;
else {
len = buf->uio_resid;
ret = midibuf_uioread(&d->midi_dbuf_in, buf, len);
if (ret < 0)
ret = -ret;
else
ret = 0;
}
if (ret == 0 && d->read != NULL)
ret = d->read(i_dev, buf, flag);
splx(s);
return (ret);
}
int
midi_write(dev_t i_dev, struct uio * buf, int flag)
{
int dev, unit, s, len, ret;
mididev_info *d;
dev = minor(i_dev);
d = get_mididev_info(i_dev, &unit);
DEB(printf("write midi%d subdev %d flag 0x%08x\n", unit, dev & 0xf, flag));
if (d == NULL)
return (ENXIO);
ret = 0;
s = splmidi();
/* Begin playing. */
d->callback(d, MIDI_CB_START | MIDI_CB_WR);
/* Have we got the data to write? */
if ((d->flags & MIDI_F_NBIO) != 0 && d->midi_dbuf_out.fl == 0)
ret = EAGAIN;
else {
len = buf->uio_resid;
if (len > d->midi_dbuf_out.fl &&
(d->flags & MIDI_F_NBIO))
len = d->midi_dbuf_out.fl;
ret = midibuf_uiowrite(&d->midi_dbuf_out, buf, len);
if (ret < 0)
ret = -ret;
else
ret = 0;
}
/* Begin playing. */
d->callback(d, MIDI_CB_START | MIDI_CB_WR);
if (ret == 0 && d->write != NULL)
ret = d->write(i_dev, buf, flag);
splx(s);
return (ret);
}
/*
* generic midi ioctl. Functions of the default driver can be
* overridden by the device-specific ioctl call.
* If a device-specific call returns ENOSYS (Function not implemented),
* the default driver is called. Otherwise, the returned value
* is passed up.
*
* The default handler, for many parameters, sets the value in the
* descriptor, sets MIDI_F_INIT, and calls the callback function with
* reason INIT. If successful, the callback returns 1 and the caller
* can update the parameter.
*/
int
midi_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p)
{
int ret = ENOSYS, dev, unit;
mididev_info *d;
struct snd_size *sndsize;
u_long s;
dev = minor(i_dev);
d = get_mididev_info(i_dev, &unit);
if (d == NULL)
return (ENXIO);
if (d->ioctl)
ret = d->ioctl(i_dev, cmd, arg, mode, p);
if (ret != ENOSYS)
return ret;
/*
* pass control to the default ioctl handler. Set ret to 0 now.
*/
ret = 0;
/*
* all routines are called with int. blocked. Make sure that
* ints are re-enabled when calling slow or blocking functions!
*/
s = splmidi();
switch(cmd) {
/*
* we start with the new ioctl interface.
*/
case AIONWRITE: /* how many bytes can write ? */
*(int *)arg = d->midi_dbuf_out.fl;
break;
case AIOSSIZE: /* set the current blocksize */
sndsize = (struct snd_size *)arg;
if (sndsize->play_size <= d->midi_dbuf_out.unit_size && sndsize->rec_size <= d->midi_dbuf_in.unit_size) {
d->flags &= ~MIDI_F_HAS_SIZE;
d->midi_dbuf_out.blocksize = d->midi_dbuf_out.unit_size;
d->midi_dbuf_in.blocksize = d->midi_dbuf_in.unit_size;
}
else {
if (sndsize->play_size > d->midi_dbuf_out.bufsize / 4)
sndsize->play_size = d->midi_dbuf_out.bufsize / 4;
if (sndsize->rec_size > d->midi_dbuf_in.bufsize / 4)
sndsize->rec_size = d->midi_dbuf_in.bufsize / 4;
/* Round up the size to the multiple of EV_SZ. */
d->midi_dbuf_out.blocksize =
((sndsize->play_size + d->midi_dbuf_out.unit_size - 1)
/ d->midi_dbuf_out.unit_size) * d->midi_dbuf_out.unit_size;
d->midi_dbuf_in.blocksize =
((sndsize->rec_size + d->midi_dbuf_in.unit_size - 1)
/ d->midi_dbuf_in.unit_size) * d->midi_dbuf_in.unit_size;
d->flags |= MIDI_F_HAS_SIZE;
}
/* FALLTHROUGH */
case AIOGSIZE: /* get the current blocksize */
sndsize = (struct snd_size *)arg;
sndsize->play_size = d->midi_dbuf_out.blocksize;
sndsize->rec_size = d->midi_dbuf_in.blocksize;
ret = 0;
break;
case AIOSTOP:
if (*(int *)arg == AIOSYNC_PLAY) /* play */
*(int *)arg = d->callback(d, MIDI_CB_STOP | MIDI_CB_WR);
else if (*(int *)arg == AIOSYNC_CAPTURE)
*(int *)arg = d->callback(d, MIDI_CB_STOP | MIDI_CB_RD);
else {
splx(s);
DEB(printf("AIOSTOP: bad channel 0x%x\n", *(int *)arg));
*(int *)arg = 0 ;
}
break ;
case AIOSYNC:
DEB(printf("AIOSYNC chan 0x%03lx pos %lu unimplemented\n",
((snd_sync_parm *)arg)->chan,
((snd_sync_parm *)arg)->pos));
break;
/*
* here follow the standard ioctls (filio.h etc.)
*/
case FIONREAD: /* get # bytes to read */
*(int *)arg = d->midi_dbuf_in.rl;
break;
case FIOASYNC: /*set/clear async i/o */
DEB( printf("FIOASYNC\n") ; )
break;
case FIONBIO: /* set/clear non-blocking i/o */
if ( *(int *)arg == 0 )
d->flags &= ~MIDI_F_NBIO ;
else
d->flags |= MIDI_F_NBIO ;
break ;
case MIOSPASSTHRU: /* set/clear passthru */
if ( *(int *)arg == 0 )
d->flags &= ~MIDI_F_PASSTHRU ;
else
d->flags |= MIDI_F_PASSTHRU ;
/* Init the queue. */
midibuf_init(&d->midi_dbuf_passthru);
/* FALLTHROUGH */
case MIOGPASSTHRU: /* get passthru */
if ((d->flags & MIDI_F_PASSTHRU) != 0)
(int *)arg = 1;
else
(int *)arg = 0;
break ;
default:
DEB(printf("default ioctl midi%d subdev %d fn 0x%08x fail\n",
unit, dev & 0xf, cmd));
ret = EINVAL;
break ;
}
splx(s);
return ret ;
}
int
midi_poll(dev_t i_dev, int events, struct proc * p)
{
int unit, dev, ret, s, lim;
mididev_info *d;
dev = minor(i_dev);
d = get_mididev_info(i_dev, &unit);
if (d == NULL)
return (ENXIO);
if (d->poll)
ret = d->poll(i_dev, events, p);
ret = 0;
s = splmidi();
/* Look up the apropriate queue and select it. */
if ((events & (POLLOUT | POLLWRNORM)) != 0) {
/* Start playing. */
d->callback(d, MIDI_CB_START | MIDI_CB_WR);
/* Find out the boundary. */
if ((d->flags & MIDI_F_HAS_SIZE) != 0)
lim = d->midi_dbuf_out.blocksize;
else
lim = d->midi_dbuf_out.unit_size;
if (d->midi_dbuf_out.fl < lim)
/* No enough space, record select. */
selrecord(p, &d->midi_dbuf_out.sel);
else
/* We can write now. */
ret |= events & (POLLOUT | POLLWRNORM);
}
if ((events & (POLLIN | POLLRDNORM)) != 0) {
/* Start recording. */
d->callback(d, MIDI_CB_START | MIDI_CB_RD);
/* Find out the boundary. */
if ((d->flags & MIDI_F_HAS_SIZE) != 0)
lim = d->midi_dbuf_in.blocksize;
else
lim = d->midi_dbuf_in.unit_size;
if (d->midi_dbuf_in.rl < lim)
/* No data ready, record select. */
selrecord(p, &d->midi_dbuf_in.sel);
else
/* We can write now. */
ret |= events & (POLLIN | POLLRDNORM);
}
splx(s);
return (ret);
}
void
midi_intr(mididev_info *d)
{
if (d->intr != NULL)
d->intr(d->intrarg, d);
}
/*
* These handle the status message of the midi drivers.
*/
int
midistat_open(dev_t i_dev, int flags, int mode, struct proc * p)
{
if (midistatbusy)
return (EBUSY);
bzero(midistatbuf, sizeof(midistatbuf));
midistatptr = 0;
if (midi_initstatus(midistatbuf, sizeof(midistatbuf) - 1))
return (ENOMEM);
midistatbusy = 1;
return (0);
}
int
midistat_close(dev_t i_dev, int flags, int mode, struct proc * p)
{
midistatbusy = 0;
return (0);
}
int
midistat_read(dev_t i_dev, struct uio * buf, int flag)
{
return midi_readstatus(midistatbuf, &midistatptr, buf);
}
/*
* finally, some "libraries"
*/
/* Inits the buffer for /dev/midistat. */
static int
midi_initstatus(char *buf, int size)
{
int i, p;
device_t dev;
mididev_info *md;
p = 0;
p += snprintf(buf, size, "FreeBSD Midi Driver (newmidi) %s %s\nInstalled devices:\n", __DATE__, __TIME__);
for (i = 0 ; i < NMIDI_MAX ; i++) {
md = &midi_info[i];
if (!MIDICONFED(md))
continue;
dev = devclass_get_device(midi_devclass, i);
if (p < size)
p += snprintf(&buf[p], size - p, "midi%d: <%s> %s\n", i, device_get_desc(dev), md->midistat);
else
return (1);
}
return (0);
}
/* Reads the status message. */
static int
midi_readstatus(char *buf, int *ptr, struct uio *uio)
{
int s, len;
s = splmidi();
len = min(uio->uio_resid, strlen(&buf[*ptr]));
if (len > 0) {
uiomove(&buf[*ptr], len, uio);
*ptr += len;
}
splx(s);
return (0);
}

294
sys/dev/sound/midi/midi.h Normal file

@ -0,0 +1,294 @@
/*
* Include file for midi driver.
*
* Copyright by Seigo Tanimura 1999.
*
* 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.
*
* $FreeBSD$
*
*/
/*
* first, include kernel header files.
*/
#ifndef _MIDI_H_
#define _MIDI_H_
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/ioccom.h>
#include <sys/filio.h>
#include <sys/sockio.h>
#include <sys/fcntl.h>
#include <sys/tty.h>
#include <sys/proc.h>
#include <sys/kernel.h> /* for DATA_SET */
#include <sys/module.h>
#include <sys/conf.h>
#include <sys/file.h>
#include <sys/uio.h>
#include <sys/syslog.h>
#include <sys/errno.h>
#include <sys/malloc.h>
#include <sys/bus.h>
#include <machine/clock.h> /* for DELAY */
#include <machine/resource.h>
#include <machine/bus_memio.h>
#include <machine/bus_pio.h>
#include <machine/bus.h>
#include <machine/clock.h> /* for DELAY */
#include <sys/soundcard.h>
#include <sys/rman.h>
#include <sys/mman.h>
#include <sys/poll.h>
#include <dev/sound/midi/miditypes.h>
#include <dev/sound/midi/midibuf.h>
#include <dev/sound/midi/midisynth.h>
#define MIDI_CDEV_MAJOR 30
/*
* descriptor of midi operations ...
*
*/
struct _mididev_info {
/*
* the first part of the descriptor is filled up from a
* template.
*/
char name[64];
int type;
d_open_t *open;
d_close_t *close;
d_read_t *read;
d_write_t *write;
d_ioctl_t *ioctl;
d_poll_t *poll;
midi_callback_t *callback;
/*
* combinations of the following flags are used as second argument in
* the callback from the dma module to the device-specific routines.
*/
#define MIDI_CB_RD 0x100 /* read callback */
#define MIDI_CB_WR 0x200 /* write callback */
#define MIDI_CB_REASON_MASK 0xff
#define MIDI_CB_START 0x01 /* start dma op */
#define MIDI_CB_STOP 0x03 /* stop dma op */
#define MIDI_CB_ABORT 0x04 /* abort dma op */
#define MIDI_CB_INIT 0x05 /* init board parameters */
/*
* callback extensions
*/
#define MIDI_CB_DMADONE 0x10
#define MIDI_CB_DMAUPDATE 0x11
#define MIDI_CB_DMASTOP 0x12
/* init can only be called with int enabled and
* no pending DMA activity.
*/
/*
* whereas from here, parameters are set at runtime.
* resources are stored in the softc of the device,
* not in the common structure.
*/
int unit; /* unit number of the device */
void *softc; /* softc for the device */
device_t dev; /* device_t for the device */
int bd_id ; /* used to hold board-id info, eg. sb version,
* mss codec type, etc. etc.
*/
midi_dbuf midi_dbuf_in; /* midi input event/message queue */
midi_dbuf midi_dbuf_out; /* midi output event/message queue */
midi_dbuf midi_dbuf_passthru; /* midi passthru event/message queue */
/*
* these parameters describe the operation of the board.
* Generic things like busy flag, speed, etc are here.
*/
volatile u_long flags ; /* 32 bits, used for various purposes. */
int fflags; /* file flag */
/*
* we have separate flags for read and write, although in some
* cases this is probably not necessary (e.g. because we cannot
* know how many processes are using the device, we cannot
* distinguish if open, close, abort are for a write or for a
* read).
*/
/*
* the following flag is used by open-close routines
* to mark the status of the device.
*/
#define MIDI_F_BUSY 0x0001 /* has been opened */
/*
* the next two are used to allow only one pending operation of
* each type.
*/
#define MIDI_F_READING 0x0004 /* have a pending read */
#define MIDI_F_WRITING 0x0008 /* have a pending write */
/*
* flag used to mark a pending close.
*/
#define MIDI_F_CLOSING 0x0040 /* a pending close */
/*
* if user has not set block size, then make it adaptive
* (0.25s, or the perhaps last read/write ?)
*/
#define MIDI_F_HAS_SIZE 0x0080 /* user set block size */
/*
* assorted flags related to operating mode.
*/
#define MIDI_F_STEREO 0x0100 /* doing stereo */
#define MIDI_F_NBIO 0x0200 /* do non-blocking i/o */
#define MIDI_F_PASSTHRU 0x0400 /* pass received data to output port */
/*
* these flags mark a pending abort on a r/w operation.
*/
#define MIDI_F_ABORTING 0x1000 /* a pending abort */
/*
* this is used to mark that board initialization is needed, e.g.
* because of a change in sampling rate, format, etc. -- It will
* be done at the next convenient time.
*/
#define MIDI_F_INIT 0x4000 /* changed parameters. need init */
int play_blocksize, rec_blocksize; /* blocksize for io and dma ops */
#define mwsel midi_dbuf_out.sel
#define mrsel midi_dbuf_in.sel
u_long interrupts; /* counter of interrupts */
u_long magic;
#define MAGIC(unit) ( 0xa4d10de0 + unit )
void *device_data ; /* just in case it is needed...*/
midi_intr_t *intr; /* interrupt handler of the upper layer (ie sequencer) */
void *intrarg; /* argument to interrupt handler */
/* The following is the interface from a midi sequencer to a midi device. */
synthdev_info synth;
/* This is the status message to display via /dev/midistat */
char midistat[128];
} ;
/*
* then ioctls and other stuff
*/
#define NMIDI_MAX 64 /* Number of supported devices */
/*
* many variables should be reduced to a range. Here define a macro
*/
#define RANGE(var, low, high) (var) = \
((var)<(low)?(low) : (var)>(high)?(high) : (var))
/*
* convert dev_t to unit and dev
*/
#define MIDIMINOR(x) (minor(x))
#define MIDIUNIT(x) ((MIDIMINOR(x) & 0x000000f0) >> 4)
#define MIDIDEV(x) (MIDIMINOR(x) & 0x0000000f)
#define MIDIMKMINOR(u, d) (((u) & 0x0f) << 4 | ((d) & 0x0f))
#define MIDIMKDEV(m, u, d) (makedev((m), MIDIMKMINOR((u), (d))))
/*
* see if the device is configured
*/
#define MIDICONFED(x) ((x)->ioctl != NULL)
/*
* finally, all default parameters
*/
#define MIDI_BUFFSIZE (4 * 1024) /* XXX */
/*
* some macros for debugging purposes
* DDB/DEB to enable/disable debugging stuff
* BVDDB to enable debugging when bootverbose
*/
#define DDB(x) x /* XXX */
#define BVDDB(x) if (bootverbose) x
#ifndef DEB
#define DEB(x)
#endif
extern mididev_info midi_info[NMIDI_MAX];
extern u_long nmidi;
extern u_long nsynth;
/* This is the generic midi drvier initializer. */
int midiinit(mididev_info *d, device_t dev);
/* This provides an access to the mididev_info. */
mididev_info *get_mididev_info(dev_t i_dev, int *unit);
/* These are the generic methods for a midi driver. */
d_open_t midi_open;
d_close_t midi_close;
d_ioctl_t midi_ioctl;
d_read_t midi_read;
d_write_t midi_write;
d_poll_t midi_poll;
/* Common interrupt handler */
void midi_intr(mididev_info *);
/*
* library functions (in midi.c)
*/
#define splmidi() spltty()
/*
* Minor numbers for the midi driver.
*/
#define MIDI_DEV_MIDIN 2 /* Raw midi access */
#define MIDI_DEV_STATUS 11 /* /dev/midistat */
#endif /* _MIDI_H_ */

@ -0,0 +1,424 @@
/*
* Copyright (C) 1999 Seigo Tanimura
* All rights reserved.
*
* 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.
*
* $FreeBSD$
*
*/
/*
* This file implements a midi event/message queue. A midi
* event/message queue holds midi events and messages to
* transmit to or received from a midi interface.
*/
#include "opt_devfs.h"
#include <dev/sound/midi/midi.h>
/* Some macros to handle the queue. */
#define DATA_AVAIL(dbuf) ((dbuf)->rl)
#define SPACE_AVAIL(dbuf) ((dbuf)->fl)
static void queuerawdata(midi_dbuf *dbuf, char *data, int len);
static void queueuiodata(midi_dbuf *dbuf, struct uio *buf, int len);
static void dequeuerawdata(midi_dbuf *dbuf, char *data, int len);
static void copyrawdata(midi_dbuf *dbuf, char *data, int len);
static void dequeueuiodata(midi_dbuf *dbuf, struct uio *buf, int len);
/*
* Here are the functions to interact to the midi device drivers.
* These are called from midi device driver functions under sys/i386/isa/snd.
*/
int
midibuf_init(midi_dbuf *dbuf)
{
if (dbuf->buf != NULL)
free(dbuf->buf, M_DEVBUF);
dbuf->buf = malloc(MIDI_BUFFSIZE, M_DEVBUF, M_NOWAIT);
bzero(dbuf->buf, MIDI_BUFFSIZE);
dbuf->bufsize = MIDI_BUFFSIZE;
dbuf->rp = dbuf->fp = 0;
dbuf->dl = 0;
dbuf->rl = 0;
dbuf->fl = dbuf->bufsize;
dbuf->int_count = 0;
dbuf->chan = 0;
/*dbuf->unit_size = 1;*/ /* The drivers are responsible. */
bzero(&dbuf->sel, sizeof(dbuf->sel));
dbuf->total = 0;
dbuf->prev_total = 0;
dbuf->blocksize = dbuf->bufsize / 4;
return (0);
}
/* The sequencer calls this function to queue data. */
int
midibuf_seqwrite(midi_dbuf *dbuf, u_char* data, int len)
{
int i, lwrt, lwritten;
/* Is this a real queue? */
if (dbuf == (midi_dbuf *)NULL)
return (0);
lwritten = 0;
/* Write down every single byte. */
while (len > 0) {
/* Find out the number of bytes to write. */
lwrt = SPACE_AVAIL(dbuf);
if (lwrt > len)
lwrt = len;
if (lwrt > 0) {
/* We can write some now. Queue the data. */
queuerawdata(dbuf, data, lwrt);
lwritten += lwrt;
len -= lwrt;
data += lwrt;
}
/* Have we got still more data to write? */
if (len > 0) {
/* Yes, sleep until we have enough space. */
i = tsleep((void *)&dbuf->tsleep_out, PRIBIO | PCATCH, "mbsqwt", 0);
if (i == EINTR || i == ERESTART)
return (-i);
}
}
return (lwritten);
}
/* sndwrite calls this function to queue data. */
int
midibuf_uiowrite(midi_dbuf *dbuf, struct uio *buf, int len)
{
int i, lwrt, lwritten;
/* Is this a real queue? */
if (dbuf == (midi_dbuf *)NULL)
return (0);
lwritten = 0;
/* Write down every single byte. */
while (len > 0) {
/* Find out the number of bytes to write. */
lwrt = SPACE_AVAIL(dbuf);
if (lwrt > len)
lwrt = len;
if (lwrt > 0) {
/* We can write some now. Queue the data. */
queueuiodata(dbuf, buf, lwrt);
lwritten += lwrt;
len -= lwrt;
}
/* Have we got still more data to write? */
if (len > 0) {
/* Yes, sleep until we have enough space. */
i = tsleep(&dbuf->tsleep_out, PRIBIO | PCATCH, "mbuiwt", 0);
if (i == EINTR || i == ERESTART)
return (-i);
}
}
return (lwritten);
}
int
midibuf_output_intr(midi_dbuf *dbuf, u_char *data, int len)
{
int lrd;
/* Is this a real queue? */
if (dbuf == (midi_dbuf *)NULL)
return (0);
/* Have we got any data in the queue? */
if ((lrd = DATA_AVAIL(dbuf)) == 0)
return (0);
/* Dequeue the data. */
if (lrd > len)
lrd = len;
dequeuerawdata(dbuf, data, lrd);
return (lrd);
}
int
midibuf_input_intr(midi_dbuf *dbuf, u_char *data, int len)
{
int lwritten;
/* Is this a real queue? */
if (dbuf == (midi_dbuf *)NULL)
return (0);
lwritten = 0;
/* Have we got any data to write? */
if (len == 0)
return (0);
/* Can we write now? */
if (SPACE_AVAIL(dbuf) < len)
return (-EAGAIN);
/* We can write some now. Queue the data. */
queuerawdata(dbuf, data, len);
lwritten = len;
/* Have we managed to write the whole data? */
if (lwritten < len)
printf("midibuf_input_intr: queue did not have enough space, discarded %d bytes out of %d bytes.\n", len - lwritten, len);
return (lwritten);
}
/* The sequencer calls this function to dequeue data. */
int
midibuf_seqread(midi_dbuf *dbuf, u_char* data, int len)
{
int i, lrd, lread;
/* Is this a real queue? */
if (dbuf == (midi_dbuf *)NULL)
return (0);
lread = 0;
/* Write down every single byte. */
while (len > 0) {
/* Have we got data to read? */
if ((lrd = DATA_AVAIL(dbuf)) == 0) {
/* No, sleep until we have data ready to read. */
i = tsleep(&dbuf->tsleep_in, PRIBIO | PCATCH, "mbsqrd", 0);
if (i == EINTR || i == ERESTART)
return (-i);
if (i == EWOULDBLOCK)
continue;
/* Find out the number of bytes to read. */
lrd = DATA_AVAIL(dbuf);
}
if (lrd > len)
lrd = len;
if (lrd > 0) {
/* We can read some data now. Dequeue the data. */
dequeuerawdata(dbuf, data, lrd);
lread += lrd;
len -= lrd;
data += lrd;
}
}
return (lread);
}
/* The sequencer calls this function to copy data without dequeueing. */
int
midibuf_seqcopy(midi_dbuf *dbuf, u_char* data, int len)
{
int i, lrd, lread;
/* Is this a real queue? */
if (dbuf == (midi_dbuf *)NULL)
return (0);
lread = 0;
/* Write down every single byte. */
while (len > 0) {
/* Have we got data to read? */
if ((lrd = DATA_AVAIL(dbuf)) == 0) {
/* No, sleep until we have data ready to read. */
i = tsleep(&dbuf->tsleep_in, PRIBIO | PCATCH, "mbsqrd", 0);
if (i == EINTR || i == ERESTART)
return (-i);
if (i == EWOULDBLOCK)
continue;
/* Find out the number of bytes to read. */
lrd = DATA_AVAIL(dbuf);
}
if (lrd > len)
lrd = len;
if (lrd > 0) {
/* We can read some data now. Copy the data. */
copyrawdata(dbuf, data, lrd);
lread += lrd;
len -= lrd;
data += lrd;
}
}
return (lread);
}
/* sndread calls this function to dequeue data. */
int
midibuf_uioread(midi_dbuf *dbuf, struct uio *buf, int len)
{
int i, lrd, lread;
/* Is this a real queue? */
if (dbuf == (midi_dbuf *)NULL)
return (0);
lread = 0;
while (len > 0 && lread == 0) {
/* Have we got data to read? */
if ((lrd = DATA_AVAIL(dbuf)) == 0) {
/* No, sleep until we have data ready to read. */
i = tsleep(&dbuf->tsleep_in, PRIBIO | PCATCH, "mbuird", 0);
if (i == EINTR || i == ERESTART)
return (-i);
if (i == EWOULDBLOCK)
continue;
/* Find out the number of bytes to read. */
lrd = DATA_AVAIL(dbuf);
}
if (lrd > len)
lrd = len;
if (lrd > 0) {
/* We can read some data now. Dequeue the data. */
dequeueuiodata(dbuf, buf, lrd);
lread += lrd;
len -= lrd;
}
}
return (lread);
}
/*
* The functions below here are the libraries for the above ones.
*/
static void
queuerawdata(midi_dbuf *dbuf, char *data, int len)
{
/* dbuf->fp might wrap around dbuf->bufsize. */
if (dbuf->bufsize - dbuf->fp < len) {
/* The new data wraps, copy them twice. */
memcpy(dbuf->buf + dbuf->fp, data, dbuf->bufsize - dbuf->fp);
memcpy(dbuf->buf, data + dbuf->bufsize - dbuf->fp, len - (dbuf->bufsize - dbuf->fp));
} else
/* The new data do not wrap, once is enough. */
memcpy(dbuf->buf + dbuf->fp, data, len);
/* Adjust the pointer and the length counters. */
dbuf->fp = (dbuf->fp + len) % dbuf->bufsize;
dbuf->fl -= len;
dbuf->rl += len;
/* Wake up the processes sleeping on input data. */
wakeup(&dbuf->tsleep_in);
if (dbuf->sel.si_pid && dbuf->rl >= dbuf->blocksize)
selwakeup(&dbuf->sel);
}
static void
queueuiodata(midi_dbuf *dbuf, struct uio *buf, int len)
{
/* dbuf->fp might wrap around dbuf->bufsize. */
if (dbuf->bufsize - dbuf->fp < len) {
/* The new data wraps, copy them twice. */
uiomove((caddr_t)(dbuf->buf + dbuf->fp), dbuf->bufsize - dbuf->fp, buf);
uiomove((caddr_t)(dbuf->buf), len - (dbuf->bufsize - dbuf->fp), buf);
} else
/* The new data do not wrap, once is enough. */
uiomove((caddr_t)(dbuf->buf + dbuf->fp), len, buf);
/* Adjust the pointer and the length counters. */
dbuf->fp = (dbuf->fp + len) % dbuf->bufsize;
dbuf->fl -= len;
dbuf->rl += len;
/* Wake up the processes sleeping on queueing. */
wakeup(&dbuf->tsleep_in);
if (dbuf->sel.si_pid && dbuf->rl >= dbuf->blocksize)
selwakeup(&dbuf->sel);
}
static void
dequeuerawdata(midi_dbuf *dbuf, char *data, int len)
{
/* Copy the data. */
copyrawdata(dbuf, data, len);
/* Adjust the pointer and the length counters. */
dbuf->rp = (dbuf->rp + len) % dbuf->bufsize;
dbuf->rl -= len;
dbuf->fl += len;
/* Wake up the processes sleeping on queueing. */
wakeup(&dbuf->tsleep_out);
if (dbuf->sel.si_pid && dbuf->fl >= dbuf->blocksize)
selwakeup(&dbuf->sel);
}
static void
copyrawdata(midi_dbuf *dbuf, char *data, int len)
{
/* dbuf->rp might wrap around dbuf->bufsize. */
if (dbuf->bufsize - dbuf->rp < len) {
/* The data to be read wraps, copy them twice. */
memcpy(data, dbuf->buf + dbuf->rp, dbuf->bufsize - dbuf->rp);
memcpy(data + dbuf->bufsize - dbuf->rp, dbuf->buf, len - (dbuf->bufsize - dbuf->rp));
} else
/* The new data do not wrap, once is enough. */
memcpy(data, dbuf->buf + dbuf->rp, len);
}
static void
dequeueuiodata(midi_dbuf *dbuf, struct uio *buf, int len)
{
/* dbuf->rp might wrap around dbuf->bufsize. */
if (dbuf->bufsize - dbuf->rp < len) {
/* The new data wraps, copy them twice. */
uiomove((caddr_t)(dbuf->buf + dbuf->rp), dbuf->bufsize - dbuf->rp, buf);
uiomove((caddr_t)(dbuf->buf), len - (dbuf->bufsize - dbuf->rp), buf);
} else
/* The new data do not wrap, once is enough. */
uiomove((caddr_t)(dbuf->buf + dbuf->rp), len, buf);
/* Adjust the pointer and the length counters. */
dbuf->rp = (dbuf->rp + len) % dbuf->bufsize;
dbuf->rl -= len;
dbuf->fl += len;
/* Wake up the processes sleeping on queueing. */
wakeup(&dbuf->tsleep_out);
if (dbuf->sel.si_pid && dbuf->fl >= dbuf->blocksize)
selwakeup(&dbuf->sel);
}

@ -0,0 +1,64 @@
/*
* Include file for midi buffer.
*
* Copyright by Seigo Tanimura 1999.
*
* 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.
*
* $FreeBSD$
*
*/
/*
* descriptor of a midi buffer. See midibuf.c for documentation.
* (rp,rl) and (fp,fl) identify the READY and FREE regions of the
* buffer. dl contains the length used for dma transfer, dl>0 also
* means that the channel is busy and there is a DMA transfer in progress.
*/
typedef struct _midi_dbuf {
char *buf;
int bufsize ;
volatile int rp, fp; /* pointers to the ready and free area */
volatile int dl; /* transfer size */
volatile int rl, fl; /* length of ready and free areas. */
int int_count;
int chan; /* dma channel */
int unit_size ; /* unit size */
struct selinfo sel;
u_long total; /* total bytes processed */
u_long prev_total; /* copy of the above when GETxPTR called */
int tsleep_in, tsleep_out; /* pillows to tsleep on */
int blocksize; /* block size */
} midi_dbuf ;
/*
* These are the midi buffer methods, used in midi interface devices.
*/
int midibuf_init(midi_dbuf *dbuf);
int midibuf_seqwrite(midi_dbuf *dbuf, u_char* data, int len);
int midibuf_uiowrite(midi_dbuf *dbuf, struct uio *buf, int len);
int midibuf_output_intr(midi_dbuf *dbuf, u_char *data, int len);
int midibuf_input_intr(midi_dbuf *dbuf, u_char *data, int len);
int midibuf_seqread(midi_dbuf *dbuf, u_char* data, int len);
int midibuf_seqcopy(midi_dbuf *dbuf, u_char* data, int len);
int midibuf_uioread(midi_dbuf *dbuf, struct uio *buf, int len);

@ -0,0 +1,632 @@
/*
* Copyright by Hannu Savolainen 1993
*
* 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.
*
* $FreeBSD$
*
*/
/*
* This is the interface for a sequencer to interact a midi driver.
* This interface translates the sequencer operations to the corresponding
* midi messages, and vice versa.
*/
#include "opt_devfs.h"
#include <stddef.h>
#include <dev/sound/midi/midi.h>
#define TYPEDRANGE(type, x, lower, upper) \
{ \
type tl, tu; \
tl = (lower); \
tu = (upper); \
if (x < tl) { \
x = tl; \
} else if(x > tu) { \
x = tu; \
} \
}
/*
* These functions goes into midisynthdev_op_desc.
*/
static mdsy_killnote_t synth_killnote;
static mdsy_setinstr_t synth_setinstr;
static mdsy_startnote_t synth_startnote;
static mdsy_reset_t synth_reset;
static mdsy_hwcontrol_t synth_hwcontrol;
static mdsy_loadpatch_t synth_loadpatch;
static mdsy_panning_t synth_panning;
static mdsy_aftertouch_t synth_aftertouch;
static mdsy_controller_t synth_controller;
static mdsy_patchmgr_t synth_patchmgr;
static mdsy_bender_t synth_bender;
static mdsy_allocvoice_t synth_allocvoice;
static mdsy_setupvoice_t synth_setupvoice;
static mdsy_sendsysex_t synth_sendsysex;
static mdsy_prefixcmd_t synth_prefixcmd;
static mdsy_volumemethod_t synth_volumemethod;
static mdsy_readraw_t synth_readraw;
static mdsy_writeraw_t synth_writeraw;
/*
* This is the synthdev_info for a midi interface device.
* You may have to replace a few of functions for an internal
* synthesizer.
*/
synthdev_info midisynth_op_desc = {
synth_killnote,
synth_setinstr,
synth_startnote,
synth_reset,
synth_hwcontrol,
synth_loadpatch,
synth_panning,
synth_aftertouch,
synth_controller,
synth_patchmgr,
synth_bender,
synth_allocvoice,
synth_setupvoice,
synth_sendsysex,
synth_prefixcmd,
synth_volumemethod,
synth_readraw,
synth_writeraw,
};
/* The following functions are local. */
static int synth_leavesysex(mididev_info *md);
/*
* Here are the main functions to interact to the midi sequencer.
* These are called from the sequencer functions in sys/i386/isa/snd/sequencer.c.
*/
static int
synth_killnote(mididev_info *md, int chn, int note, int vel)
{
int unit, msg, chp;
synthdev_info *sd;
u_char c[3];
unit = md->unit;
sd = &md->synth;
if (note < 0 || note > 127 || chn < 0 || chn > 15)
return (EINVAL);
TYPEDRANGE(int, vel, 0, 127);
if (synth_leavesysex(md) == EAGAIN)
return (EAGAIN);
msg = sd->prev_out_status & 0xf0;
chp = sd->prev_out_status & 0x0f;
if (chp == chn && ((msg == 0x90 && vel == 64) || msg == 0x80)) {
/* Use running status. */
c[0] = (u_char)note;
if (msg == 0x90)
/* The note was on. */
c[1] = 0;
else
c[1] = (u_char)vel;
if (synth_prefixcmd(md, c[0]))
return (0);
if (md->synth.writeraw(md, c, 2, 1) == EAGAIN)
return (EAGAIN);
} else {
if (vel == 64) {
c[0] = 0x90 | (chn & 0x0f); /* Note on. */
c[1] = (u_char)note;
c[2] = 0;
} else {
c[0] = 0x80 | (chn & 0x0f); /* Note off. */
c[1] = (u_char)note;
c[2] = (u_char)vel;
}
if (synth_prefixcmd(md, c[0]))
return (0);
if (md->synth.writeraw(md, c, 3, 1) == EAGAIN)
return EAGAIN;
/* Update the status. */
sd->prev_out_status = c[0];
}
return (0);
}
static int
synth_setinstr(mididev_info *md, int chn, int instr)
{
int unit;
synthdev_info *sd;
u_char c[2];
unit = md->unit;
sd = &md->synth;
if (instr < 0 || instr > 127 || chn < 0 || chn > 15)
return (EINVAL);
if (synth_leavesysex(md) == EAGAIN)
return (EAGAIN);
c[0] = 0xc0 | (chn & 0x0f); /* Progamme change. */
c[1] = (u_char)instr;
if (md->synth.writeraw(md, c, 3, 1) == EAGAIN)
return (EAGAIN);
/* Update the status. */
sd->prev_out_status = c[0];
return (0);
}
static int
synth_startnote(mididev_info *md, int chn, int note, int vel)
{
int unit, msg, chp;
synthdev_info *sd;
u_char c[3];
unit = md->unit;
sd = &md->synth;
if (note < 0 || note > 127 || chn < 0 || chn > 15)
return (EINVAL);
TYPEDRANGE(int, vel, 0, 127);
if (synth_leavesysex(md) == EAGAIN)
return (EAGAIN);
msg = sd->prev_out_status & 0xf0;
chp = sd->prev_out_status & 0x0f;
if (chp == chn && msg == 0x90) {
/* Use running status. */
c[0] = (u_char)note;
c[1] = (u_char)vel;
if (synth_prefixcmd(md, c[0]))
return (0);
if (md->synth.writeraw(md, c, 2, 1) == EAGAIN)
return (EAGAIN);
} else {
c[0] = 0x90 | (chn & 0x0f); /* Note on. */
c[1] = (u_char)note;
c[2] = (u_char)vel;
if (synth_prefixcmd(md, c[0]))
return (0);
if (md->synth.writeraw(md, c, 3, 1) == EAGAIN)
return (EAGAIN);
/* Update the status. */
sd->prev_out_status = c[0];
}
return (0);
}
static int
synth_reset(mididev_info *md)
{
synth_leavesysex(md);
return (0);
}
static int
synth_hwcontrol(mididev_info *md, u_char *event)
{
/* NOP. */
return (0);
}
static int
synth_loadpatch(mididev_info *md, int format, struct uio *buf, int offs, int count, int pmgr_flag)
{
struct sysex_info sysex;
synthdev_info *sd;
int unit, i, eox_seen, first_byte, left, src_offs, hdr_size;
u_char c[count];
unit = md->unit;
sd = &md->synth;
eox_seen = 0;
first_byte = 1;
hdr_size = offsetof(struct sysex_info, data);
if (synth_leavesysex(md) == EAGAIN)
return (EAGAIN);
if (synth_prefixcmd(md, 0xf0))
return (0);
if (format != SYSEX_PATCH) {
printf("synth_loadpatch: patch format 0x%x is invalid.\n", format);
return (EINVAL);
}
if (count < hdr_size) {
printf("synth_loadpatch: patch header is too short.\n");
return (EINVAL);
}
count -= hdr_size;
/* Copy the patch data. */
if (uiomove((caddr_t)&((char *)&sysex)[offs], hdr_size - offs, buf))
printf("synth_loadpatch: memory mangled?\n");
if (count < sysex.len) {
sysex.len = (long)count;
printf("synth_loadpatch: sysex record of %d bytes is too long, adjusted to %d bytes.\n", (int)sysex.len, count);
}
left = sysex.len;
src_offs = 0;
for (i = 0 ; i < left ; i++) {
uiomove((caddr_t)&c[i], 1, buf);
eox_seen = i > 0 && (c[i] & 0x80) != 0;
if (eox_seen && c[i] != 0xf7)
c[i] = 0xf7;
if (i == 0 && c[i] != 0x80) {
printf("synth_loadpatch: sysex does not begin with the status.\n");
return (EINVAL);
}
if (!first_byte && (c[i] & 0x80) != 0) {
md->synth.writeraw(md, c, i + 1, 0);
/* Update the status. */
sd->prev_out_status = c[i];
return (0);
}
first_byte = 0;
}
if (!eox_seen) {
c[0] = 0xf7;
md->synth.writeraw(md, c, 1, 0);
sd->prev_out_status = c[0];
}
return (0);
}
static int
synth_panning(mididev_info *md, int chn, int pan)
{
/* NOP. */
return (0);
}
static int
synth_aftertouch(mididev_info *md, int chn, int press)
{
int unit, msg, chp;
synthdev_info *sd;
u_char c[2];
unit = md->unit;
sd = &md->synth;
if (press < 0 || press > 127 || chn < 0 || chn > 15)
return (EINVAL);
if (synth_leavesysex(md) == EAGAIN)
return (EAGAIN);
msg = sd->prev_out_status & 0xf0;
chp = sd->prev_out_status & 0x0f;
if (chp == chn && msg == 0xd0) {
/* Use running status. */
c[0] = (u_char)press;
if (synth_prefixcmd(md, c[0]))
return (0);
if (md->synth.writeraw(md, c, 1, 1) == EAGAIN)
return (EAGAIN);
} else {
c[0] = 0xd0 | (chn & 0x0f); /* Channel Pressure. */
c[1] = (u_char)press;
if (synth_prefixcmd(md, c[0]))
return (0);
if (md->synth.writeraw(md, c, 2, 1) == EAGAIN)
return (EAGAIN);
/* Update the status. */
sd->prev_out_status = c[0];
}
return (0);
}
static int
synth_controller(mididev_info *md, int chn, int ctrlnum, int val)
{
int unit, msg, chp;
synthdev_info *sd;
u_char c[3];
unit = md->unit;
sd = &md->synth;
if (ctrlnum < 1 || ctrlnum > 127 || chn < 0 || chn > 15)
return (EINVAL);
if (synth_leavesysex(md) == EAGAIN)
return (EAGAIN);
msg = sd->prev_out_status & 0xf0;
chp = sd->prev_out_status & 0x0f;
if (chp == chn && msg == 0xb0) {
/* Use running status. */
c[0] = (u_char)ctrlnum;
c[1] = (u_char)val & 0x7f;
if (synth_prefixcmd(md, c[0]))
return (0);
if (md->synth.writeraw(md, c, 2, 1) == EAGAIN)
return (EAGAIN);
} else {
c[0] = 0xb0 | (chn & 0x0f); /* Control Message. */
c[1] = (u_char)ctrlnum;
if (synth_prefixcmd(md, c[0]))
return (0);
if (md->synth.writeraw(md, c, 3, 1) == EAGAIN)
return (EAGAIN);
/* Update the status. */
sd->prev_out_status = c[0];
}
return (0);
}
static int
synth_patchmgr(mididev_info *md, struct patmgr_info *rec)
{
return (EINVAL);
}
static int
synth_bender(mididev_info *md, int chn, int val)
{
int unit, msg, chp;
synthdev_info *sd;
u_char c[3];
unit = md->unit;
sd = &md->synth;
if (val < 0 || val > 16383 || chn < 0 || chn > 15)
return (EINVAL);
if (synth_leavesysex(md) == EAGAIN)
return (EAGAIN);
msg = sd->prev_out_status & 0xf0;
chp = sd->prev_out_status & 0x0f;
if (chp == chn && msg == 0xe0) {
/* Use running status. */
c[0] = (u_char)val & 0x7f;
c[1] = (u_char)(val >> 7) & 0x7f;
if (synth_prefixcmd(md, c[0]))
return (0);
if (md->synth.writeraw(md, c, 2, 1) == EAGAIN)
return (EAGAIN);
} else {
c[0] = 0xe0 | (chn & 0x0f); /* Pitch bend. */
c[1] = (u_char)val & 0x7f;
c[2] = (u_char)(val >> 7) & 0x7f;
if (synth_prefixcmd(md, c[0]))
return (0);
if (md->synth.writeraw(md, c, 3, 1) == EAGAIN)
return (EAGAIN);
/* Update the status. */
sd->prev_out_status = c[0];
}
return (0);
}
static int
synth_allocvoice(mididev_info *md, int chn, int note, struct voice_alloc_info *alloc)
{
/* NOP. */
return (0);
}
static int
synth_setupvoice(mididev_info *md, int voice, int chn)
{
/* NOP. */
return (0);
}
static int
synth_sendsysex(mididev_info *md, u_char *sysex, int len)
{
int unit, i, j;
synthdev_info *sd;
u_char c[len];
unit = md->unit;
sd = &md->synth;
for (i = 0 ; i < len ; i++) {
switch (sysex[i]) {
case 0xf0:
/* Sysex begins. */
if (synth_prefixcmd(md, 0xf0))
return (0);
sd->sysex_state = 1;
break;
case 0xf7:
/* Sysex ends. */
if (!sd->sysex_state)
return (0);
sd->sysex_state = 0;
break;
default:
if (!sd->sysex_state)
return (0);
if ((sysex[i] & 0x80) != 0) {
/* A status in a sysex? */
sysex[i] = 0xf7;
sd->sysex_state = 0;
}
break;
}
c[i] = sysex[i];
if (!sd->sysex_state)
break;
}
if (md->synth.writeraw(md, c, i, 1) == EAGAIN)
return (EAGAIN);
/* Update the status. */
for (j = i - 1 ; j >= 0 ; j--)
if ((c[j] & 0x80) != 0) {
sd->prev_out_status = c[j];
break;
}
return (0);
}
static int
synth_prefixcmd(mididev_info *md, int status)
{
/* NOP. */
return (0);
}
static int
synth_volumemethod(mididev_info *md, int mode)
{
/* NOP. */
return (0);
}
static int
synth_readraw(mididev_info *md, u_char *buf, int len, int nonblock)
{
int unit, ret, s;
if (md == NULL)
return (ENXIO);
unit = md->unit;
if (unit >= nmidi + nsynth) {
DEB(printf("synth_readraw: unit %d does not exist.\n", unit));
return (ENXIO);
}
if ((md->fflags & FREAD) == 0) {
DEB(printf("mpu_readraw: unit %d is not for reading.\n", unit));
return (EIO);
}
s = splmidi();
/* Begin recording. */
md->callback(md, MIDI_CB_START | MIDI_CB_RD);
if (nonblock) {
/* Have we got enough data to read? */
if (md->midi_dbuf_in.rl < len)
return (EAGAIN);
}
ret = midibuf_seqread(&md->midi_dbuf_in, buf, len);
splx(s);
if (ret < 0)
ret = -ret;
else
ret = 0;
return (ret);
}
static int
synth_writeraw(mididev_info *md, u_char *buf, int len, int nonblock)
{
int unit, ret, s;
if (md == NULL)
return (ENXIO);
unit = md->unit;
if (unit >= nmidi + nsynth) {
DEB(printf("synth_writeraw: unit %d does not exist.\n", unit));
return (ENXIO);
}
if ((md->fflags & FWRITE) == 0) {
DEB(printf("synth_writeraw: unit %d is not for writing.\n", unit));
return (EIO);
}
/* For nonblocking, have we got enough space to write? */
if (nonblock && md->midi_dbuf_out.fl < len)
return (EAGAIN);
s = splmidi();
ret = midibuf_seqwrite(&md->midi_dbuf_out, buf, len);
if (ret < 0)
ret = -ret;
else
ret = 0;
/* Begin playing. */
md->callback(md, MIDI_CB_START | MIDI_CB_WR);
splx(s);
return (ret);
}
/*
* The functions below here are the libraries for the above ones.
*/
static int
synth_leavesysex(mididev_info *md)
{
int unit;
synthdev_info *sd;
u_char c;
unit = md->unit;
sd = &md->synth;
if (!sd->sysex_state)
return (0);
sd->sysex_state = 0;
c = 0xf7;
if (md->synth.writeraw(md, &c, sizeof(c), 1) == EAGAIN)
return (EAGAIN);
sd->sysex_state = 0;
/* Update the status. */
sd->prev_out_status = c;
return (0);
}

@ -0,0 +1,97 @@
/*
* include file for midi synthesizer interface.
*
* Copyright by Seigo Tanimura 1999.
*
* 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.
*
* $FreeBSD$
*
*/
#define SYNTH_MAX_VOICES 32
/* This is the voice allocation state for a synthesizer. */
struct voice_alloc_info {
int max_voice;
int used_voices;
int ptr; /* For device specific use */
u_short map[SYNTH_MAX_VOICES]; /* (ch << 8) | (note+1) */
int timestamp;
int alloc_times[SYNTH_MAX_VOICES];
};
/* This is the channel information for a synthesizer. */
struct channel_info {
int pgm_num;
int bender_value;
u_char controllers[128];
};
/* These are the function types for a midi synthesizer interface. */
typedef int (mdsy_killnote_t)(mididev_info *md, int chn, int note, int vel);
typedef int (mdsy_setinstr_t)(mididev_info *md, int chn, int instr);
typedef int (mdsy_startnote_t)(mididev_info *md, int chn, int note, int vel);
typedef int (mdsy_reset_t)(mididev_info *md);
typedef int (mdsy_hwcontrol_t)(mididev_info *md, u_char *event);
typedef int (mdsy_loadpatch_t)(mididev_info *md, int format, struct uio *buf, int offs, int count, int pmgr_flag);
typedef int (mdsy_panning_t)(mididev_info *md, int chn, int pan);
typedef int (mdsy_aftertouch_t)(mididev_info *md, int chn, int press);
typedef int (mdsy_controller_t)(mididev_info *md, int chn, int ctrlnum, int val);
typedef int (mdsy_patchmgr_t)(mididev_info *md, struct patmgr_info *rec);
typedef int (mdsy_bender_t)(mididev_info *md, int chn, int val);
typedef int (mdsy_allocvoice_t)(mididev_info *md, int chn, int note, struct voice_alloc_info *alloc);
typedef int (mdsy_setupvoice_t)(mididev_info *md, int voice, int chn);
typedef int (mdsy_sendsysex_t)(mididev_info *md, u_char *sysex, int len);
typedef int (mdsy_prefixcmd_t)(mididev_info *md, int status);
typedef int (mdsy_volumemethod_t)(mididev_info *md, int mode);
typedef int (mdsy_readraw_t)(mididev_info *md, u_char *buf, int len, int nonblock);
typedef int (mdsy_writeraw_t)(mididev_info *md, u_char *buf, int len, int nonblock);
/* This is a midi synthesizer interface and state. */
struct _synthdev_info {
mdsy_killnote_t *killnote;
mdsy_setinstr_t *setinstr;
mdsy_startnote_t *startnote;
mdsy_reset_t *reset;
mdsy_hwcontrol_t *hwcontrol;
mdsy_loadpatch_t *loadpatch;
mdsy_panning_t *panning;
mdsy_aftertouch_t *aftertouch;
mdsy_controller_t *controller;
mdsy_patchmgr_t *patchmgr;
mdsy_bender_t *bender;
mdsy_allocvoice_t *allocvoice;
mdsy_setupvoice_t *setupvoice;
mdsy_sendsysex_t *sendsysex;
mdsy_prefixcmd_t *prefixcmd;
mdsy_volumemethod_t *volumemethod;
mdsy_readraw_t *readraw;
mdsy_writeraw_t *writeraw;
struct voice_alloc_info alloc; /* Voice allocation. */
struct channel_info chn_info[16]; /* Channel information. */
u_char prev_out_status; /* Previous status. */
int sysex_state; /* State of sysex transmission. */
};
typedef struct _synthdev_info synthdev_info;

@ -0,0 +1,34 @@
/*
* Include file for type definitions in midi driver.
*
* Copyright by Seigo Tanimura 1999.
*
* 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.
*
* $FreeBSD$
*
*/
typedef struct _mididev_info mididev_info;
typedef int (midi_callback_t)(mididev_info *d, int reason);
typedef void (midi_intr_t)(void *p, mididev_info *md);

File diff suppressed because it is too large Load Diff

@ -0,0 +1,234 @@
/*
* Include file for midi sequencer driver.
*
* Copyright by Seigo Tanimura 1999.
*
* 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.
*
* $FreeBSD$
*
*/
/*
* first, include kernel header files.
*/
#ifndef _SEQUENCER_H_
#define _SEQUENCER_H_
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/ioccom.h>
#include <sys/filio.h>
#include <sys/sockio.h>
#include <sys/fcntl.h>
#include <sys/tty.h>
#include <sys/proc.h>
#include <sys/kernel.h> /* for DATA_SET */
#include <sys/conf.h>
#include <sys/file.h>
#include <sys/uio.h>
#include <sys/syslog.h>
#include <sys/errno.h>
#include <sys/malloc.h>
#include <machine/clock.h> /* for DELAY */
#include <sys/soundcard.h>
#define SEQ_CDEV_MAJOR MIDI_CDEV_MAJOR
/*
* the following assumes that FreeBSD 3.X uses poll(2) instead of select(2).
* This change dates to late 1997.
*/
#include <sys/poll.h>
#define d_select_t d_poll_t
typedef struct _seqdev_info seqdev_info;
typedef int (seq_callback_t)(seqdev_info *sd, int reason);
/*
* descriptor of sequencer operations ...
*
*/
struct _seqdev_info {
/*
* the first part of the descriptor is filled up from a
* template.
*/
char name[64];
int type ;
d_open_t *open;
d_close_t *close;
d_read_t *read;
d_write_t *write;
d_ioctl_t *ioctl;
d_poll_t *poll;
seq_callback_t *callback;
/*
* combinations of the following flags are used as second argument in
* the callback from the dma module to the device-specific routines.
*/
#define SEQ_CB_RD 0x100 /* read callback */
#define SEQ_CB_WR 0x200 /* write callback */
#define SEQ_CB_REASON_MASK 0xff
#define SEQ_CB_START 0x01 /* start dma op */
#define SEQ_CB_STOP 0x03 /* stop dma op */
#define SEQ_CB_ABORT 0x04 /* abort dma op */
#define SEQ_CB_INIT 0x05 /* init board parameters */
/*
* callback extensions
*/
#define SEQ_CB_DMADONE 0x10
#define SEQ_CB_DMAUPDATE 0x11
#define SEQ_CB_DMASTOP 0x12
/* init can only be called with int enabled and
* no pending DMA activity.
*/
/*
* whereas from here, parameters are set at runtime.
* io_base == 0 means that the board is not configured.
*/
int unit; /* unit number of the device */
void *softc; /* softc for a device */
int bd_id ; /* used to hold board-id info, eg. sb version,
* mss codec type, etc. etc.
*/
midi_dbuf midi_dbuf_in; /* midi input event/message queue */
midi_dbuf midi_dbuf_out; /* midi output event/message queue */
/*
* these parameters describe the operation of the board.
* Generic things like busy flag, speed, etc are here.
*/
volatile u_long flags ; /* 32 bits, used for various purposes. */
/*
* we have separate flags for read and write, although in some
* cases this is probably not necessary (e.g. because we cannot
* know how many processes are using the device, we cannot
* distinguish if open, close, abort are for a write or for a
* read).
*/
/*
* the following flag is used by open-close routines
* to mark the status of the device.
*/
#define SEQ_F_BUSY 0x0001 /* has been opened */
/*
* the next two are used to allow only one pending operation of
* each type.
*/
#define SEQ_F_READING 0x0004 /* have a pending read */
#define SEQ_F_WRITING 0x0008 /* have a pending write */
/*
* flag used to mark a pending close.
*/
#define SEQ_F_CLOSING 0x0040 /* a pending close */
/*
* if user has not set block size, then make it adaptive
* (0.25s, or the perhaps last read/write ?)
*/
#define SEQ_F_HAS_SIZE 0x0080 /* user set block size */
/*
* assorted flags related to operating mode.
*/
#define SEQ_F_STEREO 0x0100 /* doing stereo */
#define SEQ_F_NBIO 0x0200 /* do non-blocking i/o */
/*
* these flags mark a pending abort on a r/w operation.
*/
#define SEQ_F_ABORTING 0x1000 /* a pending abort */
/*
* this is used to mark that board initialization is needed, e.g.
* because of a change in sampling rate, format, etc. -- It will
* be done at the next convenient time.
*/
#define SEQ_F_INIT 0x4000 /* changed parameters. need init */
int play_blocksize, rec_blocksize; /* blocksize for io and dma ops */
#define swsel midi_dbuf_out.sel
#define srsel midi_dbuf_in.sel
u_long interrupts; /* counter of interrupts */
u_long magic;
#define MAGIC(unit) ( 0xa4d10de0 + unit )
void *device_data ; /* just in case it is needed...*/
} ;
/*
* then ioctls and other stuff
*/
#define NSEQ_MAX 64 /* Number of supported devices */
/*
* many variables should be reduced to a range. Here define a macro
*/
#define RANGE(var, low, high) (var) = \
((var)<(low)?(low) : (var)>(high)?(high) : (var))
/*
* finally, all default parameters
*/
#define SEQ_BUFFSIZE (4 * 1024) /* XXX */
/*
* some macros for debugging purposes
* DDB/DEB to enable/disable debugging stuff
* BVDDB to enable debugging when bootverbose
*/
#define DDB(x) x /* XXX */
#define BVDDB(x) if (bootverbose) x
#ifndef DEB
#define DEB(x)
#endif
extern seqdev_info seq_info[NSEQ_MAX] ;
#define MIDI_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM
synthesizer and MIDI output) */
#endif /* _SEQUENCER_H_ */

@ -59,11 +59,9 @@ struct csa_softc {
device_t pcm; /* pcm device */
driver_intr_t* pcmintr; /* pcm intr */
void *pcmintr_arg; /* pcm intr arg */
#if notyet
device_t midi; /* midi device */
driver_intr_t* midiintr; /* midi intr */
void *midiintr_arg; /* midi intr arg */
#endif /* notyet */
void *ih; /* cookie */
struct csa_bridgeinfo binfo; /* The state of this bridge. */
@ -198,7 +196,6 @@ csa_attach(device_t dev)
scp->pcm = device_add_child(dev, "pcm", -1);
device_set_ivars(scp->pcm, func);
#if notyet
/* Midi Interface */
func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT);
if (func == NULL)
@ -208,7 +205,6 @@ csa_attach(device_t dev)
func->func = SCF_MIDI;
scp->midi = device_add_child(dev, "midi", -1);
device_set_ivars(scp->midi, func);
#endif /* notyet */
bus_generic_attach(dev);
@ -292,12 +288,10 @@ csa_setup_intr(device_t bus, device_t child,
scp->pcmintr_arg = arg;
break;
#if notyet
case SCF_MIDI:
scp->midiintr = intr;
scp->midiintr_arg = arg;
break;
#endif /* notyet */
default:
return (EINVAL);
@ -334,12 +328,10 @@ csa_teardown_intr(device_t bus, device_t child,
scp->pcmintr_arg = NULL;
break;
#if notyet
case SCF_MIDI:
scp->midiintr = NULL;
scp->midiintr_arg = NULL;
break;
#endif /* notyet */
default:
return (EINVAL);
@ -375,10 +367,8 @@ csa_intr(void *arg)
/* Invoke the handlers of the children. */
if ((hisr & (HISR_VC0 | HISR_VC1)) != 0 && scp->pcmintr != NULL)
scp->pcmintr(scp->pcmintr_arg);
#if notyet
if ((hisr & HISR_MIDI) != 0 && scp->midiintr != NULL)
scp->midiintr(scp->midiintr_arg);
#endif /* notyet */
/* Throw an eoi. */
csa_writeio(resp, BA0_HICR, HICR_IEV | HICR_CHGM);

554
sys/dev/sound/pci/csamidi.c Normal file

@ -0,0 +1,554 @@
/*-
* Copyright (c) 1999 Seigo Tanimura
* All rights reserved.
*
* 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.
*
* $FreeBSD$
*/
#include "opt_devfs.h"
#include <dev/sound/midi/midi.h>
#include <dev/sound/chip.h>
#include <dev/sound/pci/csareg.h>
#include <machine/cpufunc.h>
static devclass_t midi_devclass;
#ifndef DDB
#undef DDB
#define DDB(x)
#endif /* DDB */
#define CSAMIDI_RESET 0xff
#define CSAMIDI_UART 0x3f
#define CSAMIDI_ACK 0xfe
#define CSAMIDI_STATMASK 0xc0
#define CSAMIDI_OUTPUTBUSY 0x40
#define CSAMIDI_INPUTBUSY 0x80
#define CSAMIDI_TRYDATA 50
#define CSAMIDI_DELAY 25000
extern synthdev_info midisynth_op_desc;
/* These are the synthesizer and the midi interface information. */
static struct synth_info csamidi_synthinfo = {
"CS461x MIDI",
0,
SYNTH_TYPE_MIDI,
0,
0,
128,
128,
128,
SYNTH_CAP_INPUT,
};
static struct midi_info csamidi_midiinfo = {
"CS461x MIDI",
0,
0,
0,
};
/*
* These functions goes into csamidi_op_desc to get called
* from sound.c.
*/
static int csamidi_probe(device_t dev);
static int csamidi_attach(device_t dev);
static d_ioctl_t csamidi_ioctl;
static driver_intr_t csamidi_intr;
static midi_callback_t csamidi_callback;
/* Here is the parameter structure per a device. */
struct csamidi_softc {
device_t dev; /* device information */
mididev_info *devinfo; /* midi device information */
struct csa_bridgeinfo *binfo; /* The state of the parent. */
struct resource *io; /* Base of io map */
int io_rid; /* Io map resource ID */
struct resource *mem; /* Base of memory map */
int mem_rid; /* Memory map resource ID */
struct resource *irq; /* Irq */
int irq_rid; /* Irq resource ID */
void *ih; /* Interrupt cookie */
int fflags; /* File flags */
};
typedef struct csamidi_softc *sc_p;
/* These functions are local. */
static void csamidi_startplay(sc_p scp);
static void csamidi_xmit(sc_p scp);
static int csamidi_reset(sc_p scp);
static int csamidi_status(sc_p scp);
static int csamidi_command(sc_p scp, u_int32_t value);
static int csamidi_readdata(sc_p scp);
static int csamidi_writedata(sc_p scp, u_int32_t value);
static u_int32_t csamidi_readio(sc_p scp, u_long offset);
static void csamidi_writeio(sc_p scp, u_long offset, u_int32_t data);
static u_int32_t csamidi_readmem(sc_p scp, u_long offset);
static void csamidi_writemem(sc_p scp, u_long offset, u_int32_t data);
static int csamidi_allocres(sc_p scp, device_t dev);
static void csamidi_releaseres(sc_p scp, device_t dev);
/*
* This is the device descriptor for the midi device.
*/
static mididev_info csamidi_op_desc = {
"CS461x midi",
SNDCARD_MPU401,
NULL,
NULL,
NULL,
NULL,
csamidi_ioctl,
NULL,
csamidi_callback,
MIDI_BUFFSIZE, /* Queue Length */
0, /* XXX This is not an *audio* device! */
};
/*
* Here are the main functions to interact to the user process.
*/
static int
csamidi_probe(device_t dev)
{
char *s;
sc_p scp;
struct sndcard_func *func;
/* The parent device has already been probed. */
func = device_get_ivars(dev);
if (func == NULL || func->func != SCF_MIDI)
return (ENXIO);
s = "CS461x Midi Interface";
scp = device_get_softc(dev);
bzero(scp, sizeof(*scp));
scp->io_rid = CS461x_IO_OFFSET;
scp->mem_rid = CS461x_MEM_OFFSET;
scp->irq_rid = 0;
device_set_desc(dev, s);
return (0);
}
static int
csamidi_attach(device_t dev)
{
sc_p scp;
mididev_info *devinfo;
struct sndcard_func *func;
int unit;
scp = device_get_softc(dev);
unit = device_get_unit(dev);
func = device_get_ivars(dev);
scp->binfo = func->varinfo;
/* Allocate the resources. */
if (csamidi_allocres(scp, dev)) {
csamidi_releaseres(scp, dev);
return (ENXIO);
}
/* Fill the softc. */
scp->dev = dev;
scp->devinfo = devinfo = &midi_info[unit];
/* Fill the midi info. */
bcopy(&csamidi_op_desc, devinfo, sizeof(csamidi_op_desc));
midiinit(devinfo, dev);
devinfo->flags = 0;
bcopy(&midisynth_op_desc, &devinfo->synth, sizeof(midisynth_op_desc));
snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at irq %d",
(int)rman_get_start(scp->irq));
/* Init the queue. */
devinfo->midi_dbuf_in.unit_size = devinfo->midi_dbuf_out.unit_size = 1;
midibuf_init(&devinfo->midi_dbuf_in);
midibuf_init(&devinfo->midi_dbuf_out);
/* Increase the number of midi devices. */
nmidi++;
/* Enable interrupt. */
if (bus_setup_intr(dev, scp->irq, INTR_TYPE_TTY, csamidi_intr, scp, &scp->ih)) {
csamidi_releaseres(scp, dev);
return (ENXIO);
}
/* Reset the interface. */
csamidi_reset(scp);
return (0);
}
static int
csamidi_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc *p)
{
sc_p scp;
mididev_info *devinfo;
int unit;
struct synth_info *synthinfo;
struct midi_info *midiinfo;
unit = MIDIUNIT(i_dev);
if (unit >= nmidi + nsynth) {
DEB(printf("csamidi_ioctl: unit %d does not exist.\n", unit));
return (ENXIO);
}
devinfo = get_mididev_info(i_dev, &unit);
if (devinfo == NULL) {
DEB(printf("csamidi_ioctl: unit %d is not configured.\n", unit));
return (ENXIO);
}
scp = devinfo->softc;
switch (cmd) {
case SNDCTL_SYNTH_INFO:
synthinfo = (struct synth_info *)arg;
if (synthinfo->device > nmidi + nsynth || synthinfo->device != unit)
return (ENXIO);
bcopy(&csamidi_synthinfo, synthinfo, sizeof(csamidi_synthinfo));
synthinfo->device = unit;
return (0);
break;
case SNDCTL_MIDI_INFO:
midiinfo = (struct midi_info *)arg;
if (midiinfo->device > nmidi + nsynth || midiinfo->device != unit)
return (ENXIO);
bcopy(&csamidi_midiinfo, midiinfo, sizeof(csamidi_midiinfo));
midiinfo->device = unit;
return (0);
break;
default:
return (ENOSYS);
}
/* NOTREACHED */
return (EINVAL);
}
static void
csamidi_intr(void *arg)
{
sc_p scp;
u_char c;
mididev_info *devinfo;
scp = (sc_p)arg;
devinfo = scp->devinfo;
/* Read the received data. */
while ((csamidi_status(scp) & MIDSR_RBE) == 0) {
/* Receive the data. */
c = (u_char)csamidi_readdata(scp);
/* Queue into the passthru buffer and start transmitting if we can. */
if ((devinfo->flags & MIDI_F_PASSTHRU) != 0 && ((devinfo->flags & MIDI_F_BUSY) == 0 || (devinfo->fflags & FWRITE) == 0)) {
midibuf_input_intr(&devinfo->midi_dbuf_passthru, &c, sizeof(c));
devinfo->callback(devinfo, MIDI_CB_START | MIDI_CB_WR);
}
/* Queue if we are reading. Discard an active sensing. */
if ((devinfo->flags & MIDI_F_READING) != 0 && c != 0xfe)
midibuf_input_intr(&devinfo->midi_dbuf_in, &c, sizeof(c));
}
/* Transmit out data. */
if ((devinfo->flags & MIDI_F_WRITING) != 0 && (csamidi_status(scp) & MIDSR_TBF) == 0)
csamidi_xmit(scp);
/* Invoke the upper layer. */
midi_intr(devinfo);
}
static int
csamidi_callback(mididev_info *d, int reason)
{
int unit;
sc_p scp;
if (d == NULL) {
DEB(printf("csamidi_callback: device not configured.\n"));
return (ENXIO);
}
unit = d->unit;
scp = d->softc;
switch (reason & MIDI_CB_REASON_MASK) {
case MIDI_CB_START:
if ((reason & MIDI_CB_RD) != 0 && (d->flags & MIDI_F_READING) == 0)
/* Begin recording. */
d->flags |= MIDI_F_READING;
if ((reason & MIDI_CB_WR) != 0 && (d->flags & MIDI_F_WRITING) == 0)
/* Start playing. */
csamidi_startplay(scp);
break;
case MIDI_CB_STOP:
case MIDI_CB_ABORT:
if ((reason & MIDI_CB_RD) != 0 && (d->flags & MIDI_F_READING) != 0)
/* Stop recording. */
d->flags &= ~MIDI_F_READING;
if ((reason & MIDI_CB_WR) != 0 && (d->flags & MIDI_F_WRITING) != 0)
/* Stop Playing. */
d->flags &= ~MIDI_F_WRITING;
break;
}
return (0);
}
/*
* The functions below here are the libraries for the above ones.
*/
/*
* Starts to play the data in the output queue.
* Call this at >=splclock.
*/
static void
csamidi_startplay(sc_p scp)
{
mididev_info *devinfo;
devinfo = scp->devinfo;
/* Can we play now? */
if (devinfo->midi_dbuf_out.rl == 0)
return;
devinfo->flags |= MIDI_F_WRITING;
csamidi_xmit(scp);
}
static void
csamidi_xmit(sc_p scp)
{
register mididev_info *devinfo;
register midi_dbuf *dbuf;
u_char c;
devinfo = scp->devinfo;
/* See which source to use. */
if ((devinfo->flags & MIDI_F_PASSTHRU) == 0 || ((devinfo->flags & MIDI_F_BUSY) != 0 && (devinfo->fflags & FWRITE) != 0))
dbuf = &devinfo->midi_dbuf_out;
else
dbuf = &devinfo->midi_dbuf_passthru;
/* Transmit the data in the queue. */
while ((devinfo->flags & MIDI_F_WRITING) != 0 && (csamidi_status(scp) & MIDSR_TBF) == 0) {
/* Do we have the data to transmit? */
if (dbuf->rl == 0) {
/* Stop playing. */
devinfo->flags &= ~MIDI_F_WRITING;
break;
} else {
/* Send the data. */
midibuf_output_intr(dbuf, &c, sizeof(c));
csamidi_writedata(scp, c);
/* We are playing now. */
devinfo->flags |= MIDI_F_WRITING;
}
}
}
/* Reset midi. */
static int
csamidi_reset(sc_p scp)
{
int i, resp;
/* Reset the midi. */
resp = 0;
for (i = 0 ; i < CSAMIDI_TRYDATA ; i++) {
resp = csamidi_command(scp, MIDCR_MRST);
if (resp == 0)
break;
}
if (resp != 0)
return (1);
for (i = 0 ; i < CSAMIDI_TRYDATA ; i++) {
resp = csamidi_command(scp, MIDCR_TXE | MIDCR_RXE | MIDCR_RIE | MIDCR_TIE);
if (resp == 0)
break;
}
if (resp != 0)
return (1);
DELAY(CSAMIDI_DELAY);
return (0);
}
/* Reads the status. */
static int
csamidi_status(sc_p scp)
{
return csamidi_readio(scp, BA0_MIDSR);
}
/* Writes a command. */
static int
csamidi_command(sc_p scp, u_int32_t value)
{
csamidi_writeio(scp, BA0_MIDCR, value);
return (0);
}
/* Reads a byte of data. */
static int
csamidi_readdata(sc_p scp)
{
u_int status;
/* Is the interface ready to read? */
status = csamidi_status(scp);
if ((status & MIDSR_RBE) != 0)
/* The interface is busy. */
return (-EAGAIN);
return (int)csamidi_readio(scp, BA0_MIDRP) & 0xff;
}
/* Writes a byte of data. */
static int
csamidi_writedata(sc_p scp, u_int32_t value)
{
u_int status;
/* Is the interface ready to write? */
status = csamidi_status(scp);
if ((status & MIDSR_TBF) != 0)
/* The interface is busy. */
return (EAGAIN);
csamidi_writeio(scp, BA0_MIDWP, value & 0xff);
return (0);
}
static u_int32_t
csamidi_readio(sc_p scp, u_long offset)
{
if (offset < BA0_AC97_RESET)
return bus_space_read_4(rman_get_bustag(scp->io), rman_get_bushandle(scp->io), offset) & 0xffffffff;
else
return (0);
}
static void
csamidi_writeio(sc_p scp, u_long offset, u_int32_t data)
{
if (offset < BA0_AC97_RESET)
bus_space_write_4(rman_get_bustag(scp->io), rman_get_bushandle(scp->io), offset, data);
}
static u_int32_t
csamidi_readmem(sc_p scp, u_long offset)
{
return bus_space_read_4(rman_get_bustag(scp->mem), rman_get_bushandle(scp->mem), offset) & 0xffffffff;
}
static void
csamidi_writemem(sc_p scp, u_long offset, u_int32_t data)
{
bus_space_write_4(rman_get_bustag(scp->mem), rman_get_bushandle(scp->mem), offset, data);
}
/* Allocates resources. */
static int
csamidi_allocres(sc_p scp, device_t dev)
{
if (scp->io == NULL) {
scp->io = bus_alloc_resource(dev, SYS_RES_MEMORY, &scp->io_rid, 0, ~0, CS461x_IO_SIZE, RF_ACTIVE);
if (scp->io == NULL)
return (1);
}
if (scp->mem == NULL) {
scp->mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &scp->mem_rid, 0, ~0, CS461x_MEM_SIZE, RF_ACTIVE);
if (scp->mem == NULL)
return (1);
}
if (scp->irq == NULL) {
scp->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &scp->irq_rid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
if (scp->irq == NULL)
return (1);
}
return (0);
}
/* Releases resources. */
static void
csamidi_releaseres(sc_p scp, device_t dev)
{
if (scp->irq != NULL) {
bus_release_resource(dev, SYS_RES_IRQ, scp->irq_rid, scp->irq);
scp->irq = NULL;
}
if (scp->io != NULL) {
bus_release_resource(dev, SYS_RES_MEMORY, scp->io_rid, scp->io);
scp->io = NULL;
}
if (scp->mem != NULL) {
bus_release_resource(dev, SYS_RES_MEMORY, scp->mem_rid, scp->mem);
scp->mem = NULL;
}
}
static device_method_t csamidi_methods[] = {
/* Device interface */
DEVMETHOD(device_probe , csamidi_probe ),
DEVMETHOD(device_attach, csamidi_attach),
{ 0, 0 },
};
static driver_t csamidi_driver = {
"midi",
csamidi_methods,
sizeof(struct csamidi_softc),
};
DRIVER_MODULE(csamidi, csa, csamidi_driver, midi_devclass, 0, 0);

@ -32,6 +32,7 @@ static u_int16_t snd_mixerdefaults[SOUND_MIXER_NRDEVICES] = {
[SOUND_MIXER_VOLUME] = 75,
[SOUND_MIXER_BASS] = 50,
[SOUND_MIXER_TREBLE] = 50,
[SOUND_MIXER_SYNTH] = 75,
[SOUND_MIXER_PCM] = 75,
[SOUND_MIXER_SPEAKER] = 75,
[SOUND_MIXER_LINE] = 75,

@ -1649,8 +1649,32 @@ hint.pcm.0.flags="0x0"
# For PnP/PCI sound cards, no hints are required.
#
# midi: MIDI interfaces and synthesizers
#
device midi
# For non-pnp sound cards with no bridge drivers:
hint.midi.0.at="isa"
hint.midi.0.irq="5"
hint.midi.0.flags="0x0"
# For serial ports (this example configures port 2):
# TODO: implement generic tty-midi interface so that we can use
# other uarts.
hint.midi.0.at="isa"
hint.midi.0.port="0x2F8"
hint.midi.0.irq="3"
#
# seq: MIDI sequencer
#
device seq
# The bridge drivers for sound cards. These can be seperately configured
# for providing services to the likes of new-midi (not in the tree yet).
# for providing services to the likes of new-midi.
# When used with 'device pcm' they also provide pcm sound services.
#
# sbc: Creative SoundBlaster ISA PnP/non-PnP

@ -588,7 +588,8 @@ pnpbios_identify(driver_t *driver, device_t parent)
isa_set_logicalid(dev, pd->devid);
ISA_SET_CONFIG_CALLBACK(parent, dev, pnpbios_set_config, 0);
pnp_parse_resources(dev, &pd->devdata[0],
pd->size - sizeof(struct pnp_sysdev));
pd->size - sizeof(struct pnp_sysdev),
isa_get_vendorid(dev), isa_get_logicalid(dev), 0);
if (!device_get_desc(dev))
device_set_desc_copy(dev, pnp_eisaformat(pd->devid));

@ -54,6 +54,7 @@ struct pnp_quirk {
u_int32_t logical_id; /* ID of the device with quirk */
int type;
#define PNP_QUIRK_WRITE_REG 1 /* Need to write a pnp register */
#define PNP_QUIRK_EXTRA_IO 2 /* Has extra io ports */
int arg1;
int arg2;
};
@ -66,6 +67,24 @@ struct pnp_quirk pnp_quirks[] = {
*/
{ 0x0100561e /* GRV0001 */, 0,
PNP_QUIRK_WRITE_REG, 0xf2, 0xff },
/*
* An emu8000 does not give us other than the first
* port.
*/
{ 0x26008c0e /* SB16 */, 0x21008c0e,
PNP_QUIRK_EXTRA_IO, 0x400, 0x800 },
{ 0x42008c0e /* SB32(CTL0042) */, 0x21008c0e,
PNP_QUIRK_EXTRA_IO, 0x400, 0x800 },
{ 0x44008c0e /* SB32(CTL0044) */, 0x21008c0e,
PNP_QUIRK_EXTRA_IO, 0x400, 0x800 },
{ 0x49008c0e /* SB32(CTL0049) */, 0x21008c0e,
PNP_QUIRK_EXTRA_IO, 0x400, 0x800 },
{ 0xf1008c0e /* SB32(CTL00f1) */, 0x21008c0e,
PNP_QUIRK_EXTRA_IO, 0x400, 0x800 },
{ 0xc1008c0e /* SB64(CTL00c1) */, 0x22008c0e,
PNP_QUIRK_EXTRA_IO, 0x400, 0x800 },
{ 0xe4008c0e /* SB64(CTL00e4) */, 0x22008c0e,
PNP_QUIRK_EXTRA_IO, 0x400, 0x800 },
{ 0 }
};
@ -363,8 +382,8 @@ pnp_set_config(void *arg, struct isa_config *config, int enable)
/*
* Process quirks for a logical device.. The card must be in Config state.
*/
static void
pnp_check_quirks(u_int32_t vendor_id, u_int32_t logical_id, int ldn)
void
pnp_check_quirks(u_int32_t vendor_id, u_int32_t logical_id, int ldn, struct isa_config *config)
{
struct pnp_quirk *qp;
@ -377,6 +396,22 @@ pnp_check_quirks(u_int32_t vendor_id, u_int32_t logical_id, int ldn)
pnp_write(PNP_SET_LDN, ldn);
pnp_write(qp->arg1, qp->arg2);
break;
case PNP_QUIRK_EXTRA_IO:
if (config == NULL)
break;
if (qp->arg1 != 0) {
config->ic_nport++;
config->ic_port[config->ic_nport - 1] = config->ic_port[0];
config->ic_port[config->ic_nport - 1].ir_start += qp->arg1;
config->ic_port[config->ic_nport - 1].ir_end += qp->arg1;
}
if (qp->arg2 != 0) {
config->ic_nport++;
config->ic_port[config->ic_nport - 1] = config->ic_port[0];
config->ic_port[config->ic_nport - 1].ir_start += qp->arg2;
config->ic_port[config->ic_nport - 1].ir_end += qp->arg2;
}
break;
}
}
}
@ -461,7 +496,8 @@ pnp_create_devices(device_t parent, pnp_id *p, int csn,
*/
if (startres) {
pnp_parse_resources(dev, startres,
resinfo - startres - 1);
resinfo - startres - 1,
p->vendor_id, logical_id, ldn);
dev = 0;
startres = 0;
}
@ -471,7 +507,7 @@ pnp_create_devices(device_t parent, pnp_id *p, int csn,
* resources.
*/
bcopy(resinfo, &logical_id, 4);
pnp_check_quirks(p->vendor_id, logical_id, ldn);
pnp_check_quirks(p->vendor_id, logical_id, ldn, NULL);
compat_id = 0;
dev = BUS_ADD_CHILD(parent, ISA_ORDER_PNP, NULL, -1);
if (desc)
@ -502,7 +538,8 @@ pnp_create_devices(device_t parent, pnp_id *p, int csn,
break;
}
pnp_parse_resources(dev, startres,
resinfo - startres - 1);
resinfo - startres - 1,
p->vendor_id, logical_id, ldn);
dev = 0;
startres = 0;
scanning = 0;

@ -47,7 +47,7 @@
* Resource Data or it reaches the end of Resource Data.
*/
void
pnp_parse_resources(device_t dev, u_char *resources, int len)
pnp_parse_resources(device_t dev, u_char *resources, int len, u_int32_t vendor_id, u_int32_t logical_id, int ldn)
{
device_t parent = device_get_parent(dev);
u_char tag, *resp, *resinfo;
@ -189,6 +189,9 @@ pnp_parse_resources(device_t dev, u_char *resources, int len)
config->ic_port[config->ic_nport].ir_align =
resinfo[5];
config->ic_nport++;
pnp_check_quirks(vendor_id,
logical_id,
ldn, config);
break;
case PNP_TAG_IO_FIXED:

@ -53,7 +53,9 @@ u_char pnp_read(int d); /* currently unused, but who knows... */
| (PNP_HEXTONUM(s[5]) << 28))
char *pnp_eisaformat(u_int32_t id);
void pnp_parse_resources(device_t dev, u_char *resources, int len);
void pnp_parse_resources(device_t dev, u_char *resources, int len, u_int32_t vendor_id, u_int32_t logical_id, int ldn);
void pnp_check_quirks(u_int32_t vendor_id, u_int32_t logical_id, int ldn, struct isa_config *config);
#endif /* _KERNEL */

@ -91,6 +91,8 @@
#define SNDCARD_PSEUDO_MSS 24
#define SNDCARD_AWE32 25
#define SNDCARD_NSS 26
#define SNDCARD_UART16550 27
#define SNDCARD_OPL 28
#include <sys/types.h>
#ifndef _IOWR
@ -704,6 +706,8 @@ typedef struct {
#define SNDCTL_MIDI_PRETIME _IOWR('m', 0, int)
#define SNDCTL_MIDI_MPUMODE _IOWR('m', 1, int)
#define SNDCTL_MIDI_MPUCMD _IOWR('m', 2, mpu_command_rec)
#define MIOSPASSTHRU _IOWR('m', 3, int)
#define MIOGPASSTHRU _IOWR('m', 4, int)
/*
* IOCTL commands for /dev/dsp and /dev/audio